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