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