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