1 /* $NetBSD: sshfp_44.c,v 1.9 2022/09/23 12:15:31 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
fromtext_sshfp(ARGS_FROMTEXT)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
totext_sshfp(ARGS_TOTEXT)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
fromwire_sshfp(ARGS_FROMWIRE)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 UNUSED(options);
138
139 isc_buffer_activeregion(source, &sr);
140 if (sr.length < 2) {
141 return (ISC_R_UNEXPECTEDEND);
142 }
143
144 if ((sr.base[1] == 1 && sr.length != ISC_SHA1_DIGESTLENGTH + 2) ||
145 (sr.base[1] == 2 && sr.length != ISC_SHA256_DIGESTLENGTH + 2))
146 {
147 return (DNS_R_FORMERR);
148 }
149
150 isc_buffer_forward(source, sr.length);
151 return (mem_tobuffer(target, sr.base, sr.length));
152 }
153
154 static isc_result_t
towire_sshfp(ARGS_TOWIRE)155 towire_sshfp(ARGS_TOWIRE) {
156 isc_region_t sr;
157
158 REQUIRE(rdata->type == dns_rdatatype_sshfp);
159 REQUIRE(rdata->length != 0);
160
161 UNUSED(cctx);
162
163 dns_rdata_toregion(rdata, &sr);
164 return (mem_tobuffer(target, sr.base, sr.length));
165 }
166
167 static int
compare_sshfp(ARGS_COMPARE)168 compare_sshfp(ARGS_COMPARE) {
169 isc_region_t r1;
170 isc_region_t r2;
171
172 REQUIRE(rdata1->type == rdata2->type);
173 REQUIRE(rdata1->rdclass == rdata2->rdclass);
174 REQUIRE(rdata1->type == dns_rdatatype_sshfp);
175 REQUIRE(rdata1->length != 0);
176 REQUIRE(rdata2->length != 0);
177
178 dns_rdata_toregion(rdata1, &r1);
179 dns_rdata_toregion(rdata2, &r2);
180 return (isc_region_compare(&r1, &r2));
181 }
182
183 static isc_result_t
fromstruct_sshfp(ARGS_FROMSTRUCT)184 fromstruct_sshfp(ARGS_FROMSTRUCT) {
185 dns_rdata_sshfp_t *sshfp = source;
186
187 REQUIRE(type == dns_rdatatype_sshfp);
188 REQUIRE(sshfp != NULL);
189 REQUIRE(sshfp->common.rdtype == type);
190 REQUIRE(sshfp->common.rdclass == rdclass);
191
192 UNUSED(type);
193 UNUSED(rdclass);
194
195 RETERR(uint8_tobuffer(sshfp->algorithm, target));
196 RETERR(uint8_tobuffer(sshfp->digest_type, target));
197
198 return (mem_tobuffer(target, sshfp->digest, sshfp->length));
199 }
200
201 static isc_result_t
tostruct_sshfp(ARGS_TOSTRUCT)202 tostruct_sshfp(ARGS_TOSTRUCT) {
203 dns_rdata_sshfp_t *sshfp = target;
204 isc_region_t region;
205
206 REQUIRE(rdata->type == dns_rdatatype_sshfp);
207 REQUIRE(sshfp != NULL);
208 REQUIRE(rdata->length != 0);
209
210 sshfp->common.rdclass = rdata->rdclass;
211 sshfp->common.rdtype = rdata->type;
212 ISC_LINK_INIT(&sshfp->common, link);
213
214 dns_rdata_toregion(rdata, ®ion);
215
216 sshfp->algorithm = uint8_fromregion(®ion);
217 isc_region_consume(®ion, 1);
218 sshfp->digest_type = uint8_fromregion(®ion);
219 isc_region_consume(®ion, 1);
220 sshfp->length = region.length;
221
222 sshfp->digest = mem_maybedup(mctx, region.base, region.length);
223 if (sshfp->digest == NULL) {
224 return (ISC_R_NOMEMORY);
225 }
226
227 sshfp->mctx = mctx;
228 return (ISC_R_SUCCESS);
229 }
230
231 static void
freestruct_sshfp(ARGS_FREESTRUCT)232 freestruct_sshfp(ARGS_FREESTRUCT) {
233 dns_rdata_sshfp_t *sshfp = source;
234
235 REQUIRE(sshfp != NULL);
236 REQUIRE(sshfp->common.rdtype == dns_rdatatype_sshfp);
237
238 if (sshfp->mctx == NULL) {
239 return;
240 }
241
242 if (sshfp->digest != NULL) {
243 isc_mem_free(sshfp->mctx, sshfp->digest);
244 }
245 sshfp->mctx = NULL;
246 }
247
248 static isc_result_t
additionaldata_sshfp(ARGS_ADDLDATA)249 additionaldata_sshfp(ARGS_ADDLDATA) {
250 REQUIRE(rdata->type == dns_rdatatype_sshfp);
251
252 UNUSED(rdata);
253 UNUSED(add);
254 UNUSED(arg);
255
256 return (ISC_R_SUCCESS);
257 }
258
259 static isc_result_t
digest_sshfp(ARGS_DIGEST)260 digest_sshfp(ARGS_DIGEST) {
261 isc_region_t r;
262
263 REQUIRE(rdata->type == dns_rdatatype_sshfp);
264
265 dns_rdata_toregion(rdata, &r);
266
267 return ((digest)(arg, &r));
268 }
269
270 static bool
checkowner_sshfp(ARGS_CHECKOWNER)271 checkowner_sshfp(ARGS_CHECKOWNER) {
272 REQUIRE(type == dns_rdatatype_sshfp);
273
274 UNUSED(name);
275 UNUSED(type);
276 UNUSED(rdclass);
277 UNUSED(wildcard);
278
279 return (true);
280 }
281
282 static bool
checknames_sshfp(ARGS_CHECKNAMES)283 checknames_sshfp(ARGS_CHECKNAMES) {
284 REQUIRE(rdata->type == dns_rdatatype_sshfp);
285
286 UNUSED(rdata);
287 UNUSED(owner);
288 UNUSED(bad);
289
290 return (true);
291 }
292
293 static int
casecompare_sshfp(ARGS_COMPARE)294 casecompare_sshfp(ARGS_COMPARE) {
295 return (compare_sshfp(rdata1, rdata2));
296 }
297
298 #endif /* RDATA_GENERIC_SSHFP_44_C */
299