1 /* $NetBSD: private.c,v 1.1 2024/02/18 20:57: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 #include <stdbool.h>
17
18 #include <isc/base64.h>
19 #include <isc/print.h>
20 #include <isc/result.h>
21 #include <isc/string.h>
22 #include <isc/types.h>
23 #include <isc/util.h>
24
25 #include <dns/nsec3.h>
26 #include <dns/private.h>
27
28 /*
29 * We need to build the relevant chain if there exists a NSEC/NSEC3PARAM
30 * at the apex; normally only one or the other of NSEC/NSEC3PARAM will exist.
31 *
32 * If a NSEC3PARAM RRset exists then we will need to build a NSEC chain
33 * if all the NSEC3PARAM records (and associated chains) are slated for
34 * destruction and we have not been told to NOT build the NSEC chain.
35 *
36 * If the NSEC set exist then check to see if there is a request to create
37 * a NSEC3 chain.
38 *
39 * If neither NSEC/NSEC3PARAM RRsets exist at the origin and the private
40 * type exists then we need to examine it to determine if NSEC3 chain has
41 * been requested to be built otherwise a NSEC chain needs to be built.
42 */
43
44 #define REMOVE(x) (((x)&DNS_NSEC3FLAG_REMOVE) != 0)
45 #define CREATE(x) (((x)&DNS_NSEC3FLAG_CREATE) != 0)
46 #define INITIAL(x) (((x)&DNS_NSEC3FLAG_INITIAL) != 0)
47 #define NONSEC(x) (((x)&DNS_NSEC3FLAG_NONSEC) != 0)
48
49 #define CHECK(x) \
50 do { \
51 result = (x); \
52 if (result != ISC_R_SUCCESS) \
53 goto failure; \
54 } while (0)
55
56 /*
57 * Work out if 'param' should be ignored or not (i.e. it is in the process
58 * of being removed).
59 *
60 * Note: we 'belt-and-braces' here by also checking for a CREATE private
61 * record and keep the param record in this case.
62 */
63
64 static bool
ignore(dns_rdata_t * param,dns_rdataset_t * privateset)65 ignore(dns_rdata_t *param, dns_rdataset_t *privateset) {
66 isc_result_t result;
67
68 for (result = dns_rdataset_first(privateset); result == ISC_R_SUCCESS;
69 result = dns_rdataset_next(privateset))
70 {
71 unsigned char buf[DNS_NSEC3PARAM_BUFFERSIZE];
72 dns_rdata_t private = DNS_RDATA_INIT;
73 dns_rdata_t rdata = DNS_RDATA_INIT;
74
75 dns_rdataset_current(privateset, &private);
76 if (!dns_nsec3param_fromprivate(&private, &rdata, buf,
77 sizeof(buf)))
78 {
79 continue;
80 }
81 /*
82 * We are going to create a new NSEC3 chain so it
83 * doesn't matter if we are removing this one.
84 */
85 if (CREATE(rdata.data[1])) {
86 return (false);
87 }
88 if (rdata.data[0] != param->data[0] ||
89 rdata.data[2] != param->data[2] ||
90 rdata.data[3] != param->data[3] ||
91 rdata.data[4] != param->data[4] ||
92 memcmp(&rdata.data[5], ¶m->data[5], param->data[4]))
93 {
94 continue;
95 }
96 /*
97 * The removal of this NSEC3 chain does NOT cause a
98 * NSEC chain to be created so we don't need to tell
99 * the caller that it will be removed.
100 */
101 if (NONSEC(rdata.data[1])) {
102 return (false);
103 }
104 return (true);
105 }
106 return (false);
107 }
108
109 isc_result_t
dns_private_chains(dns_db_t * db,dns_dbversion_t * ver,dns_rdatatype_t privatetype,bool * build_nsec,bool * build_nsec3)110 dns_private_chains(dns_db_t *db, dns_dbversion_t *ver,
111 dns_rdatatype_t privatetype, bool *build_nsec,
112 bool *build_nsec3) {
113 dns_dbnode_t *node;
114 dns_rdataset_t nsecset, nsec3paramset, privateset;
115 bool nsec3chain;
116 bool signing;
117 isc_result_t result;
118 unsigned char buf[DNS_NSEC3PARAM_BUFFERSIZE];
119 unsigned int count;
120
121 node = NULL;
122 dns_rdataset_init(&nsecset);
123 dns_rdataset_init(&nsec3paramset);
124 dns_rdataset_init(&privateset);
125
126 CHECK(dns_db_getoriginnode(db, &node));
127
128 result = dns_db_findrdataset(db, node, ver, dns_rdatatype_nsec, 0,
129 (isc_stdtime_t)0, &nsecset, NULL);
130
131 if (result != ISC_R_SUCCESS && result != ISC_R_NOTFOUND) {
132 goto failure;
133 }
134
135 result = dns_db_findrdataset(db, node, ver, dns_rdatatype_nsec3param, 0,
136 (isc_stdtime_t)0, &nsec3paramset, NULL);
137 if (result != ISC_R_SUCCESS && result != ISC_R_NOTFOUND) {
138 goto failure;
139 }
140
141 if (dns_rdataset_isassociated(&nsecset) &&
142 dns_rdataset_isassociated(&nsec3paramset))
143 {
144 if (build_nsec != NULL) {
145 *build_nsec = true;
146 }
147 if (build_nsec3 != NULL) {
148 *build_nsec3 = true;
149 }
150 goto success;
151 }
152
153 if (privatetype != (dns_rdatatype_t)0) {
154 result = dns_db_findrdataset(db, node, ver, privatetype, 0,
155 (isc_stdtime_t)0, &privateset,
156 NULL);
157 if (result != ISC_R_SUCCESS && result != ISC_R_NOTFOUND) {
158 goto failure;
159 }
160 }
161
162 /*
163 * Look to see if we also need to be creating a NSEC3 chain.
164 */
165 if (dns_rdataset_isassociated(&nsecset)) {
166 if (build_nsec != NULL) {
167 *build_nsec = true;
168 }
169 if (build_nsec3 != NULL) {
170 *build_nsec3 = false;
171 }
172 if (!dns_rdataset_isassociated(&privateset)) {
173 goto success;
174 }
175 for (result = dns_rdataset_first(&privateset);
176 result == ISC_R_SUCCESS;
177 result = dns_rdataset_next(&privateset))
178 {
179 dns_rdata_t private = DNS_RDATA_INIT;
180 dns_rdata_t rdata = DNS_RDATA_INIT;
181
182 dns_rdataset_current(&privateset, &private);
183 if (!dns_nsec3param_fromprivate(&private, &rdata, buf,
184 sizeof(buf)))
185 {
186 continue;
187 }
188 if (REMOVE(rdata.data[1])) {
189 continue;
190 }
191 if (build_nsec3 != NULL) {
192 *build_nsec3 = true;
193 }
194 break;
195 }
196 goto success;
197 }
198
199 if (dns_rdataset_isassociated(&nsec3paramset)) {
200 if (build_nsec3 != NULL) {
201 *build_nsec3 = true;
202 }
203 if (build_nsec != NULL) {
204 *build_nsec = false;
205 }
206 if (!dns_rdataset_isassociated(&privateset)) {
207 goto success;
208 }
209 /*
210 * If we are in the process of building a new NSEC3 chain
211 * then we don't need to build a NSEC chain.
212 */
213 for (result = dns_rdataset_first(&privateset);
214 result == ISC_R_SUCCESS;
215 result = dns_rdataset_next(&privateset))
216 {
217 dns_rdata_t private = DNS_RDATA_INIT;
218 dns_rdata_t rdata = DNS_RDATA_INIT;
219
220 dns_rdataset_current(&privateset, &private);
221 if (!dns_nsec3param_fromprivate(&private, &rdata, buf,
222 sizeof(buf)))
223 {
224 continue;
225 }
226 if (CREATE(rdata.data[1])) {
227 goto success;
228 }
229 }
230
231 /*
232 * Check to see if there will be a active NSEC3CHAIN once
233 * the changes queued complete.
234 */
235 count = 0;
236 for (result = dns_rdataset_first(&nsec3paramset);
237 result == ISC_R_SUCCESS;
238 result = dns_rdataset_next(&nsec3paramset))
239 {
240 dns_rdata_t rdata = DNS_RDATA_INIT;
241
242 /*
243 * If there is more that one NSEC3 chain present then
244 * we don't need to construct a NSEC chain.
245 */
246 if (++count > 1) {
247 goto success;
248 }
249 dns_rdataset_current(&nsec3paramset, &rdata);
250 if (ignore(&rdata, &privateset)) {
251 continue;
252 }
253 /*
254 * We still have a good NSEC3 chain or we are
255 * not creating a NSEC chain as NONSEC is set.
256 */
257 goto success;
258 }
259
260 /*
261 * The last NSEC3 chain is being removed and does not have
262 * have NONSEC set.
263 */
264 if (build_nsec != NULL) {
265 *build_nsec = true;
266 }
267 goto success;
268 }
269
270 if (build_nsec != NULL) {
271 *build_nsec = false;
272 }
273 if (build_nsec3 != NULL) {
274 *build_nsec3 = false;
275 }
276 if (!dns_rdataset_isassociated(&privateset)) {
277 goto success;
278 }
279
280 signing = false;
281 nsec3chain = false;
282
283 for (result = dns_rdataset_first(&privateset); result == ISC_R_SUCCESS;
284 result = dns_rdataset_next(&privateset))
285 {
286 dns_rdata_t rdata = DNS_RDATA_INIT;
287 dns_rdata_t private = DNS_RDATA_INIT;
288
289 dns_rdataset_current(&privateset, &private);
290 if (!dns_nsec3param_fromprivate(&private, &rdata, buf,
291 sizeof(buf)))
292 {
293 /*
294 * Look for record that says we are signing the
295 * zone with a key.
296 */
297 if (private.length == 5 && private.data[0] != 0 &&
298 private.data[3] == 0 && private.data[4] == 0)
299 {
300 signing = true;
301 }
302 } else {
303 if (CREATE(rdata.data[1])) {
304 nsec3chain = true;
305 }
306 }
307 }
308
309 if (signing) {
310 if (nsec3chain) {
311 if (build_nsec3 != NULL) {
312 *build_nsec3 = true;
313 }
314 } else {
315 if (build_nsec != NULL) {
316 *build_nsec = true;
317 }
318 }
319 }
320
321 success:
322 result = ISC_R_SUCCESS;
323 failure:
324 if (dns_rdataset_isassociated(&nsecset)) {
325 dns_rdataset_disassociate(&nsecset);
326 }
327 if (dns_rdataset_isassociated(&nsec3paramset)) {
328 dns_rdataset_disassociate(&nsec3paramset);
329 }
330 if (dns_rdataset_isassociated(&privateset)) {
331 dns_rdataset_disassociate(&privateset);
332 }
333 if (node != NULL) {
334 dns_db_detachnode(db, &node);
335 }
336 return (result);
337 }
338
339 isc_result_t
dns_private_totext(dns_rdata_t * private,isc_buffer_t * buf)340 dns_private_totext(dns_rdata_t *private, isc_buffer_t *buf) {
341 isc_result_t result;
342
343 if (private->length < 5) {
344 return (ISC_R_NOTFOUND);
345 }
346
347 if (private->data[0] == 0) {
348 unsigned char nsec3buf[DNS_NSEC3PARAM_BUFFERSIZE];
349 unsigned char newbuf[DNS_NSEC3PARAM_BUFFERSIZE];
350 dns_rdata_t rdata = DNS_RDATA_INIT;
351 dns_rdata_nsec3param_t nsec3param;
352 bool del, init, nonsec;
353 isc_buffer_t b;
354
355 if (!dns_nsec3param_fromprivate(private, &rdata, nsec3buf,
356 sizeof(nsec3buf)))
357 {
358 CHECK(ISC_R_FAILURE);
359 }
360
361 CHECK(dns_rdata_tostruct(&rdata, &nsec3param, NULL));
362
363 del = ((nsec3param.flags & DNS_NSEC3FLAG_REMOVE) != 0);
364 init = ((nsec3param.flags & DNS_NSEC3FLAG_INITIAL) != 0);
365 nonsec = ((nsec3param.flags & DNS_NSEC3FLAG_NONSEC) != 0);
366
367 nsec3param.flags &=
368 ~(DNS_NSEC3FLAG_CREATE | DNS_NSEC3FLAG_REMOVE |
369 DNS_NSEC3FLAG_INITIAL | DNS_NSEC3FLAG_NONSEC);
370
371 if (init) {
372 isc_buffer_putstr(buf, "Pending NSEC3 chain ");
373 } else if (del) {
374 isc_buffer_putstr(buf, "Removing NSEC3 chain ");
375 } else {
376 isc_buffer_putstr(buf, "Creating NSEC3 chain ");
377 }
378
379 dns_rdata_reset(&rdata);
380 isc_buffer_init(&b, newbuf, sizeof(newbuf));
381 CHECK(dns_rdata_fromstruct(&rdata, dns_rdataclass_in,
382 dns_rdatatype_nsec3param,
383 &nsec3param, &b));
384
385 CHECK(dns_rdata_totext(&rdata, NULL, buf));
386
387 if (del && !nonsec) {
388 isc_buffer_putstr(buf, " / creating NSEC chain");
389 }
390 } else if (private->length == 5) {
391 unsigned char alg = private->data[0];
392 dns_keytag_t keyid = (private->data[2] | private->data[1] << 8);
393 char keybuf[DNS_SECALG_FORMATSIZE + BUFSIZ],
394 algbuf[DNS_SECALG_FORMATSIZE];
395 bool del = private->data[3];
396 bool complete = private->data[4];
397
398 if (del && complete) {
399 isc_buffer_putstr(buf, "Done removing signatures for ");
400 } else if (del) {
401 isc_buffer_putstr(buf, "Removing signatures for ");
402 } else if (complete) {
403 isc_buffer_putstr(buf, "Done signing with ");
404 } else {
405 isc_buffer_putstr(buf, "Signing with ");
406 }
407
408 dns_secalg_format(alg, algbuf, sizeof(algbuf));
409 snprintf(keybuf, sizeof(keybuf), "key %d/%s", keyid, algbuf);
410 isc_buffer_putstr(buf, keybuf);
411 } else {
412 return (ISC_R_NOTFOUND);
413 }
414
415 isc_buffer_putuint8(buf, 0);
416 result = ISC_R_SUCCESS;
417 failure:
418 return (result);
419 }
420