]> CyberLeo.Net >> Repos - FreeBSD/releng/9.3.git/blob - contrib/bind9/lib/dns/dnssec.c
Copy stable/9 to releng/9.3 as part of the 9.3-RELEASE cycle.
[FreeBSD/releng/9.3.git] / contrib / bind9 / lib / dns / dnssec.c
1 /*
2  * Copyright (C) 2004-2014  Internet Systems Consortium, Inc. ("ISC")
3  * Copyright (C) 1999-2003  Internet Software Consortium.
4  *
5  * Permission to use, copy, modify, and/or distribute this software for any
6  * purpose with or without fee is hereby granted, provided that the above
7  * copyright notice and this permission notice appear in all copies.
8  *
9  * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
10  * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
11  * AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
12  * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
13  * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
14  * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
15  * PERFORMANCE OF THIS SOFTWARE.
16  */
17
18 /*
19  * $Id$
20  */
21
22 /*! \file */
23
24 #include <config.h>
25
26 #include <stdlib.h>
27
28 #include <isc/buffer.h>
29 #include <isc/dir.h>
30 #include <isc/mem.h>
31 #include <isc/serial.h>
32 #include <isc/string.h>
33 #include <isc/util.h>
34
35 #include <dns/db.h>
36 #include <dns/diff.h>
37 #include <dns/dnssec.h>
38 #include <dns/fixedname.h>
39 #include <dns/keyvalues.h>
40 #include <dns/log.h>
41 #include <dns/message.h>
42 #include <dns/rdata.h>
43 #include <dns/rdatalist.h>
44 #include <dns/rdataset.h>
45 #include <dns/rdatastruct.h>
46 #include <dns/result.h>
47 #include <dns/stats.h>
48 #include <dns/tsig.h>           /* for DNS_TSIG_FUDGE */
49
50 #include <dst/result.h>
51
52 LIBDNS_EXTERNAL_DATA isc_stats_t *dns_dnssec_stats;
53
54 #define is_response(msg) (msg->flags & DNS_MESSAGEFLAG_QR)
55
56 #define RETERR(x) do { \
57         result = (x); \
58         if (result != ISC_R_SUCCESS) \
59                 goto failure; \
60         } while (0)
61
62
63 #define TYPE_SIGN 0
64 #define TYPE_VERIFY 1
65
66 static isc_result_t
67 digest_callback(void *arg, isc_region_t *data);
68
69 static int
70 rdata_compare_wrapper(const void *rdata1, const void *rdata2);
71
72 static isc_result_t
73 rdataset_to_sortedarray(dns_rdataset_t *set, isc_mem_t *mctx,
74                         dns_rdata_t **rdata, int *nrdata);
75
76 static isc_result_t
77 digest_callback(void *arg, isc_region_t *data) {
78         dst_context_t *ctx = arg;
79
80         return (dst_context_adddata(ctx, data));
81 }
82
83 static inline void
84 inc_stat(isc_statscounter_t counter) {
85         if (dns_dnssec_stats != NULL)
86                 isc_stats_increment(dns_dnssec_stats, counter);
87 }
88
89 /*
90  * Make qsort happy.
91  */
92 static int
93 rdata_compare_wrapper(const void *rdata1, const void *rdata2) {
94         return (dns_rdata_compare((const dns_rdata_t *)rdata1,
95                                   (const dns_rdata_t *)rdata2));
96 }
97
98 /*
99  * Sort the rdataset into an array.
100  */
101 static isc_result_t
102 rdataset_to_sortedarray(dns_rdataset_t *set, isc_mem_t *mctx,
103                         dns_rdata_t **rdata, int *nrdata)
104 {
105         isc_result_t ret;
106         int i = 0, n;
107         dns_rdata_t *data;
108         dns_rdataset_t rdataset;
109
110         n = dns_rdataset_count(set);
111
112         data = isc_mem_get(mctx, n * sizeof(dns_rdata_t));
113         if (data == NULL)
114                 return (ISC_R_NOMEMORY);
115
116         dns_rdataset_init(&rdataset);
117         dns_rdataset_clone(set, &rdataset);
118         ret = dns_rdataset_first(&rdataset);
119         if (ret != ISC_R_SUCCESS) {
120                 dns_rdataset_disassociate(&rdataset);
121                 isc_mem_put(mctx, data, n * sizeof(dns_rdata_t));
122                 return (ret);
123         }
124
125         /*
126          * Put them in the array.
127          */
128         do {
129                 dns_rdata_init(&data[i]);
130                 dns_rdataset_current(&rdataset, &data[i++]);
131         } while (dns_rdataset_next(&rdataset) == ISC_R_SUCCESS);
132
133         /*
134          * Sort the array.
135          */
136         qsort(data, n, sizeof(dns_rdata_t), rdata_compare_wrapper);
137         *rdata = data;
138         *nrdata = n;
139         dns_rdataset_disassociate(&rdataset);
140         return (ISC_R_SUCCESS);
141 }
142
143 isc_result_t
144 dns_dnssec_keyfromrdata(dns_name_t *name, dns_rdata_t *rdata, isc_mem_t *mctx,
145                         dst_key_t **key)
146 {
147         isc_buffer_t b;
148         isc_region_t r;
149
150         INSIST(name != NULL);
151         INSIST(rdata != NULL);
152         INSIST(mctx != NULL);
153         INSIST(key != NULL);
154         INSIST(*key == NULL);
155         REQUIRE(rdata->type == dns_rdatatype_key ||
156                 rdata->type == dns_rdatatype_dnskey);
157
158         dns_rdata_toregion(rdata, &r);
159         isc_buffer_init(&b, r.base, r.length);
160         isc_buffer_add(&b, r.length);
161         return (dst_key_fromdns(name, rdata->rdclass, &b, mctx, key));
162 }
163
164 static isc_result_t
165 digest_sig(dst_context_t *ctx, isc_boolean_t downcase, dns_rdata_t *sigrdata,
166            dns_rdata_rrsig_t *rrsig)
167 {
168         isc_region_t r;
169         isc_result_t ret;
170         dns_fixedname_t fname;
171
172         dns_rdata_toregion(sigrdata, &r);
173         INSIST(r.length >= 19);
174
175         r.length = 18;
176         ret = dst_context_adddata(ctx, &r);
177         if (ret != ISC_R_SUCCESS)
178                 return (ret);
179         if (downcase) {
180                 dns_fixedname_init(&fname);
181
182                 RUNTIME_CHECK(dns_name_downcase(&rrsig->signer,
183                                                 dns_fixedname_name(&fname),
184                                                 NULL) == ISC_R_SUCCESS);
185                 dns_name_toregion(dns_fixedname_name(&fname), &r);
186         } else
187                 dns_name_toregion(&rrsig->signer, &r);
188
189         return (dst_context_adddata(ctx, &r));
190 }
191
192 isc_result_t
193 dns_dnssec_sign(dns_name_t *name, dns_rdataset_t *set, dst_key_t *key,
194                 isc_stdtime_t *inception, isc_stdtime_t *expire,
195                 isc_mem_t *mctx, isc_buffer_t *buffer, dns_rdata_t *sigrdata)
196 {
197         dns_rdata_rrsig_t sig;
198         dns_rdata_t tmpsigrdata;
199         dns_rdata_t *rdatas;
200         int nrdatas, i;
201         isc_buffer_t sigbuf, envbuf;
202         isc_region_t r;
203         dst_context_t *ctx = NULL;
204         isc_result_t ret;
205         isc_buffer_t *databuf = NULL;
206         char data[256 + 8];
207         isc_uint32_t flags;
208         unsigned int sigsize;
209         dns_fixedname_t fnewname;
210         dns_fixedname_t fsigner;
211
212         REQUIRE(name != NULL);
213         REQUIRE(dns_name_countlabels(name) <= 255);
214         REQUIRE(set != NULL);
215         REQUIRE(key != NULL);
216         REQUIRE(inception != NULL);
217         REQUIRE(expire != NULL);
218         REQUIRE(mctx != NULL);
219         REQUIRE(sigrdata != NULL);
220
221         if (*inception >= *expire)
222                 return (DNS_R_INVALIDTIME);
223
224         /*
225          * Is the key allowed to sign data?
226          */
227         flags = dst_key_flags(key);
228         if (flags & DNS_KEYTYPE_NOAUTH)
229                 return (DNS_R_KEYUNAUTHORIZED);
230         if ((flags & DNS_KEYFLAG_OWNERMASK) != DNS_KEYOWNER_ZONE)
231                 return (DNS_R_KEYUNAUTHORIZED);
232
233         sig.mctx = mctx;
234         sig.common.rdclass = set->rdclass;
235         sig.common.rdtype = dns_rdatatype_rrsig;
236         ISC_LINK_INIT(&sig.common, link);
237
238         /*
239          * Downcase signer.
240          */
241         dns_name_init(&sig.signer, NULL);
242         dns_fixedname_init(&fsigner);
243         RUNTIME_CHECK(dns_name_downcase(dst_key_name(key),
244                       dns_fixedname_name(&fsigner), NULL) == ISC_R_SUCCESS);
245         dns_name_clone(dns_fixedname_name(&fsigner), &sig.signer);
246
247         sig.covered = set->type;
248         sig.algorithm = dst_key_alg(key);
249         sig.labels = dns_name_countlabels(name) - 1;
250         if (dns_name_iswildcard(name))
251                 sig.labels--;
252         sig.originalttl = set->ttl;
253         sig.timesigned = *inception;
254         sig.timeexpire = *expire;
255         sig.keyid = dst_key_id(key);
256         ret = dst_key_sigsize(key, &sigsize);
257         if (ret != ISC_R_SUCCESS)
258                 return (ret);
259         sig.siglen = sigsize;
260         /*
261          * The actual contents of sig.signature are not important yet, since
262          * they're not used in digest_sig().
263          */
264         sig.signature = isc_mem_get(mctx, sig.siglen);
265         if (sig.signature == NULL)
266                 return (ISC_R_NOMEMORY);
267
268         ret = isc_buffer_allocate(mctx, &databuf, sigsize + 256 + 18);
269         if (ret != ISC_R_SUCCESS)
270                 goto cleanup_signature;
271
272         dns_rdata_init(&tmpsigrdata);
273         ret = dns_rdata_fromstruct(&tmpsigrdata, sig.common.rdclass,
274                                    sig.common.rdtype, &sig, databuf);
275         if (ret != ISC_R_SUCCESS)
276                 goto cleanup_databuf;
277
278         ret = dst_context_create2(key, mctx, DNS_LOGCATEGORY_DNSSEC, &ctx);
279         if (ret != ISC_R_SUCCESS)
280                 goto cleanup_databuf;
281
282         /*
283          * Digest the SIG rdata.
284          */
285         ret = digest_sig(ctx, ISC_FALSE, &tmpsigrdata, &sig);
286         if (ret != ISC_R_SUCCESS)
287                 goto cleanup_context;
288
289         dns_fixedname_init(&fnewname);
290         RUNTIME_CHECK(dns_name_downcase(name, dns_fixedname_name(&fnewname),
291                                         NULL) == ISC_R_SUCCESS);
292         dns_name_toregion(dns_fixedname_name(&fnewname), &r);
293
294         /*
295          * Create an envelope for each rdata: <name|type|class|ttl>.
296          */
297         isc_buffer_init(&envbuf, data, sizeof(data));
298         memmove(data, r.base, r.length);
299         isc_buffer_add(&envbuf, r.length);
300         isc_buffer_putuint16(&envbuf, set->type);
301         isc_buffer_putuint16(&envbuf, set->rdclass);
302         isc_buffer_putuint32(&envbuf, set->ttl);
303
304         ret = rdataset_to_sortedarray(set, mctx, &rdatas, &nrdatas);
305         if (ret != ISC_R_SUCCESS)
306                 goto cleanup_context;
307         isc_buffer_usedregion(&envbuf, &r);
308
309         for (i = 0; i < nrdatas; i++) {
310                 isc_uint16_t len;
311                 isc_buffer_t lenbuf;
312                 isc_region_t lenr;
313
314                 /*
315                  * Skip duplicates.
316                  */
317                 if (i > 0 && dns_rdata_compare(&rdatas[i], &rdatas[i-1]) == 0)
318                     continue;
319
320                 /*
321                  * Digest the envelope.
322                  */
323                 ret = dst_context_adddata(ctx, &r);
324                 if (ret != ISC_R_SUCCESS)
325                         goto cleanup_array;
326
327                 /*
328                  * Digest the length of the rdata.
329                  */
330                 isc_buffer_init(&lenbuf, &len, sizeof(len));
331                 INSIST(rdatas[i].length < 65536);
332                 isc_buffer_putuint16(&lenbuf, (isc_uint16_t)rdatas[i].length);
333                 isc_buffer_usedregion(&lenbuf, &lenr);
334                 ret = dst_context_adddata(ctx, &lenr);
335                 if (ret != ISC_R_SUCCESS)
336                         goto cleanup_array;
337
338                 /*
339                  * Digest the rdata.
340                  */
341                 ret = dns_rdata_digest(&rdatas[i], digest_callback, ctx);
342                 if (ret != ISC_R_SUCCESS)
343                         goto cleanup_array;
344         }
345
346         isc_buffer_init(&sigbuf, sig.signature, sig.siglen);
347         ret = dst_context_sign(ctx, &sigbuf);
348         if (ret != ISC_R_SUCCESS)
349                 goto cleanup_array;
350         isc_buffer_usedregion(&sigbuf, &r);
351         if (r.length != sig.siglen) {
352                 ret = ISC_R_NOSPACE;
353                 goto cleanup_array;
354         }
355
356         ret = dns_rdata_fromstruct(sigrdata, sig.common.rdclass,
357                                    sig.common.rdtype, &sig, buffer);
358
359 cleanup_array:
360         isc_mem_put(mctx, rdatas, nrdatas * sizeof(dns_rdata_t));
361 cleanup_context:
362         dst_context_destroy(&ctx);
363 cleanup_databuf:
364         isc_buffer_free(&databuf);
365 cleanup_signature:
366         isc_mem_put(mctx, sig.signature, sig.siglen);
367
368         return (ret);
369 }
370
371 isc_result_t
372 dns_dnssec_verify2(dns_name_t *name, dns_rdataset_t *set, dst_key_t *key,
373                    isc_boolean_t ignoretime, isc_mem_t *mctx,
374                    dns_rdata_t *sigrdata, dns_name_t *wild)
375 {
376         return (dns_dnssec_verify3(name, set, key, ignoretime, 0, mctx,
377                                    sigrdata, wild));
378 }
379
380 isc_result_t
381 dns_dnssec_verify3(dns_name_t *name, dns_rdataset_t *set, dst_key_t *key,
382                    isc_boolean_t ignoretime, unsigned int maxbits,
383                    isc_mem_t *mctx, dns_rdata_t *sigrdata, dns_name_t *wild)
384 {
385         dns_rdata_rrsig_t sig;
386         dns_fixedname_t fnewname;
387         isc_region_t r;
388         isc_buffer_t envbuf;
389         dns_rdata_t *rdatas;
390         int nrdatas, i;
391         isc_stdtime_t now;
392         isc_result_t ret;
393         unsigned char data[300];
394         dst_context_t *ctx = NULL;
395         int labels = 0;
396         isc_uint32_t flags;
397         isc_boolean_t downcase = ISC_FALSE;
398
399         REQUIRE(name != NULL);
400         REQUIRE(set != NULL);
401         REQUIRE(key != NULL);
402         REQUIRE(mctx != NULL);
403         REQUIRE(sigrdata != NULL && sigrdata->type == dns_rdatatype_rrsig);
404
405         ret = dns_rdata_tostruct(sigrdata, &sig, NULL);
406         if (ret != ISC_R_SUCCESS)
407                 return (ret);
408
409         if (set->type != sig.covered)
410                 return (DNS_R_SIGINVALID);
411
412         if (isc_serial_lt(sig.timeexpire, sig.timesigned)) {
413                 inc_stat(dns_dnssecstats_fail);
414                 return (DNS_R_SIGINVALID);
415         }
416
417         if (!ignoretime) {
418                 isc_stdtime_get(&now);
419
420                 /*
421                  * Is SIG temporally valid?
422                  */
423                 if (isc_serial_lt((isc_uint32_t)now, sig.timesigned)) {
424                         inc_stat(dns_dnssecstats_fail);
425                         return (DNS_R_SIGFUTURE);
426                 } else if (isc_serial_lt(sig.timeexpire, (isc_uint32_t)now)) {
427                         inc_stat(dns_dnssecstats_fail);
428                         return (DNS_R_SIGEXPIRED);
429                 }
430         }
431
432         /*
433          * NS, SOA and DNSSKEY records are signed by their owner.
434          * DS records are signed by the parent.
435          */
436         switch (set->type) {
437         case dns_rdatatype_ns:
438         case dns_rdatatype_soa:
439         case dns_rdatatype_dnskey:
440                 if (!dns_name_equal(name, &sig.signer)) {
441                         inc_stat(dns_dnssecstats_fail);
442                         return (DNS_R_SIGINVALID);
443                 }
444                 break;
445         case dns_rdatatype_ds:
446                 if (dns_name_equal(name, &sig.signer)) {
447                         inc_stat(dns_dnssecstats_fail);
448                         return (DNS_R_SIGINVALID);
449                 }
450                 /* FALLTHROUGH */
451         default:
452                 if (!dns_name_issubdomain(name, &sig.signer)) {
453                         inc_stat(dns_dnssecstats_fail);
454                         return (DNS_R_SIGINVALID);
455                 }
456                 break;
457         }
458
459         /*
460          * Is the key allowed to sign data?
461          */
462         flags = dst_key_flags(key);
463         if (flags & DNS_KEYTYPE_NOAUTH) {
464                 inc_stat(dns_dnssecstats_fail);
465                 return (DNS_R_KEYUNAUTHORIZED);
466         }
467         if ((flags & DNS_KEYFLAG_OWNERMASK) != DNS_KEYOWNER_ZONE) {
468                 inc_stat(dns_dnssecstats_fail);
469                 return (DNS_R_KEYUNAUTHORIZED);
470         }
471
472  again:
473         ret = dst_context_create2(key, mctx, DNS_LOGCATEGORY_DNSSEC, &ctx);
474         if (ret != ISC_R_SUCCESS)
475                 goto cleanup_struct;
476
477         /*
478          * Digest the SIG rdata (not including the signature).
479          */
480         ret = digest_sig(ctx, downcase, sigrdata, &sig);
481         if (ret != ISC_R_SUCCESS)
482                 goto cleanup_context;
483
484         /*
485          * If the name is an expanded wildcard, use the wildcard name.
486          */
487         dns_fixedname_init(&fnewname);
488         labels = dns_name_countlabels(name) - 1;
489         RUNTIME_CHECK(dns_name_downcase(name, dns_fixedname_name(&fnewname),
490                                         NULL) == ISC_R_SUCCESS);
491         if (labels - sig.labels > 0)
492                 dns_name_split(dns_fixedname_name(&fnewname), sig.labels + 1,
493                                NULL, dns_fixedname_name(&fnewname));
494
495         dns_name_toregion(dns_fixedname_name(&fnewname), &r);
496
497         /*
498          * Create an envelope for each rdata: <name|type|class|ttl>.
499          */
500         isc_buffer_init(&envbuf, data, sizeof(data));
501         if (labels - sig.labels > 0) {
502                 isc_buffer_putuint8(&envbuf, 1);
503                 isc_buffer_putuint8(&envbuf, '*');
504                 memmove(data + 2, r.base, r.length);
505         }
506         else
507                 memmove(data, r.base, r.length);
508         isc_buffer_add(&envbuf, r.length);
509         isc_buffer_putuint16(&envbuf, set->type);
510         isc_buffer_putuint16(&envbuf, set->rdclass);
511         isc_buffer_putuint32(&envbuf, sig.originalttl);
512
513         ret = rdataset_to_sortedarray(set, mctx, &rdatas, &nrdatas);
514         if (ret != ISC_R_SUCCESS)
515                 goto cleanup_context;
516
517         isc_buffer_usedregion(&envbuf, &r);
518
519         for (i = 0; i < nrdatas; i++) {
520                 isc_uint16_t len;
521                 isc_buffer_t lenbuf;
522                 isc_region_t lenr;
523
524                 /*
525                  * Skip duplicates.
526                  */
527                 if (i > 0 && dns_rdata_compare(&rdatas[i], &rdatas[i-1]) == 0)
528                     continue;
529
530                 /*
531                  * Digest the envelope.
532                  */
533                 ret = dst_context_adddata(ctx, &r);
534                 if (ret != ISC_R_SUCCESS)
535                         goto cleanup_array;
536
537                 /*
538                  * Digest the rdata length.
539                  */
540                 isc_buffer_init(&lenbuf, &len, sizeof(len));
541                 INSIST(rdatas[i].length < 65536);
542                 isc_buffer_putuint16(&lenbuf, (isc_uint16_t)rdatas[i].length);
543                 isc_buffer_usedregion(&lenbuf, &lenr);
544
545                 /*
546                  * Digest the rdata.
547                  */
548                 ret = dst_context_adddata(ctx, &lenr);
549                 if (ret != ISC_R_SUCCESS)
550                         goto cleanup_array;
551                 ret = dns_rdata_digest(&rdatas[i], digest_callback, ctx);
552                 if (ret != ISC_R_SUCCESS)
553                         goto cleanup_array;
554         }
555
556         r.base = sig.signature;
557         r.length = sig.siglen;
558         ret = dst_context_verify2(ctx, maxbits, &r);
559         if (ret == ISC_R_SUCCESS && downcase) {
560                 char namebuf[DNS_NAME_FORMATSIZE];
561                 dns_name_format(&sig.signer, namebuf, sizeof(namebuf));
562                 isc_log_write(dns_lctx, DNS_LOGCATEGORY_DNSSEC,
563                               DNS_LOGMODULE_DNSSEC, ISC_LOG_DEBUG(1),
564                               "successfully validated after lower casing "
565                               "signer '%s'", namebuf);
566                 inc_stat(dns_dnssecstats_downcase);
567         } else if (ret == ISC_R_SUCCESS)
568                 inc_stat(dns_dnssecstats_asis);
569
570 cleanup_array:
571         isc_mem_put(mctx, rdatas, nrdatas * sizeof(dns_rdata_t));
572 cleanup_context:
573         dst_context_destroy(&ctx);
574         if (ret == DST_R_VERIFYFAILURE && !downcase) {
575                 downcase = ISC_TRUE;
576                 goto again;
577         }
578 cleanup_struct:
579         dns_rdata_freestruct(&sig);
580
581         if (ret == DST_R_VERIFYFAILURE)
582                 ret = DNS_R_SIGINVALID;
583
584         if (ret != ISC_R_SUCCESS)
585                 inc_stat(dns_dnssecstats_fail);
586
587         if (ret == ISC_R_SUCCESS && labels - sig.labels > 0) {
588                 if (wild != NULL)
589                         RUNTIME_CHECK(dns_name_concatenate(dns_wildcardname,
590                                                  dns_fixedname_name(&fnewname),
591                                                  wild, NULL) == ISC_R_SUCCESS);
592                 inc_stat(dns_dnssecstats_wildcard);
593                 ret = DNS_R_FROMWILDCARD;
594         }
595         return (ret);
596 }
597
598 isc_result_t
599 dns_dnssec_verify(dns_name_t *name, dns_rdataset_t *set, dst_key_t *key,
600                   isc_boolean_t ignoretime, isc_mem_t *mctx,
601                   dns_rdata_t *sigrdata)
602 {
603         isc_result_t result;
604
605         result = dns_dnssec_verify2(name, set, key, ignoretime, mctx,
606                                     sigrdata, NULL);
607         if (result == DNS_R_FROMWILDCARD)
608                 result = ISC_R_SUCCESS;
609         return (result);
610 }
611
612 isc_boolean_t
613 dns_dnssec_keyactive(dst_key_t *key, isc_stdtime_t now) {
614         isc_result_t result;
615         isc_stdtime_t publish, active, revoke, inactive, delete;
616         isc_boolean_t pubset = ISC_FALSE, actset = ISC_FALSE;
617         isc_boolean_t revset = ISC_FALSE, inactset = ISC_FALSE;
618         isc_boolean_t delset = ISC_FALSE;
619         int major, minor;
620
621         /* Is this an old-style key? */
622         result = dst_key_getprivateformat(key, &major, &minor);
623         RUNTIME_CHECK(result == ISC_R_SUCCESS);
624
625         /*
626          * Smart signing started with key format 1.3; prior to that, all
627          * keys are assumed active
628          */
629         if (major == 1 && minor <= 2)
630                 return (ISC_TRUE);
631
632         result = dst_key_gettime(key, DST_TIME_PUBLISH, &publish);
633         if (result == ISC_R_SUCCESS)
634                 pubset = ISC_TRUE;
635
636         result = dst_key_gettime(key, DST_TIME_ACTIVATE, &active);
637         if (result == ISC_R_SUCCESS)
638                 actset = ISC_TRUE;
639
640         result = dst_key_gettime(key, DST_TIME_REVOKE, &revoke);
641         if (result == ISC_R_SUCCESS)
642                 revset = ISC_TRUE;
643
644         result = dst_key_gettime(key, DST_TIME_INACTIVE, &inactive);
645         if (result == ISC_R_SUCCESS)
646                 inactset = ISC_TRUE;
647
648         result = dst_key_gettime(key, DST_TIME_DELETE, &delete);
649         if (result == ISC_R_SUCCESS)
650                 delset = ISC_TRUE;
651
652         if ((inactset && inactive <= now) || (delset && delete <= now))
653                 return (ISC_FALSE);
654
655         if (revset && revoke <= now && pubset && publish <= now)
656                 return (ISC_TRUE);
657
658         if (actset && active <= now)
659                 return (ISC_TRUE);
660
661         return (ISC_FALSE);
662 }
663
664 #define is_zone_key(key) ((dst_key_flags(key) & DNS_KEYFLAG_OWNERMASK) \
665                           == DNS_KEYOWNER_ZONE)
666
667 isc_result_t
668 dns_dnssec_findzonekeys2(dns_db_t *db, dns_dbversion_t *ver,
669                          dns_dbnode_t *node, dns_name_t *name,
670                          const char *directory, isc_mem_t *mctx,
671                          unsigned int maxkeys, dst_key_t **keys,
672                          unsigned int *nkeys)
673 {
674         dns_rdataset_t rdataset;
675         dns_rdata_t rdata = DNS_RDATA_INIT;
676         isc_result_t result;
677         dst_key_t *pubkey = NULL;
678         unsigned int count = 0;
679         isc_stdtime_t now;
680
681         REQUIRE(nkeys != NULL);
682         REQUIRE(keys != NULL);
683
684         isc_stdtime_get(&now);
685
686         *nkeys = 0;
687         memset(keys, 0, sizeof(*keys) * maxkeys);
688         dns_rdataset_init(&rdataset);
689         RETERR(dns_db_findrdataset(db, node, ver, dns_rdatatype_dnskey, 0, 0,
690                                    &rdataset, NULL));
691         RETERR(dns_rdataset_first(&rdataset));
692         while (result == ISC_R_SUCCESS && count < maxkeys) {
693                 pubkey = NULL;
694                 dns_rdataset_current(&rdataset, &rdata);
695                 RETERR(dns_dnssec_keyfromrdata(name, &rdata, mctx, &pubkey));
696                 dst_key_setttl(pubkey, rdataset.ttl);
697
698                 if (!is_zone_key(pubkey) ||
699                     (dst_key_flags(pubkey) & DNS_KEYTYPE_NOAUTH) != 0)
700                         goto next;
701                 /* Corrupted .key file? */
702                 if (!dns_name_equal(name, dst_key_name(pubkey)))
703                         goto next;
704                 keys[count] = NULL;
705                 result = dst_key_fromfile(dst_key_name(pubkey),
706                                           dst_key_id(pubkey),
707                                           dst_key_alg(pubkey),
708                                           DST_TYPE_PUBLIC|DST_TYPE_PRIVATE,
709                                           directory,
710                                           mctx, &keys[count]);
711
712                 /*
713                  * If the key was revoked and the private file
714                  * doesn't exist, maybe it was revoked internally
715                  * by named.  Try loading the unrevoked version.
716                  */
717                 if (result == ISC_R_FILENOTFOUND) {
718                         isc_uint32_t flags;
719                         flags = dst_key_flags(pubkey);
720                         if ((flags & DNS_KEYFLAG_REVOKE) != 0) {
721                                 dst_key_setflags(pubkey,
722                                                  flags & ~DNS_KEYFLAG_REVOKE);
723                                 result = dst_key_fromfile(dst_key_name(pubkey),
724                                                           dst_key_id(pubkey),
725                                                           dst_key_alg(pubkey),
726                                                           DST_TYPE_PUBLIC|
727                                                           DST_TYPE_PRIVATE,
728                                                           directory,
729                                                           mctx, &keys[count]);
730                                 if (result == ISC_R_SUCCESS &&
731                                     dst_key_pubcompare(pubkey, keys[count],
732                                                        ISC_FALSE)) {
733                                         dst_key_setflags(keys[count], flags);
734                                 }
735                                 dst_key_setflags(pubkey, flags);
736                         }
737                 }
738
739                 if (result != ISC_R_SUCCESS) {
740                         char keybuf[DNS_NAME_FORMATSIZE];
741                         char algbuf[DNS_SECALG_FORMATSIZE];
742                         dns_name_format(dst_key_name(pubkey), keybuf,
743                                         sizeof(keybuf));
744                         dns_secalg_format(dst_key_alg(pubkey), algbuf,
745                                           sizeof(algbuf));
746                         isc_log_write(dns_lctx, DNS_LOGCATEGORY_GENERAL,
747                                       DNS_LOGMODULE_DNSSEC, ISC_LOG_WARNING,
748                                       "dns_dnssec_findzonekeys2: error "
749                                       "reading private key file %s/%s/%d: %s",
750                                       keybuf, algbuf, dst_key_id(pubkey),
751                                       isc_result_totext(result));
752                 }
753
754                 if (result == ISC_R_FILENOTFOUND || result == ISC_R_NOPERM) {
755                         keys[count] = pubkey;
756                         pubkey = NULL;
757                         count++;
758                         goto next;
759                 }
760
761                 if (result != ISC_R_SUCCESS)
762                         goto failure;
763
764                 /*
765                  * If a key is marked inactive, skip it
766                  */
767                 if (!dns_dnssec_keyactive(keys[count], now)) {
768                         dst_key_setinactive(pubkey, ISC_TRUE);
769                         dst_key_free(&keys[count]);
770                         keys[count] = pubkey;
771                         pubkey = NULL;
772                         count++;
773                         goto next;
774                 }
775
776                 /*
777                  * Whatever the key's default TTL may have
778                  * been, the rdataset TTL takes priority.
779                  */
780                 dst_key_setttl(keys[count], rdataset.ttl);
781
782                 if ((dst_key_flags(keys[count]) & DNS_KEYTYPE_NOAUTH) != 0) {
783                         /* We should never get here. */
784                         dst_key_free(&keys[count]);
785                         goto next;
786                 }
787                 count++;
788  next:
789                 if (pubkey != NULL)
790                         dst_key_free(&pubkey);
791                 dns_rdata_reset(&rdata);
792                 result = dns_rdataset_next(&rdataset);
793         }
794         if (result != ISC_R_NOMORE)
795                 goto failure;
796         if (count == 0)
797                 result = ISC_R_NOTFOUND;
798         else
799                 result = ISC_R_SUCCESS;
800
801  failure:
802         if (dns_rdataset_isassociated(&rdataset))
803                 dns_rdataset_disassociate(&rdataset);
804         if (pubkey != NULL)
805                 dst_key_free(&pubkey);
806         if (result != ISC_R_SUCCESS)
807                 while (count > 0)
808                         dst_key_free(&keys[--count]);
809         *nkeys = count;
810         return (result);
811 }
812
813 isc_result_t
814 dns_dnssec_findzonekeys(dns_db_t *db, dns_dbversion_t *ver,
815                         dns_dbnode_t *node, dns_name_t *name, isc_mem_t *mctx,
816                         unsigned int maxkeys, dst_key_t **keys,
817                         unsigned int *nkeys)
818 {
819         return (dns_dnssec_findzonekeys2(db, ver, node, name, NULL, mctx,
820                                          maxkeys, keys, nkeys));
821 }
822
823 isc_result_t
824 dns_dnssec_signmessage(dns_message_t *msg, dst_key_t *key) {
825         dns_rdata_sig_t sig;    /* SIG(0) */
826         unsigned char data[512];
827         unsigned char header[DNS_MESSAGE_HEADERLEN];
828         isc_buffer_t headerbuf, databuf, sigbuf;
829         unsigned int sigsize;
830         isc_buffer_t *dynbuf = NULL;
831         dns_rdata_t *rdata;
832         dns_rdatalist_t *datalist;
833         dns_rdataset_t *dataset;
834         isc_region_t r;
835         isc_stdtime_t now;
836         dst_context_t *ctx = NULL;
837         isc_mem_t *mctx;
838         isc_result_t result;
839         isc_boolean_t signeedsfree = ISC_TRUE;
840
841         REQUIRE(msg != NULL);
842         REQUIRE(key != NULL);
843
844         if (is_response(msg))
845                 REQUIRE(msg->query.base != NULL);
846
847         mctx = msg->mctx;
848
849         memset(&sig, 0, sizeof(sig));
850
851         sig.mctx = mctx;
852         sig.common.rdclass = dns_rdataclass_any;
853         sig.common.rdtype = dns_rdatatype_sig;  /* SIG(0) */
854         ISC_LINK_INIT(&sig.common, link);
855
856         sig.covered = 0;
857         sig.algorithm = dst_key_alg(key);
858         sig.labels = 0; /* the root name */
859         sig.originalttl = 0;
860
861         isc_stdtime_get(&now);
862         sig.timesigned = now - DNS_TSIG_FUDGE;
863         sig.timeexpire = now + DNS_TSIG_FUDGE;
864
865         sig.keyid = dst_key_id(key);
866
867         dns_name_init(&sig.signer, NULL);
868         dns_name_clone(dst_key_name(key), &sig.signer);
869
870         sig.siglen = 0;
871         sig.signature = NULL;
872
873         isc_buffer_init(&databuf, data, sizeof(data));
874
875         RETERR(dst_context_create2(key, mctx, DNS_LOGCATEGORY_DNSSEC, &ctx));
876
877         /*
878          * Digest the fields of the SIG - we can cheat and use
879          * dns_rdata_fromstruct.  Since siglen is 0, the digested data
880          * is identical to dns format.
881          */
882         RETERR(dns_rdata_fromstruct(NULL, dns_rdataclass_any,
883                                     dns_rdatatype_sig /* SIG(0) */,
884                                     &sig, &databuf));
885         isc_buffer_usedregion(&databuf, &r);
886         RETERR(dst_context_adddata(ctx, &r));
887
888         /*
889          * If this is a response, digest the query.
890          */
891         if (is_response(msg))
892                 RETERR(dst_context_adddata(ctx, &msg->query));
893
894         /*
895          * Digest the header.
896          */
897         isc_buffer_init(&headerbuf, header, sizeof(header));
898         dns_message_renderheader(msg, &headerbuf);
899         isc_buffer_usedregion(&headerbuf, &r);
900         RETERR(dst_context_adddata(ctx, &r));
901
902         /*
903          * Digest the remainder of the message.
904          */
905         isc_buffer_usedregion(msg->buffer, &r);
906         isc_region_consume(&r, DNS_MESSAGE_HEADERLEN);
907         RETERR(dst_context_adddata(ctx, &r));
908
909         RETERR(dst_key_sigsize(key, &sigsize));
910         sig.siglen = sigsize;
911         sig.signature = (unsigned char *) isc_mem_get(mctx, sig.siglen);
912         if (sig.signature == NULL) {
913                 result = ISC_R_NOMEMORY;
914                 goto failure;
915         }
916
917         isc_buffer_init(&sigbuf, sig.signature, sig.siglen);
918         RETERR(dst_context_sign(ctx, &sigbuf));
919         dst_context_destroy(&ctx);
920
921         rdata = NULL;
922         RETERR(dns_message_gettemprdata(msg, &rdata));
923         RETERR(isc_buffer_allocate(msg->mctx, &dynbuf, 1024));
924         RETERR(dns_rdata_fromstruct(rdata, dns_rdataclass_any,
925                                     dns_rdatatype_sig /* SIG(0) */,
926                                     &sig, dynbuf));
927
928         isc_mem_put(mctx, sig.signature, sig.siglen);
929         signeedsfree = ISC_FALSE;
930
931         dns_message_takebuffer(msg, &dynbuf);
932
933         datalist = NULL;
934         RETERR(dns_message_gettemprdatalist(msg, &datalist));
935         datalist->rdclass = dns_rdataclass_any;
936         datalist->type = dns_rdatatype_sig;     /* SIG(0) */
937         datalist->covers = 0;
938         datalist->ttl = 0;
939         ISC_LIST_INIT(datalist->rdata);
940         ISC_LIST_APPEND(datalist->rdata, rdata, link);
941         dataset = NULL;
942         RETERR(dns_message_gettemprdataset(msg, &dataset));
943         dns_rdataset_init(dataset);
944         RUNTIME_CHECK(dns_rdatalist_tordataset(datalist, dataset) == ISC_R_SUCCESS);
945         msg->sig0 = dataset;
946
947         return (ISC_R_SUCCESS);
948
949 failure:
950         if (dynbuf != NULL)
951                 isc_buffer_free(&dynbuf);
952         if (signeedsfree)
953                 isc_mem_put(mctx, sig.signature, sig.siglen);
954         if (ctx != NULL)
955                 dst_context_destroy(&ctx);
956
957         return (result);
958 }
959
960 isc_result_t
961 dns_dnssec_verifymessage(isc_buffer_t *source, dns_message_t *msg,
962                          dst_key_t *key)
963 {
964         dns_rdata_sig_t sig;    /* SIG(0) */
965         unsigned char header[DNS_MESSAGE_HEADERLEN];
966         dns_rdata_t rdata = DNS_RDATA_INIT;
967         isc_region_t r, source_r, sig_r, header_r;
968         isc_stdtime_t now;
969         dst_context_t *ctx = NULL;
970         isc_mem_t *mctx;
971         isc_result_t result;
972         isc_uint16_t addcount;
973         isc_boolean_t signeedsfree = ISC_FALSE;
974
975         REQUIRE(source != NULL);
976         REQUIRE(msg != NULL);
977         REQUIRE(key != NULL);
978
979         mctx = msg->mctx;
980
981         msg->verify_attempted = 1;
982
983         if (is_response(msg)) {
984                 if (msg->query.base == NULL)
985                         return (DNS_R_UNEXPECTEDTSIG);
986         }
987
988         isc_buffer_usedregion(source, &source_r);
989
990         RETERR(dns_rdataset_first(msg->sig0));
991         dns_rdataset_current(msg->sig0, &rdata);
992
993         RETERR(dns_rdata_tostruct(&rdata, &sig, NULL));
994         signeedsfree = ISC_TRUE;
995
996         if (sig.labels != 0) {
997                 result = DNS_R_SIGINVALID;
998                 goto failure;
999         }
1000
1001         if (isc_serial_lt(sig.timeexpire, sig.timesigned)) {
1002                 result = DNS_R_SIGINVALID;
1003                 msg->sig0status = dns_tsigerror_badtime;
1004                 goto failure;
1005         }
1006
1007         isc_stdtime_get(&now);
1008         if (isc_serial_lt((isc_uint32_t)now, sig.timesigned)) {
1009                 result = DNS_R_SIGFUTURE;
1010                 msg->sig0status = dns_tsigerror_badtime;
1011                 goto failure;
1012         }
1013         else if (isc_serial_lt(sig.timeexpire, (isc_uint32_t)now)) {
1014                 result = DNS_R_SIGEXPIRED;
1015                 msg->sig0status = dns_tsigerror_badtime;
1016                 goto failure;
1017         }
1018
1019         if (!dns_name_equal(dst_key_name(key), &sig.signer)) {
1020                 result = DNS_R_SIGINVALID;
1021                 msg->sig0status = dns_tsigerror_badkey;
1022                 goto failure;
1023         }
1024
1025         RETERR(dst_context_create2(key, mctx, DNS_LOGCATEGORY_DNSSEC, &ctx));
1026
1027         /*
1028          * Digest the SIG(0) record, except for the signature.
1029          */
1030         dns_rdata_toregion(&rdata, &r);
1031         r.length -= sig.siglen;
1032         RETERR(dst_context_adddata(ctx, &r));
1033
1034         /*
1035          * If this is a response, digest the query.
1036          */
1037         if (is_response(msg))
1038                 RETERR(dst_context_adddata(ctx, &msg->query));
1039
1040         /*
1041          * Extract the header.
1042          */
1043         memmove(header, source_r.base, DNS_MESSAGE_HEADERLEN);
1044
1045         /*
1046          * Decrement the additional field counter.
1047          */
1048         memmove(&addcount, &header[DNS_MESSAGE_HEADERLEN - 2], 2);
1049         addcount = htons((isc_uint16_t)(ntohs(addcount) - 1));
1050         memmove(&header[DNS_MESSAGE_HEADERLEN - 2], &addcount, 2);
1051
1052         /*
1053          * Digest the modified header.
1054          */
1055         header_r.base = (unsigned char *) header;
1056         header_r.length = DNS_MESSAGE_HEADERLEN;
1057         RETERR(dst_context_adddata(ctx, &header_r));
1058
1059         /*
1060          * Digest all non-SIG(0) records.
1061          */
1062         r.base = source_r.base + DNS_MESSAGE_HEADERLEN;
1063         r.length = msg->sigstart - DNS_MESSAGE_HEADERLEN;
1064         RETERR(dst_context_adddata(ctx, &r));
1065
1066         sig_r.base = sig.signature;
1067         sig_r.length = sig.siglen;
1068         result = dst_context_verify(ctx, &sig_r);
1069         if (result != ISC_R_SUCCESS) {
1070                 msg->sig0status = dns_tsigerror_badsig;
1071                 goto failure;
1072         }
1073
1074         msg->verified_sig = 1;
1075
1076         dst_context_destroy(&ctx);
1077         dns_rdata_freestruct(&sig);
1078
1079         return (ISC_R_SUCCESS);
1080
1081 failure:
1082         if (signeedsfree)
1083                 dns_rdata_freestruct(&sig);
1084         if (ctx != NULL)
1085                 dst_context_destroy(&ctx);
1086
1087         return (result);
1088 }
1089
1090 /*%
1091  * Does this key ('rdata') self sign the rrset ('rdataset')?
1092  */
1093 isc_boolean_t
1094 dns_dnssec_selfsigns(dns_rdata_t *rdata, dns_name_t *name,
1095                      dns_rdataset_t *rdataset, dns_rdataset_t *sigrdataset,
1096                      isc_boolean_t ignoretime, isc_mem_t *mctx)
1097 {
1098         INSIST(rdataset->type == dns_rdatatype_key ||
1099                rdataset->type == dns_rdatatype_dnskey);
1100         if (rdataset->type == dns_rdatatype_key) {
1101                 INSIST(sigrdataset->type == dns_rdatatype_sig);
1102                 INSIST(sigrdataset->covers == dns_rdatatype_key);
1103         } else {
1104                 INSIST(sigrdataset->type == dns_rdatatype_rrsig);
1105                 INSIST(sigrdataset->covers == dns_rdatatype_dnskey);
1106         }
1107
1108         return (dns_dnssec_signs(rdata, name, rdataset, sigrdataset,
1109                                  ignoretime, mctx));
1110
1111 }
1112
1113 isc_boolean_t
1114 dns_dnssec_signs(dns_rdata_t *rdata, dns_name_t *name,
1115                      dns_rdataset_t *rdataset, dns_rdataset_t *sigrdataset,
1116                      isc_boolean_t ignoretime, isc_mem_t *mctx)
1117 {
1118         dst_key_t *dstkey = NULL;
1119         dns_keytag_t keytag;
1120         dns_rdata_dnskey_t key;
1121         dns_rdata_rrsig_t sig;
1122         dns_rdata_t sigrdata = DNS_RDATA_INIT;
1123         isc_result_t result;
1124
1125         INSIST(sigrdataset->type == dns_rdatatype_rrsig);
1126         if (sigrdataset->covers != rdataset->type)
1127                 return (ISC_FALSE);
1128
1129         result = dns_dnssec_keyfromrdata(name, rdata, mctx, &dstkey);
1130         if (result != ISC_R_SUCCESS)
1131                 return (ISC_FALSE);
1132         result = dns_rdata_tostruct(rdata, &key, NULL);
1133         RUNTIME_CHECK(result == ISC_R_SUCCESS);
1134
1135         keytag = dst_key_id(dstkey);
1136         for (result = dns_rdataset_first(sigrdataset);
1137              result == ISC_R_SUCCESS;
1138              result = dns_rdataset_next(sigrdataset))
1139         {
1140                 dns_rdata_reset(&sigrdata);
1141                 dns_rdataset_current(sigrdataset, &sigrdata);
1142                 result = dns_rdata_tostruct(&sigrdata, &sig, NULL);
1143                 RUNTIME_CHECK(result == ISC_R_SUCCESS);
1144
1145                 if (sig.algorithm == key.algorithm &&
1146                     sig.keyid == keytag) {
1147                         result = dns_dnssec_verify2(name, rdataset, dstkey,
1148                                                     ignoretime, mctx,
1149                                                     &sigrdata, NULL);
1150                         if (result == ISC_R_SUCCESS) {
1151                                 dst_key_free(&dstkey);
1152                                 return (ISC_TRUE);
1153                         }
1154                 }
1155         }
1156         dst_key_free(&dstkey);
1157         return (ISC_FALSE);
1158 }
1159
1160 isc_result_t
1161 dns_dnsseckey_create(isc_mem_t *mctx, dst_key_t **dstkey,
1162                      dns_dnsseckey_t **dkp)
1163 {
1164         isc_result_t result;
1165         dns_dnsseckey_t *dk;
1166         int major, minor;
1167
1168         REQUIRE(dkp != NULL && *dkp == NULL);
1169         dk = isc_mem_get(mctx, sizeof(dns_dnsseckey_t));
1170         if (dk == NULL)
1171                 return (ISC_R_NOMEMORY);
1172
1173         dk->key = *dstkey;
1174         *dstkey = NULL;
1175         dk->force_publish = ISC_FALSE;
1176         dk->force_sign = ISC_FALSE;
1177         dk->hint_publish = ISC_FALSE;
1178         dk->hint_sign = ISC_FALSE;
1179         dk->hint_remove = ISC_FALSE;
1180         dk->first_sign = ISC_FALSE;
1181         dk->is_active = ISC_FALSE;
1182         dk->prepublish = 0;
1183         dk->source = dns_keysource_unknown;
1184         dk->index = 0;
1185
1186         /* KSK or ZSK? */
1187         dk->ksk = ISC_TF((dst_key_flags(dk->key) & DNS_KEYFLAG_KSK) != 0);
1188
1189         /* Is this an old-style key? */
1190         result = dst_key_getprivateformat(dk->key, &major, &minor);
1191         INSIST(result == ISC_R_SUCCESS);
1192
1193         /* Smart signing started with key format 1.3 */
1194         dk->legacy = ISC_TF(major == 1 && minor <= 2);
1195
1196         ISC_LINK_INIT(dk, link);
1197         *dkp = dk;
1198         return (ISC_R_SUCCESS);
1199 }
1200
1201 void
1202 dns_dnsseckey_destroy(isc_mem_t *mctx, dns_dnsseckey_t **dkp) {
1203         dns_dnsseckey_t *dk;
1204
1205         REQUIRE(dkp != NULL && *dkp != NULL);
1206         dk = *dkp;
1207         if (dk->key != NULL)
1208                 dst_key_free(&dk->key);
1209         isc_mem_put(mctx, dk, sizeof(dns_dnsseckey_t));
1210         *dkp = NULL;
1211 }
1212
1213 static void
1214 get_hints(dns_dnsseckey_t *key, isc_stdtime_t now) {
1215         isc_result_t result;
1216         isc_stdtime_t publish, active, revoke, inactive, delete;
1217         isc_boolean_t pubset = ISC_FALSE, actset = ISC_FALSE;
1218         isc_boolean_t revset = ISC_FALSE, inactset = ISC_FALSE;
1219         isc_boolean_t delset = ISC_FALSE;
1220
1221         REQUIRE(key != NULL && key->key != NULL);
1222
1223         result = dst_key_gettime(key->key, DST_TIME_PUBLISH, &publish);
1224         if (result == ISC_R_SUCCESS)
1225                 pubset = ISC_TRUE;
1226
1227         result = dst_key_gettime(key->key, DST_TIME_ACTIVATE, &active);
1228         if (result == ISC_R_SUCCESS)
1229                 actset = ISC_TRUE;
1230
1231         result = dst_key_gettime(key->key, DST_TIME_REVOKE, &revoke);
1232         if (result == ISC_R_SUCCESS)
1233                 revset = ISC_TRUE;
1234
1235         result = dst_key_gettime(key->key, DST_TIME_INACTIVE, &inactive);
1236         if (result == ISC_R_SUCCESS)
1237                 inactset = ISC_TRUE;
1238
1239         result = dst_key_gettime(key->key, DST_TIME_DELETE, &delete);
1240         if (result == ISC_R_SUCCESS)
1241                 delset = ISC_TRUE;
1242
1243         /* Metadata says publish (but possibly not activate) */
1244         if (pubset && publish <= now)
1245                 key->hint_publish = ISC_TRUE;
1246
1247         /* Metadata says activate (so we must also publish) */
1248         if (actset && active <= now) {
1249                 key->hint_sign = ISC_TRUE;
1250                 key->hint_publish = ISC_TRUE;
1251         }
1252
1253         /*
1254          * Activation date is set (maybe in the future), but
1255          * publication date isn't. Most likely the user wants to
1256          * publish now and activate later.
1257          */
1258         if (actset && !pubset)
1259                 key->hint_publish = ISC_TRUE;
1260
1261         /*
1262          * If activation date is in the future, make note of how far off
1263          */
1264         if (key->hint_publish && actset && active > now) {
1265                 key->prepublish = active - now;
1266         }
1267
1268         /*
1269          * Key has been marked inactive: we can continue publishing,
1270          * but don't sign.
1271          */
1272         if (key->hint_publish && inactset && inactive <= now) {
1273                 key->hint_sign = ISC_FALSE;
1274         }
1275
1276         /*
1277          * Metadata says revoke.  If the key is published,
1278          * we *have to* sign with it per RFC5011--even if it was
1279          * not active before.
1280          *
1281          * If it hasn't already been done, we should also revoke it now.
1282          */
1283         if (key->hint_publish && (revset && revoke <= now)) {
1284                 isc_uint32_t flags;
1285                 key->hint_sign = ISC_TRUE;
1286                 flags = dst_key_flags(key->key);
1287                 if ((flags & DNS_KEYFLAG_REVOKE) == 0) {
1288                         flags |= DNS_KEYFLAG_REVOKE;
1289                         dst_key_setflags(key->key, flags);
1290                 }
1291         }
1292
1293         /*
1294          * Metadata says delete, so don't publish this key or sign with it.
1295          */
1296         if (delset && delete <= now) {
1297                 key->hint_publish = ISC_FALSE;
1298                 key->hint_sign = ISC_FALSE;
1299                 key->hint_remove = ISC_TRUE;
1300         }
1301 }
1302
1303 /*%
1304  * Get a list of DNSSEC keys from the key repository
1305  */
1306 isc_result_t
1307 dns_dnssec_findmatchingkeys(dns_name_t *origin, const char *directory,
1308                             isc_mem_t *mctx, dns_dnsseckeylist_t *keylist)
1309 {
1310         isc_result_t result = ISC_R_SUCCESS;
1311         isc_boolean_t dir_open = ISC_FALSE;
1312         dns_dnsseckeylist_t list;
1313         isc_dir_t dir;
1314         dns_dnsseckey_t *key = NULL;
1315         dst_key_t *dstkey = NULL;
1316         char namebuf[DNS_NAME_FORMATSIZE];
1317         isc_buffer_t b;
1318         unsigned int len, i;
1319         isc_stdtime_t now;
1320
1321         REQUIRE(keylist != NULL);
1322         ISC_LIST_INIT(list);
1323         isc_dir_init(&dir);
1324
1325         isc_buffer_init(&b, namebuf, sizeof(namebuf) - 1);
1326         RETERR(dns_name_tofilenametext(origin, ISC_FALSE, &b));
1327         len = isc_buffer_usedlength(&b);
1328         namebuf[len] = '\0';
1329
1330         if (directory == NULL)
1331                 directory = ".";
1332         RETERR(isc_dir_open(&dir, directory));
1333         dir_open = ISC_TRUE;
1334
1335         isc_stdtime_get(&now);
1336
1337         while (isc_dir_read(&dir) == ISC_R_SUCCESS) {
1338                 if (dir.entry.name[0] != 'K' ||
1339                     dir.entry.length < len + 1 ||
1340                     dir.entry.name[len + 1] != '+' ||
1341                     strncasecmp(dir.entry.name + 1, namebuf, len) != 0)
1342                         continue;
1343
1344                 for (i = len + 1 + 1; i < dir.entry.length ; i++)
1345                         if (dir.entry.name[i] < '0' || dir.entry.name[i] > '9')
1346                                 break;
1347
1348                 if (i == len + 1 + 1 || i >= dir.entry.length ||
1349                     dir.entry.name[i] != '+')
1350                         continue;
1351
1352                 for (i++ ; i < dir.entry.length ; i++)
1353                         if (dir.entry.name[i] < '0' || dir.entry.name[i] > '9')
1354                                 break;
1355
1356                 if (strcmp(dir.entry.name + i, ".private") != 0)
1357                                 continue;
1358
1359                 dstkey = NULL;
1360                 result = dst_key_fromnamedfile(dir.entry.name,
1361                                                directory,
1362                                                DST_TYPE_PUBLIC |
1363                                                DST_TYPE_PRIVATE,
1364                                                mctx, &dstkey);
1365
1366                 if (result != ISC_R_SUCCESS) {
1367                         isc_log_write(dns_lctx,
1368                                       DNS_LOGCATEGORY_GENERAL,
1369                                       DNS_LOGMODULE_DNSSEC,
1370                                       ISC_LOG_WARNING,
1371                                       "dns_dnssec_findmatchingkeys: "
1372                                       "error reading key file %s: %s",
1373                                       dir.entry.name,
1374                                       isc_result_totext(result));
1375                         continue;
1376                 }
1377
1378                 RETERR(dns_dnsseckey_create(mctx, &dstkey, &key));
1379                 key->source = dns_keysource_repository;
1380                 get_hints(key, now);
1381
1382                 if (key->legacy) {
1383                         dns_dnsseckey_destroy(mctx, &key);
1384                 } else {
1385                         ISC_LIST_APPEND(list, key, link);
1386                         key = NULL;
1387                 }
1388         }
1389
1390         if (!ISC_LIST_EMPTY(list)) {
1391                 result = ISC_R_SUCCESS;
1392                 ISC_LIST_APPENDLIST(*keylist, list, link);
1393         } else
1394                 result = ISC_R_NOTFOUND;
1395
1396  failure:
1397         if (dir_open)
1398                 isc_dir_close(&dir);
1399         INSIST(key == NULL);
1400         while ((key = ISC_LIST_HEAD(list)) != NULL) {
1401                 ISC_LIST_UNLINK(list, key, link);
1402                 INSIST(key->key != NULL);
1403                 dst_key_free(&key->key);
1404                 dns_dnsseckey_destroy(mctx, &key);
1405         }
1406         if (dstkey != NULL)
1407                 dst_key_free(&dstkey);
1408         return (result);
1409 }
1410
1411 /*%
1412  * Add 'newkey' to 'keylist' if it's not already there.
1413  *
1414  * If 'savekeys' is ISC_TRUE, then we need to preserve all
1415  * the keys in the keyset, regardless of whether they have
1416  * metadata indicating they should be deactivated or removed.
1417  */
1418 static isc_result_t
1419 addkey(dns_dnsseckeylist_t *keylist, dst_key_t **newkey,
1420        isc_boolean_t savekeys, isc_mem_t *mctx)
1421 {
1422         dns_dnsseckey_t *key;
1423         isc_result_t result;
1424
1425         /* Skip duplicates */
1426         for (key = ISC_LIST_HEAD(*keylist);
1427              key != NULL;
1428              key = ISC_LIST_NEXT(key, link)) {
1429                 if (dst_key_id(key->key) == dst_key_id(*newkey) &&
1430                     dst_key_alg(key->key) == dst_key_alg(*newkey) &&
1431                     dns_name_equal(dst_key_name(key->key),
1432                                    dst_key_name(*newkey)))
1433                         break;
1434         }
1435
1436         if (key != NULL) {
1437                 /*
1438                  * Found a match.  If the old key was only public and the
1439                  * new key is private, replace the old one; otherwise
1440                  * leave it.  But either way, mark the key as having
1441                  * been found in the zone.
1442                  */
1443                 if (dst_key_isprivate(key->key)) {
1444                         dst_key_free(newkey);
1445                 } else if (dst_key_isprivate(*newkey)) {
1446                         dst_key_free(&key->key);
1447                         key->key = *newkey;
1448                 }
1449
1450                 key->source = dns_keysource_zoneapex;
1451                 return (ISC_R_SUCCESS);
1452         }
1453
1454         result = dns_dnsseckey_create(mctx, newkey, &key);
1455         if (result != ISC_R_SUCCESS)
1456                 return (result);
1457         if (key->legacy || savekeys) {
1458                 key->force_publish = ISC_TRUE;
1459                 key->force_sign = dst_key_isprivate(key->key);
1460         }
1461         key->source = dns_keysource_zoneapex;
1462         ISC_LIST_APPEND(*keylist, key, link);
1463         *newkey = NULL;
1464         return (ISC_R_SUCCESS);
1465 }
1466
1467
1468 /*%
1469  * Mark all keys which signed the DNSKEY/SOA RRsets as "active",
1470  * for future reference.
1471  */
1472 static isc_result_t
1473 mark_active_keys(dns_dnsseckeylist_t *keylist, dns_rdataset_t *rrsigs) {
1474         isc_result_t result = ISC_R_SUCCESS;
1475         dns_rdata_t rdata = DNS_RDATA_INIT;
1476         dns_rdataset_t sigs;
1477         dns_dnsseckey_t *key;
1478
1479         REQUIRE(rrsigs != NULL && dns_rdataset_isassociated(rrsigs));
1480
1481         dns_rdataset_init(&sigs);
1482         dns_rdataset_clone(rrsigs, &sigs);
1483         for (key = ISC_LIST_HEAD(*keylist);
1484              key != NULL;
1485              key = ISC_LIST_NEXT(key, link)) {
1486                 isc_uint16_t keyid, sigid;
1487                 dns_secalg_t keyalg, sigalg;
1488                 keyid = dst_key_id(key->key);
1489                 keyalg = dst_key_alg(key->key);
1490
1491                 for (result = dns_rdataset_first(&sigs);
1492                      result == ISC_R_SUCCESS;
1493                      result = dns_rdataset_next(&sigs)) {
1494                         dns_rdata_rrsig_t sig;
1495
1496                         dns_rdata_reset(&rdata);
1497                         dns_rdataset_current(&sigs, &rdata);
1498                         result = dns_rdata_tostruct(&rdata, &sig, NULL);
1499                         RUNTIME_CHECK(result == ISC_R_SUCCESS);
1500                         sigalg = sig.algorithm;
1501                         sigid = sig.keyid;
1502                         if (keyid == sigid && keyalg == sigalg) {
1503                                 key->is_active = ISC_TRUE;
1504                                 break;
1505                         }
1506                 }
1507         }
1508
1509         if (result == ISC_R_NOMORE)
1510                 result = ISC_R_SUCCESS;
1511
1512         if (dns_rdataset_isassociated(&sigs))
1513                 dns_rdataset_disassociate(&sigs);
1514         return (result);
1515 }
1516
1517 /*%
1518  * Add the contents of a DNSKEY rdataset 'keyset' to 'keylist'.
1519  */
1520 isc_result_t
1521 dns_dnssec_keylistfromrdataset(dns_name_t *origin,
1522                                const char *directory, isc_mem_t *mctx,
1523                                dns_rdataset_t *keyset, dns_rdataset_t *keysigs,
1524                                dns_rdataset_t *soasigs, isc_boolean_t savekeys,
1525                                isc_boolean_t public,
1526                                dns_dnsseckeylist_t *keylist)
1527 {
1528         dns_rdataset_t keys;
1529         dns_rdata_t rdata = DNS_RDATA_INIT;
1530         dst_key_t *pubkey = NULL, *privkey = NULL;
1531         isc_result_t result;
1532
1533         REQUIRE(keyset != NULL && dns_rdataset_isassociated(keyset));
1534
1535         dns_rdataset_init(&keys);
1536
1537         dns_rdataset_clone(keyset, &keys);
1538         for (result = dns_rdataset_first(&keys);
1539              result == ISC_R_SUCCESS;
1540              result = dns_rdataset_next(&keys)) {
1541                 dns_rdata_reset(&rdata);
1542                 dns_rdataset_current(&keys, &rdata);
1543                 RETERR(dns_dnssec_keyfromrdata(origin, &rdata, mctx, &pubkey));
1544                 dst_key_setttl(pubkey, keys.ttl);
1545
1546                 if (!is_zone_key(pubkey) ||
1547                     (dst_key_flags(pubkey) & DNS_KEYTYPE_NOAUTH) != 0)
1548                         goto skip;
1549
1550                 /* Corrupted .key file? */
1551                 if (!dns_name_equal(origin, dst_key_name(pubkey)))
1552                         goto skip;
1553
1554                 if (public) {
1555                         RETERR(addkey(keylist, &pubkey, savekeys, mctx));
1556                         goto skip;
1557                 }
1558
1559                 result = dst_key_fromfile(dst_key_name(pubkey),
1560                                           dst_key_id(pubkey),
1561                                           dst_key_alg(pubkey),
1562                                           DST_TYPE_PUBLIC|DST_TYPE_PRIVATE,
1563                                           directory, mctx, &privkey);
1564
1565                 /*
1566                  * If the key was revoked and the private file
1567                  * doesn't exist, maybe it was revoked internally
1568                  * by named.  Try loading the unrevoked version.
1569                  */
1570                 if (result == ISC_R_FILENOTFOUND) {
1571                         isc_uint32_t flags;
1572                         flags = dst_key_flags(pubkey);
1573                         if ((flags & DNS_KEYFLAG_REVOKE) != 0) {
1574                                 dst_key_setflags(pubkey,
1575                                                  flags & ~DNS_KEYFLAG_REVOKE);
1576                                 result = dst_key_fromfile(dst_key_name(pubkey),
1577                                                           dst_key_id(pubkey),
1578                                                           dst_key_alg(pubkey),
1579                                                           DST_TYPE_PUBLIC|
1580                                                           DST_TYPE_PRIVATE,
1581                                                           directory,
1582                                                           mctx, &privkey);
1583                                 if (result == ISC_R_SUCCESS &&
1584                                     dst_key_pubcompare(pubkey, privkey,
1585                                                        ISC_FALSE)) {
1586                                         dst_key_setflags(privkey, flags);
1587                                 }
1588                                 dst_key_setflags(pubkey, flags);
1589                         }
1590                 }
1591
1592                 if (result != ISC_R_SUCCESS) {
1593                         char keybuf[DNS_NAME_FORMATSIZE];
1594                         char algbuf[DNS_SECALG_FORMATSIZE];
1595                         dns_name_format(dst_key_name(pubkey), keybuf,
1596                                         sizeof(keybuf));
1597                         dns_secalg_format(dst_key_alg(pubkey), algbuf,
1598                                           sizeof(algbuf));
1599                         isc_log_write(dns_lctx, DNS_LOGCATEGORY_GENERAL,
1600                                       DNS_LOGMODULE_DNSSEC, ISC_LOG_WARNING,
1601                                       "dns_dnssec_keylistfromrdataset: error "
1602                                       "reading private key file %s/%s/%d: %s",
1603                                       keybuf, algbuf, dst_key_id(pubkey),
1604                                       isc_result_totext(result));
1605                 }
1606
1607                 if (result == ISC_R_FILENOTFOUND || result == ISC_R_NOPERM) {
1608                         RETERR(addkey(keylist, &pubkey, savekeys, mctx));
1609                         goto skip;
1610                 }
1611                 RETERR(result);
1612
1613                 /* This should never happen. */
1614                 if ((dst_key_flags(privkey) & DNS_KEYTYPE_NOAUTH) != 0)
1615                         goto skip;
1616
1617                 /*
1618                  * Whatever the key's default TTL may have
1619                  * been, the rdataset TTL takes priority.
1620                  */
1621                 dst_key_setttl(privkey, dst_key_getttl(pubkey));
1622
1623                 RETERR(addkey(keylist, &privkey, savekeys, mctx));
1624  skip:
1625                 if (pubkey != NULL)
1626                         dst_key_free(&pubkey);
1627                 if (privkey != NULL)
1628                         dst_key_free(&privkey);
1629         }
1630
1631         if (result != ISC_R_NOMORE)
1632                 RETERR(result);
1633
1634         if (keysigs != NULL && dns_rdataset_isassociated(keysigs))
1635                 RETERR(mark_active_keys(keylist, keysigs));
1636
1637         if (soasigs != NULL && dns_rdataset_isassociated(soasigs))
1638                 RETERR(mark_active_keys(keylist, soasigs));
1639
1640         result = ISC_R_SUCCESS;
1641
1642  failure:
1643         if (dns_rdataset_isassociated(&keys))
1644                 dns_rdataset_disassociate(&keys);
1645         if (pubkey != NULL)
1646                 dst_key_free(&pubkey);
1647         if (privkey != NULL)
1648                 dst_key_free(&privkey);
1649         return (result);
1650 }
1651
1652 static isc_result_t
1653 make_dnskey(dst_key_t *key, unsigned char *buf, int bufsize,
1654             dns_rdata_t *target)
1655 {
1656         isc_result_t result;
1657         isc_buffer_t b;
1658         isc_region_t r;
1659
1660         isc_buffer_init(&b, buf, bufsize);
1661         result = dst_key_todns(key, &b);
1662         if (result != ISC_R_SUCCESS)
1663                 return (result);
1664
1665         dns_rdata_reset(target);
1666         isc_buffer_usedregion(&b, &r);
1667         dns_rdata_fromregion(target, dst_key_class(key),
1668                              dns_rdatatype_dnskey, &r);
1669         return (ISC_R_SUCCESS);
1670 }
1671
1672 static isc_result_t
1673 publish_key(dns_diff_t *diff, dns_dnsseckey_t *key, dns_name_t *origin,
1674             dns_ttl_t ttl, isc_mem_t *mctx, isc_boolean_t allzsk,
1675             void (*report)(const char *, ...))
1676 {
1677         isc_result_t result;
1678         dns_difftuple_t *tuple = NULL;
1679         unsigned char buf[DST_KEY_MAXSIZE];
1680         dns_rdata_t dnskey = DNS_RDATA_INIT;
1681         char alg[80];
1682
1683         dns_rdata_reset(&dnskey);
1684         RETERR(make_dnskey(key->key, buf, sizeof(buf), &dnskey));
1685
1686         dns_secalg_format(dst_key_alg(key->key), alg, sizeof(alg));
1687         report("Fetching %s %d/%s from key %s.",
1688                key->ksk ?  (allzsk ?  "KSK/ZSK" : "KSK") : "ZSK",
1689                dst_key_id(key->key), alg,
1690                key->source == dns_keysource_user ?  "file" : "repository");
1691
1692         if (key->prepublish && ttl > key->prepublish) {
1693                 char keystr[DST_KEY_FORMATSIZE];
1694                 isc_stdtime_t now;
1695
1696                 dst_key_format(key->key, keystr, sizeof(keystr));
1697                 report("Key %s: Delaying activation to match the DNSKEY TTL.\n",
1698                        keystr, ttl);
1699
1700                 isc_stdtime_get(&now);
1701                 dst_key_settime(key->key, DST_TIME_ACTIVATE, now + ttl);
1702         }
1703
1704         /* publish key */
1705         RETERR(dns_difftuple_create(mctx, DNS_DIFFOP_ADD, origin, ttl,
1706                                     &dnskey, &tuple));
1707         dns_diff_appendminimal(diff, &tuple);
1708         result = ISC_R_SUCCESS;
1709
1710  failure:
1711         return (result);
1712 }
1713
1714 static isc_result_t
1715 remove_key(dns_diff_t *diff, dns_dnsseckey_t *key, dns_name_t *origin,
1716           dns_ttl_t ttl, isc_mem_t *mctx, const char *reason,
1717           void (*report)(const char *, ...))
1718 {
1719         isc_result_t result;
1720         dns_difftuple_t *tuple = NULL;
1721         unsigned char buf[DST_KEY_MAXSIZE];
1722         dns_rdata_t dnskey = DNS_RDATA_INIT;
1723         char alg[80];
1724
1725         dns_secalg_format(dst_key_alg(key->key), alg, sizeof(alg));
1726         report("Removing %s key %d/%s from DNSKEY RRset.",
1727                reason, dst_key_id(key->key), alg);
1728
1729         RETERR(make_dnskey(key->key, buf, sizeof(buf), &dnskey));
1730         RETERR(dns_difftuple_create(mctx, DNS_DIFFOP_DEL, origin, ttl, &dnskey,
1731                                     &tuple));
1732         dns_diff_appendminimal(diff, &tuple);
1733         result = ISC_R_SUCCESS;
1734
1735  failure:
1736         return (result);
1737 }
1738
1739 /*
1740  * Update 'keys' with information from 'newkeys'.
1741  *
1742  * If 'removed' is not NULL, any keys that are being removed from
1743  * the zone will be added to the list for post-removal processing.
1744  */
1745 isc_result_t
1746 dns_dnssec_updatekeys(dns_dnsseckeylist_t *keys, dns_dnsseckeylist_t *newkeys,
1747                       dns_dnsseckeylist_t *removed, dns_name_t *origin,
1748                       dns_ttl_t hint_ttl, dns_diff_t *diff,
1749                       isc_boolean_t allzsk, isc_mem_t *mctx,
1750                       void (*report)(const char *, ...))
1751 {
1752         isc_result_t result;
1753         dns_dnsseckey_t *key, *key1, *key2, *next;
1754         isc_boolean_t found_ttl = ISC_FALSE;
1755         dns_ttl_t ttl = hint_ttl;
1756
1757         /*
1758          * First, look through the existing key list to find keys
1759          * supplied from the command line which are not in the zone.
1760          * Update the zone to include them.
1761          *
1762          * Also, if there are keys published in the zone already,
1763          * use their TTL for all subsequent published keys.
1764          */
1765         for (key = ISC_LIST_HEAD(*keys);
1766              key != NULL;
1767              key = ISC_LIST_NEXT(key, link)) {
1768                 if (key->source == dns_keysource_user &&
1769                     (key->hint_publish || key->force_publish)) {
1770                         RETERR(publish_key(diff, key, origin, ttl,
1771                                            mctx, allzsk, report));
1772                 }
1773                 if (key->source == dns_keysource_zoneapex) {
1774                         ttl = dst_key_getttl(key->key);
1775                         found_ttl = ISC_TRUE;
1776                 }
1777         }
1778
1779         /*
1780          * If there were no existing keys, use the smallest nonzero
1781          * TTL of the keys found in the repository.
1782          */
1783         if (!found_ttl && !ISC_LIST_EMPTY(*newkeys)) {
1784                 dns_ttl_t shortest = 0;
1785
1786                 for (key = ISC_LIST_HEAD(*newkeys);
1787                      key != NULL;
1788                      key = ISC_LIST_NEXT(key, link)) {
1789                         dns_ttl_t thisttl = dst_key_getttl(key->key);
1790                         if (thisttl != 0 &&
1791                             (shortest == 0 || thisttl < shortest))
1792                                 shortest = thisttl;
1793                 }
1794
1795                 if (shortest != 0)
1796                         ttl = shortest;
1797         }
1798
1799         /*
1800          * Second, scan the list of newly found keys looking for matches
1801          * with known keys, and update accordingly.
1802          */
1803         for (key1 = ISC_LIST_HEAD(*newkeys); key1 != NULL; key1 = next) {
1804                 isc_boolean_t key_revoked = ISC_FALSE;
1805
1806                 next = ISC_LIST_NEXT(key1, link);
1807
1808                 for (key2 = ISC_LIST_HEAD(*keys);
1809                      key2 != NULL;
1810                      key2 = ISC_LIST_NEXT(key2, link)) {
1811                         int f1 = dst_key_flags(key1->key);
1812                         int f2 = dst_key_flags(key2->key);
1813                         int nr1 = f1 & ~DNS_KEYFLAG_REVOKE;
1814                         int nr2 = f2 & ~DNS_KEYFLAG_REVOKE;
1815                         if (nr1 == nr2 &&
1816                             dst_key_alg(key1->key) == dst_key_alg(key2->key) &&
1817                             dst_key_pubcompare(key1->key, key2->key,
1818                                                ISC_TRUE)) {
1819                                 int r1, r2;
1820                                 r1 = dst_key_flags(key1->key) &
1821                                         DNS_KEYFLAG_REVOKE;
1822                                 r2 = dst_key_flags(key2->key) &
1823                                         DNS_KEYFLAG_REVOKE;
1824                                 key_revoked = ISC_TF(r1 != r2);
1825                                 break;
1826                         }
1827                 }
1828
1829                 /* No match found in keys; add the new key. */
1830                 if (key2 == NULL) {
1831                         ISC_LIST_UNLINK(*newkeys, key1, link);
1832                         ISC_LIST_APPEND(*keys, key1, link);
1833
1834                         if (key1->source != dns_keysource_zoneapex &&
1835                             (key1->hint_publish || key1->force_publish)) {
1836                                 RETERR(publish_key(diff, key1, origin, ttl,
1837                                                    mctx, allzsk, report));
1838                                 if (key1->hint_sign || key1->force_sign)
1839                                         key1->first_sign = ISC_TRUE;
1840                         }
1841
1842                         continue;
1843                 }
1844
1845                 /* Match found: remove or update it as needed */
1846                 if (key1->hint_remove) {
1847                         RETERR(remove_key(diff, key2, origin, ttl, mctx,
1848                                           "expired", report));
1849                         ISC_LIST_UNLINK(*keys, key2, link);
1850                         if (removed != NULL)
1851                                 ISC_LIST_APPEND(*removed, key2, link);
1852                         else
1853                                 dns_dnsseckey_destroy(mctx, &key2);
1854                 } else if (key_revoked &&
1855                          (dst_key_flags(key1->key) & DNS_KEYFLAG_REVOKE) != 0) {
1856
1857                         /*
1858                          * A previously valid key has been revoked.
1859                          * We need to remove the old version and pull
1860                          * in the new one.
1861                          */
1862                         RETERR(remove_key(diff, key2, origin, ttl, mctx,
1863                                           "revoked", report));
1864                         ISC_LIST_UNLINK(*keys, key2, link);
1865                         if (removed != NULL)
1866                                 ISC_LIST_APPEND(*removed, key2, link);
1867                         else
1868                                 dns_dnsseckey_destroy(mctx, &key2);
1869
1870                         RETERR(publish_key(diff, key1, origin, ttl,
1871                                            mctx, allzsk, report));
1872                         ISC_LIST_UNLINK(*newkeys, key1, link);
1873                         ISC_LIST_APPEND(*keys, key1, link);
1874
1875                         /*
1876                          * XXX: The revoke flag is only defined for trust
1877                          * anchors.  Setting the flag on a non-KSK is legal,
1878                          * but not defined in any RFC.  It seems reasonable
1879                          * to treat it the same as a KSK: keep it in the
1880                          * zone, sign the DNSKEY set with it, but not
1881                          * sign other records with it.
1882                          */
1883                         key1->ksk = ISC_TRUE;
1884                         continue;
1885                 } else {
1886                         if (!key2->is_active &&
1887                             (key1->hint_sign || key1->force_sign))
1888                                 key2->first_sign = ISC_TRUE;
1889                         key2->hint_sign = key1->hint_sign;
1890                         key2->hint_publish = key1->hint_publish;
1891                 }
1892         }
1893
1894         /* Free any leftover keys in newkeys */
1895         while (!ISC_LIST_EMPTY(*newkeys)) {
1896                 key1 = ISC_LIST_HEAD(*newkeys);
1897                 ISC_LIST_UNLINK(*newkeys, key1, link);
1898                 dns_dnsseckey_destroy(mctx, &key1);
1899         }
1900
1901         result = ISC_R_SUCCESS;
1902
1903  failure:
1904         return (result);
1905 }