]> CyberLeo.Net >> Repos - FreeBSD/releng/9.2.git/blob - contrib/bind9/lib/dns/dnssec.c
- Copy stable/9 to releng/9.2 as part of the 9.2-RELEASE cycle.
[FreeBSD/releng/9.2.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_create(key, mctx, &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         memcpy(sig.signature, r.base, sig.siglen);
356
357         ret = dns_rdata_fromstruct(sigrdata, sig.common.rdclass,
358                                    sig.common.rdtype, &sig, buffer);
359
360 cleanup_array:
361         isc_mem_put(mctx, rdatas, nrdatas * sizeof(dns_rdata_t));
362 cleanup_context:
363         dst_context_destroy(&ctx);
364 cleanup_databuf:
365         isc_buffer_free(&databuf);
366 cleanup_signature:
367         isc_mem_put(mctx, sig.signature, sig.siglen);
368
369         return (ret);
370 }
371
372 isc_result_t
373 dns_dnssec_verify2(dns_name_t *name, dns_rdataset_t *set, dst_key_t *key,
374                    isc_boolean_t ignoretime, isc_mem_t *mctx,
375                    dns_rdata_t *sigrdata, dns_name_t *wild)
376 {
377         dns_rdata_rrsig_t sig;
378         dns_fixedname_t fnewname;
379         isc_region_t r;
380         isc_buffer_t envbuf;
381         dns_rdata_t *rdatas;
382         int nrdatas, i;
383         isc_stdtime_t now;
384         isc_result_t ret;
385         unsigned char data[300];
386         dst_context_t *ctx = NULL;
387         int labels = 0;
388         isc_uint32_t flags;
389         isc_boolean_t downcase = ISC_FALSE;
390
391         REQUIRE(name != NULL);
392         REQUIRE(set != NULL);
393         REQUIRE(key != NULL);
394         REQUIRE(mctx != NULL);
395         REQUIRE(sigrdata != NULL && sigrdata->type == dns_rdatatype_rrsig);
396
397         ret = dns_rdata_tostruct(sigrdata, &sig, NULL);
398         if (ret != ISC_R_SUCCESS)
399                 return (ret);
400
401         if (set->type != sig.covered)
402                 return (DNS_R_SIGINVALID);
403
404         if (isc_serial_lt(sig.timeexpire, sig.timesigned)) {
405                 inc_stat(dns_dnssecstats_fail);
406                 return (DNS_R_SIGINVALID);
407         }
408
409         if (!ignoretime) {
410                 isc_stdtime_get(&now);
411
412                 /*
413                  * Is SIG temporally valid?
414                  */
415                 if (isc_serial_lt((isc_uint32_t)now, sig.timesigned)) {
416                         inc_stat(dns_dnssecstats_fail);
417                         return (DNS_R_SIGFUTURE);
418                 } else if (isc_serial_lt(sig.timeexpire, (isc_uint32_t)now)) {
419                         inc_stat(dns_dnssecstats_fail);
420                         return (DNS_R_SIGEXPIRED);
421                 }
422         }
423
424         /*
425          * NS, SOA and DNSSKEY records are signed by their owner.
426          * DS records are signed by the parent.
427          */
428         switch (set->type) {
429         case dns_rdatatype_ns:
430         case dns_rdatatype_soa:
431         case dns_rdatatype_dnskey:
432                 if (!dns_name_equal(name, &sig.signer)) {
433                         inc_stat(dns_dnssecstats_fail);
434                         return (DNS_R_SIGINVALID);
435                 }
436                 break;
437         case dns_rdatatype_ds:
438                 if (dns_name_equal(name, &sig.signer)) {
439                         inc_stat(dns_dnssecstats_fail);
440                         return (DNS_R_SIGINVALID);
441                 }
442                 /* FALLTHROUGH */
443         default:
444                 if (!dns_name_issubdomain(name, &sig.signer)) {
445                         inc_stat(dns_dnssecstats_fail);
446                         return (DNS_R_SIGINVALID);
447                 }
448                 break;
449         }
450
451         /*
452          * Is the key allowed to sign data?
453          */
454         flags = dst_key_flags(key);
455         if (flags & DNS_KEYTYPE_NOAUTH) {
456                 inc_stat(dns_dnssecstats_fail);
457                 return (DNS_R_KEYUNAUTHORIZED);
458         }
459         if ((flags & DNS_KEYFLAG_OWNERMASK) != DNS_KEYOWNER_ZONE) {
460                 inc_stat(dns_dnssecstats_fail);
461                 return (DNS_R_KEYUNAUTHORIZED);
462         }
463
464  again:
465         ret = dst_context_create(key, mctx, &ctx);
466         if (ret != ISC_R_SUCCESS)
467                 goto cleanup_struct;
468
469         /*
470          * Digest the SIG rdata (not including the signature).
471          */
472         ret = digest_sig(ctx, downcase, sigrdata, &sig);
473         if (ret != ISC_R_SUCCESS)
474                 goto cleanup_context;
475
476         /*
477          * If the name is an expanded wildcard, use the wildcard name.
478          */
479         dns_fixedname_init(&fnewname);
480         labels = dns_name_countlabels(name) - 1;
481         RUNTIME_CHECK(dns_name_downcase(name, dns_fixedname_name(&fnewname),
482                                         NULL) == ISC_R_SUCCESS);
483         if (labels - sig.labels > 0)
484                 dns_name_split(dns_fixedname_name(&fnewname), sig.labels + 1,
485                                NULL, dns_fixedname_name(&fnewname));
486
487         dns_name_toregion(dns_fixedname_name(&fnewname), &r);
488
489         /*
490          * Create an envelope for each rdata: <name|type|class|ttl>.
491          */
492         isc_buffer_init(&envbuf, data, sizeof(data));
493         if (labels - sig.labels > 0) {
494                 isc_buffer_putuint8(&envbuf, 1);
495                 isc_buffer_putuint8(&envbuf, '*');
496                 memcpy(data + 2, r.base, r.length);
497         }
498         else
499                 memcpy(data, r.base, r.length);
500         isc_buffer_add(&envbuf, r.length);
501         isc_buffer_putuint16(&envbuf, set->type);
502         isc_buffer_putuint16(&envbuf, set->rdclass);
503         isc_buffer_putuint32(&envbuf, sig.originalttl);
504
505         ret = rdataset_to_sortedarray(set, mctx, &rdatas, &nrdatas);
506         if (ret != ISC_R_SUCCESS)
507                 goto cleanup_context;
508
509         isc_buffer_usedregion(&envbuf, &r);
510
511         for (i = 0; i < nrdatas; i++) {
512                 isc_uint16_t len;
513                 isc_buffer_t lenbuf;
514                 isc_region_t lenr;
515
516                 /*
517                  * Skip duplicates.
518                  */
519                 if (i > 0 && dns_rdata_compare(&rdatas[i], &rdatas[i-1]) == 0)
520                     continue;
521
522                 /*
523                  * Digest the envelope.
524                  */
525                 ret = dst_context_adddata(ctx, &r);
526                 if (ret != ISC_R_SUCCESS)
527                         goto cleanup_array;
528
529                 /*
530                  * Digest the rdata length.
531                  */
532                 isc_buffer_init(&lenbuf, &len, sizeof(len));
533                 INSIST(rdatas[i].length < 65536);
534                 isc_buffer_putuint16(&lenbuf, (isc_uint16_t)rdatas[i].length);
535                 isc_buffer_usedregion(&lenbuf, &lenr);
536
537                 /*
538                  * Digest the rdata.
539                  */
540                 ret = dst_context_adddata(ctx, &lenr);
541                 if (ret != ISC_R_SUCCESS)
542                         goto cleanup_array;
543                 ret = dns_rdata_digest(&rdatas[i], digest_callback, ctx);
544                 if (ret != ISC_R_SUCCESS)
545                         goto cleanup_array;
546         }
547
548         r.base = sig.signature;
549         r.length = sig.siglen;
550         ret = dst_context_verify(ctx, &r);
551         if (ret == ISC_R_SUCCESS && downcase) {
552                 char namebuf[DNS_NAME_FORMATSIZE];
553                 dns_name_format(&sig.signer, namebuf, sizeof(namebuf));
554                 isc_log_write(dns_lctx, DNS_LOGCATEGORY_GENERAL,
555                               DNS_LOGMODULE_DNSSEC, ISC_LOG_INFO,
556                               "sucessfully validated after lower casing "
557                               "signer '%s'", namebuf);
558                 inc_stat(dns_dnssecstats_downcase);
559         } else if (ret == ISC_R_SUCCESS)
560                 inc_stat(dns_dnssecstats_asis);
561
562 cleanup_array:
563         isc_mem_put(mctx, rdatas, nrdatas * sizeof(dns_rdata_t));
564 cleanup_context:
565         dst_context_destroy(&ctx);
566         if (ret == DST_R_VERIFYFAILURE && !downcase) {
567                 downcase = ISC_TRUE;
568                 goto again;
569         }
570 cleanup_struct:
571         dns_rdata_freestruct(&sig);
572
573         if (ret == DST_R_VERIFYFAILURE)
574                 ret = DNS_R_SIGINVALID;
575
576         if (ret != ISC_R_SUCCESS)
577                 inc_stat(dns_dnssecstats_fail);
578
579         if (ret == ISC_R_SUCCESS && labels - sig.labels > 0) {
580                 if (wild != NULL)
581                         RUNTIME_CHECK(dns_name_concatenate(dns_wildcardname,
582                                                  dns_fixedname_name(&fnewname),
583                                                  wild, NULL) == ISC_R_SUCCESS);
584                 inc_stat(dns_dnssecstats_wildcard);
585                 ret = DNS_R_FROMWILDCARD;
586         }
587         return (ret);
588 }
589
590 isc_result_t
591 dns_dnssec_verify(dns_name_t *name, dns_rdataset_t *set, dst_key_t *key,
592                   isc_boolean_t ignoretime, isc_mem_t *mctx,
593                   dns_rdata_t *sigrdata)
594 {
595         isc_result_t result;
596
597         result = dns_dnssec_verify2(name, set, key, ignoretime, mctx,
598                                     sigrdata, NULL);
599         if (result == DNS_R_FROMWILDCARD)
600                 result = ISC_R_SUCCESS;
601         return (result);
602 }
603
604 static isc_boolean_t
605 key_active(dst_key_t *key, isc_stdtime_t now) {
606         isc_result_t result;
607         isc_stdtime_t publish, active, revoke, inactive, delete;
608         isc_boolean_t pubset = ISC_FALSE, actset = ISC_FALSE;
609         isc_boolean_t revset = ISC_FALSE, inactset = ISC_FALSE;
610         isc_boolean_t delset = ISC_FALSE;
611         int major, minor;
612
613         /* Is this an old-style key? */
614         result = dst_key_getprivateformat(key, &major, &minor);
615         RUNTIME_CHECK(result == ISC_R_SUCCESS);
616
617         /*
618          * Smart signing started with key format 1.3; prior to that, all
619          * keys are assumed active
620          */
621         if (major == 1 && minor <= 2)
622                 return (ISC_TRUE);
623
624         result = dst_key_gettime(key, DST_TIME_PUBLISH, &publish);
625         if (result == ISC_R_SUCCESS)
626                 pubset = ISC_TRUE;
627
628         result = dst_key_gettime(key, DST_TIME_ACTIVATE, &active);
629         if (result == ISC_R_SUCCESS)
630                 actset = ISC_TRUE;
631
632         result = dst_key_gettime(key, DST_TIME_REVOKE, &revoke);
633         if (result == ISC_R_SUCCESS)
634                 revset = ISC_TRUE;
635
636         result = dst_key_gettime(key, DST_TIME_INACTIVE, &inactive);
637         if (result == ISC_R_SUCCESS)
638                 inactset = ISC_TRUE;
639
640         result = dst_key_gettime(key, DST_TIME_DELETE, &delete);
641         if (result == ISC_R_SUCCESS)
642                 delset = ISC_TRUE;
643
644         if ((inactset && inactive <= now) || (delset && delete <= now))
645                 return (ISC_FALSE);
646
647         if (revset && revoke <= now && pubset && publish <= now)
648                 return (ISC_TRUE);
649
650         if (actset && active <= now)
651                 return (ISC_TRUE);
652
653         return (ISC_FALSE);
654 }
655
656 #define is_zone_key(key) ((dst_key_flags(key) & DNS_KEYFLAG_OWNERMASK) \
657                           == DNS_KEYOWNER_ZONE)
658
659 isc_result_t
660 dns_dnssec_findzonekeys2(dns_db_t *db, dns_dbversion_t *ver,
661                          dns_dbnode_t *node, dns_name_t *name,
662                          const char *directory, isc_mem_t *mctx,
663                          unsigned int maxkeys, dst_key_t **keys,
664                          unsigned int *nkeys)
665 {
666         dns_rdataset_t rdataset;
667         dns_rdata_t rdata = DNS_RDATA_INIT;
668         isc_result_t result;
669         dst_key_t *pubkey = NULL;
670         unsigned int count = 0;
671         isc_stdtime_t now;
672
673         REQUIRE(nkeys != NULL);
674         REQUIRE(keys != NULL);
675
676         isc_stdtime_get(&now);
677
678         *nkeys = 0;
679         dns_rdataset_init(&rdataset);
680         RETERR(dns_db_findrdataset(db, node, ver, dns_rdatatype_dnskey, 0, 0,
681                                    &rdataset, NULL));
682         RETERR(dns_rdataset_first(&rdataset));
683         while (result == ISC_R_SUCCESS && count < maxkeys) {
684                 pubkey = NULL;
685                 dns_rdataset_current(&rdataset, &rdata);
686                 RETERR(dns_dnssec_keyfromrdata(name, &rdata, mctx, &pubkey));
687                 if (!is_zone_key(pubkey) ||
688                     (dst_key_flags(pubkey) & DNS_KEYTYPE_NOAUTH) != 0)
689                         goto next;
690                 /* Corrupted .key file? */
691                 if (!dns_name_equal(name, dst_key_name(pubkey)))
692                         goto next;
693                 keys[count] = NULL;
694                 result = dst_key_fromfile(dst_key_name(pubkey),
695                                           dst_key_id(pubkey),
696                                           dst_key_alg(pubkey),
697                                           DST_TYPE_PUBLIC|DST_TYPE_PRIVATE,
698                                           directory,
699                                           mctx, &keys[count]);
700
701                 /*
702                  * If the key was revoked and the private file
703                  * doesn't exist, maybe it was revoked internally
704                  * by named.  Try loading the unrevoked version.
705                  */
706                 if (result == ISC_R_FILENOTFOUND) {
707                         isc_uint32_t flags;
708                         flags = dst_key_flags(pubkey);
709                         if ((flags & DNS_KEYFLAG_REVOKE) != 0) {
710                                 dst_key_setflags(pubkey,
711                                                  flags & ~DNS_KEYFLAG_REVOKE);
712                                 result = dst_key_fromfile(dst_key_name(pubkey),
713                                                           dst_key_id(pubkey),
714                                                           dst_key_alg(pubkey),
715                                                           DST_TYPE_PUBLIC|
716                                                           DST_TYPE_PRIVATE,
717                                                           directory,
718                                                           mctx, &keys[count]);
719                                 if (result == ISC_R_SUCCESS &&
720                                     dst_key_pubcompare(pubkey, keys[count],
721                                                        ISC_FALSE)) {
722                                         dst_key_setflags(keys[count], flags);
723                                 }
724                                 dst_key_setflags(pubkey, flags);
725                         }
726                 }
727
728                 if (result != ISC_R_SUCCESS) {
729                         char keybuf[DNS_NAME_FORMATSIZE];
730                         char algbuf[DNS_SECALG_FORMATSIZE];
731                         dns_name_format(dst_key_name(pubkey), keybuf,
732                                         sizeof(keybuf));
733                         dns_secalg_format(dst_key_alg(pubkey), algbuf,
734                                           sizeof(algbuf));
735                         isc_log_write(dns_lctx, DNS_LOGCATEGORY_GENERAL,
736                                       DNS_LOGMODULE_DNSSEC, ISC_LOG_WARNING,
737                                       "dns_dnssec_findzonekeys2: error "
738                                       "reading private key file %s/%s/%d: %s",
739                                       keybuf, algbuf, dst_key_id(pubkey),
740                                       isc_result_totext(result));
741                 }
742
743                 if (result == ISC_R_FILENOTFOUND || result == ISC_R_NOPERM) {
744                         keys[count] = pubkey;
745                         pubkey = NULL;
746                         count++;
747                         goto next;
748                 }
749
750                 if (result != ISC_R_SUCCESS)
751                         goto failure;
752
753                 /*
754                  * If a key is marked inactive, skip it
755                  */
756                 if (!key_active(keys[count], now)) {
757                         dst_key_free(&keys[count]);
758                         keys[count] = pubkey;
759                         pubkey = NULL;
760                         count++;
761                         goto next;
762                 }
763
764                 if ((dst_key_flags(keys[count]) & DNS_KEYTYPE_NOAUTH) != 0) {
765                         /* We should never get here. */
766                         dst_key_free(&keys[count]);
767                         goto next;
768                 }
769                 count++;
770  next:
771                 if (pubkey != NULL)
772                         dst_key_free(&pubkey);
773                 dns_rdata_reset(&rdata);
774                 result = dns_rdataset_next(&rdataset);
775         }
776         if (result != ISC_R_NOMORE)
777                 goto failure;
778         if (count == 0)
779                 result = ISC_R_NOTFOUND;
780         else
781                 result = ISC_R_SUCCESS;
782
783  failure:
784         if (dns_rdataset_isassociated(&rdataset))
785                 dns_rdataset_disassociate(&rdataset);
786         if (pubkey != NULL)
787                 dst_key_free(&pubkey);
788         if (result != ISC_R_SUCCESS)
789                 while (count > 0)
790                         dst_key_free(&keys[--count]);
791         *nkeys = count;
792         return (result);
793 }
794
795 isc_result_t
796 dns_dnssec_findzonekeys(dns_db_t *db, dns_dbversion_t *ver,
797                         dns_dbnode_t *node, dns_name_t *name, isc_mem_t *mctx,
798                         unsigned int maxkeys, dst_key_t **keys,
799                         unsigned int *nkeys)
800 {
801         return (dns_dnssec_findzonekeys2(db, ver, node, name, NULL, mctx,
802                                          maxkeys, keys, nkeys));
803 }
804
805 isc_result_t
806 dns_dnssec_signmessage(dns_message_t *msg, dst_key_t *key) {
807         dns_rdata_sig_t sig;    /* SIG(0) */
808         unsigned char data[512];
809         unsigned char header[DNS_MESSAGE_HEADERLEN];
810         isc_buffer_t headerbuf, databuf, sigbuf;
811         unsigned int sigsize;
812         isc_buffer_t *dynbuf = NULL;
813         dns_rdata_t *rdata;
814         dns_rdatalist_t *datalist;
815         dns_rdataset_t *dataset;
816         isc_region_t r;
817         isc_stdtime_t now;
818         dst_context_t *ctx = NULL;
819         isc_mem_t *mctx;
820         isc_result_t result;
821         isc_boolean_t signeedsfree = ISC_TRUE;
822
823         REQUIRE(msg != NULL);
824         REQUIRE(key != NULL);
825
826         if (is_response(msg))
827                 REQUIRE(msg->query.base != NULL);
828
829         mctx = msg->mctx;
830
831         memset(&sig, 0, sizeof(sig));
832
833         sig.mctx = mctx;
834         sig.common.rdclass = dns_rdataclass_any;
835         sig.common.rdtype = dns_rdatatype_sig;  /* SIG(0) */
836         ISC_LINK_INIT(&sig.common, link);
837
838         sig.covered = 0;
839         sig.algorithm = dst_key_alg(key);
840         sig.labels = 0; /* the root name */
841         sig.originalttl = 0;
842
843         isc_stdtime_get(&now);
844         sig.timesigned = now - DNS_TSIG_FUDGE;
845         sig.timeexpire = now + DNS_TSIG_FUDGE;
846
847         sig.keyid = dst_key_id(key);
848
849         dns_name_init(&sig.signer, NULL);
850         dns_name_clone(dst_key_name(key), &sig.signer);
851
852         sig.siglen = 0;
853         sig.signature = NULL;
854
855         isc_buffer_init(&databuf, data, sizeof(data));
856
857         RETERR(dst_context_create(key, mctx, &ctx));
858
859         /*
860          * Digest the fields of the SIG - we can cheat and use
861          * dns_rdata_fromstruct.  Since siglen is 0, the digested data
862          * is identical to dns format.
863          */
864         RETERR(dns_rdata_fromstruct(NULL, dns_rdataclass_any,
865                                     dns_rdatatype_sig /* SIG(0) */,
866                                     &sig, &databuf));
867         isc_buffer_usedregion(&databuf, &r);
868         RETERR(dst_context_adddata(ctx, &r));
869
870         /*
871          * If this is a response, digest the query.
872          */
873         if (is_response(msg))
874                 RETERR(dst_context_adddata(ctx, &msg->query));
875
876         /*
877          * Digest the header.
878          */
879         isc_buffer_init(&headerbuf, header, sizeof(header));
880         dns_message_renderheader(msg, &headerbuf);
881         isc_buffer_usedregion(&headerbuf, &r);
882         RETERR(dst_context_adddata(ctx, &r));
883
884         /*
885          * Digest the remainder of the message.
886          */
887         isc_buffer_usedregion(msg->buffer, &r);
888         isc_region_consume(&r, DNS_MESSAGE_HEADERLEN);
889         RETERR(dst_context_adddata(ctx, &r));
890
891         RETERR(dst_key_sigsize(key, &sigsize));
892         sig.siglen = sigsize;
893         sig.signature = (unsigned char *) isc_mem_get(mctx, sig.siglen);
894         if (sig.signature == NULL) {
895                 result = ISC_R_NOMEMORY;
896                 goto failure;
897         }
898
899         isc_buffer_init(&sigbuf, sig.signature, sig.siglen);
900         RETERR(dst_context_sign(ctx, &sigbuf));
901         dst_context_destroy(&ctx);
902
903         rdata = NULL;
904         RETERR(dns_message_gettemprdata(msg, &rdata));
905         RETERR(isc_buffer_allocate(msg->mctx, &dynbuf, 1024));
906         RETERR(dns_rdata_fromstruct(rdata, dns_rdataclass_any,
907                                     dns_rdatatype_sig /* SIG(0) */,
908                                     &sig, dynbuf));
909
910         isc_mem_put(mctx, sig.signature, sig.siglen);
911         signeedsfree = ISC_FALSE;
912
913         dns_message_takebuffer(msg, &dynbuf);
914
915         datalist = NULL;
916         RETERR(dns_message_gettemprdatalist(msg, &datalist));
917         datalist->rdclass = dns_rdataclass_any;
918         datalist->type = dns_rdatatype_sig;     /* SIG(0) */
919         datalist->covers = 0;
920         datalist->ttl = 0;
921         ISC_LIST_INIT(datalist->rdata);
922         ISC_LIST_APPEND(datalist->rdata, rdata, link);
923         dataset = NULL;
924         RETERR(dns_message_gettemprdataset(msg, &dataset));
925         dns_rdataset_init(dataset);
926         RUNTIME_CHECK(dns_rdatalist_tordataset(datalist, dataset) == ISC_R_SUCCESS);
927         msg->sig0 = dataset;
928
929         return (ISC_R_SUCCESS);
930
931 failure:
932         if (dynbuf != NULL)
933                 isc_buffer_free(&dynbuf);
934         if (signeedsfree)
935                 isc_mem_put(mctx, sig.signature, sig.siglen);
936         if (ctx != NULL)
937                 dst_context_destroy(&ctx);
938
939         return (result);
940 }
941
942 isc_result_t
943 dns_dnssec_verifymessage(isc_buffer_t *source, dns_message_t *msg,
944                          dst_key_t *key)
945 {
946         dns_rdata_sig_t sig;    /* SIG(0) */
947         unsigned char header[DNS_MESSAGE_HEADERLEN];
948         dns_rdata_t rdata = DNS_RDATA_INIT;
949         isc_region_t r, source_r, sig_r, header_r;
950         isc_stdtime_t now;
951         dst_context_t *ctx = NULL;
952         isc_mem_t *mctx;
953         isc_result_t result;
954         isc_uint16_t addcount;
955         isc_boolean_t signeedsfree = ISC_FALSE;
956
957         REQUIRE(source != NULL);
958         REQUIRE(msg != NULL);
959         REQUIRE(key != NULL);
960
961         mctx = msg->mctx;
962
963         msg->verify_attempted = 1;
964
965         if (is_response(msg)) {
966                 if (msg->query.base == NULL)
967                         return (DNS_R_UNEXPECTEDTSIG);
968         }
969
970         isc_buffer_usedregion(source, &source_r);
971
972         RETERR(dns_rdataset_first(msg->sig0));
973         dns_rdataset_current(msg->sig0, &rdata);
974
975         RETERR(dns_rdata_tostruct(&rdata, &sig, NULL));
976         signeedsfree = ISC_TRUE;
977
978         if (sig.labels != 0) {
979                 result = DNS_R_SIGINVALID;
980                 goto failure;
981         }
982
983         if (isc_serial_lt(sig.timeexpire, sig.timesigned)) {
984                 result = DNS_R_SIGINVALID;
985                 msg->sig0status = dns_tsigerror_badtime;
986                 goto failure;
987         }
988
989         isc_stdtime_get(&now);
990         if (isc_serial_lt((isc_uint32_t)now, sig.timesigned)) {
991                 result = DNS_R_SIGFUTURE;
992                 msg->sig0status = dns_tsigerror_badtime;
993                 goto failure;
994         }
995         else if (isc_serial_lt(sig.timeexpire, (isc_uint32_t)now)) {
996                 result = DNS_R_SIGEXPIRED;
997                 msg->sig0status = dns_tsigerror_badtime;
998                 goto failure;
999         }
1000
1001         if (!dns_name_equal(dst_key_name(key), &sig.signer)) {
1002                 result = DNS_R_SIGINVALID;
1003                 msg->sig0status = dns_tsigerror_badkey;
1004                 goto failure;
1005         }
1006
1007         RETERR(dst_context_create(key, mctx, &ctx));
1008
1009         /*
1010          * Digest the SIG(0) record, except for the signature.
1011          */
1012         dns_rdata_toregion(&rdata, &r);
1013         r.length -= sig.siglen;
1014         RETERR(dst_context_adddata(ctx, &r));
1015
1016         /*
1017          * If this is a response, digest the query.
1018          */
1019         if (is_response(msg))
1020                 RETERR(dst_context_adddata(ctx, &msg->query));
1021
1022         /*
1023          * Extract the header.
1024          */
1025         memcpy(header, source_r.base, DNS_MESSAGE_HEADERLEN);
1026
1027         /*
1028          * Decrement the additional field counter.
1029          */
1030         memcpy(&addcount, &header[DNS_MESSAGE_HEADERLEN - 2], 2);
1031         addcount = htons((isc_uint16_t)(ntohs(addcount) - 1));
1032         memcpy(&header[DNS_MESSAGE_HEADERLEN - 2], &addcount, 2);
1033
1034         /*
1035          * Digest the modified header.
1036          */
1037         header_r.base = (unsigned char *) header;
1038         header_r.length = DNS_MESSAGE_HEADERLEN;
1039         RETERR(dst_context_adddata(ctx, &header_r));
1040
1041         /*
1042          * Digest all non-SIG(0) records.
1043          */
1044         r.base = source_r.base + DNS_MESSAGE_HEADERLEN;
1045         r.length = msg->sigstart - DNS_MESSAGE_HEADERLEN;
1046         RETERR(dst_context_adddata(ctx, &r));
1047
1048         sig_r.base = sig.signature;
1049         sig_r.length = sig.siglen;
1050         result = dst_context_verify(ctx, &sig_r);
1051         if (result != ISC_R_SUCCESS) {
1052                 msg->sig0status = dns_tsigerror_badsig;
1053                 goto failure;
1054         }
1055
1056         msg->verified_sig = 1;
1057
1058         dst_context_destroy(&ctx);
1059         dns_rdata_freestruct(&sig);
1060
1061         return (ISC_R_SUCCESS);
1062
1063 failure:
1064         if (signeedsfree)
1065                 dns_rdata_freestruct(&sig);
1066         if (ctx != NULL)
1067                 dst_context_destroy(&ctx);
1068
1069         return (result);
1070 }
1071
1072 /*%
1073  * Does this key ('rdata') self sign the rrset ('rdataset')?
1074  */
1075 isc_boolean_t
1076 dns_dnssec_selfsigns(dns_rdata_t *rdata, dns_name_t *name,
1077                      dns_rdataset_t *rdataset, dns_rdataset_t *sigrdataset,
1078                      isc_boolean_t ignoretime, isc_mem_t *mctx)
1079 {
1080         INSIST(rdataset->type == dns_rdatatype_key ||
1081                rdataset->type == dns_rdatatype_dnskey);
1082         if (rdataset->type == dns_rdatatype_key) {
1083                 INSIST(sigrdataset->type == dns_rdatatype_sig);
1084                 INSIST(sigrdataset->covers == dns_rdatatype_key);
1085         } else {
1086                 INSIST(sigrdataset->type == dns_rdatatype_rrsig);
1087                 INSIST(sigrdataset->covers == dns_rdatatype_dnskey);
1088         }
1089
1090         return (dns_dnssec_signs(rdata, name, rdataset, sigrdataset,
1091                                  ignoretime, mctx));
1092
1093 }
1094
1095 isc_boolean_t
1096 dns_dnssec_signs(dns_rdata_t *rdata, dns_name_t *name,
1097                      dns_rdataset_t *rdataset, dns_rdataset_t *sigrdataset,
1098                      isc_boolean_t ignoretime, isc_mem_t *mctx)
1099 {
1100         dst_key_t *dstkey = NULL;
1101         dns_keytag_t keytag;
1102         dns_rdata_dnskey_t key;
1103         dns_rdata_rrsig_t sig;
1104         dns_rdata_t sigrdata = DNS_RDATA_INIT;
1105         isc_result_t result;
1106
1107         INSIST(sigrdataset->type == dns_rdatatype_rrsig);
1108         if (sigrdataset->covers != rdataset->type)
1109                 return (ISC_FALSE);
1110
1111         result = dns_dnssec_keyfromrdata(name, rdata, mctx, &dstkey);
1112         if (result != ISC_R_SUCCESS)
1113                 return (ISC_FALSE);
1114         result = dns_rdata_tostruct(rdata, &key, NULL);
1115         RUNTIME_CHECK(result == ISC_R_SUCCESS);
1116
1117         keytag = dst_key_id(dstkey);
1118         for (result = dns_rdataset_first(sigrdataset);
1119              result == ISC_R_SUCCESS;
1120              result = dns_rdataset_next(sigrdataset))
1121         {
1122                 dns_rdata_reset(&sigrdata);
1123                 dns_rdataset_current(sigrdataset, &sigrdata);
1124                 result = dns_rdata_tostruct(&sigrdata, &sig, NULL);
1125                 RUNTIME_CHECK(result == ISC_R_SUCCESS);
1126
1127                 if (sig.algorithm == key.algorithm &&
1128                     sig.keyid == keytag) {
1129                         result = dns_dnssec_verify2(name, rdataset, dstkey,
1130                                                     ignoretime, mctx,
1131                                                     &sigrdata, NULL);
1132                         if (result == ISC_R_SUCCESS) {
1133                                 dst_key_free(&dstkey);
1134                                 return (ISC_TRUE);
1135                         }
1136                 }
1137         }
1138         dst_key_free(&dstkey);
1139         return (ISC_FALSE);
1140 }
1141
1142 isc_result_t
1143 dns_dnsseckey_create(isc_mem_t *mctx, dst_key_t **dstkey,
1144                      dns_dnsseckey_t **dkp)
1145 {
1146         isc_result_t result;
1147         dns_dnsseckey_t *dk;
1148         int major, minor;
1149
1150         REQUIRE(dkp != NULL && *dkp == NULL);
1151         dk = isc_mem_get(mctx, sizeof(dns_dnsseckey_t));
1152         if (dk == NULL)
1153                 return (ISC_R_NOMEMORY);
1154
1155         dk->key = *dstkey;
1156         *dstkey = NULL;
1157         dk->force_publish = ISC_FALSE;
1158         dk->force_sign = ISC_FALSE;
1159         dk->hint_publish = ISC_FALSE;
1160         dk->hint_sign = ISC_FALSE;
1161         dk->hint_remove = ISC_FALSE;
1162         dk->first_sign = ISC_FALSE;
1163         dk->is_active = ISC_FALSE;
1164         dk->prepublish = 0;
1165         dk->source = dns_keysource_unknown;
1166         dk->index = 0;
1167
1168         /* KSK or ZSK? */
1169         dk->ksk = ISC_TF((dst_key_flags(dk->key) & DNS_KEYFLAG_KSK) != 0);
1170
1171         /* Is this an old-style key? */
1172         result = dst_key_getprivateformat(dk->key, &major, &minor);
1173         INSIST(result == ISC_R_SUCCESS);
1174
1175         /* Smart signing started with key format 1.3 */
1176         dk->legacy = ISC_TF(major == 1 && minor <= 2);
1177
1178         ISC_LINK_INIT(dk, link);
1179         *dkp = dk;
1180         return (ISC_R_SUCCESS);
1181 }
1182
1183 void
1184 dns_dnsseckey_destroy(isc_mem_t *mctx, dns_dnsseckey_t **dkp) {
1185         dns_dnsseckey_t *dk;
1186
1187         REQUIRE(dkp != NULL && *dkp != NULL);
1188         dk = *dkp;
1189         if (dk->key != NULL)
1190                 dst_key_free(&dk->key);
1191         isc_mem_put(mctx, dk, sizeof(dns_dnsseckey_t));
1192         *dkp = NULL;
1193 }
1194
1195 static void
1196 get_hints(dns_dnsseckey_t *key, isc_stdtime_t now) {
1197         isc_result_t result;
1198         isc_stdtime_t publish, active, revoke, inactive, delete;
1199         isc_boolean_t pubset = ISC_FALSE, actset = ISC_FALSE;
1200         isc_boolean_t revset = ISC_FALSE, inactset = ISC_FALSE;
1201         isc_boolean_t delset = ISC_FALSE;
1202
1203         REQUIRE(key != NULL && key->key != NULL);
1204
1205         result = dst_key_gettime(key->key, DST_TIME_PUBLISH, &publish);
1206         if (result == ISC_R_SUCCESS)
1207                 pubset = ISC_TRUE;
1208
1209         result = dst_key_gettime(key->key, DST_TIME_ACTIVATE, &active);
1210         if (result == ISC_R_SUCCESS)
1211                 actset = ISC_TRUE;
1212
1213         result = dst_key_gettime(key->key, DST_TIME_REVOKE, &revoke);
1214         if (result == ISC_R_SUCCESS)
1215                 revset = ISC_TRUE;
1216
1217         result = dst_key_gettime(key->key, DST_TIME_INACTIVE, &inactive);
1218         if (result == ISC_R_SUCCESS)
1219                 inactset = ISC_TRUE;
1220
1221         result = dst_key_gettime(key->key, DST_TIME_DELETE, &delete);
1222         if (result == ISC_R_SUCCESS)
1223                 delset = ISC_TRUE;
1224
1225         /* Metadata says publish (but possibly not activate) */
1226         if (pubset && publish <= now)
1227                 key->hint_publish = ISC_TRUE;
1228
1229         /* Metadata says activate (so we must also publish) */
1230         if (actset && active <= now) {
1231                 key->hint_sign = ISC_TRUE;
1232                 key->hint_publish = ISC_TRUE;
1233         }
1234
1235         /*
1236          * Activation date is set (maybe in the future), but
1237          * publication date isn't. Most likely the user wants to
1238          * publish now and activate later.
1239          */
1240         if (actset && !pubset)
1241                 key->hint_publish = ISC_TRUE;
1242
1243         /*
1244          * If activation date is in the future, make note of how far off
1245          */
1246         if (key->hint_publish && actset && active > now) {
1247                 key->prepublish = active - now;
1248         }
1249
1250         /*
1251          * Key has been marked inactive: we can continue publishing,
1252          * but don't sign.
1253          */
1254         if (key->hint_publish && inactset && inactive <= now) {
1255                 key->hint_sign = ISC_FALSE;
1256         }
1257
1258         /*
1259          * Metadata says revoke.  If the key is published,
1260          * we *have to* sign with it per RFC5011--even if it was
1261          * not active before.
1262          *
1263          * If it hasn't already been done, we should also revoke it now.
1264          */
1265         if (key->hint_publish && (revset && revoke <= now)) {
1266                 isc_uint32_t flags;
1267                 key->hint_sign = ISC_TRUE;
1268                 flags = dst_key_flags(key->key);
1269                 if ((flags & DNS_KEYFLAG_REVOKE) == 0) {
1270                         flags |= DNS_KEYFLAG_REVOKE;
1271                         dst_key_setflags(key->key, flags);
1272                 }
1273         }
1274
1275         /*
1276          * Metadata says delete, so don't publish this key or sign with it.
1277          */
1278         if (delset && delete <= now) {
1279                 key->hint_publish = ISC_FALSE;
1280                 key->hint_sign = ISC_FALSE;
1281                 key->hint_remove = ISC_TRUE;
1282         }
1283 }
1284
1285 /*%
1286  * Get a list of DNSSEC keys from the key repository
1287  */
1288 isc_result_t
1289 dns_dnssec_findmatchingkeys(dns_name_t *origin, const char *directory,
1290                             isc_mem_t *mctx, dns_dnsseckeylist_t *keylist)
1291 {
1292         isc_result_t result = ISC_R_SUCCESS;
1293         isc_boolean_t dir_open = ISC_FALSE;
1294         dns_dnsseckeylist_t list;
1295         isc_dir_t dir;
1296         dns_dnsseckey_t *key = NULL;
1297         dst_key_t *dstkey = NULL;
1298         char namebuf[DNS_NAME_FORMATSIZE], *p;
1299         isc_buffer_t b;
1300         unsigned int len;
1301         isc_stdtime_t now;
1302
1303         REQUIRE(keylist != NULL);
1304         ISC_LIST_INIT(list);
1305         isc_dir_init(&dir);
1306
1307         isc_buffer_init(&b, namebuf, sizeof(namebuf) - 1);
1308         RETERR(dns_name_tofilenametext(origin, ISC_FALSE, &b));
1309         len = isc_buffer_usedlength(&b);
1310         namebuf[len] = '\0';
1311
1312         if (directory == NULL)
1313                 directory = ".";
1314         RETERR(isc_dir_open(&dir, directory));
1315         dir_open = ISC_TRUE;
1316
1317         isc_stdtime_get(&now);
1318
1319         while (isc_dir_read(&dir) == ISC_R_SUCCESS) {
1320                 if (dir.entry.name[0] == 'K' &&
1321                     dir.entry.length > len + 1 &&
1322                     dir.entry.name[len + 1] == '+' &&
1323                     strncasecmp(dir.entry.name + 1, namebuf, len) == 0) {
1324                         p = strrchr(dir.entry.name, '.');
1325                         if (p != NULL && strcmp(p, ".private") != 0)
1326                                 continue;
1327
1328                         dstkey = NULL;
1329                         result = dst_key_fromnamedfile(dir.entry.name,
1330                                                        directory,
1331                                                        DST_TYPE_PUBLIC |
1332                                                        DST_TYPE_PRIVATE,
1333                                                        mctx, &dstkey);
1334
1335                         if (result != ISC_R_SUCCESS) {
1336                                 isc_log_write(dns_lctx,
1337                                               DNS_LOGCATEGORY_GENERAL,
1338                                               DNS_LOGMODULE_DNSSEC,
1339                                               ISC_LOG_WARNING,
1340                                               "dns_dnssec_findmatchingkeys: "
1341                                               "error reading key file %s: %s",
1342                                               dir.entry.name,
1343                                               isc_result_totext(result));
1344                                 continue;
1345                         }
1346
1347                         RETERR(dns_dnsseckey_create(mctx, &dstkey, &key));
1348                         key->source = dns_keysource_repository;
1349                         get_hints(key, now);
1350
1351                         if (key->legacy) {
1352                                 dns_dnsseckey_destroy(mctx, &key);
1353                         } else {
1354                                 ISC_LIST_APPEND(list, key, link);
1355                                 key = NULL;
1356                         }
1357                 }
1358         }
1359
1360         if (!ISC_LIST_EMPTY(list))
1361                 ISC_LIST_APPENDLIST(*keylist, list, link);
1362         else
1363                 result = ISC_R_NOTFOUND;
1364
1365  failure:
1366         if (dir_open)
1367                 isc_dir_close(&dir);
1368         INSIST(key == NULL);
1369         while ((key = ISC_LIST_HEAD(list)) != NULL) {
1370                 ISC_LIST_UNLINK(list, key, link);
1371                 INSIST(key->key != NULL);
1372                 dst_key_free(&key->key);
1373                 dns_dnsseckey_destroy(mctx, &key);
1374         }
1375         if (dstkey != NULL)
1376                 dst_key_free(&dstkey);
1377         return (result);
1378 }
1379
1380 /*%
1381  * Add 'newkey' to 'keylist' if it's not already there.
1382  *
1383  * If 'savekeys' is ISC_TRUE, then we need to preserve all
1384  * the keys in the keyset, regardless of whether they have
1385  * metadata indicating they should be deactivated or removed.
1386  */
1387 static isc_result_t
1388 addkey(dns_dnsseckeylist_t *keylist, dst_key_t **newkey,
1389        isc_boolean_t savekeys, isc_mem_t *mctx)
1390 {
1391         dns_dnsseckey_t *key;
1392         isc_result_t result;
1393
1394         /* Skip duplicates */
1395         for (key = ISC_LIST_HEAD(*keylist);
1396              key != NULL;
1397              key = ISC_LIST_NEXT(key, link)) {
1398                 if (dst_key_id(key->key) == dst_key_id(*newkey) &&
1399                     dst_key_alg(key->key) == dst_key_alg(*newkey) &&
1400                     dns_name_equal(dst_key_name(key->key),
1401                                    dst_key_name(*newkey)))
1402                         break;
1403         }
1404
1405         if (key != NULL) {
1406                 /*
1407                  * Found a match.  If the old key was only public and the
1408                  * new key is private, replace the old one; otherwise
1409                  * leave it.  But either way, mark the key as having
1410                  * been found in the zone.
1411                  */
1412                 if (dst_key_isprivate(key->key)) {
1413                         dst_key_free(newkey);
1414                 } else if (dst_key_isprivate(*newkey)) {
1415                         dst_key_free(&key->key);
1416                         key->key = *newkey;
1417                 }
1418
1419                 key->source = dns_keysource_zoneapex;
1420                 return (ISC_R_SUCCESS);
1421         }
1422
1423         result = dns_dnsseckey_create(mctx, newkey, &key);
1424         if (result != ISC_R_SUCCESS)
1425                 return (result);
1426         if (key->legacy || savekeys) {
1427                 key->force_publish = ISC_TRUE;
1428                 key->force_sign = dst_key_isprivate(key->key);
1429         }
1430         key->source = dns_keysource_zoneapex;
1431         ISC_LIST_APPEND(*keylist, key, link);
1432         *newkey = NULL;
1433         return (ISC_R_SUCCESS);
1434 }
1435
1436
1437 /*%
1438  * Mark all keys which signed the DNSKEY/SOA RRsets as "active",
1439  * for future reference.
1440  */
1441 static isc_result_t
1442 mark_active_keys(dns_dnsseckeylist_t *keylist, dns_rdataset_t *rrsigs) {
1443         isc_result_t result = ISC_R_SUCCESS;
1444         dns_rdata_t rdata = DNS_RDATA_INIT;
1445         dns_rdataset_t sigs;
1446         dns_dnsseckey_t *key;
1447
1448         REQUIRE(rrsigs != NULL && dns_rdataset_isassociated(rrsigs));
1449
1450         dns_rdataset_init(&sigs);
1451         dns_rdataset_clone(rrsigs, &sigs);
1452         for (key = ISC_LIST_HEAD(*keylist);
1453              key != NULL;
1454              key = ISC_LIST_NEXT(key, link)) {
1455                 isc_uint16_t keyid, sigid;
1456                 dns_secalg_t keyalg, sigalg;
1457                 keyid = dst_key_id(key->key);
1458                 keyalg = dst_key_alg(key->key);
1459
1460                 for (result = dns_rdataset_first(&sigs);
1461                      result == ISC_R_SUCCESS;
1462                      result = dns_rdataset_next(&sigs)) {
1463                         dns_rdata_rrsig_t sig;
1464
1465                         dns_rdata_reset(&rdata);
1466                         dns_rdataset_current(&sigs, &rdata);
1467                         result = dns_rdata_tostruct(&rdata, &sig, NULL);
1468                         RUNTIME_CHECK(result == ISC_R_SUCCESS);
1469                         sigalg = sig.algorithm;
1470                         sigid = sig.keyid;
1471                         if (keyid == sigid && keyalg == sigalg) {
1472                                 key->is_active = ISC_TRUE;
1473                                 break;
1474                         }
1475                 }
1476         }
1477
1478         if (result == ISC_R_NOMORE)
1479                 result = ISC_R_SUCCESS;
1480
1481         if (dns_rdataset_isassociated(&sigs))
1482                 dns_rdataset_disassociate(&sigs);
1483         return (result);
1484 }
1485
1486 /*%
1487  * Add the contents of a DNSKEY rdataset 'keyset' to 'keylist'.
1488  */
1489 isc_result_t
1490 dns_dnssec_keylistfromrdataset(dns_name_t *origin,
1491                                const char *directory, isc_mem_t *mctx,
1492                                dns_rdataset_t *keyset, dns_rdataset_t *keysigs,
1493                                dns_rdataset_t *soasigs, isc_boolean_t savekeys,
1494                                isc_boolean_t public,
1495                                dns_dnsseckeylist_t *keylist)
1496 {
1497         dns_rdataset_t keys;
1498         dns_rdata_t rdata = DNS_RDATA_INIT;
1499         dst_key_t *pubkey = NULL, *privkey = NULL;
1500         isc_result_t result;
1501
1502         REQUIRE(keyset != NULL && dns_rdataset_isassociated(keyset));
1503
1504         dns_rdataset_init(&keys);
1505
1506         dns_rdataset_clone(keyset, &keys);
1507         for (result = dns_rdataset_first(&keys);
1508              result == ISC_R_SUCCESS;
1509              result = dns_rdataset_next(&keys)) {
1510                 dns_rdata_reset(&rdata);
1511                 dns_rdataset_current(&keys, &rdata);
1512                 RETERR(dns_dnssec_keyfromrdata(origin, &rdata, mctx, &pubkey));
1513
1514                 if (!is_zone_key(pubkey) ||
1515                     (dst_key_flags(pubkey) & DNS_KEYTYPE_NOAUTH) != 0)
1516                         goto skip;
1517
1518                 /* Corrupted .key file? */
1519                 if (!dns_name_equal(origin, dst_key_name(pubkey)))
1520                         goto skip;
1521
1522                 if (public) {
1523                         RETERR(addkey(keylist, &pubkey, savekeys, mctx));
1524                         goto skip;
1525                 }
1526
1527                 result = dst_key_fromfile(dst_key_name(pubkey),
1528                                           dst_key_id(pubkey),
1529                                           dst_key_alg(pubkey),
1530                                           DST_TYPE_PUBLIC|DST_TYPE_PRIVATE,
1531                                           directory, mctx, &privkey);
1532
1533                 /*
1534                  * If the key was revoked and the private file
1535                  * doesn't exist, maybe it was revoked internally
1536                  * by named.  Try loading the unrevoked version.
1537                  */
1538                 if (result == ISC_R_FILENOTFOUND) {
1539                         isc_uint32_t flags;
1540                         flags = dst_key_flags(pubkey);
1541                         if ((flags & DNS_KEYFLAG_REVOKE) != 0) {
1542                                 dst_key_setflags(pubkey,
1543                                                  flags & ~DNS_KEYFLAG_REVOKE);
1544                                 result = dst_key_fromfile(dst_key_name(pubkey),
1545                                                           dst_key_id(pubkey),
1546                                                           dst_key_alg(pubkey),
1547                                                           DST_TYPE_PUBLIC|
1548                                                           DST_TYPE_PRIVATE,
1549                                                           directory,
1550                                                           mctx, &privkey);
1551                                 if (result == ISC_R_SUCCESS &&
1552                                     dst_key_pubcompare(pubkey, privkey,
1553                                                        ISC_FALSE)) {
1554                                         dst_key_setflags(privkey, flags);
1555                                 }
1556                                 dst_key_setflags(pubkey, flags);
1557                         }
1558                 }
1559
1560                 if (result != ISC_R_SUCCESS) {
1561                         char keybuf[DNS_NAME_FORMATSIZE];
1562                         char algbuf[DNS_SECALG_FORMATSIZE];
1563                         dns_name_format(dst_key_name(pubkey), keybuf,
1564                                         sizeof(keybuf));
1565                         dns_secalg_format(dst_key_alg(pubkey), algbuf,
1566                                           sizeof(algbuf));
1567                         isc_log_write(dns_lctx, DNS_LOGCATEGORY_GENERAL,
1568                                       DNS_LOGMODULE_DNSSEC, ISC_LOG_WARNING,
1569                                       "dns_dnssec_keylistfromrdataset: error "
1570                                       "reading private key file %s/%s/%d: %s",
1571                                       keybuf, algbuf, dst_key_id(pubkey),
1572                                       isc_result_totext(result));
1573                 }
1574
1575                 if (result == ISC_R_FILENOTFOUND || result == ISC_R_NOPERM) {
1576                         RETERR(addkey(keylist, &pubkey, savekeys, mctx));
1577                         goto skip;
1578                 }
1579                 RETERR(result);
1580
1581                 /* This should never happen. */
1582                 if ((dst_key_flags(privkey) & DNS_KEYTYPE_NOAUTH) != 0)
1583                         goto skip;
1584
1585                 RETERR(addkey(keylist, &privkey, savekeys, mctx));
1586  skip:
1587                 if (pubkey != NULL)
1588                         dst_key_free(&pubkey);
1589                 if (privkey != NULL)
1590                         dst_key_free(&privkey);
1591         }
1592
1593         if (result != ISC_R_NOMORE)
1594                 RETERR(result);
1595
1596         if (keysigs != NULL && dns_rdataset_isassociated(keysigs))
1597                 RETERR(mark_active_keys(keylist, keysigs));
1598
1599         if (soasigs != NULL && dns_rdataset_isassociated(soasigs))
1600                 RETERR(mark_active_keys(keylist, soasigs));
1601
1602         result = ISC_R_SUCCESS;
1603
1604  failure:
1605         if (dns_rdataset_isassociated(&keys))
1606                 dns_rdataset_disassociate(&keys);
1607         if (pubkey != NULL)
1608                 dst_key_free(&pubkey);
1609         if (privkey != NULL)
1610                 dst_key_free(&privkey);
1611         return (result);
1612 }
1613
1614 static isc_result_t
1615 make_dnskey(dst_key_t *key, unsigned char *buf, int bufsize,
1616             dns_rdata_t *target)
1617 {
1618         isc_result_t result;
1619         isc_buffer_t b;
1620         isc_region_t r;
1621
1622         isc_buffer_init(&b, buf, bufsize);
1623         result = dst_key_todns(key, &b);
1624         if (result != ISC_R_SUCCESS)
1625                 return (result);
1626
1627         dns_rdata_reset(target);
1628         isc_buffer_usedregion(&b, &r);
1629         dns_rdata_fromregion(target, dst_key_class(key),
1630                              dns_rdatatype_dnskey, &r);
1631         return (ISC_R_SUCCESS);
1632 }
1633
1634 static isc_result_t
1635 publish_key(dns_diff_t *diff, dns_dnsseckey_t *key, dns_name_t *origin,
1636             dns_ttl_t ttl, isc_mem_t *mctx, isc_boolean_t allzsk,
1637             void (*report)(const char *, ...))
1638 {
1639         isc_result_t result;
1640         dns_difftuple_t *tuple = NULL;
1641         unsigned char buf[DST_KEY_MAXSIZE];
1642         dns_rdata_t dnskey = DNS_RDATA_INIT;
1643         char alg[80];
1644
1645         dns_rdata_reset(&dnskey);
1646         RETERR(make_dnskey(key->key, buf, sizeof(buf), &dnskey));
1647
1648         dns_secalg_format(dst_key_alg(key->key), alg, sizeof(alg));
1649         report("Fetching %s %d/%s from key %s.",
1650                key->ksk ?  (allzsk ?  "KSK/ZSK" : "KSK") : "ZSK",
1651                dst_key_id(key->key), alg,
1652                key->source == dns_keysource_user ?  "file" : "repository");
1653
1654         if (key->prepublish && ttl > key->prepublish) {
1655                 char keystr[DST_KEY_FORMATSIZE];
1656                 isc_stdtime_t now;
1657
1658                 dst_key_format(key->key, keystr, sizeof(keystr));
1659                 report("Key %s: Delaying activation to match the DNSKEY TTL.\n",
1660                        keystr, ttl);
1661
1662                 isc_stdtime_get(&now);
1663                 dst_key_settime(key->key, DST_TIME_ACTIVATE, now + ttl);
1664         }
1665
1666         /* publish key */
1667         RETERR(dns_difftuple_create(mctx, DNS_DIFFOP_ADD, origin, ttl,
1668                                     &dnskey, &tuple));
1669         dns_diff_appendminimal(diff, &tuple);
1670         result = ISC_R_SUCCESS;
1671
1672  failure:
1673         return (result);
1674 }
1675
1676 static isc_result_t
1677 remove_key(dns_diff_t *diff, dns_dnsseckey_t *key, dns_name_t *origin,
1678           dns_ttl_t ttl, isc_mem_t *mctx, const char *reason,
1679           void (*report)(const char *, ...))
1680 {
1681         isc_result_t result;
1682         dns_difftuple_t *tuple = NULL;
1683         unsigned char buf[DST_KEY_MAXSIZE];
1684         dns_rdata_t dnskey = DNS_RDATA_INIT;
1685         char alg[80];
1686
1687         dns_secalg_format(dst_key_alg(key->key), alg, sizeof(alg));
1688         report("Removing %s key %d/%s from DNSKEY RRset.",
1689                reason, dst_key_id(key->key), alg);
1690
1691         RETERR(make_dnskey(key->key, buf, sizeof(buf), &dnskey));
1692         RETERR(dns_difftuple_create(mctx, DNS_DIFFOP_DEL, origin, ttl, &dnskey,
1693                                     &tuple));
1694         dns_diff_appendminimal(diff, &tuple);
1695         result = ISC_R_SUCCESS;
1696
1697  failure:
1698         return (result);
1699 }
1700
1701 /*
1702  * Update 'keys' with information from 'newkeys'.
1703  *
1704  * If 'removed' is not NULL, any keys that are being removed from
1705  * the zone will be added to the list for post-removal processing.
1706  */
1707 isc_result_t
1708 dns_dnssec_updatekeys(dns_dnsseckeylist_t *keys, dns_dnsseckeylist_t *newkeys,
1709                       dns_dnsseckeylist_t *removed, dns_name_t *origin,
1710                       dns_ttl_t ttl, dns_diff_t *diff, isc_boolean_t allzsk,
1711                       isc_mem_t *mctx, void (*report)(const char *, ...))
1712 {
1713         isc_result_t result;
1714         dns_dnsseckey_t *key, *key1, *key2, *next;
1715
1716         /*
1717          * First, look through the existing key list to find keys
1718          * supplied from the command line which are not in the zone.
1719          * Update the zone to include them.
1720          */
1721         for (key = ISC_LIST_HEAD(*keys);
1722              key != NULL;
1723              key = ISC_LIST_NEXT(key, link)) {
1724                 if (key->source == dns_keysource_user &&
1725                     (key->hint_publish || key->force_publish)) {
1726                         RETERR(publish_key(diff, key, origin, ttl,
1727                                            mctx, allzsk, report));
1728                 }
1729         }
1730
1731         /*
1732          * Second, scan the list of newly found keys looking for matches
1733          * with known keys, and update accordingly.
1734          */
1735         for (key1 = ISC_LIST_HEAD(*newkeys); key1 != NULL; key1 = next) {
1736                 isc_boolean_t key_revoked = ISC_FALSE;
1737
1738                 next = ISC_LIST_NEXT(key1, link);
1739
1740                 for (key2 = ISC_LIST_HEAD(*keys);
1741                      key2 != NULL;
1742                      key2 = ISC_LIST_NEXT(key2, link)) {
1743                         if (dst_key_pubcompare(key1->key, key2->key,
1744                                                ISC_TRUE)) {
1745                                 int r1, r2;
1746                                 r1 = dst_key_flags(key1->key) &
1747                                         DNS_KEYFLAG_REVOKE;
1748                                 r2 = dst_key_flags(key2->key) &
1749                                         DNS_KEYFLAG_REVOKE;
1750                                 key_revoked = ISC_TF(r1 != r2);
1751                                 break;
1752                         }
1753                 }
1754
1755                 /* No match found in keys; add the new key. */
1756                 if (key2 == NULL) {
1757                         ISC_LIST_UNLINK(*newkeys, key1, link);
1758                         ISC_LIST_APPEND(*keys, key1, link);
1759
1760                         if (key1->source != dns_keysource_zoneapex &&
1761                             (key1->hint_publish || key1->force_publish)) {
1762                                 RETERR(publish_key(diff, key1, origin, ttl,
1763                                                    mctx, allzsk, report));
1764                                 if (key1->hint_sign || key1->force_sign)
1765                                         key1->first_sign = ISC_TRUE;
1766                         }
1767
1768                         continue;
1769                 }
1770
1771                 /* Match found: remove or update it as needed */
1772                 if (key1->hint_remove) {
1773                         RETERR(remove_key(diff, key2, origin, ttl, mctx,
1774                                           "expired", report));
1775                         ISC_LIST_UNLINK(*keys, key2, link);
1776                         if (removed != NULL)
1777                                 ISC_LIST_APPEND(*removed, key2, link);
1778                         else
1779                                 dns_dnsseckey_destroy(mctx, &key2);
1780                 } else if (key_revoked &&
1781                          (dst_key_flags(key1->key) & DNS_KEYFLAG_REVOKE) != 0) {
1782
1783                         /*
1784                          * A previously valid key has been revoked.
1785                          * We need to remove the old version and pull
1786                          * in the new one.
1787                          */
1788                         RETERR(remove_key(diff, key2, origin, ttl, mctx,
1789                                           "revoked", report));
1790                         ISC_LIST_UNLINK(*keys, key2, link);
1791                         if (removed != NULL)
1792                                 ISC_LIST_APPEND(*removed, key2, link);
1793                         else
1794                                 dns_dnsseckey_destroy(mctx, &key2);
1795
1796                         RETERR(publish_key(diff, key1, origin, ttl,
1797                                            mctx, allzsk, report));
1798                         ISC_LIST_UNLINK(*newkeys, key1, link);
1799                         ISC_LIST_APPEND(*keys, key1, link);
1800
1801                         /*
1802                          * XXX: The revoke flag is only defined for trust
1803                          * anchors.  Setting the flag on a non-KSK is legal,
1804                          * but not defined in any RFC.  It seems reasonable
1805                          * to treat it the same as a KSK: keep it in the
1806                          * zone, sign the DNSKEY set with it, but not
1807                          * sign other records with it.
1808                          */
1809                         key1->ksk = ISC_TRUE;
1810                         continue;
1811                 } else {
1812                         if (!key2->is_active &&
1813                             (key1->hint_sign || key1->force_sign))
1814                                 key2->first_sign = ISC_TRUE;
1815                         key2->hint_sign = key1->hint_sign;
1816                         key2->hint_publish = key1->hint_publish;
1817                 }
1818         }
1819
1820         /* Free any leftover keys in newkeys */
1821         while (!ISC_LIST_EMPTY(*newkeys)) {
1822                 key1 = ISC_LIST_HEAD(*newkeys);
1823                 ISC_LIST_UNLINK(*newkeys, key1, link);
1824                 dns_dnsseckey_destroy(mctx, &key1);
1825         }
1826
1827         result = ISC_R_SUCCESS;
1828
1829  failure:
1830         return (result);
1831 }