1 /* $NetBSD: sshfp_44.c,v 1.11 2025/01/26 16:25:33 christos Exp $ */ 2 3 /* 4 * Copyright (C) Internet Systems Consortium, Inc. ("ISC") 5 * 6 * SPDX-License-Identifier: MPL-2.0 7 * 8 * This Source Code Form is subject to the terms of the Mozilla Public 9 * License, v. 2.0. If a copy of the MPL was not distributed with this 10 * file, you can obtain one at https://mozilla.org/MPL/2.0/. 11 * 12 * See the COPYRIGHT file distributed with this work for additional 13 * information regarding copyright ownership. 14 */ 15 16 /* RFC 4255 */ 17 18 #ifndef RDATA_GENERIC_SSHFP_44_C 19 #define RDATA_GENERIC_SSHFP_44_C 20 21 #define RRTYPE_SSHFP_ATTRIBUTES (0) 22 23 static isc_result_t 24 fromtext_sshfp(ARGS_FROMTEXT) { 25 isc_token_t token; 26 int len = -1; 27 28 REQUIRE(type == dns_rdatatype_sshfp); 29 30 UNUSED(type); 31 UNUSED(rdclass); 32 UNUSED(origin); 33 UNUSED(options); 34 UNUSED(callbacks); 35 36 /* 37 * Algorithm. 38 */ 39 RETERR(isc_lex_getmastertoken(lexer, &token, isc_tokentype_number, 40 false)); 41 if (token.value.as_ulong > 0xffU) { 42 RETTOK(ISC_R_RANGE); 43 } 44 RETERR(uint8_tobuffer(token.value.as_ulong, target)); 45 46 /* 47 * Digest type. 48 */ 49 RETERR(isc_lex_getmastertoken(lexer, &token, isc_tokentype_number, 50 false)); 51 if (token.value.as_ulong > 0xffU) { 52 RETTOK(ISC_R_RANGE); 53 } 54 RETERR(uint8_tobuffer(token.value.as_ulong, target)); 55 56 /* 57 * Enforce known digest lengths. 58 */ 59 switch (token.value.as_ulong) { 60 case 1: 61 len = ISC_SHA1_DIGESTLENGTH; 62 break; 63 case 2: 64 len = ISC_SHA256_DIGESTLENGTH; 65 break; 66 default: 67 break; 68 } 69 70 /* 71 * Digest. 72 */ 73 return isc_hex_tobuffer(lexer, target, len); 74 } 75 76 static isc_result_t 77 totext_sshfp(ARGS_TOTEXT) { 78 isc_region_t sr; 79 char buf[sizeof("64000 ")]; 80 unsigned int n; 81 82 REQUIRE(rdata->type == dns_rdatatype_sshfp); 83 REQUIRE(rdata->length != 0); 84 85 UNUSED(tctx); 86 87 dns_rdata_toregion(rdata, &sr); 88 89 /* 90 * Algorithm. 91 */ 92 n = uint8_fromregion(&sr); 93 isc_region_consume(&sr, 1); 94 snprintf(buf, sizeof(buf), "%u ", n); 95 RETERR(str_totext(buf, target)); 96 97 /* 98 * Digest type. 99 */ 100 n = uint8_fromregion(&sr); 101 isc_region_consume(&sr, 1); 102 snprintf(buf, sizeof(buf), "%u", n); 103 RETERR(str_totext(buf, target)); 104 105 if (sr.length == 0U) { 106 return ISC_R_SUCCESS; 107 } 108 109 /* 110 * Digest. 111 */ 112 if ((tctx->flags & DNS_STYLEFLAG_MULTILINE) != 0) { 113 RETERR(str_totext(" (", target)); 114 } 115 RETERR(str_totext(tctx->linebreak, target)); 116 if (tctx->width == 0) { /* No splitting */ 117 RETERR(isc_hex_totext(&sr, 0, "", target)); 118 } else { 119 RETERR(isc_hex_totext(&sr, tctx->width - 2, tctx->linebreak, 120 target)); 121 } 122 if ((tctx->flags & DNS_STYLEFLAG_MULTILINE) != 0) { 123 RETERR(str_totext(" )", target)); 124 } 125 return ISC_R_SUCCESS; 126 } 127 128 static isc_result_t 129 fromwire_sshfp(ARGS_FROMWIRE) { 130 isc_region_t sr; 131 132 REQUIRE(type == dns_rdatatype_sshfp); 133 134 UNUSED(type); 135 UNUSED(rdclass); 136 UNUSED(dctx); 137 138 isc_buffer_activeregion(source, &sr); 139 if (sr.length < 2) { 140 return ISC_R_UNEXPECTEDEND; 141 } 142 143 if ((sr.base[1] == 1 && sr.length != ISC_SHA1_DIGESTLENGTH + 2) || 144 (sr.base[1] == 2 && sr.length != ISC_SHA256_DIGESTLENGTH + 2)) 145 { 146 return DNS_R_FORMERR; 147 } 148 149 isc_buffer_forward(source, sr.length); 150 return mem_tobuffer(target, sr.base, sr.length); 151 } 152 153 static isc_result_t 154 towire_sshfp(ARGS_TOWIRE) { 155 isc_region_t sr; 156 157 REQUIRE(rdata->type == dns_rdatatype_sshfp); 158 REQUIRE(rdata->length != 0); 159 160 UNUSED(cctx); 161 162 dns_rdata_toregion(rdata, &sr); 163 return mem_tobuffer(target, sr.base, sr.length); 164 } 165 166 static int 167 compare_sshfp(ARGS_COMPARE) { 168 isc_region_t r1; 169 isc_region_t r2; 170 171 REQUIRE(rdata1->type == rdata2->type); 172 REQUIRE(rdata1->rdclass == rdata2->rdclass); 173 REQUIRE(rdata1->type == dns_rdatatype_sshfp); 174 REQUIRE(rdata1->length != 0); 175 REQUIRE(rdata2->length != 0); 176 177 dns_rdata_toregion(rdata1, &r1); 178 dns_rdata_toregion(rdata2, &r2); 179 return isc_region_compare(&r1, &r2); 180 } 181 182 static isc_result_t 183 fromstruct_sshfp(ARGS_FROMSTRUCT) { 184 dns_rdata_sshfp_t *sshfp = source; 185 186 REQUIRE(type == dns_rdatatype_sshfp); 187 REQUIRE(sshfp != NULL); 188 REQUIRE(sshfp->common.rdtype == type); 189 REQUIRE(sshfp->common.rdclass == rdclass); 190 191 UNUSED(type); 192 UNUSED(rdclass); 193 194 RETERR(uint8_tobuffer(sshfp->algorithm, target)); 195 RETERR(uint8_tobuffer(sshfp->digest_type, target)); 196 197 return mem_tobuffer(target, sshfp->digest, sshfp->length); 198 } 199 200 static isc_result_t 201 tostruct_sshfp(ARGS_TOSTRUCT) { 202 dns_rdata_sshfp_t *sshfp = target; 203 isc_region_t region; 204 205 REQUIRE(rdata->type == dns_rdatatype_sshfp); 206 REQUIRE(sshfp != NULL); 207 REQUIRE(rdata->length != 0); 208 209 sshfp->common.rdclass = rdata->rdclass; 210 sshfp->common.rdtype = rdata->type; 211 ISC_LINK_INIT(&sshfp->common, link); 212 213 dns_rdata_toregion(rdata, ®ion); 214 215 sshfp->algorithm = uint8_fromregion(®ion); 216 isc_region_consume(®ion, 1); 217 sshfp->digest_type = uint8_fromregion(®ion); 218 isc_region_consume(®ion, 1); 219 sshfp->length = region.length; 220 221 sshfp->digest = mem_maybedup(mctx, region.base, region.length); 222 sshfp->mctx = mctx; 223 return ISC_R_SUCCESS; 224 } 225 226 static void 227 freestruct_sshfp(ARGS_FREESTRUCT) { 228 dns_rdata_sshfp_t *sshfp = source; 229 230 REQUIRE(sshfp != NULL); 231 REQUIRE(sshfp->common.rdtype == dns_rdatatype_sshfp); 232 233 if (sshfp->mctx == NULL) { 234 return; 235 } 236 237 if (sshfp->digest != NULL) { 238 isc_mem_free(sshfp->mctx, sshfp->digest); 239 } 240 sshfp->mctx = NULL; 241 } 242 243 static isc_result_t 244 additionaldata_sshfp(ARGS_ADDLDATA) { 245 REQUIRE(rdata->type == dns_rdatatype_sshfp); 246 247 UNUSED(rdata); 248 UNUSED(owner); 249 UNUSED(add); 250 UNUSED(arg); 251 252 return ISC_R_SUCCESS; 253 } 254 255 static isc_result_t 256 digest_sshfp(ARGS_DIGEST) { 257 isc_region_t r; 258 259 REQUIRE(rdata->type == dns_rdatatype_sshfp); 260 261 dns_rdata_toregion(rdata, &r); 262 263 return (digest)(arg, &r); 264 } 265 266 static bool 267 checkowner_sshfp(ARGS_CHECKOWNER) { 268 REQUIRE(type == dns_rdatatype_sshfp); 269 270 UNUSED(name); 271 UNUSED(type); 272 UNUSED(rdclass); 273 UNUSED(wildcard); 274 275 return true; 276 } 277 278 static bool 279 checknames_sshfp(ARGS_CHECKNAMES) { 280 REQUIRE(rdata->type == dns_rdatatype_sshfp); 281 282 UNUSED(rdata); 283 UNUSED(owner); 284 UNUSED(bad); 285 286 return true; 287 } 288 289 static int 290 casecompare_sshfp(ARGS_COMPARE) { 291 return compare_sshfp(rdata1, rdata2); 292 } 293 294 #endif /* RDATA_GENERIC_SSHFP_44_C */ 295