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, &region);
215 
216 	sshfp->algorithm = uint8_fromregion(&region);
217 	isc_region_consume(&region, 1);
218 	sshfp->digest_type = uint8_fromregion(&region);
219 	isc_region_consume(&region, 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