]> CyberLeo.Net >> Repos - FreeBSD/stable/9.git/blob - contrib/bind9/lib/dns/dnssec.c
Update BIND to 9.9.6-P1
[FreeBSD/stable/9.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
1251                 /* Only publish if publish time has already passed. */
1252                 if (pubset && publish <= now)
1253                         key->hint_publish = ISC_TRUE;
1254         }
1255
1256         /*
1257          * Activation date is set (maybe in the future), but
1258          * publication date isn't. Most likely the user wants to
1259          * publish now and activate later.
1260          */
1261         if (actset && !pubset)
1262                 key->hint_publish = ISC_TRUE;
1263
1264         /*
1265          * If activation date is in the future, make note of how far off
1266          */
1267         if (key->hint_publish && actset && active > now) {
1268                 key->prepublish = active - now;
1269         }
1270
1271         /*
1272          * Key has been marked inactive: we can continue publishing,
1273          * but don't sign.
1274          */
1275         if (key->hint_publish && inactset && inactive <= now) {
1276                 key->hint_sign = ISC_FALSE;
1277         }
1278
1279         /*
1280          * Metadata says revoke.  If the key is published,
1281          * we *have to* sign with it per RFC5011--even if it was
1282          * not active before.
1283          *
1284          * If it hasn't already been done, we should also revoke it now.
1285          */
1286         if (key->hint_publish && (revset && revoke <= now)) {
1287                 isc_uint32_t flags;
1288                 key->hint_sign = ISC_TRUE;
1289                 flags = dst_key_flags(key->key);
1290                 if ((flags & DNS_KEYFLAG_REVOKE) == 0) {
1291                         flags |= DNS_KEYFLAG_REVOKE;
1292                         dst_key_setflags(key->key, flags);
1293                 }
1294         }
1295
1296         /*
1297          * Metadata says delete, so don't publish this key or sign with it.
1298          */
1299         if (delset && delete <= now) {
1300                 key->hint_publish = ISC_FALSE;
1301                 key->hint_sign = ISC_FALSE;
1302                 key->hint_remove = ISC_TRUE;
1303         }
1304 }
1305
1306 /*%
1307  * Get a list of DNSSEC keys from the key repository
1308  */
1309 isc_result_t
1310 dns_dnssec_findmatchingkeys(dns_name_t *origin, const char *directory,
1311                             isc_mem_t *mctx, dns_dnsseckeylist_t *keylist)
1312 {
1313         isc_result_t result = ISC_R_SUCCESS;
1314         isc_boolean_t dir_open = ISC_FALSE;
1315         dns_dnsseckeylist_t list;
1316         isc_dir_t dir;
1317         dns_dnsseckey_t *key = NULL;
1318         dst_key_t *dstkey = NULL;
1319         char namebuf[DNS_NAME_FORMATSIZE];
1320         isc_buffer_t b;
1321         unsigned int len, i;
1322         isc_stdtime_t now;
1323
1324         REQUIRE(keylist != NULL);
1325         ISC_LIST_INIT(list);
1326         isc_dir_init(&dir);
1327
1328         isc_buffer_init(&b, namebuf, sizeof(namebuf) - 1);
1329         RETERR(dns_name_tofilenametext(origin, ISC_FALSE, &b));
1330         len = isc_buffer_usedlength(&b);
1331         namebuf[len] = '\0';
1332
1333         if (directory == NULL)
1334                 directory = ".";
1335         RETERR(isc_dir_open(&dir, directory));
1336         dir_open = ISC_TRUE;
1337
1338         isc_stdtime_get(&now);
1339
1340         while (isc_dir_read(&dir) == ISC_R_SUCCESS) {
1341                 if (dir.entry.name[0] != 'K' ||
1342                     dir.entry.length < len + 1 ||
1343                     dir.entry.name[len + 1] != '+' ||
1344                     strncasecmp(dir.entry.name + 1, namebuf, len) != 0)
1345                         continue;
1346
1347                 for (i = len + 1 + 1; i < dir.entry.length ; i++)
1348                         if (dir.entry.name[i] < '0' || dir.entry.name[i] > '9')
1349                                 break;
1350
1351                 if (i == len + 1 + 1 || i >= dir.entry.length ||
1352                     dir.entry.name[i] != '+')
1353                         continue;
1354
1355                 for (i++ ; i < dir.entry.length ; i++)
1356                         if (dir.entry.name[i] < '0' || dir.entry.name[i] > '9')
1357                                 break;
1358
1359                 if (strcmp(dir.entry.name + i, ".private") != 0)
1360                                 continue;
1361
1362                 dstkey = NULL;
1363                 result = dst_key_fromnamedfile(dir.entry.name,
1364                                                directory,
1365                                                DST_TYPE_PUBLIC |
1366                                                DST_TYPE_PRIVATE,
1367                                                mctx, &dstkey);
1368
1369                 if (result != ISC_R_SUCCESS) {
1370                         isc_log_write(dns_lctx,
1371                                       DNS_LOGCATEGORY_GENERAL,
1372                                       DNS_LOGMODULE_DNSSEC,
1373                                       ISC_LOG_WARNING,
1374                                       "dns_dnssec_findmatchingkeys: "
1375                                       "error reading key file %s: %s",
1376                                       dir.entry.name,
1377                                       isc_result_totext(result));
1378                         continue;
1379                 }
1380
1381                 RETERR(dns_dnsseckey_create(mctx, &dstkey, &key));
1382                 key->source = dns_keysource_repository;
1383                 get_hints(key, now);
1384
1385                 if (key->legacy) {
1386                         dns_dnsseckey_destroy(mctx, &key);
1387                 } else {
1388                         ISC_LIST_APPEND(list, key, link);
1389                         key = NULL;
1390                 }
1391         }
1392
1393         if (!ISC_LIST_EMPTY(list)) {
1394                 result = ISC_R_SUCCESS;
1395                 ISC_LIST_APPENDLIST(*keylist, list, link);
1396         } else
1397                 result = ISC_R_NOTFOUND;
1398
1399  failure:
1400         if (dir_open)
1401                 isc_dir_close(&dir);
1402         INSIST(key == NULL);
1403         while ((key = ISC_LIST_HEAD(list)) != NULL) {
1404                 ISC_LIST_UNLINK(list, key, link);
1405                 INSIST(key->key != NULL);
1406                 dst_key_free(&key->key);
1407                 dns_dnsseckey_destroy(mctx, &key);
1408         }
1409         if (dstkey != NULL)
1410                 dst_key_free(&dstkey);
1411         return (result);
1412 }
1413
1414 /*%
1415  * Add 'newkey' to 'keylist' if it's not already there.
1416  *
1417  * If 'savekeys' is ISC_TRUE, then we need to preserve all
1418  * the keys in the keyset, regardless of whether they have
1419  * metadata indicating they should be deactivated or removed.
1420  */
1421 static isc_result_t
1422 addkey(dns_dnsseckeylist_t *keylist, dst_key_t **newkey,
1423        isc_boolean_t savekeys, isc_mem_t *mctx)
1424 {
1425         dns_dnsseckey_t *key;
1426         isc_result_t result;
1427
1428         /* Skip duplicates */
1429         for (key = ISC_LIST_HEAD(*keylist);
1430              key != NULL;
1431              key = ISC_LIST_NEXT(key, link)) {
1432                 if (dst_key_id(key->key) == dst_key_id(*newkey) &&
1433                     dst_key_alg(key->key) == dst_key_alg(*newkey) &&
1434                     dns_name_equal(dst_key_name(key->key),
1435                                    dst_key_name(*newkey)))
1436                         break;
1437         }
1438
1439         if (key != NULL) {
1440                 /*
1441                  * Found a match.  If the old key was only public and the
1442                  * new key is private, replace the old one; otherwise
1443                  * leave it.  But either way, mark the key as having
1444                  * been found in the zone.
1445                  */
1446                 if (dst_key_isprivate(key->key)) {
1447                         dst_key_free(newkey);
1448                 } else if (dst_key_isprivate(*newkey)) {
1449                         dst_key_free(&key->key);
1450                         key->key = *newkey;
1451                 }
1452
1453                 key->source = dns_keysource_zoneapex;
1454                 return (ISC_R_SUCCESS);
1455         }
1456
1457         result = dns_dnsseckey_create(mctx, newkey, &key);
1458         if (result != ISC_R_SUCCESS)
1459                 return (result);
1460         if (key->legacy || savekeys) {
1461                 key->force_publish = ISC_TRUE;
1462                 key->force_sign = dst_key_isprivate(key->key);
1463         }
1464         key->source = dns_keysource_zoneapex;
1465         ISC_LIST_APPEND(*keylist, key, link);
1466         *newkey = NULL;
1467         return (ISC_R_SUCCESS);
1468 }
1469
1470
1471 /*%
1472  * Mark all keys which signed the DNSKEY/SOA RRsets as "active",
1473  * for future reference.
1474  */
1475 static isc_result_t
1476 mark_active_keys(dns_dnsseckeylist_t *keylist, dns_rdataset_t *rrsigs) {
1477         isc_result_t result = ISC_R_SUCCESS;
1478         dns_rdata_t rdata = DNS_RDATA_INIT;
1479         dns_rdataset_t sigs;
1480         dns_dnsseckey_t *key;
1481
1482         REQUIRE(rrsigs != NULL && dns_rdataset_isassociated(rrsigs));
1483
1484         dns_rdataset_init(&sigs);
1485         dns_rdataset_clone(rrsigs, &sigs);
1486         for (key = ISC_LIST_HEAD(*keylist);
1487              key != NULL;
1488              key = ISC_LIST_NEXT(key, link)) {
1489                 isc_uint16_t keyid, sigid;
1490                 dns_secalg_t keyalg, sigalg;
1491                 keyid = dst_key_id(key->key);
1492                 keyalg = dst_key_alg(key->key);
1493
1494                 for (result = dns_rdataset_first(&sigs);
1495                      result == ISC_R_SUCCESS;
1496                      result = dns_rdataset_next(&sigs)) {
1497                         dns_rdata_rrsig_t sig;
1498
1499                         dns_rdata_reset(&rdata);
1500                         dns_rdataset_current(&sigs, &rdata);
1501                         result = dns_rdata_tostruct(&rdata, &sig, NULL);
1502                         RUNTIME_CHECK(result == ISC_R_SUCCESS);
1503                         sigalg = sig.algorithm;
1504                         sigid = sig.keyid;
1505                         if (keyid == sigid && keyalg == sigalg) {
1506                                 key->is_active = ISC_TRUE;
1507                                 break;
1508                         }
1509                 }
1510         }
1511
1512         if (result == ISC_R_NOMORE)
1513                 result = ISC_R_SUCCESS;
1514
1515         if (dns_rdataset_isassociated(&sigs))
1516                 dns_rdataset_disassociate(&sigs);
1517         return (result);
1518 }
1519
1520 /*%
1521  * Add the contents of a DNSKEY rdataset 'keyset' to 'keylist'.
1522  */
1523 isc_result_t
1524 dns_dnssec_keylistfromrdataset(dns_name_t *origin,
1525                                const char *directory, isc_mem_t *mctx,
1526                                dns_rdataset_t *keyset, dns_rdataset_t *keysigs,
1527                                dns_rdataset_t *soasigs, isc_boolean_t savekeys,
1528                                isc_boolean_t publickey,
1529                                dns_dnsseckeylist_t *keylist)
1530 {
1531         dns_rdataset_t keys;
1532         dns_rdata_t rdata = DNS_RDATA_INIT;
1533         dst_key_t *pubkey = NULL, *privkey = NULL;
1534         isc_result_t result;
1535
1536         REQUIRE(keyset != NULL && dns_rdataset_isassociated(keyset));
1537
1538         dns_rdataset_init(&keys);
1539
1540         dns_rdataset_clone(keyset, &keys);
1541         for (result = dns_rdataset_first(&keys);
1542              result == ISC_R_SUCCESS;
1543              result = dns_rdataset_next(&keys)) {
1544                 dns_rdata_reset(&rdata);
1545                 dns_rdataset_current(&keys, &rdata);
1546                 RETERR(dns_dnssec_keyfromrdata(origin, &rdata, mctx, &pubkey));
1547                 dst_key_setttl(pubkey, keys.ttl);
1548
1549                 if (!is_zone_key(pubkey) ||
1550                     (dst_key_flags(pubkey) & DNS_KEYTYPE_NOAUTH) != 0)
1551                         goto skip;
1552
1553                 /* Corrupted .key file? */
1554                 if (!dns_name_equal(origin, dst_key_name(pubkey)))
1555                         goto skip;
1556
1557                 if (publickey) {
1558                         RETERR(addkey(keylist, &pubkey, savekeys, mctx));
1559                         goto skip;
1560                 }
1561
1562                 result = dst_key_fromfile(dst_key_name(pubkey),
1563                                           dst_key_id(pubkey),
1564                                           dst_key_alg(pubkey),
1565                                           DST_TYPE_PUBLIC|DST_TYPE_PRIVATE,
1566                                           directory, mctx, &privkey);
1567
1568                 /*
1569                  * If the key was revoked and the private file
1570                  * doesn't exist, maybe it was revoked internally
1571                  * by named.  Try loading the unrevoked version.
1572                  */
1573                 if (result == ISC_R_FILENOTFOUND) {
1574                         isc_uint32_t flags;
1575                         flags = dst_key_flags(pubkey);
1576                         if ((flags & DNS_KEYFLAG_REVOKE) != 0) {
1577                                 dst_key_setflags(pubkey,
1578                                                  flags & ~DNS_KEYFLAG_REVOKE);
1579                                 result = dst_key_fromfile(dst_key_name(pubkey),
1580                                                           dst_key_id(pubkey),
1581                                                           dst_key_alg(pubkey),
1582                                                           DST_TYPE_PUBLIC|
1583                                                           DST_TYPE_PRIVATE,
1584                                                           directory,
1585                                                           mctx, &privkey);
1586                                 if (result == ISC_R_SUCCESS &&
1587                                     dst_key_pubcompare(pubkey, privkey,
1588                                                        ISC_FALSE)) {
1589                                         dst_key_setflags(privkey, flags);
1590                                 }
1591                                 dst_key_setflags(pubkey, flags);
1592                         }
1593                 }
1594
1595                 if (result != ISC_R_SUCCESS) {
1596                         char keybuf[DNS_NAME_FORMATSIZE];
1597                         char algbuf[DNS_SECALG_FORMATSIZE];
1598                         dns_name_format(dst_key_name(pubkey), keybuf,
1599                                         sizeof(keybuf));
1600                         dns_secalg_format(dst_key_alg(pubkey), algbuf,
1601                                           sizeof(algbuf));
1602                         isc_log_write(dns_lctx, DNS_LOGCATEGORY_GENERAL,
1603                                       DNS_LOGMODULE_DNSSEC, ISC_LOG_WARNING,
1604                                       "dns_dnssec_keylistfromrdataset: error "
1605                                       "reading private key file %s/%s/%d: %s",
1606                                       keybuf, algbuf, dst_key_id(pubkey),
1607                                       isc_result_totext(result));
1608                 }
1609
1610                 if (result == ISC_R_FILENOTFOUND || result == ISC_R_NOPERM) {
1611                         RETERR(addkey(keylist, &pubkey, savekeys, mctx));
1612                         goto skip;
1613                 }
1614                 RETERR(result);
1615
1616                 /* This should never happen. */
1617                 if ((dst_key_flags(privkey) & DNS_KEYTYPE_NOAUTH) != 0)
1618                         goto skip;
1619
1620                 /*
1621                  * Whatever the key's default TTL may have
1622                  * been, the rdataset TTL takes priority.
1623                  */
1624                 dst_key_setttl(privkey, dst_key_getttl(pubkey));
1625
1626                 RETERR(addkey(keylist, &privkey, savekeys, mctx));
1627  skip:
1628                 if (pubkey != NULL)
1629                         dst_key_free(&pubkey);
1630                 if (privkey != NULL)
1631                         dst_key_free(&privkey);
1632         }
1633
1634         if (result != ISC_R_NOMORE)
1635                 RETERR(result);
1636
1637         if (keysigs != NULL && dns_rdataset_isassociated(keysigs))
1638                 RETERR(mark_active_keys(keylist, keysigs));
1639
1640         if (soasigs != NULL && dns_rdataset_isassociated(soasigs))
1641                 RETERR(mark_active_keys(keylist, soasigs));
1642
1643         result = ISC_R_SUCCESS;
1644
1645  failure:
1646         if (dns_rdataset_isassociated(&keys))
1647                 dns_rdataset_disassociate(&keys);
1648         if (pubkey != NULL)
1649                 dst_key_free(&pubkey);
1650         if (privkey != NULL)
1651                 dst_key_free(&privkey);
1652         return (result);
1653 }
1654
1655 static isc_result_t
1656 make_dnskey(dst_key_t *key, unsigned char *buf, int bufsize,
1657             dns_rdata_t *target)
1658 {
1659         isc_result_t result;
1660         isc_buffer_t b;
1661         isc_region_t r;
1662
1663         isc_buffer_init(&b, buf, bufsize);
1664         result = dst_key_todns(key, &b);
1665         if (result != ISC_R_SUCCESS)
1666                 return (result);
1667
1668         dns_rdata_reset(target);
1669         isc_buffer_usedregion(&b, &r);
1670         dns_rdata_fromregion(target, dst_key_class(key),
1671                              dns_rdatatype_dnskey, &r);
1672         return (ISC_R_SUCCESS);
1673 }
1674
1675 static isc_result_t
1676 publish_key(dns_diff_t *diff, dns_dnsseckey_t *key, dns_name_t *origin,
1677             dns_ttl_t ttl, isc_mem_t *mctx, isc_boolean_t allzsk,
1678             void (*report)(const char *, ...))
1679 {
1680         isc_result_t result;
1681         dns_difftuple_t *tuple = NULL;
1682         unsigned char buf[DST_KEY_MAXSIZE];
1683         dns_rdata_t dnskey = DNS_RDATA_INIT;
1684         char alg[80];
1685
1686         dns_rdata_reset(&dnskey);
1687         RETERR(make_dnskey(key->key, buf, sizeof(buf), &dnskey));
1688
1689         dns_secalg_format(dst_key_alg(key->key), alg, sizeof(alg));
1690         report("Fetching %s %d/%s from key %s.",
1691                key->ksk ?  (allzsk ?  "KSK/ZSK" : "KSK") : "ZSK",
1692                dst_key_id(key->key), alg,
1693                key->source == dns_keysource_user ?  "file" : "repository");
1694
1695         if (key->prepublish && ttl > key->prepublish) {
1696                 char keystr[DST_KEY_FORMATSIZE];
1697                 isc_stdtime_t now;
1698
1699                 dst_key_format(key->key, keystr, sizeof(keystr));
1700                 report("Key %s: Delaying activation to match the DNSKEY TTL.\n",
1701                        keystr, ttl);
1702
1703                 isc_stdtime_get(&now);
1704                 dst_key_settime(key->key, DST_TIME_ACTIVATE, now + ttl);
1705         }
1706
1707         /* publish key */
1708         RETERR(dns_difftuple_create(mctx, DNS_DIFFOP_ADD, origin, ttl,
1709                                     &dnskey, &tuple));
1710         dns_diff_appendminimal(diff, &tuple);
1711         result = ISC_R_SUCCESS;
1712
1713  failure:
1714         return (result);
1715 }
1716
1717 static isc_result_t
1718 remove_key(dns_diff_t *diff, dns_dnsseckey_t *key, dns_name_t *origin,
1719           dns_ttl_t ttl, isc_mem_t *mctx, const char *reason,
1720           void (*report)(const char *, ...))
1721 {
1722         isc_result_t result;
1723         dns_difftuple_t *tuple = NULL;
1724         unsigned char buf[DST_KEY_MAXSIZE];
1725         dns_rdata_t dnskey = DNS_RDATA_INIT;
1726         char alg[80];
1727
1728         dns_secalg_format(dst_key_alg(key->key), alg, sizeof(alg));
1729         report("Removing %s key %d/%s from DNSKEY RRset.",
1730                reason, dst_key_id(key->key), alg);
1731
1732         RETERR(make_dnskey(key->key, buf, sizeof(buf), &dnskey));
1733         RETERR(dns_difftuple_create(mctx, DNS_DIFFOP_DEL, origin, ttl, &dnskey,
1734                                     &tuple));
1735         dns_diff_appendminimal(diff, &tuple);
1736         result = ISC_R_SUCCESS;
1737
1738  failure:
1739         return (result);
1740 }
1741
1742 /*
1743  * Update 'keys' with information from 'newkeys'.
1744  *
1745  * If 'removed' is not NULL, any keys that are being removed from
1746  * the zone will be added to the list for post-removal processing.
1747  */
1748 isc_result_t
1749 dns_dnssec_updatekeys(dns_dnsseckeylist_t *keys, dns_dnsseckeylist_t *newkeys,
1750                       dns_dnsseckeylist_t *removed, dns_name_t *origin,
1751                       dns_ttl_t hint_ttl, dns_diff_t *diff,
1752                       isc_boolean_t allzsk, isc_mem_t *mctx,
1753                       void (*report)(const char *, ...))
1754 {
1755         isc_result_t result;
1756         dns_dnsseckey_t *key, *key1, *key2, *next;
1757         isc_boolean_t found_ttl = ISC_FALSE;
1758         dns_ttl_t ttl = hint_ttl;
1759
1760         /*
1761          * First, look through the existing key list to find keys
1762          * supplied from the command line which are not in the zone.
1763          * Update the zone to include them.
1764          *
1765          * Also, if there are keys published in the zone already,
1766          * use their TTL for all subsequent published keys.
1767          */
1768         for (key = ISC_LIST_HEAD(*keys);
1769              key != NULL;
1770              key = ISC_LIST_NEXT(key, link)) {
1771                 if (key->source == dns_keysource_user &&
1772                     (key->hint_publish || key->force_publish)) {
1773                         RETERR(publish_key(diff, key, origin, ttl,
1774                                            mctx, allzsk, report));
1775                 }
1776                 if (key->source == dns_keysource_zoneapex) {
1777                         ttl = dst_key_getttl(key->key);
1778                         found_ttl = ISC_TRUE;
1779                 }
1780         }
1781
1782         /*
1783          * If there were no existing keys, use the smallest nonzero
1784          * TTL of the keys found in the repository.
1785          */
1786         if (!found_ttl && !ISC_LIST_EMPTY(*newkeys)) {
1787                 dns_ttl_t shortest = 0;
1788
1789                 for (key = ISC_LIST_HEAD(*newkeys);
1790                      key != NULL;
1791                      key = ISC_LIST_NEXT(key, link)) {
1792                         dns_ttl_t thisttl = dst_key_getttl(key->key);
1793                         if (thisttl != 0 &&
1794                             (shortest == 0 || thisttl < shortest))
1795                                 shortest = thisttl;
1796                 }
1797
1798                 if (shortest != 0)
1799                         ttl = shortest;
1800         }
1801
1802         /*
1803          * Second, scan the list of newly found keys looking for matches
1804          * with known keys, and update accordingly.
1805          */
1806         for (key1 = ISC_LIST_HEAD(*newkeys); key1 != NULL; key1 = next) {
1807                 isc_boolean_t key_revoked = ISC_FALSE;
1808
1809                 next = ISC_LIST_NEXT(key1, link);
1810
1811                 for (key2 = ISC_LIST_HEAD(*keys);
1812                      key2 != NULL;
1813                      key2 = ISC_LIST_NEXT(key2, link)) {
1814                         int f1 = dst_key_flags(key1->key);
1815                         int f2 = dst_key_flags(key2->key);
1816                         int nr1 = f1 & ~DNS_KEYFLAG_REVOKE;
1817                         int nr2 = f2 & ~DNS_KEYFLAG_REVOKE;
1818                         if (nr1 == nr2 &&
1819                             dst_key_alg(key1->key) == dst_key_alg(key2->key) &&
1820                             dst_key_pubcompare(key1->key, key2->key,
1821                                                ISC_TRUE)) {
1822                                 int r1, r2;
1823                                 r1 = dst_key_flags(key1->key) &
1824                                         DNS_KEYFLAG_REVOKE;
1825                                 r2 = dst_key_flags(key2->key) &
1826                                         DNS_KEYFLAG_REVOKE;
1827                                 key_revoked = ISC_TF(r1 != r2);
1828                                 break;
1829                         }
1830                 }
1831
1832                 /* No match found in keys; add the new key. */
1833                 if (key2 == NULL) {
1834                         ISC_LIST_UNLINK(*newkeys, key1, link);
1835                         ISC_LIST_APPEND(*keys, key1, link);
1836
1837                         if (key1->source != dns_keysource_zoneapex &&
1838                             (key1->hint_publish || key1->force_publish)) {
1839                                 RETERR(publish_key(diff, key1, origin, ttl,
1840                                                    mctx, allzsk, report));
1841                                 if (key1->hint_sign || key1->force_sign)
1842                                         key1->first_sign = ISC_TRUE;
1843                         }
1844
1845                         continue;
1846                 }
1847
1848                 /* Match found: remove or update it as needed */
1849                 if (key1->hint_remove) {
1850                         RETERR(remove_key(diff, key2, origin, ttl, mctx,
1851                                           "expired", report));
1852                         ISC_LIST_UNLINK(*keys, key2, link);
1853                         if (removed != NULL)
1854                                 ISC_LIST_APPEND(*removed, key2, link);
1855                         else
1856                                 dns_dnsseckey_destroy(mctx, &key2);
1857                 } else if (key_revoked &&
1858                          (dst_key_flags(key1->key) & DNS_KEYFLAG_REVOKE) != 0) {
1859
1860                         /*
1861                          * A previously valid key has been revoked.
1862                          * We need to remove the old version and pull
1863                          * in the new one.
1864                          */
1865                         RETERR(remove_key(diff, key2, origin, ttl, mctx,
1866                                           "revoked", report));
1867                         ISC_LIST_UNLINK(*keys, key2, link);
1868                         if (removed != NULL)
1869                                 ISC_LIST_APPEND(*removed, key2, link);
1870                         else
1871                                 dns_dnsseckey_destroy(mctx, &key2);
1872
1873                         RETERR(publish_key(diff, key1, origin, ttl,
1874                                            mctx, allzsk, report));
1875                         ISC_LIST_UNLINK(*newkeys, key1, link);
1876                         ISC_LIST_APPEND(*keys, key1, link);
1877
1878                         /*
1879                          * XXX: The revoke flag is only defined for trust
1880                          * anchors.  Setting the flag on a non-KSK is legal,
1881                          * but not defined in any RFC.  It seems reasonable
1882                          * to treat it the same as a KSK: keep it in the
1883                          * zone, sign the DNSKEY set with it, but not
1884                          * sign other records with it.
1885                          */
1886                         key1->ksk = ISC_TRUE;
1887                         continue;
1888                 } else {
1889                         if (!key2->is_active &&
1890                             (key1->hint_sign || key1->force_sign))
1891                                 key2->first_sign = ISC_TRUE;
1892                         key2->hint_sign = key1->hint_sign;
1893                         key2->hint_publish = key1->hint_publish;
1894                 }
1895         }
1896
1897         /* Free any leftover keys in newkeys */
1898         while (!ISC_LIST_EMPTY(*newkeys)) {
1899                 key1 = ISC_LIST_HEAD(*newkeys);
1900                 ISC_LIST_UNLINK(*newkeys, key1, link);
1901                 dns_dnsseckey_destroy(mctx, &key1);
1902         }
1903
1904         result = ISC_R_SUCCESS;
1905
1906  failure:
1907         return (result);
1908 }