Sync usage with man page.
[netbsd-mini2440.git] / external / bsd / bind / dist / lib / dns / dnssec.c
blobd347d1d3dcb4046b9ab46609458f9acafcb7554b
1 /* $NetBSD$ */
3 /*
4 * Copyright (C) 2004-2009 Internet Systems Consortium, Inc. ("ISC")
5 * Copyright (C) 1999-2003 Internet Software Consortium.
7 * Permission to use, copy, modify, and/or distribute this software for any
8 * purpose with or without fee is hereby granted, provided that the above
9 * copyright notice and this permission notice appear in all copies.
11 * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
12 * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
13 * AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
14 * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
15 * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
16 * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
17 * PERFORMANCE OF THIS SOFTWARE.
21 * Id: dnssec.c,v 1.115 2009/11/24 23:48:12 tbox Exp
24 /*! \file */
26 #include <config.h>
28 #include <stdlib.h>
30 #include <isc/buffer.h>
31 #include <isc/dir.h>
32 #include <isc/mem.h>
33 #include <isc/serial.h>
34 #include <isc/string.h>
35 #include <isc/util.h>
37 #include <dns/db.h>
38 #include <dns/diff.h>
39 #include <dns/dnssec.h>
40 #include <dns/fixedname.h>
41 #include <dns/keyvalues.h>
42 #include <dns/message.h>
43 #include <dns/rdata.h>
44 #include <dns/rdatalist.h>
45 #include <dns/rdataset.h>
46 #include <dns/rdatastruct.h>
47 #include <dns/result.h>
48 #include <dns/tsig.h> /* for DNS_TSIG_FUDGE */
50 #include <dst/result.h>
52 #define is_response(msg) (msg->flags & DNS_MESSAGEFLAG_QR)
54 #define RETERR(x) do { \
55 result = (x); \
56 if (result != ISC_R_SUCCESS) \
57 goto failure; \
58 } while (0)
61 #define TYPE_SIGN 0
62 #define TYPE_VERIFY 1
64 static isc_result_t
65 digest_callback(void *arg, isc_region_t *data);
67 static int
68 rdata_compare_wrapper(const void *rdata1, const void *rdata2);
70 static isc_result_t
71 rdataset_to_sortedarray(dns_rdataset_t *set, isc_mem_t *mctx,
72 dns_rdata_t **rdata, int *nrdata);
74 static isc_result_t
75 digest_callback(void *arg, isc_region_t *data) {
76 dst_context_t *ctx = arg;
78 return (dst_context_adddata(ctx, data));
82 * Make qsort happy.
84 static int
85 rdata_compare_wrapper(const void *rdata1, const void *rdata2) {
86 return (dns_rdata_compare((const dns_rdata_t *)rdata1,
87 (const dns_rdata_t *)rdata2));
91 * Sort the rdataset into an array.
93 static isc_result_t
94 rdataset_to_sortedarray(dns_rdataset_t *set, isc_mem_t *mctx,
95 dns_rdata_t **rdata, int *nrdata)
97 isc_result_t ret;
98 int i = 0, n;
99 dns_rdata_t *data;
100 dns_rdataset_t rdataset;
102 n = dns_rdataset_count(set);
104 data = isc_mem_get(mctx, n * sizeof(dns_rdata_t));
105 if (data == NULL)
106 return (ISC_R_NOMEMORY);
108 dns_rdataset_init(&rdataset);
109 dns_rdataset_clone(set, &rdataset);
110 ret = dns_rdataset_first(&rdataset);
111 if (ret != ISC_R_SUCCESS) {
112 dns_rdataset_disassociate(&rdataset);
113 isc_mem_put(mctx, data, n * sizeof(dns_rdata_t));
114 return (ret);
118 * Put them in the array.
120 do {
121 dns_rdata_init(&data[i]);
122 dns_rdataset_current(&rdataset, &data[i++]);
123 } while (dns_rdataset_next(&rdataset) == ISC_R_SUCCESS);
126 * Sort the array.
128 qsort(data, n, sizeof(dns_rdata_t), rdata_compare_wrapper);
129 *rdata = data;
130 *nrdata = n;
131 dns_rdataset_disassociate(&rdataset);
132 return (ISC_R_SUCCESS);
135 isc_result_t
136 dns_dnssec_keyfromrdata(dns_name_t *name, dns_rdata_t *rdata, isc_mem_t *mctx,
137 dst_key_t **key)
139 isc_buffer_t b;
140 isc_region_t r;
142 INSIST(name != NULL);
143 INSIST(rdata != NULL);
144 INSIST(mctx != NULL);
145 INSIST(key != NULL);
146 INSIST(*key == NULL);
147 REQUIRE(rdata->type == dns_rdatatype_key ||
148 rdata->type == dns_rdatatype_dnskey);
150 dns_rdata_toregion(rdata, &r);
151 isc_buffer_init(&b, r.base, r.length);
152 isc_buffer_add(&b, r.length);
153 return (dst_key_fromdns(name, rdata->rdclass, &b, mctx, key));
156 static isc_result_t
157 digest_sig(dst_context_t *ctx, dns_rdata_t *sigrdata, dns_rdata_rrsig_t *sig) {
158 isc_region_t r;
159 isc_result_t ret;
160 dns_fixedname_t fname;
162 dns_rdata_toregion(sigrdata, &r);
163 INSIST(r.length >= 19);
165 r.length = 18;
166 ret = dst_context_adddata(ctx, &r);
167 if (ret != ISC_R_SUCCESS)
168 return (ret);
169 dns_fixedname_init(&fname);
170 RUNTIME_CHECK(dns_name_downcase(&sig->signer,
171 dns_fixedname_name(&fname), NULL)
172 == ISC_R_SUCCESS);
173 dns_name_toregion(dns_fixedname_name(&fname), &r);
174 return (dst_context_adddata(ctx, &r));
177 isc_result_t
178 dns_dnssec_sign(dns_name_t *name, dns_rdataset_t *set, dst_key_t *key,
179 isc_stdtime_t *inception, isc_stdtime_t *expire,
180 isc_mem_t *mctx, isc_buffer_t *buffer, dns_rdata_t *sigrdata)
182 dns_rdata_rrsig_t sig;
183 dns_rdata_t tmpsigrdata;
184 dns_rdata_t *rdatas;
185 int nrdatas, i;
186 isc_buffer_t sigbuf, envbuf;
187 isc_region_t r;
188 dst_context_t *ctx = NULL;
189 isc_result_t ret;
190 isc_buffer_t *databuf = NULL;
191 char data[256 + 8];
192 isc_uint32_t flags;
193 unsigned int sigsize;
194 dns_fixedname_t fnewname;
196 REQUIRE(name != NULL);
197 REQUIRE(dns_name_countlabels(name) <= 255);
198 REQUIRE(set != NULL);
199 REQUIRE(key != NULL);
200 REQUIRE(inception != NULL);
201 REQUIRE(expire != NULL);
202 REQUIRE(mctx != NULL);
203 REQUIRE(sigrdata != NULL);
205 if (*inception >= *expire)
206 return (DNS_R_INVALIDTIME);
209 * Is the key allowed to sign data?
211 flags = dst_key_flags(key);
212 if (flags & DNS_KEYTYPE_NOAUTH)
213 return (DNS_R_KEYUNAUTHORIZED);
214 if ((flags & DNS_KEYFLAG_OWNERMASK) != DNS_KEYOWNER_ZONE)
215 return (DNS_R_KEYUNAUTHORIZED);
217 sig.mctx = mctx;
218 sig.common.rdclass = set->rdclass;
219 sig.common.rdtype = dns_rdatatype_rrsig;
220 ISC_LINK_INIT(&sig.common, link);
222 dns_name_init(&sig.signer, NULL);
223 dns_name_clone(dst_key_name(key), &sig.signer);
225 sig.covered = set->type;
226 sig.algorithm = dst_key_alg(key);
227 sig.labels = dns_name_countlabels(name) - 1;
228 if (dns_name_iswildcard(name))
229 sig.labels--;
230 sig.originalttl = set->ttl;
231 sig.timesigned = *inception;
232 sig.timeexpire = *expire;
233 sig.keyid = dst_key_id(key);
234 ret = dst_key_sigsize(key, &sigsize);
235 if (ret != ISC_R_SUCCESS)
236 return (ret);
237 sig.siglen = sigsize;
239 * The actual contents of sig.signature are not important yet, since
240 * they're not used in digest_sig().
242 sig.signature = isc_mem_get(mctx, sig.siglen);
243 if (sig.signature == NULL)
244 return (ISC_R_NOMEMORY);
246 ret = isc_buffer_allocate(mctx, &databuf, sigsize + 256 + 18);
247 if (ret != ISC_R_SUCCESS)
248 goto cleanup_signature;
250 dns_rdata_init(&tmpsigrdata);
251 ret = dns_rdata_fromstruct(&tmpsigrdata, sig.common.rdclass,
252 sig.common.rdtype, &sig, databuf);
253 if (ret != ISC_R_SUCCESS)
254 goto cleanup_databuf;
256 ret = dst_context_create(key, mctx, &ctx);
257 if (ret != ISC_R_SUCCESS)
258 goto cleanup_databuf;
261 * Digest the SIG rdata.
263 ret = digest_sig(ctx, &tmpsigrdata, &sig);
264 if (ret != ISC_R_SUCCESS)
265 goto cleanup_context;
267 dns_fixedname_init(&fnewname);
268 RUNTIME_CHECK(dns_name_downcase(name, dns_fixedname_name(&fnewname),
269 NULL) == ISC_R_SUCCESS);
270 dns_name_toregion(dns_fixedname_name(&fnewname), &r);
273 * Create an envelope for each rdata: <name|type|class|ttl>.
275 isc_buffer_init(&envbuf, data, sizeof(data));
276 memcpy(data, r.base, r.length);
277 isc_buffer_add(&envbuf, r.length);
278 isc_buffer_putuint16(&envbuf, set->type);
279 isc_buffer_putuint16(&envbuf, set->rdclass);
280 isc_buffer_putuint32(&envbuf, set->ttl);
282 ret = rdataset_to_sortedarray(set, mctx, &rdatas, &nrdatas);
283 if (ret != ISC_R_SUCCESS)
284 goto cleanup_context;
285 isc_buffer_usedregion(&envbuf, &r);
287 for (i = 0; i < nrdatas; i++) {
288 isc_uint16_t len;
289 isc_buffer_t lenbuf;
290 isc_region_t lenr;
293 * Skip duplicates.
295 if (i > 0 && dns_rdata_compare(&rdatas[i], &rdatas[i-1]) == 0)
296 continue;
299 * Digest the envelope.
301 ret = dst_context_adddata(ctx, &r);
302 if (ret != ISC_R_SUCCESS)
303 goto cleanup_array;
306 * Digest the length of the rdata.
308 isc_buffer_init(&lenbuf, &len, sizeof(len));
309 INSIST(rdatas[i].length < 65536);
310 isc_buffer_putuint16(&lenbuf, (isc_uint16_t)rdatas[i].length);
311 isc_buffer_usedregion(&lenbuf, &lenr);
312 ret = dst_context_adddata(ctx, &lenr);
313 if (ret != ISC_R_SUCCESS)
314 goto cleanup_array;
317 * Digest the rdata.
319 ret = dns_rdata_digest(&rdatas[i], digest_callback, ctx);
320 if (ret != ISC_R_SUCCESS)
321 goto cleanup_array;
324 isc_buffer_init(&sigbuf, sig.signature, sig.siglen);
325 ret = dst_context_sign(ctx, &sigbuf);
326 if (ret != ISC_R_SUCCESS)
327 goto cleanup_array;
328 isc_buffer_usedregion(&sigbuf, &r);
329 if (r.length != sig.siglen) {
330 ret = ISC_R_NOSPACE;
331 goto cleanup_array;
333 memcpy(sig.signature, r.base, sig.siglen);
335 ret = dns_rdata_fromstruct(sigrdata, sig.common.rdclass,
336 sig.common.rdtype, &sig, buffer);
338 cleanup_array:
339 isc_mem_put(mctx, rdatas, nrdatas * sizeof(dns_rdata_t));
340 cleanup_context:
341 dst_context_destroy(&ctx);
342 cleanup_databuf:
343 isc_buffer_free(&databuf);
344 cleanup_signature:
345 isc_mem_put(mctx, sig.signature, sig.siglen);
347 return (ret);
350 isc_result_t
351 dns_dnssec_verify2(dns_name_t *name, dns_rdataset_t *set, dst_key_t *key,
352 isc_boolean_t ignoretime, isc_mem_t *mctx,
353 dns_rdata_t *sigrdata, dns_name_t *wild)
355 dns_rdata_rrsig_t sig;
356 dns_fixedname_t fnewname;
357 isc_region_t r;
358 isc_buffer_t envbuf;
359 dns_rdata_t *rdatas;
360 int nrdatas, i;
361 isc_stdtime_t now;
362 isc_result_t ret;
363 unsigned char data[300];
364 dst_context_t *ctx = NULL;
365 int labels = 0;
366 isc_uint32_t flags;
368 REQUIRE(name != NULL);
369 REQUIRE(set != NULL);
370 REQUIRE(key != NULL);
371 REQUIRE(mctx != NULL);
372 REQUIRE(sigrdata != NULL && sigrdata->type == dns_rdatatype_rrsig);
374 ret = dns_rdata_tostruct(sigrdata, &sig, NULL);
375 if (ret != ISC_R_SUCCESS)
376 return (ret);
378 if (set->type != sig.covered)
379 return (DNS_R_SIGINVALID);
381 if (isc_serial_lt(sig.timeexpire, sig.timesigned))
382 return (DNS_R_SIGINVALID);
384 if (!ignoretime) {
385 isc_stdtime_get(&now);
388 * Is SIG temporally valid?
390 if (isc_serial_lt((isc_uint32_t)now, sig.timesigned))
391 return (DNS_R_SIGFUTURE);
392 else if (isc_serial_lt(sig.timeexpire, (isc_uint32_t)now))
393 return (DNS_R_SIGEXPIRED);
397 * NS, SOA and DNSSKEY records are signed by their owner.
398 * DS records are signed by the parent.
400 switch (set->type) {
401 case dns_rdatatype_ns:
402 case dns_rdatatype_soa:
403 case dns_rdatatype_dnskey:
404 if (!dns_name_equal(name, &sig.signer))
405 return (DNS_R_SIGINVALID);
406 break;
407 case dns_rdatatype_ds:
408 if (dns_name_equal(name, &sig.signer))
409 return (DNS_R_SIGINVALID);
410 /* FALLTHROUGH */
411 default:
412 if (!dns_name_issubdomain(name, &sig.signer))
413 return (DNS_R_SIGINVALID);
414 break;
418 * Is the key allowed to sign data?
420 flags = dst_key_flags(key);
421 if (flags & DNS_KEYTYPE_NOAUTH)
422 return (DNS_R_KEYUNAUTHORIZED);
423 if ((flags & DNS_KEYFLAG_OWNERMASK) != DNS_KEYOWNER_ZONE)
424 return (DNS_R_KEYUNAUTHORIZED);
426 ret = dst_context_create(key, mctx, &ctx);
427 if (ret != ISC_R_SUCCESS)
428 goto cleanup_struct;
431 * Digest the SIG rdata (not including the signature).
433 ret = digest_sig(ctx, sigrdata, &sig);
434 if (ret != ISC_R_SUCCESS)
435 goto cleanup_context;
438 * If the name is an expanded wildcard, use the wildcard name.
440 dns_fixedname_init(&fnewname);
441 labels = dns_name_countlabels(name) - 1;
442 RUNTIME_CHECK(dns_name_downcase(name, dns_fixedname_name(&fnewname),
443 NULL) == ISC_R_SUCCESS);
444 if (labels - sig.labels > 0)
445 dns_name_split(dns_fixedname_name(&fnewname), sig.labels + 1,
446 NULL, dns_fixedname_name(&fnewname));
448 dns_name_toregion(dns_fixedname_name(&fnewname), &r);
451 * Create an envelope for each rdata: <name|type|class|ttl>.
453 isc_buffer_init(&envbuf, data, sizeof(data));
454 if (labels - sig.labels > 0) {
455 isc_buffer_putuint8(&envbuf, 1);
456 isc_buffer_putuint8(&envbuf, '*');
457 memcpy(data + 2, r.base, r.length);
459 else
460 memcpy(data, r.base, r.length);
461 isc_buffer_add(&envbuf, r.length);
462 isc_buffer_putuint16(&envbuf, set->type);
463 isc_buffer_putuint16(&envbuf, set->rdclass);
464 isc_buffer_putuint32(&envbuf, sig.originalttl);
466 ret = rdataset_to_sortedarray(set, mctx, &rdatas, &nrdatas);
467 if (ret != ISC_R_SUCCESS)
468 goto cleanup_context;
470 isc_buffer_usedregion(&envbuf, &r);
472 for (i = 0; i < nrdatas; i++) {
473 isc_uint16_t len;
474 isc_buffer_t lenbuf;
475 isc_region_t lenr;
478 * Skip duplicates.
480 if (i > 0 && dns_rdata_compare(&rdatas[i], &rdatas[i-1]) == 0)
481 continue;
484 * Digest the envelope.
486 ret = dst_context_adddata(ctx, &r);
487 if (ret != ISC_R_SUCCESS)
488 goto cleanup_array;
491 * Digest the rdata length.
493 isc_buffer_init(&lenbuf, &len, sizeof(len));
494 INSIST(rdatas[i].length < 65536);
495 isc_buffer_putuint16(&lenbuf, (isc_uint16_t)rdatas[i].length);
496 isc_buffer_usedregion(&lenbuf, &lenr);
499 * Digest the rdata.
501 ret = dst_context_adddata(ctx, &lenr);
502 if (ret != ISC_R_SUCCESS)
503 goto cleanup_array;
504 ret = dns_rdata_digest(&rdatas[i], digest_callback, ctx);
505 if (ret != ISC_R_SUCCESS)
506 goto cleanup_array;
509 r.base = sig.signature;
510 r.length = sig.siglen;
511 ret = dst_context_verify(ctx, &r);
512 if (ret == DST_R_VERIFYFAILURE)
513 ret = DNS_R_SIGINVALID;
515 cleanup_array:
516 isc_mem_put(mctx, rdatas, nrdatas * sizeof(dns_rdata_t));
517 cleanup_context:
518 dst_context_destroy(&ctx);
519 cleanup_struct:
520 dns_rdata_freestruct(&sig);
522 if (ret == ISC_R_SUCCESS && labels - sig.labels > 0) {
523 if (wild != NULL)
524 RUNTIME_CHECK(dns_name_concatenate(dns_wildcardname,
525 dns_fixedname_name(&fnewname),
526 wild, NULL) == ISC_R_SUCCESS);
527 ret = DNS_R_FROMWILDCARD;
529 return (ret);
532 isc_result_t
533 dns_dnssec_verify(dns_name_t *name, dns_rdataset_t *set, dst_key_t *key,
534 isc_boolean_t ignoretime, isc_mem_t *mctx,
535 dns_rdata_t *sigrdata)
537 isc_result_t result;
539 result = dns_dnssec_verify2(name, set, key, ignoretime, mctx,
540 sigrdata, NULL);
541 if (result == DNS_R_FROMWILDCARD)
542 result = ISC_R_SUCCESS;
543 return (result);
546 static isc_boolean_t
547 key_active(dst_key_t *key) {
548 isc_result_t result;
549 isc_stdtime_t now, publish, active, revoke, inactive, delete;
550 isc_boolean_t pubset = ISC_FALSE, actset = ISC_FALSE;
551 isc_boolean_t revset = ISC_FALSE, inactset = ISC_FALSE;
552 isc_boolean_t delset = ISC_FALSE;
553 int major, minor;
555 /* Is this an old-style key? */
556 result = dst_key_getprivateformat(key, &major, &minor);
559 * Smart signing started with key format 1.3; prior to that, all
560 * keys are assumed active
562 if (major == 1 && minor <= 2)
563 return (ISC_TRUE);
565 isc_stdtime_get(&now);
567 result = dst_key_gettime(key, DST_TIME_PUBLISH, &publish);
568 if (result == ISC_R_SUCCESS)
569 pubset = ISC_TRUE;
571 result = dst_key_gettime(key, DST_TIME_ACTIVATE, &active);
572 if (result == ISC_R_SUCCESS)
573 actset = ISC_TRUE;
575 result = dst_key_gettime(key, DST_TIME_REVOKE, &revoke);
576 if (result == ISC_R_SUCCESS)
577 revset = ISC_TRUE;
579 result = dst_key_gettime(key, DST_TIME_INACTIVE, &inactive);
580 if (result == ISC_R_SUCCESS)
581 inactset = ISC_TRUE;
583 result = dst_key_gettime(key, DST_TIME_DELETE, &delete);
584 if (result == ISC_R_SUCCESS)
585 delset = ISC_TRUE;
587 if ((inactset && inactive <= now) || (delset && delete <= now))
588 return (ISC_FALSE);
590 if (revset && revoke <= now && pubset && publish <= now)
591 return (ISC_TRUE);
593 if (actset && active <= now)
594 return (ISC_TRUE);
596 return (ISC_FALSE);
599 #define is_zone_key(key) ((dst_key_flags(key) & DNS_KEYFLAG_OWNERMASK) \
600 == DNS_KEYOWNER_ZONE)
602 isc_result_t
603 dns_dnssec_findzonekeys2(dns_db_t *db, dns_dbversion_t *ver,
604 dns_dbnode_t *node, dns_name_t *name,
605 const char *directory, isc_mem_t *mctx,
606 unsigned int maxkeys, dst_key_t **keys,
607 unsigned int *nkeys)
609 dns_rdataset_t rdataset;
610 dns_rdata_t rdata = DNS_RDATA_INIT;
611 isc_result_t result;
612 dst_key_t *pubkey = NULL;
613 unsigned int count = 0;
615 REQUIRE(nkeys != NULL);
616 REQUIRE(keys != NULL);
618 *nkeys = 0;
619 dns_rdataset_init(&rdataset);
620 RETERR(dns_db_findrdataset(db, node, ver, dns_rdatatype_dnskey, 0, 0,
621 &rdataset, NULL));
622 RETERR(dns_rdataset_first(&rdataset));
623 while (result == ISC_R_SUCCESS && count < maxkeys) {
624 pubkey = NULL;
625 dns_rdataset_current(&rdataset, &rdata);
626 RETERR(dns_dnssec_keyfromrdata(name, &rdata, mctx, &pubkey));
627 if (!is_zone_key(pubkey) ||
628 (dst_key_flags(pubkey) & DNS_KEYTYPE_NOAUTH) != 0)
629 goto next;
630 /* Corrupted .key file? */
631 if (!dns_name_equal(name, dst_key_name(pubkey)))
632 goto next;
633 keys[count] = NULL;
634 result = dst_key_fromfile(dst_key_name(pubkey),
635 dst_key_id(pubkey),
636 dst_key_alg(pubkey),
637 DST_TYPE_PUBLIC|DST_TYPE_PRIVATE,
638 directory,
639 mctx, &keys[count]);
642 * If the key was revoked and the private file
643 * doesn't exist, maybe it was revoked internally
644 * by named. Try loading the unrevoked version.
646 if (result == ISC_R_FILENOTFOUND) {
647 isc_uint32_t flags;
648 flags = dst_key_flags(pubkey);
649 if ((flags & DNS_KEYFLAG_REVOKE) != 0) {
650 dst_key_setflags(pubkey,
651 flags & ~DNS_KEYFLAG_REVOKE);
652 result = dst_key_fromfile(dst_key_name(pubkey),
653 dst_key_id(pubkey),
654 dst_key_alg(pubkey),
655 DST_TYPE_PUBLIC|
656 DST_TYPE_PRIVATE,
657 directory,
658 mctx, &keys[count]);
659 if (result == ISC_R_SUCCESS &&
660 dst_key_pubcompare(pubkey, keys[count],
661 ISC_FALSE)) {
662 dst_key_setflags(keys[count], flags);
664 dst_key_setflags(pubkey, flags);
668 if (result == ISC_R_FILENOTFOUND) {
669 keys[count] = pubkey;
670 pubkey = NULL;
671 count++;
672 goto next;
675 if (result != ISC_R_SUCCESS)
676 goto failure;
679 * If a key is marked inactive, skip it
681 if (!key_active(keys[count])) {
682 dst_key_free(&keys[count]);
683 keys[count] = pubkey;
684 pubkey = NULL;
685 count++;
686 goto next;
689 if ((dst_key_flags(keys[count]) & DNS_KEYTYPE_NOAUTH) != 0) {
690 /* We should never get here. */
691 dst_key_free(&keys[count]);
692 goto next;
694 count++;
695 next:
696 if (pubkey != NULL)
697 dst_key_free(&pubkey);
698 dns_rdata_reset(&rdata);
699 result = dns_rdataset_next(&rdataset);
701 if (result != ISC_R_NOMORE)
702 goto failure;
703 if (count == 0)
704 result = ISC_R_NOTFOUND;
705 else
706 result = ISC_R_SUCCESS;
708 failure:
709 if (dns_rdataset_isassociated(&rdataset))
710 dns_rdataset_disassociate(&rdataset);
711 if (pubkey != NULL)
712 dst_key_free(&pubkey);
713 if (result != ISC_R_SUCCESS)
714 while (count > 0)
715 dst_key_free(&keys[--count]);
716 *nkeys = count;
717 return (result);
720 isc_result_t
721 dns_dnssec_findzonekeys(dns_db_t *db, dns_dbversion_t *ver,
722 dns_dbnode_t *node, dns_name_t *name, isc_mem_t *mctx,
723 unsigned int maxkeys, dst_key_t **keys,
724 unsigned int *nkeys)
726 return (dns_dnssec_findzonekeys2(db, ver, node, name, NULL, mctx,
727 maxkeys, keys, nkeys));
730 isc_result_t
731 dns_dnssec_signmessage(dns_message_t *msg, dst_key_t *key) {
732 dns_rdata_sig_t sig; /* SIG(0) */
733 unsigned char data[512];
734 unsigned char header[DNS_MESSAGE_HEADERLEN];
735 isc_buffer_t headerbuf, databuf, sigbuf;
736 unsigned int sigsize;
737 isc_buffer_t *dynbuf = NULL;
738 dns_rdata_t *rdata;
739 dns_rdatalist_t *datalist;
740 dns_rdataset_t *dataset;
741 isc_region_t r;
742 isc_stdtime_t now;
743 dst_context_t *ctx = NULL;
744 isc_mem_t *mctx;
745 isc_result_t result;
746 isc_boolean_t signeedsfree = ISC_TRUE;
748 REQUIRE(msg != NULL);
749 REQUIRE(key != NULL);
751 if (is_response(msg))
752 REQUIRE(msg->query.base != NULL);
754 mctx = msg->mctx;
756 memset(&sig, 0, sizeof(sig));
758 sig.mctx = mctx;
759 sig.common.rdclass = dns_rdataclass_any;
760 sig.common.rdtype = dns_rdatatype_sig; /* SIG(0) */
761 ISC_LINK_INIT(&sig.common, link);
763 sig.covered = 0;
764 sig.algorithm = dst_key_alg(key);
765 sig.labels = 0; /* the root name */
766 sig.originalttl = 0;
768 isc_stdtime_get(&now);
769 sig.timesigned = now - DNS_TSIG_FUDGE;
770 sig.timeexpire = now + DNS_TSIG_FUDGE;
772 sig.keyid = dst_key_id(key);
774 dns_name_init(&sig.signer, NULL);
775 dns_name_clone(dst_key_name(key), &sig.signer);
777 sig.siglen = 0;
778 sig.signature = NULL;
780 isc_buffer_init(&databuf, data, sizeof(data));
782 RETERR(dst_context_create(key, mctx, &ctx));
785 * Digest the fields of the SIG - we can cheat and use
786 * dns_rdata_fromstruct. Since siglen is 0, the digested data
787 * is identical to dns format.
789 RETERR(dns_rdata_fromstruct(NULL, dns_rdataclass_any,
790 dns_rdatatype_sig /* SIG(0) */,
791 &sig, &databuf));
792 isc_buffer_usedregion(&databuf, &r);
793 RETERR(dst_context_adddata(ctx, &r));
796 * If this is a response, digest the query.
798 if (is_response(msg))
799 RETERR(dst_context_adddata(ctx, &msg->query));
802 * Digest the header.
804 isc_buffer_init(&headerbuf, header, sizeof(header));
805 dns_message_renderheader(msg, &headerbuf);
806 isc_buffer_usedregion(&headerbuf, &r);
807 RETERR(dst_context_adddata(ctx, &r));
810 * Digest the remainder of the message.
812 isc_buffer_usedregion(msg->buffer, &r);
813 isc_region_consume(&r, DNS_MESSAGE_HEADERLEN);
814 RETERR(dst_context_adddata(ctx, &r));
816 RETERR(dst_key_sigsize(key, &sigsize));
817 sig.siglen = sigsize;
818 sig.signature = (unsigned char *) isc_mem_get(mctx, sig.siglen);
819 if (sig.signature == NULL) {
820 result = ISC_R_NOMEMORY;
821 goto failure;
824 isc_buffer_init(&sigbuf, sig.signature, sig.siglen);
825 RETERR(dst_context_sign(ctx, &sigbuf));
826 dst_context_destroy(&ctx);
828 rdata = NULL;
829 RETERR(dns_message_gettemprdata(msg, &rdata));
830 RETERR(isc_buffer_allocate(msg->mctx, &dynbuf, 1024));
831 RETERR(dns_rdata_fromstruct(rdata, dns_rdataclass_any,
832 dns_rdatatype_sig /* SIG(0) */,
833 &sig, dynbuf));
835 isc_mem_put(mctx, sig.signature, sig.siglen);
836 signeedsfree = ISC_FALSE;
838 dns_message_takebuffer(msg, &dynbuf);
840 datalist = NULL;
841 RETERR(dns_message_gettemprdatalist(msg, &datalist));
842 datalist->rdclass = dns_rdataclass_any;
843 datalist->type = dns_rdatatype_sig; /* SIG(0) */
844 datalist->covers = 0;
845 datalist->ttl = 0;
846 ISC_LIST_INIT(datalist->rdata);
847 ISC_LIST_APPEND(datalist->rdata, rdata, link);
848 dataset = NULL;
849 RETERR(dns_message_gettemprdataset(msg, &dataset));
850 dns_rdataset_init(dataset);
851 RUNTIME_CHECK(dns_rdatalist_tordataset(datalist, dataset) == ISC_R_SUCCESS);
852 msg->sig0 = dataset;
854 return (ISC_R_SUCCESS);
856 failure:
857 if (dynbuf != NULL)
858 isc_buffer_free(&dynbuf);
859 if (signeedsfree)
860 isc_mem_put(mctx, sig.signature, sig.siglen);
861 if (ctx != NULL)
862 dst_context_destroy(&ctx);
864 return (result);
867 isc_result_t
868 dns_dnssec_verifymessage(isc_buffer_t *source, dns_message_t *msg,
869 dst_key_t *key)
871 dns_rdata_sig_t sig; /* SIG(0) */
872 unsigned char header[DNS_MESSAGE_HEADERLEN];
873 dns_rdata_t rdata = DNS_RDATA_INIT;
874 isc_region_t r, source_r, sig_r, header_r;
875 isc_stdtime_t now;
876 dst_context_t *ctx = NULL;
877 isc_mem_t *mctx;
878 isc_result_t result;
879 isc_uint16_t addcount;
880 isc_boolean_t signeedsfree = ISC_FALSE;
882 REQUIRE(source != NULL);
883 REQUIRE(msg != NULL);
884 REQUIRE(key != NULL);
886 mctx = msg->mctx;
888 msg->verify_attempted = 1;
890 if (is_response(msg)) {
891 if (msg->query.base == NULL)
892 return (DNS_R_UNEXPECTEDTSIG);
895 isc_buffer_usedregion(source, &source_r);
897 RETERR(dns_rdataset_first(msg->sig0));
898 dns_rdataset_current(msg->sig0, &rdata);
900 RETERR(dns_rdata_tostruct(&rdata, &sig, NULL));
901 signeedsfree = ISC_TRUE;
903 if (sig.labels != 0) {
904 result = DNS_R_SIGINVALID;
905 goto failure;
908 if (isc_serial_lt(sig.timeexpire, sig.timesigned)) {
909 result = DNS_R_SIGINVALID;
910 msg->sig0status = dns_tsigerror_badtime;
911 goto failure;
914 isc_stdtime_get(&now);
915 if (isc_serial_lt((isc_uint32_t)now, sig.timesigned)) {
916 result = DNS_R_SIGFUTURE;
917 msg->sig0status = dns_tsigerror_badtime;
918 goto failure;
920 else if (isc_serial_lt(sig.timeexpire, (isc_uint32_t)now)) {
921 result = DNS_R_SIGEXPIRED;
922 msg->sig0status = dns_tsigerror_badtime;
923 goto failure;
926 if (!dns_name_equal(dst_key_name(key), &sig.signer)) {
927 result = DNS_R_SIGINVALID;
928 msg->sig0status = dns_tsigerror_badkey;
929 goto failure;
932 RETERR(dst_context_create(key, mctx, &ctx));
935 * Digest the SIG(0) record, except for the signature.
937 dns_rdata_toregion(&rdata, &r);
938 r.length -= sig.siglen;
939 RETERR(dst_context_adddata(ctx, &r));
942 * If this is a response, digest the query.
944 if (is_response(msg))
945 RETERR(dst_context_adddata(ctx, &msg->query));
948 * Extract the header.
950 memcpy(header, source_r.base, DNS_MESSAGE_HEADERLEN);
953 * Decrement the additional field counter.
955 memcpy(&addcount, &header[DNS_MESSAGE_HEADERLEN - 2], 2);
956 addcount = htons((isc_uint16_t)(ntohs(addcount) - 1));
957 memcpy(&header[DNS_MESSAGE_HEADERLEN - 2], &addcount, 2);
960 * Digest the modified header.
962 header_r.base = (unsigned char *) header;
963 header_r.length = DNS_MESSAGE_HEADERLEN;
964 RETERR(dst_context_adddata(ctx, &header_r));
967 * Digest all non-SIG(0) records.
969 r.base = source_r.base + DNS_MESSAGE_HEADERLEN;
970 r.length = msg->sigstart - DNS_MESSAGE_HEADERLEN;
971 RETERR(dst_context_adddata(ctx, &r));
973 sig_r.base = sig.signature;
974 sig_r.length = sig.siglen;
975 result = dst_context_verify(ctx, &sig_r);
976 if (result != ISC_R_SUCCESS) {
977 msg->sig0status = dns_tsigerror_badsig;
978 goto failure;
981 msg->verified_sig = 1;
983 dst_context_destroy(&ctx);
984 dns_rdata_freestruct(&sig);
986 return (ISC_R_SUCCESS);
988 failure:
989 if (signeedsfree)
990 dns_rdata_freestruct(&sig);
991 if (ctx != NULL)
992 dst_context_destroy(&ctx);
994 return (result);
998 * Does this key ('rdata') self sign the rrset ('rdataset')?
1000 isc_boolean_t
1001 dns_dnssec_selfsigns(dns_rdata_t *rdata, dns_name_t *name,
1002 dns_rdataset_t *rdataset, dns_rdataset_t *sigrdataset,
1003 isc_boolean_t ignoretime, isc_mem_t *mctx)
1005 dst_key_t *dstkey = NULL;
1006 dns_keytag_t keytag;
1007 dns_rdata_dnskey_t key;
1008 dns_rdata_rrsig_t sig;
1009 dns_rdata_t sigrdata = DNS_RDATA_INIT;
1010 isc_result_t result;
1012 INSIST(rdataset->type == dns_rdatatype_key ||
1013 rdataset->type == dns_rdatatype_dnskey);
1014 if (rdataset->type == dns_rdatatype_key) {
1015 INSIST(sigrdataset->type == dns_rdatatype_sig);
1016 INSIST(sigrdataset->covers == dns_rdatatype_key);
1017 } else {
1018 INSIST(sigrdataset->type == dns_rdatatype_rrsig);
1019 INSIST(sigrdataset->covers == dns_rdatatype_dnskey);
1022 result = dns_dnssec_keyfromrdata(name, rdata, mctx, &dstkey);
1023 if (result != ISC_R_SUCCESS)
1024 return (ISC_FALSE);
1025 result = dns_rdata_tostruct(rdata, &key, NULL);
1026 RUNTIME_CHECK(result == ISC_R_SUCCESS);
1028 keytag = dst_key_id(dstkey);
1029 for (result = dns_rdataset_first(sigrdataset);
1030 result == ISC_R_SUCCESS;
1031 result = dns_rdataset_next(sigrdataset))
1033 dns_rdata_reset(&sigrdata);
1034 dns_rdataset_current(sigrdataset, &sigrdata);
1035 result = dns_rdata_tostruct(&sigrdata, &sig, NULL);
1036 RUNTIME_CHECK(result == ISC_R_SUCCESS);
1038 if (sig.algorithm == key.algorithm &&
1039 sig.keyid == keytag) {
1040 result = dns_dnssec_verify2(name, rdataset, dstkey,
1041 ignoretime, mctx,
1042 &sigrdata, NULL);
1043 if (result == ISC_R_SUCCESS) {
1044 dst_key_free(&dstkey);
1045 return (ISC_TRUE);
1049 dst_key_free(&dstkey);
1050 return (ISC_FALSE);
1053 isc_result_t
1054 dns_dnsseckey_create(isc_mem_t *mctx, dst_key_t **dstkey,
1055 dns_dnsseckey_t **dkp)
1057 isc_result_t result;
1058 dns_dnsseckey_t *dk;
1059 int major, minor;
1061 REQUIRE(dkp != NULL && *dkp == NULL);
1062 dk = isc_mem_get(mctx, sizeof(dns_dnsseckey_t));
1063 if (dk == NULL)
1064 return (ISC_R_NOMEMORY);
1066 dk->key = *dstkey;
1067 *dstkey = NULL;
1068 dk->force_publish = ISC_FALSE;
1069 dk->force_sign = ISC_FALSE;
1070 dk->hint_publish = ISC_FALSE;
1071 dk->hint_sign = ISC_FALSE;
1072 dk->hint_remove = ISC_FALSE;
1073 dk->first_sign = ISC_FALSE;
1074 dk->is_active = ISC_FALSE;
1075 dk->prepublish = 0;
1076 dk->source = dns_keysource_unknown;
1077 dk->index = 0;
1079 /* KSK or ZSK? */
1080 dk->ksk = ISC_TF((dst_key_flags(dk->key) & DNS_KEYFLAG_KSK) != 0);
1082 /* Is this an old-style key? */
1083 result = dst_key_getprivateformat(dk->key, &major, &minor);
1085 /* Smart signing started with key format 1.3 */
1086 dk->legacy = ISC_TF(major == 1 && minor <= 2);
1088 ISC_LINK_INIT(dk, link);
1089 *dkp = dk;
1090 return (ISC_R_SUCCESS);
1093 void
1094 dns_dnsseckey_destroy(isc_mem_t *mctx, dns_dnsseckey_t **dkp) {
1095 dns_dnsseckey_t *dk;
1097 REQUIRE(dkp != NULL && *dkp != NULL);
1098 dk = *dkp;
1099 if (dk->key != NULL)
1100 dst_key_free(&dk->key);
1101 isc_mem_put(mctx, dk, sizeof(dns_dnsseckey_t));
1102 *dkp = NULL;
1105 static void
1106 get_hints(dns_dnsseckey_t *key) {
1107 isc_result_t result;
1108 isc_stdtime_t now, publish, active, revoke, inactive, delete;
1109 isc_boolean_t pubset = ISC_FALSE, actset = ISC_FALSE;
1110 isc_boolean_t revset = ISC_FALSE, inactset = ISC_FALSE;
1111 isc_boolean_t delset = ISC_FALSE;
1113 REQUIRE(key != NULL && key->key != NULL);
1115 isc_stdtime_get(&now);
1117 result = dst_key_gettime(key->key, DST_TIME_PUBLISH, &publish);
1118 if (result == ISC_R_SUCCESS)
1119 pubset = ISC_TRUE;
1121 result = dst_key_gettime(key->key, DST_TIME_ACTIVATE, &active);
1122 if (result == ISC_R_SUCCESS)
1123 actset = ISC_TRUE;
1125 result = dst_key_gettime(key->key, DST_TIME_REVOKE, &revoke);
1126 if (result == ISC_R_SUCCESS)
1127 revset = ISC_TRUE;
1129 result = dst_key_gettime(key->key, DST_TIME_INACTIVE, &inactive);
1130 if (result == ISC_R_SUCCESS)
1131 inactset = ISC_TRUE;
1133 result = dst_key_gettime(key->key, DST_TIME_DELETE, &delete);
1134 if (result == ISC_R_SUCCESS)
1135 delset = ISC_TRUE;
1137 /* Metadata says publish (but possibly not activate) */
1138 if (pubset && publish <= now)
1139 key->hint_publish = ISC_TRUE;
1141 /* Metadata says activate (so we must also publish) */
1142 if (actset && active <= now) {
1143 key->hint_sign = ISC_TRUE;
1144 key->hint_publish = ISC_TRUE;
1148 * Activation date is set (maybe in the future), but
1149 * publication date isn't. Most likely the user wants to
1150 * publish now and activate later.
1152 if (actset && !pubset)
1153 key->hint_publish = ISC_TRUE;
1156 * If activation date is in the future, make note of how far off
1158 if (key->hint_publish && actset && active > now) {
1159 key->prepublish = active - now;
1163 * Key has been marked inactive: we can continue publishing,
1164 * but don't sign.
1166 if (key->hint_publish && inactset && inactive <= now) {
1167 key->hint_sign = ISC_FALSE;
1171 * Metadata says revoke. If the key is published,
1172 * we *have to* sign with it per RFC5011--even if it was
1173 * not active before.
1175 * If it hasn't already been done, we should also revoke it now.
1177 if (key->hint_publish && (revset && revoke <= now)) {
1178 isc_uint32_t flags;
1179 key->hint_sign = ISC_TRUE;
1180 flags = dst_key_flags(key->key);
1181 if ((flags & DNS_KEYFLAG_REVOKE) == 0) {
1182 flags |= DNS_KEYFLAG_REVOKE;
1183 dst_key_setflags(key->key, flags);
1188 * Metadata says delete, so don't publish this key or sign with it.
1190 if (delset && delete <= now) {
1191 key->hint_publish = ISC_FALSE;
1192 key->hint_sign = ISC_FALSE;
1193 key->hint_remove = ISC_TRUE;
1198 * Get a list of DNSSEC keys from the key repository
1200 isc_result_t
1201 dns_dnssec_findmatchingkeys(dns_name_t *origin, const char *directory,
1202 isc_mem_t *mctx, dns_dnsseckeylist_t *keylist)
1204 isc_result_t result = ISC_R_SUCCESS;
1205 isc_boolean_t dir_open = ISC_FALSE;
1206 dns_dnsseckeylist_t list;
1207 isc_dir_t dir;
1208 dns_dnsseckey_t *key = NULL;
1209 dst_key_t *dstkey = NULL;
1210 char namebuf[DNS_NAME_FORMATSIZE], *p;
1211 isc_buffer_t b;
1212 unsigned int len;
1214 REQUIRE(keylist != NULL);
1215 ISC_LIST_INIT(list);
1216 isc_dir_init(&dir);
1218 isc_buffer_init(&b, namebuf, sizeof(namebuf) - 1);
1219 RETERR(dns_name_totext(origin, ISC_FALSE, &b));
1220 len = isc_buffer_usedlength(&b);
1221 namebuf[len] = '\0';
1223 if (directory == NULL)
1224 directory = ".";
1225 RETERR(isc_dir_open(&dir, directory));
1226 dir_open = ISC_TRUE;
1228 while (isc_dir_read(&dir) == ISC_R_SUCCESS) {
1229 if (dir.entry.name[0] == 'K' &&
1230 dir.entry.length > len + 1 &&
1231 dir.entry.name[len + 1] == '+' &&
1232 strncasecmp(dir.entry.name + 1, namebuf, len) == 0) {
1233 p = strrchr(dir.entry.name, '.');
1234 if (p != NULL && strcmp(p, ".private") != 0)
1235 continue;
1237 dstkey = NULL;
1238 RETERR(dst_key_fromnamedfile(dir.entry.name, directory,
1239 DST_TYPE_PUBLIC | DST_TYPE_PRIVATE,
1240 mctx, &dstkey));
1242 RETERR(dns_dnsseckey_create(mctx, &dstkey, &key));
1243 key->source = dns_keysource_repository;
1244 get_hints(key);
1246 if (key->legacy) {
1247 dns_dnsseckey_destroy(mctx, &key);
1248 } else {
1249 ISC_LIST_APPEND(list, key, link);
1250 key = NULL;
1255 if (!ISC_LIST_EMPTY(list))
1256 ISC_LIST_APPENDLIST(*keylist, list, link);
1257 else
1258 result = ISC_R_NOTFOUND;
1260 failure:
1261 if (dir_open)
1262 isc_dir_close(&dir);
1263 INSIST(key == NULL);
1264 while ((key = ISC_LIST_HEAD(list)) != NULL) {
1265 ISC_LIST_UNLINK(list, key, link);
1266 INSIST(key->key != NULL);
1267 dst_key_free(&key->key);
1268 dns_dnsseckey_destroy(mctx, &key);
1270 if (dstkey != NULL)
1271 dst_key_free(&dstkey);
1272 return (result);
1276 * Add 'newkey' to 'keylist' if it's not already there.
1278 * If 'savekeys' is ISC_TRUE, then we need to preserve all
1279 * the keys in the keyset, regardless of whether they have
1280 * metadata indicating they should be deactivated or removed.
1282 static void
1283 addkey(dns_dnsseckeylist_t *keylist, dst_key_t **newkey,
1284 isc_boolean_t savekeys, isc_mem_t *mctx)
1286 dns_dnsseckey_t *key;
1288 /* Skip duplicates */
1289 for (key = ISC_LIST_HEAD(*keylist);
1290 key != NULL;
1291 key = ISC_LIST_NEXT(key, link)) {
1292 if (dst_key_id(key->key) == dst_key_id(*newkey) &&
1293 dst_key_alg(key->key) == dst_key_alg(*newkey) &&
1294 dns_name_equal(dst_key_name(key->key),
1295 dst_key_name(*newkey)))
1296 break;
1299 if (key != NULL) {
1301 * Found a match. If the old key was only public and the
1302 * new key is private, replace the old one; otherwise
1303 * leave it. But either way, mark the key as having
1304 * been found in the zone.
1306 if (dst_key_isprivate(key->key)) {
1307 dst_key_free(newkey);
1308 } else if (dst_key_isprivate(*newkey)) {
1309 dst_key_free(&key->key);
1310 key->key = *newkey;
1313 key->source = dns_keysource_zoneapex;
1314 return;
1317 dns_dnsseckey_create(mctx, newkey, &key);
1318 if (key->legacy || savekeys) {
1319 key->force_publish = ISC_TRUE;
1320 key->force_sign = dst_key_isprivate(key->key);
1322 key->source = dns_keysource_zoneapex;
1323 ISC_LIST_APPEND(*keylist, key, link);
1324 *newkey = NULL;
1329 * Mark all keys which signed the DNSKEY/SOA RRsets as "active",
1330 * for future reference.
1332 static isc_result_t
1333 mark_active_keys(dns_dnsseckeylist_t *keylist, dns_rdataset_t *rrsigs) {
1334 isc_result_t result = ISC_R_SUCCESS;
1335 dns_rdata_t rdata = DNS_RDATA_INIT;
1336 dns_rdataset_t sigs;
1337 dns_dnsseckey_t *key;
1339 REQUIRE(rrsigs != NULL && dns_rdataset_isassociated(rrsigs));
1341 dns_rdataset_init(&sigs);
1342 dns_rdataset_clone(rrsigs, &sigs);
1343 for (key = ISC_LIST_HEAD(*keylist);
1344 key != NULL;
1345 key = ISC_LIST_NEXT(key, link)) {
1346 isc_uint16_t keyid, sigid;
1347 dns_secalg_t keyalg, sigalg;
1348 keyid = dst_key_id(key->key);
1349 keyalg = dst_key_alg(key->key);
1351 for (result = dns_rdataset_first(&sigs);
1352 result == ISC_R_SUCCESS;
1353 result = dns_rdataset_next(&sigs)) {
1354 dns_rdata_rrsig_t sig;
1356 dns_rdata_reset(&rdata);
1357 dns_rdataset_current(&sigs, &rdata);
1358 result = dns_rdata_tostruct(&rdata, &sig, NULL);
1359 RUNTIME_CHECK(result == ISC_R_SUCCESS);
1360 sigalg = sig.algorithm;
1361 sigid = sig.keyid;
1362 if (keyid == sigid && keyalg == sigalg) {
1363 key->is_active = ISC_TRUE;
1364 break;
1369 if (result == ISC_R_NOMORE)
1370 result = ISC_R_SUCCESS;
1372 if (dns_rdataset_isassociated(&sigs))
1373 dns_rdataset_disassociate(&sigs);
1374 return (result);
1378 * Add the contents of a DNSKEY rdataset 'keyset' to 'keylist'.
1380 isc_result_t
1381 dns_dnssec_keylistfromrdataset(dns_name_t *origin,
1382 const char *directory, isc_mem_t *mctx,
1383 dns_rdataset_t *keyset, dns_rdataset_t *keysigs,
1384 dns_rdataset_t *soasigs, isc_boolean_t savekeys,
1385 isc_boolean_t public,
1386 dns_dnsseckeylist_t *keylist)
1388 dns_rdataset_t keys;
1389 dns_rdata_t rdata = DNS_RDATA_INIT;
1390 dst_key_t *pubkey = NULL, *privkey = NULL;
1391 isc_result_t result;
1393 REQUIRE(keyset != NULL && dns_rdataset_isassociated(keyset));
1395 dns_rdataset_init(&keys);
1397 dns_rdataset_clone(keyset, &keys);
1398 for (result = dns_rdataset_first(&keys);
1399 result == ISC_R_SUCCESS;
1400 result = dns_rdataset_next(&keys)) {
1401 dns_rdata_reset(&rdata);
1402 dns_rdataset_current(&keys, &rdata);
1403 RETERR(dns_dnssec_keyfromrdata(origin, &rdata, mctx, &pubkey));
1405 if (!is_zone_key(pubkey) ||
1406 (dst_key_flags(pubkey) & DNS_KEYTYPE_NOAUTH) != 0)
1407 goto skip;
1409 /* Corrupted .key file? */
1410 if (!dns_name_equal(origin, dst_key_name(pubkey)))
1411 goto skip;
1413 if (public) {
1414 addkey(keylist, &pubkey, savekeys, mctx);
1415 goto skip;
1418 result = dst_key_fromfile(dst_key_name(pubkey),
1419 dst_key_id(pubkey),
1420 dst_key_alg(pubkey),
1421 DST_TYPE_PUBLIC|DST_TYPE_PRIVATE,
1422 directory, mctx, &privkey);
1423 if (result == ISC_R_FILENOTFOUND) {
1424 addkey(keylist, &pubkey, savekeys, mctx);
1425 goto skip;
1427 RETERR(result);
1429 /* This should never happen. */
1430 if ((dst_key_flags(privkey) & DNS_KEYTYPE_NOAUTH) != 0)
1431 goto skip;
1433 addkey(keylist, &privkey, savekeys, mctx);
1434 skip:
1435 if (pubkey != NULL)
1436 dst_key_free(&pubkey);
1437 if (privkey != NULL)
1438 dst_key_free(&privkey);
1441 if (result != ISC_R_NOMORE)
1442 RETERR(result);
1444 if (keysigs != NULL && dns_rdataset_isassociated(keysigs))
1445 RETERR(mark_active_keys(keylist, keysigs));
1447 if (soasigs != NULL && dns_rdataset_isassociated(soasigs))
1448 RETERR(mark_active_keys(keylist, soasigs));
1450 result = ISC_R_SUCCESS;
1452 failure:
1453 if (dns_rdataset_isassociated(&keys))
1454 dns_rdataset_disassociate(&keys);
1455 if (pubkey != NULL)
1456 dst_key_free(&pubkey);
1457 if (privkey != NULL)
1458 dst_key_free(&privkey);
1459 return (result);
1462 static isc_result_t
1463 make_dnskey(dst_key_t *key, unsigned char *buf, int bufsize,
1464 dns_rdata_t *target)
1466 isc_result_t result;
1467 isc_buffer_t b;
1468 isc_region_t r;
1470 isc_buffer_init(&b, buf, bufsize);
1471 result = dst_key_todns(key, &b);
1472 if (result != ISC_R_SUCCESS)
1473 return (result);
1475 dns_rdata_reset(target);
1476 isc_buffer_usedregion(&b, &r);
1477 dns_rdata_fromregion(target, dst_key_class(key),
1478 dns_rdatatype_dnskey, &r);
1479 return (ISC_R_SUCCESS);
1482 static isc_result_t
1483 publish_key(dns_diff_t *diff, dns_dnsseckey_t *key, dns_name_t *origin,
1484 dns_ttl_t ttl, isc_mem_t *mctx, isc_boolean_t allzsk,
1485 void (*report)(const char *, ...))
1487 isc_result_t result;
1488 dns_difftuple_t *tuple = NULL;
1489 unsigned char buf[DST_KEY_MAXSIZE];
1490 dns_rdata_t dnskey = DNS_RDATA_INIT;
1491 char alg[80];
1493 dns_rdata_reset(&dnskey);
1494 RETERR(make_dnskey(key->key, buf, sizeof(buf), &dnskey));
1496 dns_secalg_format(dst_key_alg(key->key), alg, sizeof(alg));
1497 report("Fetching %s %d/%s from key %s.",
1498 key->ksk ? (allzsk ? "KSK/ZSK" : "KSK") : "ZSK",
1499 dst_key_id(key->key), alg,
1500 key->source == dns_keysource_user ? "file" : "repository");
1502 if (key->prepublish && ttl > key->prepublish) {
1503 char keystr[DST_KEY_FORMATSIZE];
1504 isc_stdtime_t now;
1506 dst_key_format(key->key, keystr, sizeof(keystr));
1507 report("Key %s: Delaying activation to match the DNSKEY TTL.\n",
1508 keystr, ttl);
1510 isc_stdtime_get(&now);
1511 dst_key_settime(key->key, DST_TIME_ACTIVATE, now + ttl);
1514 /* publish key */
1515 RETERR(dns_difftuple_create(mctx, DNS_DIFFOP_ADD, origin, ttl,
1516 &dnskey, &tuple));
1517 dns_diff_appendminimal(diff, &tuple);
1518 result = ISC_R_SUCCESS;
1520 failure:
1521 return (result);
1524 static isc_result_t
1525 remove_key(dns_diff_t *diff, dns_dnsseckey_t *key, dns_name_t *origin,
1526 dns_ttl_t ttl, isc_mem_t *mctx, const char *reason,
1527 void (*report)(const char *, ...))
1529 isc_result_t result;
1530 dns_difftuple_t *tuple = NULL;
1531 unsigned char buf[DST_KEY_MAXSIZE];
1532 dns_rdata_t dnskey = DNS_RDATA_INIT;
1533 char alg[80];
1535 dns_secalg_format(dst_key_alg(key->key), alg, sizeof(alg));
1536 report("Removing %s key %d/%s from DNSKEY RRset.",
1537 reason, dst_key_id(key->key), alg);
1539 RETERR(make_dnskey(key->key, buf, sizeof(buf), &dnskey));
1540 RETERR(dns_difftuple_create(mctx, DNS_DIFFOP_DEL, origin, ttl, &dnskey,
1541 &tuple));
1542 dns_diff_appendminimal(diff, &tuple);
1543 result = ISC_R_SUCCESS;
1545 failure:
1546 return (result);
1550 * Update 'keys' with information from 'newkeys'.
1552 * If 'removed' is not NULL, any keys that are being removed from
1553 * the zone will be added to the list for post-removal processing.
1555 isc_result_t
1556 dns_dnssec_updatekeys(dns_dnsseckeylist_t *keys, dns_dnsseckeylist_t *newkeys,
1557 dns_dnsseckeylist_t *removed, dns_name_t *origin,
1558 dns_ttl_t ttl, dns_diff_t *diff, isc_boolean_t allzsk,
1559 isc_mem_t *mctx, void (*report)(const char *, ...))
1561 isc_result_t result;
1562 dns_dnsseckey_t *key, *key1, *key2, *next;
1565 * First, look through the existing key list to find keys
1566 * supplied from the command line which are not in the zone.
1567 * Update the zone to include them.
1569 for (key = ISC_LIST_HEAD(*keys);
1570 key != NULL;
1571 key = ISC_LIST_NEXT(key, link)) {
1572 if (key->source == dns_keysource_user &&
1573 (key->hint_publish || key->force_publish)) {
1574 RETERR(publish_key(diff, key, origin, ttl,
1575 mctx, allzsk, report));
1580 * Second, scan the list of newly found keys looking for matches
1581 * with known keys, and update accordingly.
1583 for (key1 = ISC_LIST_HEAD(*newkeys); key1 != NULL; key1 = next) {
1584 isc_boolean_t key_revoked = ISC_FALSE;
1586 next = ISC_LIST_NEXT(key1, link);
1588 for (key2 = ISC_LIST_HEAD(*keys);
1589 key2 != NULL;
1590 key2 = ISC_LIST_NEXT(key2, link)) {
1591 if (dst_key_pubcompare(key1->key, key2->key,
1592 ISC_TRUE)) {
1593 int r1, r2;
1594 r1 = dst_key_flags(key1->key) &
1595 DNS_KEYFLAG_REVOKE;
1596 r2 = dst_key_flags(key2->key) &
1597 DNS_KEYFLAG_REVOKE;
1598 key_revoked = ISC_TF(r1 != r2);
1599 break;
1603 /* No match found in keys; add the new key. */
1604 if (key2 == NULL) {
1605 dns_dnsseckey_t *next;
1607 next = ISC_LIST_NEXT(key1, link);
1608 ISC_LIST_UNLINK(*newkeys, key1, link);
1609 ISC_LIST_APPEND(*keys, key1, link);
1611 if (key1->source != dns_keysource_zoneapex &&
1612 (key1->hint_publish || key1->force_publish)) {
1613 RETERR(publish_key(diff, key1, origin, ttl,
1614 mctx, allzsk, report));
1615 if (key1->hint_sign || key1->force_sign)
1616 key1->first_sign = ISC_TRUE;
1619 continue;
1622 /* Match found: remove or update it as needed */
1623 if (key1->hint_remove) {
1624 RETERR(remove_key(diff, key2, origin, ttl, mctx,
1625 "expired", report));
1626 ISC_LIST_UNLINK(*keys, key2, link);
1627 if (removed != NULL)
1628 ISC_LIST_APPEND(*removed, key2, link);
1629 else
1630 dns_dnsseckey_destroy(mctx, &key2);
1631 } else if (key_revoked &&
1632 (dst_key_flags(key1->key) & DNS_KEYFLAG_REVOKE) != 0) {
1635 * A previously valid key has been revoked.
1636 * We need to remove the old version and pull
1637 * in the new one.
1639 RETERR(remove_key(diff, key2, origin, ttl, mctx,
1640 "revoked", report));
1641 ISC_LIST_UNLINK(*keys, key2, link);
1642 if (removed != NULL)
1643 ISC_LIST_APPEND(*removed, key2, link);
1644 else
1645 dns_dnsseckey_destroy(mctx, &key2);
1647 RETERR(publish_key(diff, key1, origin, ttl,
1648 mctx, allzsk, report));
1649 ISC_LIST_UNLINK(*newkeys, key1, link);
1650 ISC_LIST_APPEND(*keys, key1, link);
1653 * XXX: The revoke flag is only defined for trust
1654 * anchors. Setting the flag on a non-KSK is legal,
1655 * but not defined in any RFC. It seems reasonable
1656 * to treat it the same as a KSK: keep it in the
1657 * zone, sign the DNSKEY set with it, but not
1658 * sign other records with it.
1660 key1->ksk = ISC_TRUE;
1661 continue;
1662 } else {
1663 if (!key2->is_active &&
1664 (key1->hint_sign || key1->force_sign))
1665 key2->first_sign = ISC_TRUE;
1666 key2->hint_sign = key1->hint_sign;
1667 key2->hint_publish = key1->hint_publish;
1671 /* Free any leftover keys in newkeys */
1672 while (!ISC_LIST_EMPTY(*newkeys)) {
1673 key1 = ISC_LIST_HEAD(*newkeys);
1674 ISC_LIST_UNLINK(*newkeys, key1, link);
1675 dns_dnsseckey_destroy(mctx, &key1);
1678 result = ISC_R_SUCCESS;
1680 failure:
1681 return (result);