]> CyberLeo.Net >> Repos - FreeBSD/stable/9.git/blob - contrib/bind9/lib/dns/dnssec.c
MFC r254651:
[FreeBSD/stable/9.git] / contrib / bind9 / lib / dns / dnssec.c
1 /*
2  * Copyright (C) 2004-2012  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         memcpy(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                 memcpy(data + 2, r.base, r.length);
505         }
506         else
507                 memcpy(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 static isc_boolean_t
613 key_active(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         dns_rdataset_init(&rdataset);
688         RETERR(dns_db_findrdataset(db, node, ver, dns_rdatatype_dnskey, 0, 0,
689                                    &rdataset, NULL));
690         RETERR(dns_rdataset_first(&rdataset));
691         while (result == ISC_R_SUCCESS && count < maxkeys) {
692                 pubkey = NULL;
693                 dns_rdataset_current(&rdataset, &rdata);
694                 RETERR(dns_dnssec_keyfromrdata(name, &rdata, mctx, &pubkey));
695                 dst_key_setttl(pubkey, rdataset.ttl);
696
697                 if (!is_zone_key(pubkey) ||
698                     (dst_key_flags(pubkey) & DNS_KEYTYPE_NOAUTH) != 0)
699                         goto next;
700                 /* Corrupted .key file? */
701                 if (!dns_name_equal(name, dst_key_name(pubkey)))
702                         goto next;
703                 keys[count] = NULL;
704                 result = dst_key_fromfile(dst_key_name(pubkey),
705                                           dst_key_id(pubkey),
706                                           dst_key_alg(pubkey),
707                                           DST_TYPE_PUBLIC|DST_TYPE_PRIVATE,
708                                           directory,
709                                           mctx, &keys[count]);
710
711                 /*
712                  * If the key was revoked and the private file
713                  * doesn't exist, maybe it was revoked internally
714                  * by named.  Try loading the unrevoked version.
715                  */
716                 if (result == ISC_R_FILENOTFOUND) {
717                         isc_uint32_t flags;
718                         flags = dst_key_flags(pubkey);
719                         if ((flags & DNS_KEYFLAG_REVOKE) != 0) {
720                                 dst_key_setflags(pubkey,
721                                                  flags & ~DNS_KEYFLAG_REVOKE);
722                                 result = dst_key_fromfile(dst_key_name(pubkey),
723                                                           dst_key_id(pubkey),
724                                                           dst_key_alg(pubkey),
725                                                           DST_TYPE_PUBLIC|
726                                                           DST_TYPE_PRIVATE,
727                                                           directory,
728                                                           mctx, &keys[count]);
729                                 if (result == ISC_R_SUCCESS &&
730                                     dst_key_pubcompare(pubkey, keys[count],
731                                                        ISC_FALSE)) {
732                                         dst_key_setflags(keys[count], flags);
733                                 }
734                                 dst_key_setflags(pubkey, flags);
735                         }
736                 }
737
738                 if (result != ISC_R_SUCCESS) {
739                         char keybuf[DNS_NAME_FORMATSIZE];
740                         char algbuf[DNS_SECALG_FORMATSIZE];
741                         dns_name_format(dst_key_name(pubkey), keybuf,
742                                         sizeof(keybuf));
743                         dns_secalg_format(dst_key_alg(pubkey), algbuf,
744                                           sizeof(algbuf));
745                         isc_log_write(dns_lctx, DNS_LOGCATEGORY_GENERAL,
746                                       DNS_LOGMODULE_DNSSEC, ISC_LOG_WARNING,
747                                       "dns_dnssec_findzonekeys2: error "
748                                       "reading private key file %s/%s/%d: %s",
749                                       keybuf, algbuf, dst_key_id(pubkey),
750                                       isc_result_totext(result));
751                 }
752
753                 if (result == ISC_R_FILENOTFOUND || result == ISC_R_NOPERM) {
754                         keys[count] = pubkey;
755                         pubkey = NULL;
756                         count++;
757                         goto next;
758                 }
759
760                 if (result != ISC_R_SUCCESS)
761                         goto failure;
762
763                 /*
764                  * If a key is marked inactive, skip it
765                  */
766                 if (!key_active(keys[count], now)) {
767                         dst_key_free(&keys[count]);
768                         keys[count] = pubkey;
769                         pubkey = NULL;
770                         count++;
771                         goto next;
772                 }
773
774                 /*
775                  * Whatever the key's default TTL may have
776                  * been, the rdataset TTL takes priority.
777                  */
778                 dst_key_setttl(keys[count], rdataset.ttl);
779
780                 if ((dst_key_flags(keys[count]) & DNS_KEYTYPE_NOAUTH) != 0) {
781                         /* We should never get here. */
782                         dst_key_free(&keys[count]);
783                         goto next;
784                 }
785                 count++;
786  next:
787                 if (pubkey != NULL)
788                         dst_key_free(&pubkey);
789                 dns_rdata_reset(&rdata);
790                 result = dns_rdataset_next(&rdataset);
791         }
792         if (result != ISC_R_NOMORE)
793                 goto failure;
794         if (count == 0)
795                 result = ISC_R_NOTFOUND;
796         else
797                 result = ISC_R_SUCCESS;
798
799  failure:
800         if (dns_rdataset_isassociated(&rdataset))
801                 dns_rdataset_disassociate(&rdataset);
802         if (pubkey != NULL)
803                 dst_key_free(&pubkey);
804         if (result != ISC_R_SUCCESS)
805                 while (count > 0)
806                         dst_key_free(&keys[--count]);
807         *nkeys = count;
808         return (result);
809 }
810
811 isc_result_t
812 dns_dnssec_findzonekeys(dns_db_t *db, dns_dbversion_t *ver,
813                         dns_dbnode_t *node, dns_name_t *name, isc_mem_t *mctx,
814                         unsigned int maxkeys, dst_key_t **keys,
815                         unsigned int *nkeys)
816 {
817         return (dns_dnssec_findzonekeys2(db, ver, node, name, NULL, mctx,
818                                          maxkeys, keys, nkeys));
819 }
820
821 isc_result_t
822 dns_dnssec_signmessage(dns_message_t *msg, dst_key_t *key) {
823         dns_rdata_sig_t sig;    /* SIG(0) */
824         unsigned char data[512];
825         unsigned char header[DNS_MESSAGE_HEADERLEN];
826         isc_buffer_t headerbuf, databuf, sigbuf;
827         unsigned int sigsize;
828         isc_buffer_t *dynbuf = NULL;
829         dns_rdata_t *rdata;
830         dns_rdatalist_t *datalist;
831         dns_rdataset_t *dataset;
832         isc_region_t r;
833         isc_stdtime_t now;
834         dst_context_t *ctx = NULL;
835         isc_mem_t *mctx;
836         isc_result_t result;
837         isc_boolean_t signeedsfree = ISC_TRUE;
838
839         REQUIRE(msg != NULL);
840         REQUIRE(key != NULL);
841
842         if (is_response(msg))
843                 REQUIRE(msg->query.base != NULL);
844
845         mctx = msg->mctx;
846
847         memset(&sig, 0, sizeof(sig));
848
849         sig.mctx = mctx;
850         sig.common.rdclass = dns_rdataclass_any;
851         sig.common.rdtype = dns_rdatatype_sig;  /* SIG(0) */
852         ISC_LINK_INIT(&sig.common, link);
853
854         sig.covered = 0;
855         sig.algorithm = dst_key_alg(key);
856         sig.labels = 0; /* the root name */
857         sig.originalttl = 0;
858
859         isc_stdtime_get(&now);
860         sig.timesigned = now - DNS_TSIG_FUDGE;
861         sig.timeexpire = now + DNS_TSIG_FUDGE;
862
863         sig.keyid = dst_key_id(key);
864
865         dns_name_init(&sig.signer, NULL);
866         dns_name_clone(dst_key_name(key), &sig.signer);
867
868         sig.siglen = 0;
869         sig.signature = NULL;
870
871         isc_buffer_init(&databuf, data, sizeof(data));
872
873         RETERR(dst_context_create2(key, mctx, DNS_LOGCATEGORY_DNSSEC, &ctx));
874
875         /*
876          * Digest the fields of the SIG - we can cheat and use
877          * dns_rdata_fromstruct.  Since siglen is 0, the digested data
878          * is identical to dns format.
879          */
880         RETERR(dns_rdata_fromstruct(NULL, dns_rdataclass_any,
881                                     dns_rdatatype_sig /* SIG(0) */,
882                                     &sig, &databuf));
883         isc_buffer_usedregion(&databuf, &r);
884         RETERR(dst_context_adddata(ctx, &r));
885
886         /*
887          * If this is a response, digest the query.
888          */
889         if (is_response(msg))
890                 RETERR(dst_context_adddata(ctx, &msg->query));
891
892         /*
893          * Digest the header.
894          */
895         isc_buffer_init(&headerbuf, header, sizeof(header));
896         dns_message_renderheader(msg, &headerbuf);
897         isc_buffer_usedregion(&headerbuf, &r);
898         RETERR(dst_context_adddata(ctx, &r));
899
900         /*
901          * Digest the remainder of the message.
902          */
903         isc_buffer_usedregion(msg->buffer, &r);
904         isc_region_consume(&r, DNS_MESSAGE_HEADERLEN);
905         RETERR(dst_context_adddata(ctx, &r));
906
907         RETERR(dst_key_sigsize(key, &sigsize));
908         sig.siglen = sigsize;
909         sig.signature = (unsigned char *) isc_mem_get(mctx, sig.siglen);
910         if (sig.signature == NULL) {
911                 result = ISC_R_NOMEMORY;
912                 goto failure;
913         }
914
915         isc_buffer_init(&sigbuf, sig.signature, sig.siglen);
916         RETERR(dst_context_sign(ctx, &sigbuf));
917         dst_context_destroy(&ctx);
918
919         rdata = NULL;
920         RETERR(dns_message_gettemprdata(msg, &rdata));
921         RETERR(isc_buffer_allocate(msg->mctx, &dynbuf, 1024));
922         RETERR(dns_rdata_fromstruct(rdata, dns_rdataclass_any,
923                                     dns_rdatatype_sig /* SIG(0) */,
924                                     &sig, dynbuf));
925
926         isc_mem_put(mctx, sig.signature, sig.siglen);
927         signeedsfree = ISC_FALSE;
928
929         dns_message_takebuffer(msg, &dynbuf);
930
931         datalist = NULL;
932         RETERR(dns_message_gettemprdatalist(msg, &datalist));
933         datalist->rdclass = dns_rdataclass_any;
934         datalist->type = dns_rdatatype_sig;     /* SIG(0) */
935         datalist->covers = 0;
936         datalist->ttl = 0;
937         ISC_LIST_INIT(datalist->rdata);
938         ISC_LIST_APPEND(datalist->rdata, rdata, link);
939         dataset = NULL;
940         RETERR(dns_message_gettemprdataset(msg, &dataset));
941         dns_rdataset_init(dataset);
942         RUNTIME_CHECK(dns_rdatalist_tordataset(datalist, dataset) == ISC_R_SUCCESS);
943         msg->sig0 = dataset;
944
945         return (ISC_R_SUCCESS);
946
947 failure:
948         if (dynbuf != NULL)
949                 isc_buffer_free(&dynbuf);
950         if (signeedsfree)
951                 isc_mem_put(mctx, sig.signature, sig.siglen);
952         if (ctx != NULL)
953                 dst_context_destroy(&ctx);
954
955         return (result);
956 }
957
958 isc_result_t
959 dns_dnssec_verifymessage(isc_buffer_t *source, dns_message_t *msg,
960                          dst_key_t *key)
961 {
962         dns_rdata_sig_t sig;    /* SIG(0) */
963         unsigned char header[DNS_MESSAGE_HEADERLEN];
964         dns_rdata_t rdata = DNS_RDATA_INIT;
965         isc_region_t r, source_r, sig_r, header_r;
966         isc_stdtime_t now;
967         dst_context_t *ctx = NULL;
968         isc_mem_t *mctx;
969         isc_result_t result;
970         isc_uint16_t addcount;
971         isc_boolean_t signeedsfree = ISC_FALSE;
972
973         REQUIRE(source != NULL);
974         REQUIRE(msg != NULL);
975         REQUIRE(key != NULL);
976
977         mctx = msg->mctx;
978
979         msg->verify_attempted = 1;
980
981         if (is_response(msg)) {
982                 if (msg->query.base == NULL)
983                         return (DNS_R_UNEXPECTEDTSIG);
984         }
985
986         isc_buffer_usedregion(source, &source_r);
987
988         RETERR(dns_rdataset_first(msg->sig0));
989         dns_rdataset_current(msg->sig0, &rdata);
990
991         RETERR(dns_rdata_tostruct(&rdata, &sig, NULL));
992         signeedsfree = ISC_TRUE;
993
994         if (sig.labels != 0) {
995                 result = DNS_R_SIGINVALID;
996                 goto failure;
997         }
998
999         if (isc_serial_lt(sig.timeexpire, sig.timesigned)) {
1000                 result = DNS_R_SIGINVALID;
1001                 msg->sig0status = dns_tsigerror_badtime;
1002                 goto failure;
1003         }
1004
1005         isc_stdtime_get(&now);
1006         if (isc_serial_lt((isc_uint32_t)now, sig.timesigned)) {
1007                 result = DNS_R_SIGFUTURE;
1008                 msg->sig0status = dns_tsigerror_badtime;
1009                 goto failure;
1010         }
1011         else if (isc_serial_lt(sig.timeexpire, (isc_uint32_t)now)) {
1012                 result = DNS_R_SIGEXPIRED;
1013                 msg->sig0status = dns_tsigerror_badtime;
1014                 goto failure;
1015         }
1016
1017         if (!dns_name_equal(dst_key_name(key), &sig.signer)) {
1018                 result = DNS_R_SIGINVALID;
1019                 msg->sig0status = dns_tsigerror_badkey;
1020                 goto failure;
1021         }
1022
1023         RETERR(dst_context_create2(key, mctx, DNS_LOGCATEGORY_DNSSEC, &ctx));
1024
1025         /*
1026          * Digest the SIG(0) record, except for the signature.
1027          */
1028         dns_rdata_toregion(&rdata, &r);
1029         r.length -= sig.siglen;
1030         RETERR(dst_context_adddata(ctx, &r));
1031
1032         /*
1033          * If this is a response, digest the query.
1034          */
1035         if (is_response(msg))
1036                 RETERR(dst_context_adddata(ctx, &msg->query));
1037
1038         /*
1039          * Extract the header.
1040          */
1041         memcpy(header, source_r.base, DNS_MESSAGE_HEADERLEN);
1042
1043         /*
1044          * Decrement the additional field counter.
1045          */
1046         memcpy(&addcount, &header[DNS_MESSAGE_HEADERLEN - 2], 2);
1047         addcount = htons((isc_uint16_t)(ntohs(addcount) - 1));
1048         memcpy(&header[DNS_MESSAGE_HEADERLEN - 2], &addcount, 2);
1049
1050         /*
1051          * Digest the modified header.
1052          */
1053         header_r.base = (unsigned char *) header;
1054         header_r.length = DNS_MESSAGE_HEADERLEN;
1055         RETERR(dst_context_adddata(ctx, &header_r));
1056
1057         /*
1058          * Digest all non-SIG(0) records.
1059          */
1060         r.base = source_r.base + DNS_MESSAGE_HEADERLEN;
1061         r.length = msg->sigstart - DNS_MESSAGE_HEADERLEN;
1062         RETERR(dst_context_adddata(ctx, &r));
1063
1064         sig_r.base = sig.signature;
1065         sig_r.length = sig.siglen;
1066         result = dst_context_verify(ctx, &sig_r);
1067         if (result != ISC_R_SUCCESS) {
1068                 msg->sig0status = dns_tsigerror_badsig;
1069                 goto failure;
1070         }
1071
1072         msg->verified_sig = 1;
1073
1074         dst_context_destroy(&ctx);
1075         dns_rdata_freestruct(&sig);
1076
1077         return (ISC_R_SUCCESS);
1078
1079 failure:
1080         if (signeedsfree)
1081                 dns_rdata_freestruct(&sig);
1082         if (ctx != NULL)
1083                 dst_context_destroy(&ctx);
1084
1085         return (result);
1086 }
1087
1088 /*%
1089  * Does this key ('rdata') self sign the rrset ('rdataset')?
1090  */
1091 isc_boolean_t
1092 dns_dnssec_selfsigns(dns_rdata_t *rdata, dns_name_t *name,
1093                      dns_rdataset_t *rdataset, dns_rdataset_t *sigrdataset,
1094                      isc_boolean_t ignoretime, isc_mem_t *mctx)
1095 {
1096         INSIST(rdataset->type == dns_rdatatype_key ||
1097                rdataset->type == dns_rdatatype_dnskey);
1098         if (rdataset->type == dns_rdatatype_key) {
1099                 INSIST(sigrdataset->type == dns_rdatatype_sig);
1100                 INSIST(sigrdataset->covers == dns_rdatatype_key);
1101         } else {
1102                 INSIST(sigrdataset->type == dns_rdatatype_rrsig);
1103                 INSIST(sigrdataset->covers == dns_rdatatype_dnskey);
1104         }
1105
1106         return (dns_dnssec_signs(rdata, name, rdataset, sigrdataset,
1107                                  ignoretime, mctx));
1108
1109 }
1110
1111 isc_boolean_t
1112 dns_dnssec_signs(dns_rdata_t *rdata, dns_name_t *name,
1113                      dns_rdataset_t *rdataset, dns_rdataset_t *sigrdataset,
1114                      isc_boolean_t ignoretime, isc_mem_t *mctx)
1115 {
1116         dst_key_t *dstkey = NULL;
1117         dns_keytag_t keytag;
1118         dns_rdata_dnskey_t key;
1119         dns_rdata_rrsig_t sig;
1120         dns_rdata_t sigrdata = DNS_RDATA_INIT;
1121         isc_result_t result;
1122
1123         INSIST(sigrdataset->type == dns_rdatatype_rrsig);
1124         if (sigrdataset->covers != rdataset->type)
1125                 return (ISC_FALSE);
1126
1127         result = dns_dnssec_keyfromrdata(name, rdata, mctx, &dstkey);
1128         if (result != ISC_R_SUCCESS)
1129                 return (ISC_FALSE);
1130         result = dns_rdata_tostruct(rdata, &key, NULL);
1131         RUNTIME_CHECK(result == ISC_R_SUCCESS);
1132
1133         keytag = dst_key_id(dstkey);
1134         for (result = dns_rdataset_first(sigrdataset);
1135              result == ISC_R_SUCCESS;
1136              result = dns_rdataset_next(sigrdataset))
1137         {
1138                 dns_rdata_reset(&sigrdata);
1139                 dns_rdataset_current(sigrdataset, &sigrdata);
1140                 result = dns_rdata_tostruct(&sigrdata, &sig, NULL);
1141                 RUNTIME_CHECK(result == ISC_R_SUCCESS);
1142
1143                 if (sig.algorithm == key.algorithm &&
1144                     sig.keyid == keytag) {
1145                         result = dns_dnssec_verify2(name, rdataset, dstkey,
1146                                                     ignoretime, mctx,
1147                                                     &sigrdata, NULL);
1148                         if (result == ISC_R_SUCCESS) {
1149                                 dst_key_free(&dstkey);
1150                                 return (ISC_TRUE);
1151                         }
1152                 }
1153         }
1154         dst_key_free(&dstkey);
1155         return (ISC_FALSE);
1156 }
1157
1158 isc_result_t
1159 dns_dnsseckey_create(isc_mem_t *mctx, dst_key_t **dstkey,
1160                      dns_dnsseckey_t **dkp)
1161 {
1162         isc_result_t result;
1163         dns_dnsseckey_t *dk;
1164         int major, minor;
1165
1166         REQUIRE(dkp != NULL && *dkp == NULL);
1167         dk = isc_mem_get(mctx, sizeof(dns_dnsseckey_t));
1168         if (dk == NULL)
1169                 return (ISC_R_NOMEMORY);
1170
1171         dk->key = *dstkey;
1172         *dstkey = NULL;
1173         dk->force_publish = ISC_FALSE;
1174         dk->force_sign = ISC_FALSE;
1175         dk->hint_publish = ISC_FALSE;
1176         dk->hint_sign = ISC_FALSE;
1177         dk->hint_remove = ISC_FALSE;
1178         dk->first_sign = ISC_FALSE;
1179         dk->is_active = ISC_FALSE;
1180         dk->prepublish = 0;
1181         dk->source = dns_keysource_unknown;
1182         dk->index = 0;
1183
1184         /* KSK or ZSK? */
1185         dk->ksk = ISC_TF((dst_key_flags(dk->key) & DNS_KEYFLAG_KSK) != 0);
1186
1187         /* Is this an old-style key? */
1188         result = dst_key_getprivateformat(dk->key, &major, &minor);
1189         INSIST(result == ISC_R_SUCCESS);
1190
1191         /* Smart signing started with key format 1.3 */
1192         dk->legacy = ISC_TF(major == 1 && minor <= 2);
1193
1194         ISC_LINK_INIT(dk, link);
1195         *dkp = dk;
1196         return (ISC_R_SUCCESS);
1197 }
1198
1199 void
1200 dns_dnsseckey_destroy(isc_mem_t *mctx, dns_dnsseckey_t **dkp) {
1201         dns_dnsseckey_t *dk;
1202
1203         REQUIRE(dkp != NULL && *dkp != NULL);
1204         dk = *dkp;
1205         if (dk->key != NULL)
1206                 dst_key_free(&dk->key);
1207         isc_mem_put(mctx, dk, sizeof(dns_dnsseckey_t));
1208         *dkp = NULL;
1209 }
1210
1211 static void
1212 get_hints(dns_dnsseckey_t *key, isc_stdtime_t now) {
1213         isc_result_t result;
1214         isc_stdtime_t publish, active, revoke, inactive, delete;
1215         isc_boolean_t pubset = ISC_FALSE, actset = ISC_FALSE;
1216         isc_boolean_t revset = ISC_FALSE, inactset = ISC_FALSE;
1217         isc_boolean_t delset = ISC_FALSE;
1218
1219         REQUIRE(key != NULL && key->key != NULL);
1220
1221         result = dst_key_gettime(key->key, DST_TIME_PUBLISH, &publish);
1222         if (result == ISC_R_SUCCESS)
1223                 pubset = ISC_TRUE;
1224
1225         result = dst_key_gettime(key->key, DST_TIME_ACTIVATE, &active);
1226         if (result == ISC_R_SUCCESS)
1227                 actset = ISC_TRUE;
1228
1229         result = dst_key_gettime(key->key, DST_TIME_REVOKE, &revoke);
1230         if (result == ISC_R_SUCCESS)
1231                 revset = ISC_TRUE;
1232
1233         result = dst_key_gettime(key->key, DST_TIME_INACTIVE, &inactive);
1234         if (result == ISC_R_SUCCESS)
1235                 inactset = ISC_TRUE;
1236
1237         result = dst_key_gettime(key->key, DST_TIME_DELETE, &delete);
1238         if (result == ISC_R_SUCCESS)
1239                 delset = ISC_TRUE;
1240
1241         /* Metadata says publish (but possibly not activate) */
1242         if (pubset && publish <= now)
1243                 key->hint_publish = ISC_TRUE;
1244
1245         /* Metadata says activate (so we must also publish) */
1246         if (actset && active <= now) {
1247                 key->hint_sign = ISC_TRUE;
1248                 key->hint_publish = ISC_TRUE;
1249         }
1250
1251         /*
1252          * Activation date is set (maybe in the future), but
1253          * publication date isn't. Most likely the user wants to
1254          * publish now and activate later.
1255          */
1256         if (actset && !pubset)
1257                 key->hint_publish = ISC_TRUE;
1258
1259         /*
1260          * If activation date is in the future, make note of how far off
1261          */
1262         if (key->hint_publish && actset && active > now) {
1263                 key->prepublish = active - now;
1264         }
1265
1266         /*
1267          * Key has been marked inactive: we can continue publishing,
1268          * but don't sign.
1269          */
1270         if (key->hint_publish && inactset && inactive <= now) {
1271                 key->hint_sign = ISC_FALSE;
1272         }
1273
1274         /*
1275          * Metadata says revoke.  If the key is published,
1276          * we *have to* sign with it per RFC5011--even if it was
1277          * not active before.
1278          *
1279          * If it hasn't already been done, we should also revoke it now.
1280          */
1281         if (key->hint_publish && (revset && revoke <= now)) {
1282                 isc_uint32_t flags;
1283                 key->hint_sign = ISC_TRUE;
1284                 flags = dst_key_flags(key->key);
1285                 if ((flags & DNS_KEYFLAG_REVOKE) == 0) {
1286                         flags |= DNS_KEYFLAG_REVOKE;
1287                         dst_key_setflags(key->key, flags);
1288                 }
1289         }
1290
1291         /*
1292          * Metadata says delete, so don't publish this key or sign with it.
1293          */
1294         if (delset && delete <= now) {
1295                 key->hint_publish = ISC_FALSE;
1296                 key->hint_sign = ISC_FALSE;
1297                 key->hint_remove = ISC_TRUE;
1298         }
1299 }
1300
1301 /*%
1302  * Get a list of DNSSEC keys from the key repository
1303  */
1304 isc_result_t
1305 dns_dnssec_findmatchingkeys(dns_name_t *origin, const char *directory,
1306                             isc_mem_t *mctx, dns_dnsseckeylist_t *keylist)
1307 {
1308         isc_result_t result = ISC_R_SUCCESS;
1309         isc_boolean_t dir_open = ISC_FALSE;
1310         dns_dnsseckeylist_t list;
1311         isc_dir_t dir;
1312         dns_dnsseckey_t *key = NULL;
1313         dst_key_t *dstkey = NULL;
1314         char namebuf[DNS_NAME_FORMATSIZE], *p;
1315         isc_buffer_t b;
1316         unsigned int len;
1317         isc_stdtime_t now;
1318
1319         REQUIRE(keylist != NULL);
1320         ISC_LIST_INIT(list);
1321         isc_dir_init(&dir);
1322
1323         isc_buffer_init(&b, namebuf, sizeof(namebuf) - 1);
1324         RETERR(dns_name_tofilenametext(origin, ISC_FALSE, &b));
1325         len = isc_buffer_usedlength(&b);
1326         namebuf[len] = '\0';
1327
1328         if (directory == NULL)
1329                 directory = ".";
1330         RETERR(isc_dir_open(&dir, directory));
1331         dir_open = ISC_TRUE;
1332
1333         isc_stdtime_get(&now);
1334
1335         while (isc_dir_read(&dir) == ISC_R_SUCCESS) {
1336                 if (dir.entry.name[0] == 'K' &&
1337                     dir.entry.length > len + 1 &&
1338                     dir.entry.name[len + 1] == '+' &&
1339                     strncasecmp(dir.entry.name + 1, namebuf, len) == 0) {
1340                         p = strrchr(dir.entry.name, '.');
1341                         if (p != NULL && strcmp(p, ".private") != 0)
1342                                 continue;
1343
1344                         dstkey = NULL;
1345                         result = dst_key_fromnamedfile(dir.entry.name,
1346                                                        directory,
1347                                                        DST_TYPE_PUBLIC |
1348                                                        DST_TYPE_PRIVATE,
1349                                                        mctx, &dstkey);
1350
1351                         if (result != ISC_R_SUCCESS) {
1352                                 isc_log_write(dns_lctx,
1353                                               DNS_LOGCATEGORY_GENERAL,
1354                                               DNS_LOGMODULE_DNSSEC,
1355                                               ISC_LOG_WARNING,
1356                                               "dns_dnssec_findmatchingkeys: "
1357                                               "error reading key file %s: %s",
1358                                               dir.entry.name,
1359                                               isc_result_totext(result));
1360                                 continue;
1361                         }
1362
1363                         RETERR(dns_dnsseckey_create(mctx, &dstkey, &key));
1364                         key->source = dns_keysource_repository;
1365                         get_hints(key, now);
1366
1367                         if (key->legacy) {
1368                                 dns_dnsseckey_destroy(mctx, &key);
1369                         } else {
1370                                 ISC_LIST_APPEND(list, key, link);
1371                                 key = NULL;
1372                         }
1373                 }
1374         }
1375
1376         if (!ISC_LIST_EMPTY(list))
1377                 ISC_LIST_APPENDLIST(*keylist, list, link);
1378         else
1379                 result = ISC_R_NOTFOUND;
1380
1381  failure:
1382         if (dir_open)
1383                 isc_dir_close(&dir);
1384         INSIST(key == NULL);
1385         while ((key = ISC_LIST_HEAD(list)) != NULL) {
1386                 ISC_LIST_UNLINK(list, key, link);
1387                 INSIST(key->key != NULL);
1388                 dst_key_free(&key->key);
1389                 dns_dnsseckey_destroy(mctx, &key);
1390         }
1391         if (dstkey != NULL)
1392                 dst_key_free(&dstkey);
1393         return (result);
1394 }
1395
1396 /*%
1397  * Add 'newkey' to 'keylist' if it's not already there.
1398  *
1399  * If 'savekeys' is ISC_TRUE, then we need to preserve all
1400  * the keys in the keyset, regardless of whether they have
1401  * metadata indicating they should be deactivated or removed.
1402  */
1403 static isc_result_t
1404 addkey(dns_dnsseckeylist_t *keylist, dst_key_t **newkey,
1405        isc_boolean_t savekeys, isc_mem_t *mctx)
1406 {
1407         dns_dnsseckey_t *key;
1408         isc_result_t result;
1409
1410         /* Skip duplicates */
1411         for (key = ISC_LIST_HEAD(*keylist);
1412              key != NULL;
1413              key = ISC_LIST_NEXT(key, link)) {
1414                 if (dst_key_id(key->key) == dst_key_id(*newkey) &&
1415                     dst_key_alg(key->key) == dst_key_alg(*newkey) &&
1416                     dns_name_equal(dst_key_name(key->key),
1417                                    dst_key_name(*newkey)))
1418                         break;
1419         }
1420
1421         if (key != NULL) {
1422                 /*
1423                  * Found a match.  If the old key was only public and the
1424                  * new key is private, replace the old one; otherwise
1425                  * leave it.  But either way, mark the key as having
1426                  * been found in the zone.
1427                  */
1428                 if (dst_key_isprivate(key->key)) {
1429                         dst_key_free(newkey);
1430                 } else if (dst_key_isprivate(*newkey)) {
1431                         dst_key_free(&key->key);
1432                         key->key = *newkey;
1433                 }
1434
1435                 key->source = dns_keysource_zoneapex;
1436                 return (ISC_R_SUCCESS);
1437         }
1438
1439         result = dns_dnsseckey_create(mctx, newkey, &key);
1440         if (result != ISC_R_SUCCESS)
1441                 return (result);
1442         if (key->legacy || savekeys) {
1443                 key->force_publish = ISC_TRUE;
1444                 key->force_sign = dst_key_isprivate(key->key);
1445         }
1446         key->source = dns_keysource_zoneapex;
1447         ISC_LIST_APPEND(*keylist, key, link);
1448         *newkey = NULL;
1449         return (ISC_R_SUCCESS);
1450 }
1451
1452
1453 /*%
1454  * Mark all keys which signed the DNSKEY/SOA RRsets as "active",
1455  * for future reference.
1456  */
1457 static isc_result_t
1458 mark_active_keys(dns_dnsseckeylist_t *keylist, dns_rdataset_t *rrsigs) {
1459         isc_result_t result = ISC_R_SUCCESS;
1460         dns_rdata_t rdata = DNS_RDATA_INIT;
1461         dns_rdataset_t sigs;
1462         dns_dnsseckey_t *key;
1463
1464         REQUIRE(rrsigs != NULL && dns_rdataset_isassociated(rrsigs));
1465
1466         dns_rdataset_init(&sigs);
1467         dns_rdataset_clone(rrsigs, &sigs);
1468         for (key = ISC_LIST_HEAD(*keylist);
1469              key != NULL;
1470              key = ISC_LIST_NEXT(key, link)) {
1471                 isc_uint16_t keyid, sigid;
1472                 dns_secalg_t keyalg, sigalg;
1473                 keyid = dst_key_id(key->key);
1474                 keyalg = dst_key_alg(key->key);
1475
1476                 for (result = dns_rdataset_first(&sigs);
1477                      result == ISC_R_SUCCESS;
1478                      result = dns_rdataset_next(&sigs)) {
1479                         dns_rdata_rrsig_t sig;
1480
1481                         dns_rdata_reset(&rdata);
1482                         dns_rdataset_current(&sigs, &rdata);
1483                         result = dns_rdata_tostruct(&rdata, &sig, NULL);
1484                         RUNTIME_CHECK(result == ISC_R_SUCCESS);
1485                         sigalg = sig.algorithm;
1486                         sigid = sig.keyid;
1487                         if (keyid == sigid && keyalg == sigalg) {
1488                                 key->is_active = ISC_TRUE;
1489                                 break;
1490                         }
1491                 }
1492         }
1493
1494         if (result == ISC_R_NOMORE)
1495                 result = ISC_R_SUCCESS;
1496
1497         if (dns_rdataset_isassociated(&sigs))
1498                 dns_rdataset_disassociate(&sigs);
1499         return (result);
1500 }
1501
1502 /*%
1503  * Add the contents of a DNSKEY rdataset 'keyset' to 'keylist'.
1504  */
1505 isc_result_t
1506 dns_dnssec_keylistfromrdataset(dns_name_t *origin,
1507                                const char *directory, isc_mem_t *mctx,
1508                                dns_rdataset_t *keyset, dns_rdataset_t *keysigs,
1509                                dns_rdataset_t *soasigs, isc_boolean_t savekeys,
1510                                isc_boolean_t public,
1511                                dns_dnsseckeylist_t *keylist)
1512 {
1513         dns_rdataset_t keys;
1514         dns_rdata_t rdata = DNS_RDATA_INIT;
1515         dst_key_t *pubkey = NULL, *privkey = NULL;
1516         isc_result_t result;
1517
1518         REQUIRE(keyset != NULL && dns_rdataset_isassociated(keyset));
1519
1520         dns_rdataset_init(&keys);
1521
1522         dns_rdataset_clone(keyset, &keys);
1523         for (result = dns_rdataset_first(&keys);
1524              result == ISC_R_SUCCESS;
1525              result = dns_rdataset_next(&keys)) {
1526                 dns_rdata_reset(&rdata);
1527                 dns_rdataset_current(&keys, &rdata);
1528                 RETERR(dns_dnssec_keyfromrdata(origin, &rdata, mctx, &pubkey));
1529                 dst_key_setttl(pubkey, keys.ttl);
1530
1531                 if (!is_zone_key(pubkey) ||
1532                     (dst_key_flags(pubkey) & DNS_KEYTYPE_NOAUTH) != 0)
1533                         goto skip;
1534
1535                 /* Corrupted .key file? */
1536                 if (!dns_name_equal(origin, dst_key_name(pubkey)))
1537                         goto skip;
1538
1539                 if (public) {
1540                         RETERR(addkey(keylist, &pubkey, savekeys, mctx));
1541                         goto skip;
1542                 }
1543
1544                 result = dst_key_fromfile(dst_key_name(pubkey),
1545                                           dst_key_id(pubkey),
1546                                           dst_key_alg(pubkey),
1547                                           DST_TYPE_PUBLIC|DST_TYPE_PRIVATE,
1548                                           directory, mctx, &privkey);
1549
1550                 /*
1551                  * If the key was revoked and the private file
1552                  * doesn't exist, maybe it was revoked internally
1553                  * by named.  Try loading the unrevoked version.
1554                  */
1555                 if (result == ISC_R_FILENOTFOUND) {
1556                         isc_uint32_t flags;
1557                         flags = dst_key_flags(pubkey);
1558                         if ((flags & DNS_KEYFLAG_REVOKE) != 0) {
1559                                 dst_key_setflags(pubkey,
1560                                                  flags & ~DNS_KEYFLAG_REVOKE);
1561                                 result = dst_key_fromfile(dst_key_name(pubkey),
1562                                                           dst_key_id(pubkey),
1563                                                           dst_key_alg(pubkey),
1564                                                           DST_TYPE_PUBLIC|
1565                                                           DST_TYPE_PRIVATE,
1566                                                           directory,
1567                                                           mctx, &privkey);
1568                                 if (result == ISC_R_SUCCESS &&
1569                                     dst_key_pubcompare(pubkey, privkey,
1570                                                        ISC_FALSE)) {
1571                                         dst_key_setflags(privkey, flags);
1572                                 }
1573                                 dst_key_setflags(pubkey, flags);
1574                         }
1575                 }
1576
1577                 if (result != ISC_R_SUCCESS) {
1578                         char keybuf[DNS_NAME_FORMATSIZE];
1579                         char algbuf[DNS_SECALG_FORMATSIZE];
1580                         dns_name_format(dst_key_name(pubkey), keybuf,
1581                                         sizeof(keybuf));
1582                         dns_secalg_format(dst_key_alg(pubkey), algbuf,
1583                                           sizeof(algbuf));
1584                         isc_log_write(dns_lctx, DNS_LOGCATEGORY_GENERAL,
1585                                       DNS_LOGMODULE_DNSSEC, ISC_LOG_WARNING,
1586                                       "dns_dnssec_keylistfromrdataset: error "
1587                                       "reading private key file %s/%s/%d: %s",
1588                                       keybuf, algbuf, dst_key_id(pubkey),
1589                                       isc_result_totext(result));
1590                 }
1591
1592                 if (result == ISC_R_FILENOTFOUND || result == ISC_R_NOPERM) {
1593                         RETERR(addkey(keylist, &pubkey, savekeys, mctx));
1594                         goto skip;
1595                 }
1596                 RETERR(result);
1597
1598                 /* This should never happen. */
1599                 if ((dst_key_flags(privkey) & DNS_KEYTYPE_NOAUTH) != 0)
1600                         goto skip;
1601
1602                 /*
1603                  * Whatever the key's default TTL may have
1604                  * been, the rdataset TTL takes priority.
1605                  */
1606                 dst_key_setttl(privkey, dst_key_getttl(pubkey));
1607
1608                 RETERR(addkey(keylist, &privkey, savekeys, mctx));
1609  skip:
1610                 if (pubkey != NULL)
1611                         dst_key_free(&pubkey);
1612                 if (privkey != NULL)
1613                         dst_key_free(&privkey);
1614         }
1615
1616         if (result != ISC_R_NOMORE)
1617                 RETERR(result);
1618
1619         if (keysigs != NULL && dns_rdataset_isassociated(keysigs))
1620                 RETERR(mark_active_keys(keylist, keysigs));
1621
1622         if (soasigs != NULL && dns_rdataset_isassociated(soasigs))
1623                 RETERR(mark_active_keys(keylist, soasigs));
1624
1625         result = ISC_R_SUCCESS;
1626
1627  failure:
1628         if (dns_rdataset_isassociated(&keys))
1629                 dns_rdataset_disassociate(&keys);
1630         if (pubkey != NULL)
1631                 dst_key_free(&pubkey);
1632         if (privkey != NULL)
1633                 dst_key_free(&privkey);
1634         return (result);
1635 }
1636
1637 static isc_result_t
1638 make_dnskey(dst_key_t *key, unsigned char *buf, int bufsize,
1639             dns_rdata_t *target)
1640 {
1641         isc_result_t result;
1642         isc_buffer_t b;
1643         isc_region_t r;
1644
1645         isc_buffer_init(&b, buf, bufsize);
1646         result = dst_key_todns(key, &b);
1647         if (result != ISC_R_SUCCESS)
1648                 return (result);
1649
1650         dns_rdata_reset(target);
1651         isc_buffer_usedregion(&b, &r);
1652         dns_rdata_fromregion(target, dst_key_class(key),
1653                              dns_rdatatype_dnskey, &r);
1654         return (ISC_R_SUCCESS);
1655 }
1656
1657 static isc_result_t
1658 publish_key(dns_diff_t *diff, dns_dnsseckey_t *key, dns_name_t *origin,
1659             dns_ttl_t ttl, isc_mem_t *mctx, isc_boolean_t allzsk,
1660             void (*report)(const char *, ...))
1661 {
1662         isc_result_t result;
1663         dns_difftuple_t *tuple = NULL;
1664         unsigned char buf[DST_KEY_MAXSIZE];
1665         dns_rdata_t dnskey = DNS_RDATA_INIT;
1666         char alg[80];
1667
1668         dns_rdata_reset(&dnskey);
1669         RETERR(make_dnskey(key->key, buf, sizeof(buf), &dnskey));
1670
1671         dns_secalg_format(dst_key_alg(key->key), alg, sizeof(alg));
1672         report("Fetching %s %d/%s from key %s.",
1673                key->ksk ?  (allzsk ?  "KSK/ZSK" : "KSK") : "ZSK",
1674                dst_key_id(key->key), alg,
1675                key->source == dns_keysource_user ?  "file" : "repository");
1676
1677         if (key->prepublish && ttl > key->prepublish) {
1678                 char keystr[DST_KEY_FORMATSIZE];
1679                 isc_stdtime_t now;
1680
1681                 dst_key_format(key->key, keystr, sizeof(keystr));
1682                 report("Key %s: Delaying activation to match the DNSKEY TTL.\n",
1683                        keystr, ttl);
1684
1685                 isc_stdtime_get(&now);
1686                 dst_key_settime(key->key, DST_TIME_ACTIVATE, now + ttl);
1687         }
1688
1689         /* publish key */
1690         RETERR(dns_difftuple_create(mctx, DNS_DIFFOP_ADD, origin, ttl,
1691                                     &dnskey, &tuple));
1692         dns_diff_appendminimal(diff, &tuple);
1693         result = ISC_R_SUCCESS;
1694
1695  failure:
1696         return (result);
1697 }
1698
1699 static isc_result_t
1700 remove_key(dns_diff_t *diff, dns_dnsseckey_t *key, dns_name_t *origin,
1701           dns_ttl_t ttl, isc_mem_t *mctx, const char *reason,
1702           void (*report)(const char *, ...))
1703 {
1704         isc_result_t result;
1705         dns_difftuple_t *tuple = NULL;
1706         unsigned char buf[DST_KEY_MAXSIZE];
1707         dns_rdata_t dnskey = DNS_RDATA_INIT;
1708         char alg[80];
1709
1710         dns_secalg_format(dst_key_alg(key->key), alg, sizeof(alg));
1711         report("Removing %s key %d/%s from DNSKEY RRset.",
1712                reason, dst_key_id(key->key), alg);
1713
1714         RETERR(make_dnskey(key->key, buf, sizeof(buf), &dnskey));
1715         RETERR(dns_difftuple_create(mctx, DNS_DIFFOP_DEL, origin, ttl, &dnskey,
1716                                     &tuple));
1717         dns_diff_appendminimal(diff, &tuple);
1718         result = ISC_R_SUCCESS;
1719
1720  failure:
1721         return (result);
1722 }
1723
1724 /*
1725  * Update 'keys' with information from 'newkeys'.
1726  *
1727  * If 'removed' is not NULL, any keys that are being removed from
1728  * the zone will be added to the list for post-removal processing.
1729  */
1730 isc_result_t
1731 dns_dnssec_updatekeys(dns_dnsseckeylist_t *keys, dns_dnsseckeylist_t *newkeys,
1732                       dns_dnsseckeylist_t *removed, dns_name_t *origin,
1733                       dns_ttl_t hint_ttl, dns_diff_t *diff,
1734                       isc_boolean_t allzsk, isc_mem_t *mctx,
1735                       void (*report)(const char *, ...))
1736 {
1737         isc_result_t result;
1738         dns_dnsseckey_t *key, *key1, *key2, *next;
1739         isc_boolean_t found_ttl = ISC_FALSE;
1740         dns_ttl_t ttl = hint_ttl;
1741
1742         /*
1743          * First, look through the existing key list to find keys
1744          * supplied from the command line which are not in the zone.
1745          * Update the zone to include them.
1746          *
1747          * Also, if there are keys published in the zone already,
1748          * use their TTL for all subsequent published keys.
1749          */
1750         for (key = ISC_LIST_HEAD(*keys);
1751              key != NULL;
1752              key = ISC_LIST_NEXT(key, link)) {
1753                 if (key->source == dns_keysource_user &&
1754                     (key->hint_publish || key->force_publish)) {
1755                         RETERR(publish_key(diff, key, origin, ttl,
1756                                            mctx, allzsk, report));
1757                 }
1758                 if (key->source == dns_keysource_zoneapex) {
1759                         ttl = dst_key_getttl(key->key);
1760                         found_ttl = ISC_TRUE;
1761                 }
1762         }
1763
1764         /*
1765          * If there were no existing keys, use the smallest nonzero
1766          * TTL of the keys found in the repository.
1767          */
1768         if (!found_ttl && !ISC_LIST_EMPTY(*newkeys)) {
1769                 dns_ttl_t shortest = 0;
1770
1771                 for (key = ISC_LIST_HEAD(*newkeys);
1772                      key != NULL;
1773                      key = ISC_LIST_NEXT(key, link)) {
1774                         dns_ttl_t thisttl = dst_key_getttl(key->key);
1775                         if (thisttl != 0 &&
1776                             (shortest == 0 || thisttl < shortest))
1777                                 shortest = thisttl;
1778                 }
1779
1780                 if (shortest != 0)
1781                         ttl = shortest;
1782         }
1783
1784         /*
1785          * Second, scan the list of newly found keys looking for matches
1786          * with known keys, and update accordingly.
1787          */
1788         for (key1 = ISC_LIST_HEAD(*newkeys); key1 != NULL; key1 = next) {
1789                 isc_boolean_t key_revoked = ISC_FALSE;
1790
1791                 next = ISC_LIST_NEXT(key1, link);
1792
1793                 for (key2 = ISC_LIST_HEAD(*keys);
1794                      key2 != NULL;
1795                      key2 = ISC_LIST_NEXT(key2, link)) {
1796                         if (dst_key_pubcompare(key1->key, key2->key,
1797                                                ISC_TRUE)) {
1798                                 int r1, r2;
1799                                 r1 = dst_key_flags(key1->key) &
1800                                         DNS_KEYFLAG_REVOKE;
1801                                 r2 = dst_key_flags(key2->key) &
1802                                         DNS_KEYFLAG_REVOKE;
1803                                 key_revoked = ISC_TF(r1 != r2);
1804                                 break;
1805                         }
1806                 }
1807
1808                 /* No match found in keys; add the new key. */
1809                 if (key2 == NULL) {
1810                         ISC_LIST_UNLINK(*newkeys, key1, link);
1811                         ISC_LIST_APPEND(*keys, key1, link);
1812
1813                         if (key1->source != dns_keysource_zoneapex &&
1814                             (key1->hint_publish || key1->force_publish)) {
1815                                 RETERR(publish_key(diff, key1, origin, ttl,
1816                                                    mctx, allzsk, report));
1817                                 if (key1->hint_sign || key1->force_sign)
1818                                         key1->first_sign = ISC_TRUE;
1819                         }
1820
1821                         continue;
1822                 }
1823
1824                 /* Match found: remove or update it as needed */
1825                 if (key1->hint_remove) {
1826                         RETERR(remove_key(diff, key2, origin, ttl, mctx,
1827                                           "expired", report));
1828                         ISC_LIST_UNLINK(*keys, key2, link);
1829                         if (removed != NULL)
1830                                 ISC_LIST_APPEND(*removed, key2, link);
1831                         else
1832                                 dns_dnsseckey_destroy(mctx, &key2);
1833                 } else if (key_revoked &&
1834                          (dst_key_flags(key1->key) & DNS_KEYFLAG_REVOKE) != 0) {
1835
1836                         /*
1837                          * A previously valid key has been revoked.
1838                          * We need to remove the old version and pull
1839                          * in the new one.
1840                          */
1841                         RETERR(remove_key(diff, key2, origin, ttl, mctx,
1842                                           "revoked", report));
1843                         ISC_LIST_UNLINK(*keys, key2, link);
1844                         if (removed != NULL)
1845                                 ISC_LIST_APPEND(*removed, key2, link);
1846                         else
1847                                 dns_dnsseckey_destroy(mctx, &key2);
1848
1849                         RETERR(publish_key(diff, key1, origin, ttl,
1850                                            mctx, allzsk, report));
1851                         ISC_LIST_UNLINK(*newkeys, key1, link);
1852                         ISC_LIST_APPEND(*keys, key1, link);
1853
1854                         /*
1855                          * XXX: The revoke flag is only defined for trust
1856                          * anchors.  Setting the flag on a non-KSK is legal,
1857                          * but not defined in any RFC.  It seems reasonable
1858                          * to treat it the same as a KSK: keep it in the
1859                          * zone, sign the DNSKEY set with it, but not
1860                          * sign other records with it.
1861                          */
1862                         key1->ksk = ISC_TRUE;
1863                         continue;
1864                 } else {
1865                         if (!key2->is_active &&
1866                             (key1->hint_sign || key1->force_sign))
1867                                 key2->first_sign = ISC_TRUE;
1868                         key2->hint_sign = key1->hint_sign;
1869                         key2->hint_publish = key1->hint_publish;
1870                 }
1871         }
1872
1873         /* Free any leftover keys in newkeys */
1874         while (!ISC_LIST_EMPTY(*newkeys)) {
1875                 key1 = ISC_LIST_HEAD(*newkeys);
1876                 ISC_LIST_UNLINK(*newkeys, key1, link);
1877                 dns_dnsseckey_destroy(mctx, &key1);
1878         }
1879
1880         result = ISC_R_SUCCESS;
1881
1882  failure:
1883         return (result);
1884 }