]> CyberLeo.Net >> Repos - FreeBSD/releng/9.0.git/blob - contrib/bind9/lib/dns/dnssec.c
Copy stable/9 to releng/9.0 as part of the FreeBSD 9.0-RELEASE release
[FreeBSD/releng/9.0.git] / contrib / bind9 / lib / dns / dnssec.c
1 /*
2  * Copyright (C) 2004-2011  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: dnssec.c,v 1.119.170.4 2011-05-06 21:07:50 each Exp $
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) {
1138         isc_result_t result;
1139         isc_stdtime_t now, 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         isc_stdtime_get(&now);
1147
1148         result = dst_key_gettime(key->key, DST_TIME_PUBLISH, &publish);
1149         if (result == ISC_R_SUCCESS)
1150                 pubset = ISC_TRUE;
1151
1152         result = dst_key_gettime(key->key, DST_TIME_ACTIVATE, &active);
1153         if (result == ISC_R_SUCCESS)
1154                 actset = ISC_TRUE;
1155
1156         result = dst_key_gettime(key->key, DST_TIME_REVOKE, &revoke);
1157         if (result == ISC_R_SUCCESS)
1158                 revset = ISC_TRUE;
1159
1160         result = dst_key_gettime(key->key, DST_TIME_INACTIVE, &inactive);
1161         if (result == ISC_R_SUCCESS)
1162                 inactset = ISC_TRUE;
1163
1164         result = dst_key_gettime(key->key, DST_TIME_DELETE, &delete);
1165         if (result == ISC_R_SUCCESS)
1166                 delset = ISC_TRUE;
1167
1168         /* Metadata says publish (but possibly not activate) */
1169         if (pubset && publish <= now)
1170                 key->hint_publish = ISC_TRUE;
1171
1172         /* Metadata says activate (so we must also publish) */
1173         if (actset && active <= now) {
1174                 key->hint_sign = ISC_TRUE;
1175                 key->hint_publish = ISC_TRUE;
1176         }
1177
1178         /*
1179          * Activation date is set (maybe in the future), but
1180          * publication date isn't. Most likely the user wants to
1181          * publish now and activate later.
1182          */
1183         if (actset && !pubset)
1184                 key->hint_publish = ISC_TRUE;
1185
1186         /*
1187          * If activation date is in the future, make note of how far off
1188          */
1189         if (key->hint_publish && actset && active > now) {
1190                 key->prepublish = active - now;
1191         }
1192
1193         /*
1194          * Key has been marked inactive: we can continue publishing,
1195          * but don't sign.
1196          */
1197         if (key->hint_publish && inactset && inactive <= now) {
1198                 key->hint_sign = ISC_FALSE;
1199         }
1200
1201         /*
1202          * Metadata says revoke.  If the key is published,
1203          * we *have to* sign with it per RFC5011--even if it was
1204          * not active before.
1205          *
1206          * If it hasn't already been done, we should also revoke it now.
1207          */
1208         if (key->hint_publish && (revset && revoke <= now)) {
1209                 isc_uint32_t flags;
1210                 key->hint_sign = ISC_TRUE;
1211                 flags = dst_key_flags(key->key);
1212                 if ((flags & DNS_KEYFLAG_REVOKE) == 0) {
1213                         flags |= DNS_KEYFLAG_REVOKE;
1214                         dst_key_setflags(key->key, flags);
1215                 }
1216         }
1217
1218         /*
1219          * Metadata says delete, so don't publish this key or sign with it.
1220          */
1221         if (delset && delete <= now) {
1222                 key->hint_publish = ISC_FALSE;
1223                 key->hint_sign = ISC_FALSE;
1224                 key->hint_remove = ISC_TRUE;
1225         }
1226 }
1227
1228 /*%
1229  * Get a list of DNSSEC keys from the key repository
1230  */
1231 isc_result_t
1232 dns_dnssec_findmatchingkeys(dns_name_t *origin, const char *directory,
1233                             isc_mem_t *mctx, dns_dnsseckeylist_t *keylist)
1234 {
1235         isc_result_t result = ISC_R_SUCCESS;
1236         isc_boolean_t dir_open = ISC_FALSE;
1237         dns_dnsseckeylist_t list;
1238         isc_dir_t dir;
1239         dns_dnsseckey_t *key = NULL;
1240         dst_key_t *dstkey = NULL;
1241         char namebuf[DNS_NAME_FORMATSIZE], *p;
1242         isc_buffer_t b;
1243         unsigned int len;
1244
1245         REQUIRE(keylist != NULL);
1246         ISC_LIST_INIT(list);
1247         isc_dir_init(&dir);
1248
1249         isc_buffer_init(&b, namebuf, sizeof(namebuf) - 1);
1250         RETERR(dns_name_totext(origin, ISC_FALSE, &b));
1251         len = isc_buffer_usedlength(&b);
1252         namebuf[len] = '\0';
1253
1254         if (directory == NULL)
1255                 directory = ".";
1256         RETERR(isc_dir_open(&dir, directory));
1257         dir_open = ISC_TRUE;
1258
1259         while (isc_dir_read(&dir) == ISC_R_SUCCESS) {
1260                 if (dir.entry.name[0] == 'K' &&
1261                     dir.entry.length > len + 1 &&
1262                     dir.entry.name[len + 1] == '+' &&
1263                     strncasecmp(dir.entry.name + 1, namebuf, len) == 0) {
1264                         p = strrchr(dir.entry.name, '.');
1265                         if (p != NULL && strcmp(p, ".private") != 0)
1266                                 continue;
1267
1268                         dstkey = NULL;
1269                         result = dst_key_fromnamedfile(dir.entry.name,
1270                                                        directory,
1271                                                        DST_TYPE_PUBLIC |
1272                                                        DST_TYPE_PRIVATE,
1273                                                        mctx, &dstkey);
1274
1275                         if (result != ISC_R_SUCCESS) {
1276                                 isc_log_write(dns_lctx,
1277                                               DNS_LOGCATEGORY_GENERAL,
1278                                               DNS_LOGMODULE_DNSSEC,
1279                                               ISC_LOG_WARNING,
1280                                               "dns_dnssec_findmatchingkeys: "
1281                                               "error reading key file %s: %s",
1282                                               dir.entry.name,
1283                                               isc_result_totext(result));
1284                                 continue;
1285                         }
1286
1287                         RETERR(dns_dnsseckey_create(mctx, &dstkey, &key));
1288                         key->source = dns_keysource_repository;
1289                         get_hints(key);
1290
1291                         if (key->legacy) {
1292                                 dns_dnsseckey_destroy(mctx, &key);
1293                         } else {
1294                                 ISC_LIST_APPEND(list, key, link);
1295                                 key = NULL;
1296                         }
1297                 }
1298         }
1299
1300         if (!ISC_LIST_EMPTY(list))
1301                 ISC_LIST_APPENDLIST(*keylist, list, link);
1302         else
1303                 result = ISC_R_NOTFOUND;
1304
1305  failure:
1306         if (dir_open)
1307                 isc_dir_close(&dir);
1308         INSIST(key == NULL);
1309         while ((key = ISC_LIST_HEAD(list)) != NULL) {
1310                 ISC_LIST_UNLINK(list, key, link);
1311                 INSIST(key->key != NULL);
1312                 dst_key_free(&key->key);
1313                 dns_dnsseckey_destroy(mctx, &key);
1314         }
1315         if (dstkey != NULL)
1316                 dst_key_free(&dstkey);
1317         return (result);
1318 }
1319
1320 /*%
1321  * Add 'newkey' to 'keylist' if it's not already there.
1322  *
1323  * If 'savekeys' is ISC_TRUE, then we need to preserve all
1324  * the keys in the keyset, regardless of whether they have
1325  * metadata indicating they should be deactivated or removed.
1326  */
1327 static void
1328 addkey(dns_dnsseckeylist_t *keylist, dst_key_t **newkey,
1329        isc_boolean_t savekeys, isc_mem_t *mctx)
1330 {
1331         dns_dnsseckey_t *key;
1332
1333         /* Skip duplicates */
1334         for (key = ISC_LIST_HEAD(*keylist);
1335              key != NULL;
1336              key = ISC_LIST_NEXT(key, link)) {
1337                 if (dst_key_id(key->key) == dst_key_id(*newkey) &&
1338                     dst_key_alg(key->key) == dst_key_alg(*newkey) &&
1339                     dns_name_equal(dst_key_name(key->key),
1340                                    dst_key_name(*newkey)))
1341                         break;
1342         }
1343
1344         if (key != NULL) {
1345                 /*
1346                  * Found a match.  If the old key was only public and the
1347                  * new key is private, replace the old one; otherwise
1348                  * leave it.  But either way, mark the key as having
1349                  * been found in the zone.
1350                  */
1351                 if (dst_key_isprivate(key->key)) {
1352                         dst_key_free(newkey);
1353                 } else if (dst_key_isprivate(*newkey)) {
1354                         dst_key_free(&key->key);
1355                         key->key = *newkey;
1356                 }
1357
1358                 key->source = dns_keysource_zoneapex;
1359                 return;
1360         }
1361
1362         dns_dnsseckey_create(mctx, newkey, &key);
1363         if (key->legacy || savekeys) {
1364                 key->force_publish = ISC_TRUE;
1365                 key->force_sign = dst_key_isprivate(key->key);
1366         }
1367         key->source = dns_keysource_zoneapex;
1368         ISC_LIST_APPEND(*keylist, key, link);
1369         *newkey = NULL;
1370 }
1371
1372
1373 /*%
1374  * Mark all keys which signed the DNSKEY/SOA RRsets as "active",
1375  * for future reference.
1376  */
1377 static isc_result_t
1378 mark_active_keys(dns_dnsseckeylist_t *keylist, dns_rdataset_t *rrsigs) {
1379         isc_result_t result = ISC_R_SUCCESS;
1380         dns_rdata_t rdata = DNS_RDATA_INIT;
1381         dns_rdataset_t sigs;
1382         dns_dnsseckey_t *key;
1383
1384         REQUIRE(rrsigs != NULL && dns_rdataset_isassociated(rrsigs));
1385
1386         dns_rdataset_init(&sigs);
1387         dns_rdataset_clone(rrsigs, &sigs);
1388         for (key = ISC_LIST_HEAD(*keylist);
1389              key != NULL;
1390              key = ISC_LIST_NEXT(key, link)) {
1391                 isc_uint16_t keyid, sigid;
1392                 dns_secalg_t keyalg, sigalg;
1393                 keyid = dst_key_id(key->key);
1394                 keyalg = dst_key_alg(key->key);
1395
1396                 for (result = dns_rdataset_first(&sigs);
1397                      result == ISC_R_SUCCESS;
1398                      result = dns_rdataset_next(&sigs)) {
1399                         dns_rdata_rrsig_t sig;
1400
1401                         dns_rdata_reset(&rdata);
1402                         dns_rdataset_current(&sigs, &rdata);
1403                         result = dns_rdata_tostruct(&rdata, &sig, NULL);
1404                         RUNTIME_CHECK(result == ISC_R_SUCCESS);
1405                         sigalg = sig.algorithm;
1406                         sigid = sig.keyid;
1407                         if (keyid == sigid && keyalg == sigalg) {
1408                                 key->is_active = ISC_TRUE;
1409                                 break;
1410                         }
1411                 }
1412         }
1413
1414         if (result == ISC_R_NOMORE)
1415                 result = ISC_R_SUCCESS;
1416
1417         if (dns_rdataset_isassociated(&sigs))
1418                 dns_rdataset_disassociate(&sigs);
1419         return (result);
1420 }
1421
1422 /*%
1423  * Add the contents of a DNSKEY rdataset 'keyset' to 'keylist'.
1424  */
1425 isc_result_t
1426 dns_dnssec_keylistfromrdataset(dns_name_t *origin,
1427                                const char *directory, isc_mem_t *mctx,
1428                                dns_rdataset_t *keyset, dns_rdataset_t *keysigs,
1429                                dns_rdataset_t *soasigs, isc_boolean_t savekeys,
1430                                isc_boolean_t public,
1431                                dns_dnsseckeylist_t *keylist)
1432 {
1433         dns_rdataset_t keys;
1434         dns_rdata_t rdata = DNS_RDATA_INIT;
1435         dst_key_t *pubkey = NULL, *privkey = NULL;
1436         isc_result_t result;
1437
1438         REQUIRE(keyset != NULL && dns_rdataset_isassociated(keyset));
1439
1440         dns_rdataset_init(&keys);
1441
1442         dns_rdataset_clone(keyset, &keys);
1443         for (result = dns_rdataset_first(&keys);
1444              result == ISC_R_SUCCESS;
1445              result = dns_rdataset_next(&keys)) {
1446                 dns_rdata_reset(&rdata);
1447                 dns_rdataset_current(&keys, &rdata);
1448                 RETERR(dns_dnssec_keyfromrdata(origin, &rdata, mctx, &pubkey));
1449
1450                 if (!is_zone_key(pubkey) ||
1451                     (dst_key_flags(pubkey) & DNS_KEYTYPE_NOAUTH) != 0)
1452                         goto skip;
1453
1454                 /* Corrupted .key file? */
1455                 if (!dns_name_equal(origin, dst_key_name(pubkey)))
1456                         goto skip;
1457
1458                 if (public) {
1459                         addkey(keylist, &pubkey, savekeys, mctx);
1460                         goto skip;
1461                 }
1462
1463                 result = dst_key_fromfile(dst_key_name(pubkey),
1464                                           dst_key_id(pubkey),
1465                                           dst_key_alg(pubkey),
1466                                           DST_TYPE_PUBLIC|DST_TYPE_PRIVATE,
1467                                           directory, mctx, &privkey);
1468
1469                 /*
1470                  * If the key was revoked and the private file
1471                  * doesn't exist, maybe it was revoked internally
1472                  * by named.  Try loading the unrevoked version.
1473                  */
1474                 if (result == ISC_R_FILENOTFOUND) {
1475                         isc_uint32_t flags;
1476                         flags = dst_key_flags(pubkey);
1477                         if ((flags & DNS_KEYFLAG_REVOKE) != 0) {
1478                                 dst_key_setflags(pubkey,
1479                                                  flags & ~DNS_KEYFLAG_REVOKE);
1480                                 result = dst_key_fromfile(dst_key_name(pubkey),
1481                                                           dst_key_id(pubkey),
1482                                                           dst_key_alg(pubkey),
1483                                                           DST_TYPE_PUBLIC|
1484                                                           DST_TYPE_PRIVATE,
1485                                                           directory,
1486                                                           mctx, &privkey);
1487                                 if (result == ISC_R_SUCCESS &&
1488                                     dst_key_pubcompare(pubkey, privkey,
1489                                                        ISC_FALSE)) {
1490                                         dst_key_setflags(privkey, flags);
1491                                 }
1492                                 dst_key_setflags(pubkey, flags);
1493                         }
1494                 }
1495
1496                 if (result != ISC_R_SUCCESS) {
1497                         char keybuf[DNS_NAME_FORMATSIZE];
1498                         char algbuf[DNS_SECALG_FORMATSIZE];
1499                         dns_name_format(dst_key_name(pubkey), keybuf,
1500                                         sizeof(keybuf));
1501                         dns_secalg_format(dst_key_alg(pubkey), algbuf,
1502                                           sizeof(algbuf));
1503                         isc_log_write(dns_lctx, DNS_LOGCATEGORY_GENERAL,
1504                                       DNS_LOGMODULE_DNSSEC, ISC_LOG_WARNING,
1505                                       "dns_dnssec_keylistfromrdataset: error "
1506                                       "reading private key file %s/%s/%d: %s",
1507                                       keybuf, algbuf, dst_key_id(pubkey),
1508                                       isc_result_totext(result));
1509                 }
1510
1511                 if (result == ISC_R_FILENOTFOUND || result == ISC_R_NOPERM) {
1512                         addkey(keylist, &pubkey, savekeys, mctx);
1513                         goto skip;
1514                 }
1515                 RETERR(result);
1516
1517                 /* This should never happen. */
1518                 if ((dst_key_flags(privkey) & DNS_KEYTYPE_NOAUTH) != 0)
1519                         goto skip;
1520
1521                 addkey(keylist, &privkey, savekeys, mctx);
1522  skip:
1523                 if (pubkey != NULL)
1524                         dst_key_free(&pubkey);
1525                 if (privkey != NULL)
1526                         dst_key_free(&privkey);
1527         }
1528
1529         if (result != ISC_R_NOMORE)
1530                 RETERR(result);
1531
1532         if (keysigs != NULL && dns_rdataset_isassociated(keysigs))
1533                 RETERR(mark_active_keys(keylist, keysigs));
1534
1535         if (soasigs != NULL && dns_rdataset_isassociated(soasigs))
1536                 RETERR(mark_active_keys(keylist, soasigs));
1537
1538         result = ISC_R_SUCCESS;
1539
1540  failure:
1541         if (dns_rdataset_isassociated(&keys))
1542                 dns_rdataset_disassociate(&keys);
1543         if (pubkey != NULL)
1544                 dst_key_free(&pubkey);
1545         if (privkey != NULL)
1546                 dst_key_free(&privkey);
1547         return (result);
1548 }
1549
1550 static isc_result_t
1551 make_dnskey(dst_key_t *key, unsigned char *buf, int bufsize,
1552             dns_rdata_t *target)
1553 {
1554         isc_result_t result;
1555         isc_buffer_t b;
1556         isc_region_t r;
1557
1558         isc_buffer_init(&b, buf, bufsize);
1559         result = dst_key_todns(key, &b);
1560         if (result != ISC_R_SUCCESS)
1561                 return (result);
1562
1563         dns_rdata_reset(target);
1564         isc_buffer_usedregion(&b, &r);
1565         dns_rdata_fromregion(target, dst_key_class(key),
1566                              dns_rdatatype_dnskey, &r);
1567         return (ISC_R_SUCCESS);
1568 }
1569
1570 static isc_result_t
1571 publish_key(dns_diff_t *diff, dns_dnsseckey_t *key, dns_name_t *origin,
1572             dns_ttl_t ttl, isc_mem_t *mctx, isc_boolean_t allzsk,
1573             void (*report)(const char *, ...))
1574 {
1575         isc_result_t result;
1576         dns_difftuple_t *tuple = NULL;
1577         unsigned char buf[DST_KEY_MAXSIZE];
1578         dns_rdata_t dnskey = DNS_RDATA_INIT;
1579         char alg[80];
1580
1581         dns_rdata_reset(&dnskey);
1582         RETERR(make_dnskey(key->key, buf, sizeof(buf), &dnskey));
1583
1584         dns_secalg_format(dst_key_alg(key->key), alg, sizeof(alg));
1585         report("Fetching %s %d/%s from key %s.",
1586                key->ksk ?  (allzsk ?  "KSK/ZSK" : "KSK") : "ZSK",
1587                dst_key_id(key->key), alg,
1588                key->source == dns_keysource_user ?  "file" : "repository");
1589
1590         if (key->prepublish && ttl > key->prepublish) {
1591                 char keystr[DST_KEY_FORMATSIZE];
1592                 isc_stdtime_t now;
1593
1594                 dst_key_format(key->key, keystr, sizeof(keystr));
1595                 report("Key %s: Delaying activation to match the DNSKEY TTL.\n",
1596                        keystr, ttl);
1597
1598                 isc_stdtime_get(&now);
1599                 dst_key_settime(key->key, DST_TIME_ACTIVATE, now + ttl);
1600         }
1601
1602         /* publish key */
1603         RETERR(dns_difftuple_create(mctx, DNS_DIFFOP_ADD, origin, ttl,
1604                                     &dnskey, &tuple));
1605         dns_diff_appendminimal(diff, &tuple);
1606         result = ISC_R_SUCCESS;
1607
1608  failure:
1609         return (result);
1610 }
1611
1612 static isc_result_t
1613 remove_key(dns_diff_t *diff, dns_dnsseckey_t *key, dns_name_t *origin,
1614           dns_ttl_t ttl, isc_mem_t *mctx, const char *reason,
1615           void (*report)(const char *, ...))
1616 {
1617         isc_result_t result;
1618         dns_difftuple_t *tuple = NULL;
1619         unsigned char buf[DST_KEY_MAXSIZE];
1620         dns_rdata_t dnskey = DNS_RDATA_INIT;
1621         char alg[80];
1622
1623         dns_secalg_format(dst_key_alg(key->key), alg, sizeof(alg));
1624         report("Removing %s key %d/%s from DNSKEY RRset.",
1625                reason, dst_key_id(key->key), alg);
1626
1627         RETERR(make_dnskey(key->key, buf, sizeof(buf), &dnskey));
1628         RETERR(dns_difftuple_create(mctx, DNS_DIFFOP_DEL, origin, ttl, &dnskey,
1629                                     &tuple));
1630         dns_diff_appendminimal(diff, &tuple);
1631         result = ISC_R_SUCCESS;
1632
1633  failure:
1634         return (result);
1635 }
1636
1637 /*
1638  * Update 'keys' with information from 'newkeys'.
1639  *
1640  * If 'removed' is not NULL, any keys that are being removed from
1641  * the zone will be added to the list for post-removal processing.
1642  */
1643 isc_result_t
1644 dns_dnssec_updatekeys(dns_dnsseckeylist_t *keys, dns_dnsseckeylist_t *newkeys,
1645                       dns_dnsseckeylist_t *removed, dns_name_t *origin,
1646                       dns_ttl_t ttl, dns_diff_t *diff, isc_boolean_t allzsk,
1647                       isc_mem_t *mctx, void (*report)(const char *, ...))
1648 {
1649         isc_result_t result;
1650         dns_dnsseckey_t *key, *key1, *key2, *next;
1651
1652         /*
1653          * First, look through the existing key list to find keys
1654          * supplied from the command line which are not in the zone.
1655          * Update the zone to include them.
1656          */
1657         for (key = ISC_LIST_HEAD(*keys);
1658              key != NULL;
1659              key = ISC_LIST_NEXT(key, link)) {
1660                 if (key->source == dns_keysource_user &&
1661                     (key->hint_publish || key->force_publish)) {
1662                         RETERR(publish_key(diff, key, origin, ttl,
1663                                            mctx, allzsk, report));
1664                 }
1665         }
1666
1667         /*
1668          * Second, scan the list of newly found keys looking for matches
1669          * with known keys, and update accordingly.
1670          */
1671         for (key1 = ISC_LIST_HEAD(*newkeys); key1 != NULL; key1 = next) {
1672                 isc_boolean_t key_revoked = ISC_FALSE;
1673
1674                 next = ISC_LIST_NEXT(key1, link);
1675
1676                 for (key2 = ISC_LIST_HEAD(*keys);
1677                      key2 != NULL;
1678                      key2 = ISC_LIST_NEXT(key2, link)) {
1679                         if (dst_key_pubcompare(key1->key, key2->key,
1680                                                ISC_TRUE)) {
1681                                 int r1, r2;
1682                                 r1 = dst_key_flags(key1->key) &
1683                                         DNS_KEYFLAG_REVOKE;
1684                                 r2 = dst_key_flags(key2->key) &
1685                                         DNS_KEYFLAG_REVOKE;
1686                                 key_revoked = ISC_TF(r1 != r2);
1687                                 break;
1688                         }
1689                 }
1690
1691                 /* No match found in keys; add the new key. */
1692                 if (key2 == NULL) {
1693                         ISC_LIST_UNLINK(*newkeys, key1, link);
1694                         ISC_LIST_APPEND(*keys, key1, link);
1695
1696                         if (key1->source != dns_keysource_zoneapex &&
1697                             (key1->hint_publish || key1->force_publish)) {
1698                                 RETERR(publish_key(diff, key1, origin, ttl,
1699                                                    mctx, allzsk, report));
1700                                 if (key1->hint_sign || key1->force_sign)
1701                                         key1->first_sign = ISC_TRUE;
1702                         }
1703
1704                         continue;
1705                 }
1706
1707                 /* Match found: remove or update it as needed */
1708                 if (key1->hint_remove) {
1709                         RETERR(remove_key(diff, key2, origin, ttl, mctx,
1710                                           "expired", report));
1711                         ISC_LIST_UNLINK(*keys, key2, link);
1712                         if (removed != NULL)
1713                                 ISC_LIST_APPEND(*removed, key2, link);
1714                         else
1715                                 dns_dnsseckey_destroy(mctx, &key2);
1716                 } else if (key_revoked &&
1717                          (dst_key_flags(key1->key) & DNS_KEYFLAG_REVOKE) != 0) {
1718
1719                         /*
1720                          * A previously valid key has been revoked.
1721                          * We need to remove the old version and pull
1722                          * in the new one.
1723                          */
1724                         RETERR(remove_key(diff, key2, origin, ttl, mctx,
1725                                           "revoked", report));
1726                         ISC_LIST_UNLINK(*keys, key2, link);
1727                         if (removed != NULL)
1728                                 ISC_LIST_APPEND(*removed, key2, link);
1729                         else
1730                                 dns_dnsseckey_destroy(mctx, &key2);
1731
1732                         RETERR(publish_key(diff, key1, origin, ttl,
1733                                            mctx, allzsk, report));
1734                         ISC_LIST_UNLINK(*newkeys, key1, link);
1735                         ISC_LIST_APPEND(*keys, key1, link);
1736
1737                         /*
1738                          * XXX: The revoke flag is only defined for trust
1739                          * anchors.  Setting the flag on a non-KSK is legal,
1740                          * but not defined in any RFC.  It seems reasonable
1741                          * to treat it the same as a KSK: keep it in the
1742                          * zone, sign the DNSKEY set with it, but not
1743                          * sign other records with it.
1744                          */
1745                         key1->ksk = ISC_TRUE;
1746                         continue;
1747                 } else {
1748                         if (!key2->is_active &&
1749                             (key1->hint_sign || key1->force_sign))
1750                                 key2->first_sign = ISC_TRUE;
1751                         key2->hint_sign = key1->hint_sign;
1752                         key2->hint_publish = key1->hint_publish;
1753                 }
1754         }
1755
1756         /* Free any leftover keys in newkeys */
1757         while (!ISC_LIST_EMPTY(*newkeys)) {
1758                 key1 = ISC_LIST_HEAD(*newkeys);
1759                 ISC_LIST_UNLINK(*newkeys, key1, link);
1760                 dns_dnsseckey_destroy(mctx, &key1);
1761         }
1762
1763         result = ISC_R_SUCCESS;
1764
1765  failure:
1766         return (result);
1767 }