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