dnssec.c

Go to the documentation of this file.
00001 /*
00002  * Copyright (C) 2004-2015  Internet Systems Consortium, Inc. ("ISC")
00003  * Copyright (C) 1999-2003  Internet Software Consortium.
00004  *
00005  * Permission to use, copy, modify, and/or distribute this software for any
00006  * purpose with or without fee is hereby granted, provided that the above
00007  * copyright notice and this permission notice appear in all copies.
00008  *
00009  * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
00010  * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
00011  * AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
00012  * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
00013  * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
00014  * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
00015  * PERFORMANCE OF THIS SOFTWARE.
00016  */
00017 
00018 /*! \file */
00019 
00020 #include <config.h>
00021 
00022 #include <stdlib.h>
00023 
00024 #include <isc/buffer.h>
00025 #include <isc/dir.h>
00026 #include <isc/mem.h>
00027 #include <isc/print.h>
00028 #include <isc/serial.h>
00029 #include <isc/string.h>
00030 #include <isc/util.h>
00031 
00032 #include <dns/db.h>
00033 #include <dns/diff.h>
00034 #include <dns/dnssec.h>
00035 #include <dns/fixedname.h>
00036 #include <dns/keyvalues.h>
00037 #include <dns/log.h>
00038 #include <dns/message.h>
00039 #include <dns/rdata.h>
00040 #include <dns/rdatalist.h>
00041 #include <dns/rdataset.h>
00042 #include <dns/rdatastruct.h>
00043 #include <dns/result.h>
00044 #include <dns/stats.h>
00045 #include <dns/tsig.h>           /* for DNS_TSIG_FUDGE */
00046 
00047 #include <dst/result.h>
00048 
00049 LIBDNS_EXTERNAL_DATA isc_stats_t *dns_dnssec_stats;
00050 
00051 #define is_response(msg) (msg->flags & DNS_MESSAGEFLAG_QR)
00052 
00053 #define RETERR(x) do { \
00054         result = (x); \
00055         if (result != ISC_R_SUCCESS) \
00056                 goto failure; \
00057         } while (0)
00058 
00059 
00060 #define TYPE_SIGN 0
00061 #define TYPE_VERIFY 1
00062 
00063 static isc_result_t
00064 digest_callback(void *arg, isc_region_t *data);
00065 
00066 static int
00067 rdata_compare_wrapper(const void *rdata1, const void *rdata2);
00068 
00069 static isc_result_t
00070 rdataset_to_sortedarray(dns_rdataset_t *set, isc_mem_t *mctx,
00071                         dns_rdata_t **rdata, int *nrdata);
00072 
00073 static isc_result_t
00074 digest_callback(void *arg, isc_region_t *data) {
00075         dst_context_t *ctx = arg;
00076 
00077         return (dst_context_adddata(ctx, data));
00078 }
00079 
00080 static inline void
00081 inc_stat(isc_statscounter_t counter) {
00082         if (dns_dnssec_stats != NULL)
00083                 isc_stats_increment(dns_dnssec_stats, counter);
00084 }
00085 
00086 /*
00087  * Make qsort happy.
00088  */
00089 static int
00090 rdata_compare_wrapper(const void *rdata1, const void *rdata2) {
00091         return (dns_rdata_compare((const dns_rdata_t *)rdata1,
00092                                   (const dns_rdata_t *)rdata2));
00093 }
00094 
00095 /*
00096  * Sort the rdataset into an array.
00097  */
00098 static isc_result_t
00099 rdataset_to_sortedarray(dns_rdataset_t *set, isc_mem_t *mctx,
00100                         dns_rdata_t **rdata, int *nrdata)
00101 {
00102         isc_result_t ret;
00103         int i = 0, n;
00104         dns_rdata_t *data;
00105         dns_rdataset_t rdataset;
00106 
00107         n = dns_rdataset_count(set);
00108 
00109         data = isc_mem_get(mctx, n * sizeof(dns_rdata_t));
00110         if (data == NULL)
00111                 return (ISC_R_NOMEMORY);
00112 
00113         dns_rdataset_init(&rdataset);
00114         dns_rdataset_clone(set, &rdataset);
00115         ret = dns_rdataset_first(&rdataset);
00116         if (ret != ISC_R_SUCCESS) {
00117                 dns_rdataset_disassociate(&rdataset);
00118                 isc_mem_put(mctx, data, n * sizeof(dns_rdata_t));
00119                 return (ret);
00120         }
00121 
00122         /*
00123          * Put them in the array.
00124          */
00125         do {
00126                 dns_rdata_init(&data[i]);
00127                 dns_rdataset_current(&rdataset, &data[i++]);
00128         } while (dns_rdataset_next(&rdataset) == ISC_R_SUCCESS);
00129 
00130         /*
00131          * Sort the array.
00132          */
00133         qsort(data, n, sizeof(dns_rdata_t), rdata_compare_wrapper);
00134         *rdata = data;
00135         *nrdata = n;
00136         dns_rdataset_disassociate(&rdataset);
00137         return (ISC_R_SUCCESS);
00138 }
00139 
00140 isc_result_t
00141 dns_dnssec_keyfromrdata(dns_name_t *name, dns_rdata_t *rdata, isc_mem_t *mctx,
00142                         dst_key_t **key)
00143 {
00144         isc_buffer_t b;
00145         isc_region_t r;
00146 
00147         INSIST(name != NULL);
00148         INSIST(rdata != NULL);
00149         INSIST(mctx != NULL);
00150         INSIST(key != NULL);
00151         INSIST(*key == NULL);
00152         REQUIRE(rdata->type == dns_rdatatype_key ||
00153                 rdata->type == dns_rdatatype_dnskey);
00154 
00155         dns_rdata_toregion(rdata, &r);
00156         isc_buffer_init(&b, r.base, r.length);
00157         isc_buffer_add(&b, r.length);
00158         return (dst_key_fromdns(name, rdata->rdclass, &b, mctx, key));
00159 }
00160 
00161 static isc_result_t
00162 digest_sig(dst_context_t *ctx, isc_boolean_t downcase, dns_rdata_t *sigrdata,
00163            dns_rdata_rrsig_t *rrsig)
00164 {
00165         isc_region_t r;
00166         isc_result_t ret;
00167         dns_fixedname_t fname;
00168 
00169         dns_rdata_toregion(sigrdata, &r);
00170         INSIST(r.length >= 19);
00171 
00172         r.length = 18;
00173         ret = dst_context_adddata(ctx, &r);
00174         if (ret != ISC_R_SUCCESS)
00175                 return (ret);
00176         if (downcase) {
00177                 dns_fixedname_init(&fname);
00178 
00179                 RUNTIME_CHECK(dns_name_downcase(&rrsig->signer,
00180                                                 dns_fixedname_name(&fname),
00181                                                 NULL) == ISC_R_SUCCESS);
00182                 dns_name_toregion(dns_fixedname_name(&fname), &r);
00183         } else
00184                 dns_name_toregion(&rrsig->signer, &r);
00185 
00186         return (dst_context_adddata(ctx, &r));
00187 }
00188 
00189 isc_result_t
00190 dns_dnssec_sign(dns_name_t *name, dns_rdataset_t *set, dst_key_t *key,
00191                 isc_stdtime_t *inception, isc_stdtime_t *expire,
00192                 isc_mem_t *mctx, isc_buffer_t *buffer, dns_rdata_t *sigrdata)
00193 {
00194         dns_rdata_rrsig_t sig;
00195         dns_rdata_t tmpsigrdata;
00196         dns_rdata_t *rdatas;
00197         int nrdatas, i;
00198         isc_buffer_t sigbuf, envbuf;
00199         isc_region_t r;
00200         dst_context_t *ctx = NULL;
00201         isc_result_t ret;
00202         isc_buffer_t *databuf = NULL;
00203         char data[256 + 8];
00204         isc_uint32_t flags;
00205         unsigned int sigsize;
00206         dns_fixedname_t fnewname;
00207         dns_fixedname_t fsigner;
00208 
00209         REQUIRE(name != NULL);
00210         REQUIRE(dns_name_countlabels(name) <= 255);
00211         REQUIRE(set != NULL);
00212         REQUIRE(key != NULL);
00213         REQUIRE(inception != NULL);
00214         REQUIRE(expire != NULL);
00215         REQUIRE(mctx != NULL);
00216         REQUIRE(sigrdata != NULL);
00217 
00218         if (*inception >= *expire)
00219                 return (DNS_R_INVALIDTIME);
00220 
00221         /*
00222          * Is the key allowed to sign data?
00223          */
00224         flags = dst_key_flags(key);
00225         if (flags & DNS_KEYTYPE_NOAUTH)
00226                 return (DNS_R_KEYUNAUTHORIZED);
00227         if ((flags & DNS_KEYFLAG_OWNERMASK) != DNS_KEYOWNER_ZONE)
00228                 return (DNS_R_KEYUNAUTHORIZED);
00229 
00230         sig.mctx = mctx;
00231         sig.common.rdclass = set->rdclass;
00232         sig.common.rdtype = dns_rdatatype_rrsig;
00233         ISC_LINK_INIT(&sig.common, link);
00234 
00235         /*
00236          * Downcase signer.
00237          */
00238         dns_name_init(&sig.signer, NULL);
00239         dns_fixedname_init(&fsigner);
00240         RUNTIME_CHECK(dns_name_downcase(dst_key_name(key),
00241                       dns_fixedname_name(&fsigner), NULL) == ISC_R_SUCCESS);
00242         dns_name_clone(dns_fixedname_name(&fsigner), &sig.signer);
00243 
00244         sig.covered = set->type;
00245         sig.algorithm = dst_key_alg(key);
00246         sig.labels = dns_name_countlabels(name) - 1;
00247         if (dns_name_iswildcard(name))
00248                 sig.labels--;
00249         sig.originalttl = set->ttl;
00250         sig.timesigned = *inception;
00251         sig.timeexpire = *expire;
00252         sig.keyid = dst_key_id(key);
00253         ret = dst_key_sigsize(key, &sigsize);
00254         if (ret != ISC_R_SUCCESS)
00255                 return (ret);
00256         sig.siglen = sigsize;
00257         /*
00258          * The actual contents of sig.signature are not important yet, since
00259          * they're not used in digest_sig().
00260          */
00261         sig.signature = isc_mem_get(mctx, sig.siglen);
00262         if (sig.signature == NULL)
00263                 return (ISC_R_NOMEMORY);
00264 
00265         ret = isc_buffer_allocate(mctx, &databuf, sigsize + 256 + 18);
00266         if (ret != ISC_R_SUCCESS)
00267                 goto cleanup_signature;
00268 
00269         dns_rdata_init(&tmpsigrdata);
00270         ret = dns_rdata_fromstruct(&tmpsigrdata, sig.common.rdclass,
00271                                    sig.common.rdtype, &sig, databuf);
00272         if (ret != ISC_R_SUCCESS)
00273                 goto cleanup_databuf;
00274 
00275         ret = dst_context_create3(key, mctx,
00276                                   DNS_LOGCATEGORY_DNSSEC, ISC_TRUE, &ctx);
00277         if (ret != ISC_R_SUCCESS)
00278                 goto cleanup_databuf;
00279 
00280         /*
00281          * Digest the SIG rdata.
00282          */
00283         ret = digest_sig(ctx, ISC_FALSE, &tmpsigrdata, &sig);
00284         if (ret != ISC_R_SUCCESS)
00285                 goto cleanup_context;
00286 
00287         dns_fixedname_init(&fnewname);
00288         RUNTIME_CHECK(dns_name_downcase(name, dns_fixedname_name(&fnewname),
00289                                         NULL) == ISC_R_SUCCESS);
00290         dns_name_toregion(dns_fixedname_name(&fnewname), &r);
00291 
00292         /*
00293          * Create an envelope for each rdata: <name|type|class|ttl>.
00294          */
00295         isc_buffer_init(&envbuf, data, sizeof(data));
00296         memmove(data, r.base, r.length);
00297         isc_buffer_add(&envbuf, r.length);
00298         isc_buffer_putuint16(&envbuf, set->type);
00299         isc_buffer_putuint16(&envbuf, set->rdclass);
00300         isc_buffer_putuint32(&envbuf, set->ttl);
00301 
00302         ret = rdataset_to_sortedarray(set, mctx, &rdatas, &nrdatas);
00303         if (ret != ISC_R_SUCCESS)
00304                 goto cleanup_context;
00305         isc_buffer_usedregion(&envbuf, &r);
00306 
00307         for (i = 0; i < nrdatas; i++) {
00308                 isc_uint16_t len;
00309                 isc_buffer_t lenbuf;
00310                 isc_region_t lenr;
00311 
00312                 /*
00313                  * Skip duplicates.
00314                  */
00315                 if (i > 0 && dns_rdata_compare(&rdatas[i], &rdatas[i-1]) == 0)
00316                     continue;
00317 
00318                 /*
00319                  * Digest the envelope.
00320                  */
00321                 ret = dst_context_adddata(ctx, &r);
00322                 if (ret != ISC_R_SUCCESS)
00323                         goto cleanup_array;
00324 
00325                 /*
00326                  * Digest the length of the rdata.
00327                  */
00328                 isc_buffer_init(&lenbuf, &len, sizeof(len));
00329                 INSIST(rdatas[i].length < 65536);
00330                 isc_buffer_putuint16(&lenbuf, (isc_uint16_t)rdatas[i].length);
00331                 isc_buffer_usedregion(&lenbuf, &lenr);
00332                 ret = dst_context_adddata(ctx, &lenr);
00333                 if (ret != ISC_R_SUCCESS)
00334                         goto cleanup_array;
00335 
00336                 /*
00337                  * Digest the rdata.
00338                  */
00339                 ret = dns_rdata_digest(&rdatas[i], digest_callback, ctx);
00340                 if (ret != ISC_R_SUCCESS)
00341                         goto cleanup_array;
00342         }
00343 
00344         isc_buffer_init(&sigbuf, sig.signature, sig.siglen);
00345         ret = dst_context_sign(ctx, &sigbuf);
00346         if (ret != ISC_R_SUCCESS)
00347                 goto cleanup_array;
00348         isc_buffer_usedregion(&sigbuf, &r);
00349         if (r.length != sig.siglen) {
00350                 ret = ISC_R_NOSPACE;
00351                 goto cleanup_array;
00352         }
00353 
00354         ret = dns_rdata_fromstruct(sigrdata, sig.common.rdclass,
00355                                    sig.common.rdtype, &sig, buffer);
00356 
00357 cleanup_array:
00358         isc_mem_put(mctx, rdatas, nrdatas * sizeof(dns_rdata_t));
00359 cleanup_context:
00360         dst_context_destroy(&ctx);
00361 cleanup_databuf:
00362         isc_buffer_free(&databuf);
00363 cleanup_signature:
00364         isc_mem_put(mctx, sig.signature, sig.siglen);
00365 
00366         return (ret);
00367 }
00368 
00369 isc_result_t
00370 dns_dnssec_verify2(dns_name_t *name, dns_rdataset_t *set, dst_key_t *key,
00371                    isc_boolean_t ignoretime, isc_mem_t *mctx,
00372                    dns_rdata_t *sigrdata, dns_name_t *wild)
00373 {
00374         return (dns_dnssec_verify3(name, set, key, ignoretime, 0, mctx,
00375                                    sigrdata, wild));
00376 }
00377 
00378 isc_result_t
00379 dns_dnssec_verify3(dns_name_t *name, dns_rdataset_t *set, dst_key_t *key,
00380                    isc_boolean_t ignoretime, unsigned int maxbits,
00381                    isc_mem_t *mctx, dns_rdata_t *sigrdata, dns_name_t *wild)
00382 {
00383         dns_rdata_rrsig_t sig;
00384         dns_fixedname_t fnewname;
00385         isc_region_t r;
00386         isc_buffer_t envbuf;
00387         dns_rdata_t *rdatas;
00388         int nrdatas, i;
00389         isc_stdtime_t now;
00390         isc_result_t ret;
00391         unsigned char data[300];
00392         dst_context_t *ctx = NULL;
00393         int labels = 0;
00394         isc_uint32_t flags;
00395         isc_boolean_t downcase = ISC_FALSE;
00396 
00397         REQUIRE(name != NULL);
00398         REQUIRE(set != NULL);
00399         REQUIRE(key != NULL);
00400         REQUIRE(mctx != NULL);
00401         REQUIRE(sigrdata != NULL && sigrdata->type == dns_rdatatype_rrsig);
00402 
00403         ret = dns_rdata_tostruct(sigrdata, &sig, NULL);
00404         if (ret != ISC_R_SUCCESS)
00405                 return (ret);
00406 
00407         if (set->type != sig.covered)
00408                 return (DNS_R_SIGINVALID);
00409 
00410         if (isc_serial_lt(sig.timeexpire, sig.timesigned)) {
00411                 inc_stat(dns_dnssecstats_fail);
00412                 return (DNS_R_SIGINVALID);
00413         }
00414 
00415         if (!ignoretime) {
00416                 isc_stdtime_get(&now);
00417 
00418                 /*
00419                  * Is SIG temporally valid?
00420                  */
00421                 if (isc_serial_lt((isc_uint32_t)now, sig.timesigned)) {
00422                         inc_stat(dns_dnssecstats_fail);
00423                         return (DNS_R_SIGFUTURE);
00424                 } else if (isc_serial_lt(sig.timeexpire, (isc_uint32_t)now)) {
00425                         inc_stat(dns_dnssecstats_fail);
00426                         return (DNS_R_SIGEXPIRED);
00427                 }
00428         }
00429 
00430         /*
00431          * NS, SOA and DNSSKEY records are signed by their owner.
00432          * DS records are signed by the parent.
00433          */
00434         switch (set->type) {
00435         case dns_rdatatype_ns:
00436         case dns_rdatatype_soa:
00437         case dns_rdatatype_dnskey:
00438                 if (!dns_name_equal(name, &sig.signer)) {
00439                         inc_stat(dns_dnssecstats_fail);
00440                         return (DNS_R_SIGINVALID);
00441                 }
00442                 break;
00443         case dns_rdatatype_ds:
00444                 if (dns_name_equal(name, &sig.signer)) {
00445                         inc_stat(dns_dnssecstats_fail);
00446                         return (DNS_R_SIGINVALID);
00447                 }
00448                 /* FALLTHROUGH */
00449         default:
00450                 if (!dns_name_issubdomain(name, &sig.signer)) {
00451                         inc_stat(dns_dnssecstats_fail);
00452                         return (DNS_R_SIGINVALID);
00453                 }
00454                 break;
00455         }
00456 
00457         /*
00458          * Is the key allowed to sign data?
00459          */
00460         flags = dst_key_flags(key);
00461         if (flags & DNS_KEYTYPE_NOAUTH) {
00462                 inc_stat(dns_dnssecstats_fail);
00463                 return (DNS_R_KEYUNAUTHORIZED);
00464         }
00465         if ((flags & DNS_KEYFLAG_OWNERMASK) != DNS_KEYOWNER_ZONE) {
00466                 inc_stat(dns_dnssecstats_fail);
00467                 return (DNS_R_KEYUNAUTHORIZED);
00468         }
00469 
00470  again:
00471         ret = dst_context_create4(key, mctx, DNS_LOGCATEGORY_DNSSEC,
00472                                   ISC_FALSE, maxbits, &ctx);
00473         if (ret != ISC_R_SUCCESS)
00474                 goto cleanup_struct;
00475 
00476         /*
00477          * Digest the SIG rdata (not including the signature).
00478          */
00479         ret = digest_sig(ctx, downcase, sigrdata, &sig);
00480         if (ret != ISC_R_SUCCESS)
00481                 goto cleanup_context;
00482 
00483         /*
00484          * If the name is an expanded wildcard, use the wildcard name.
00485          */
00486         dns_fixedname_init(&fnewname);
00487         labels = dns_name_countlabels(name) - 1;
00488         RUNTIME_CHECK(dns_name_downcase(name, dns_fixedname_name(&fnewname),
00489                                         NULL) == ISC_R_SUCCESS);
00490         if (labels - sig.labels > 0)
00491                 dns_name_split(dns_fixedname_name(&fnewname), sig.labels + 1,
00492                                NULL, dns_fixedname_name(&fnewname));
00493 
00494         dns_name_toregion(dns_fixedname_name(&fnewname), &r);
00495 
00496         /*
00497          * Create an envelope for each rdata: <name|type|class|ttl>.
00498          */
00499         isc_buffer_init(&envbuf, data, sizeof(data));
00500         if (labels - sig.labels > 0) {
00501                 isc_buffer_putuint8(&envbuf, 1);
00502                 isc_buffer_putuint8(&envbuf, '*');
00503                 memmove(data + 2, r.base, r.length);
00504         }
00505         else
00506                 memmove(data, r.base, r.length);
00507         isc_buffer_add(&envbuf, r.length);
00508         isc_buffer_putuint16(&envbuf, set->type);
00509         isc_buffer_putuint16(&envbuf, set->rdclass);
00510         isc_buffer_putuint32(&envbuf, sig.originalttl);
00511 
00512         ret = rdataset_to_sortedarray(set, mctx, &rdatas, &nrdatas);
00513         if (ret != ISC_R_SUCCESS)
00514                 goto cleanup_context;
00515 
00516         isc_buffer_usedregion(&envbuf, &r);
00517 
00518         for (i = 0; i < nrdatas; i++) {
00519                 isc_uint16_t len;
00520                 isc_buffer_t lenbuf;
00521                 isc_region_t lenr;
00522 
00523                 /*
00524                  * Skip duplicates.
00525                  */
00526                 if (i > 0 && dns_rdata_compare(&rdatas[i], &rdatas[i-1]) == 0)
00527                     continue;
00528 
00529                 /*
00530                  * Digest the envelope.
00531                  */
00532                 ret = dst_context_adddata(ctx, &r);
00533                 if (ret != ISC_R_SUCCESS)
00534                         goto cleanup_array;
00535 
00536                 /*
00537                  * Digest the rdata length.
00538                  */
00539                 isc_buffer_init(&lenbuf, &len, sizeof(len));
00540                 INSIST(rdatas[i].length < 65536);
00541                 isc_buffer_putuint16(&lenbuf, (isc_uint16_t)rdatas[i].length);
00542                 isc_buffer_usedregion(&lenbuf, &lenr);
00543 
00544                 /*
00545                  * Digest the rdata.
00546                  */
00547                 ret = dst_context_adddata(ctx, &lenr);
00548                 if (ret != ISC_R_SUCCESS)
00549                         goto cleanup_array;
00550                 ret = dns_rdata_digest(&rdatas[i], digest_callback, ctx);
00551                 if (ret != ISC_R_SUCCESS)
00552                         goto cleanup_array;
00553         }
00554 
00555         r.base = sig.signature;
00556         r.length = sig.siglen;
00557         ret = dst_context_verify2(ctx, maxbits, &r);
00558         if (ret == ISC_R_SUCCESS && downcase) {
00559                 char namebuf[DNS_NAME_FORMATSIZE];
00560                 dns_name_format(&sig.signer, namebuf, sizeof(namebuf));
00561                 isc_log_write(dns_lctx, DNS_LOGCATEGORY_DNSSEC,
00562                               DNS_LOGMODULE_DNSSEC, ISC_LOG_DEBUG(1),
00563                               "successfully validated after lower casing "
00564                               "signer '%s'", namebuf);
00565                 inc_stat(dns_dnssecstats_downcase);
00566         } else if (ret == ISC_R_SUCCESS)
00567                 inc_stat(dns_dnssecstats_asis);
00568 
00569 cleanup_array:
00570         isc_mem_put(mctx, rdatas, nrdatas * sizeof(dns_rdata_t));
00571 cleanup_context:
00572         dst_context_destroy(&ctx);
00573         if (ret == DST_R_VERIFYFAILURE && !downcase) {
00574                 downcase = ISC_TRUE;
00575                 goto again;
00576         }
00577 cleanup_struct:
00578         dns_rdata_freestruct(&sig);
00579 
00580         if (ret == DST_R_VERIFYFAILURE)
00581                 ret = DNS_R_SIGINVALID;
00582 
00583         if (ret != ISC_R_SUCCESS)
00584                 inc_stat(dns_dnssecstats_fail);
00585 
00586         if (ret == ISC_R_SUCCESS && labels - sig.labels > 0) {
00587                 if (wild != NULL)
00588                         RUNTIME_CHECK(dns_name_concatenate(dns_wildcardname,
00589                                                  dns_fixedname_name(&fnewname),
00590                                                  wild, NULL) == ISC_R_SUCCESS);
00591                 inc_stat(dns_dnssecstats_wildcard);
00592                 ret = DNS_R_FROMWILDCARD;
00593         }
00594         return (ret);
00595 }
00596 
00597 isc_result_t
00598 dns_dnssec_verify(dns_name_t *name, dns_rdataset_t *set, dst_key_t *key,
00599                   isc_boolean_t ignoretime, isc_mem_t *mctx,
00600                   dns_rdata_t *sigrdata)
00601 {
00602         isc_result_t result;
00603 
00604         result = dns_dnssec_verify2(name, set, key, ignoretime, mctx,
00605                                     sigrdata, NULL);
00606         if (result == DNS_R_FROMWILDCARD)
00607                 result = ISC_R_SUCCESS;
00608         return (result);
00609 }
00610 
00611 isc_boolean_t
00612 dns_dnssec_keyactive(dst_key_t *key, isc_stdtime_t now) {
00613         isc_result_t result;
00614         isc_stdtime_t publish, active, revoke, inactive, delete;
00615         isc_boolean_t pubset = ISC_FALSE, actset = ISC_FALSE;
00616         isc_boolean_t revset = ISC_FALSE, inactset = ISC_FALSE;
00617         isc_boolean_t delset = ISC_FALSE;
00618         int major, minor;
00619 
00620         /* Is this an old-style key? */
00621         result = dst_key_getprivateformat(key, &major, &minor);
00622         RUNTIME_CHECK(result == ISC_R_SUCCESS);
00623 
00624         /*
00625          * Smart signing started with key format 1.3; prior to that, all
00626          * keys are assumed active
00627          */
00628         if (major == 1 && minor <= 2)
00629                 return (ISC_TRUE);
00630 
00631         result = dst_key_gettime(key, DST_TIME_PUBLISH, &publish);
00632         if (result == ISC_R_SUCCESS)
00633                 pubset = ISC_TRUE;
00634 
00635         result = dst_key_gettime(key, DST_TIME_ACTIVATE, &active);
00636         if (result == ISC_R_SUCCESS)
00637                 actset = ISC_TRUE;
00638 
00639         result = dst_key_gettime(key, DST_TIME_REVOKE, &revoke);
00640         if (result == ISC_R_SUCCESS)
00641                 revset = ISC_TRUE;
00642 
00643         result = dst_key_gettime(key, DST_TIME_INACTIVE, &inactive);
00644         if (result == ISC_R_SUCCESS)
00645                 inactset = ISC_TRUE;
00646 
00647         result = dst_key_gettime(key, DST_TIME_DELETE, &delete);
00648         if (result == ISC_R_SUCCESS)
00649                 delset = ISC_TRUE;
00650 
00651         if ((inactset && inactive <= now) || (delset && delete <= now))
00652                 return (ISC_FALSE);
00653 
00654         if (revset && revoke <= now && pubset && publish <= now)
00655                 return (ISC_TRUE);
00656 
00657         if (actset && active <= now)
00658                 return (ISC_TRUE);
00659 
00660         return (ISC_FALSE);
00661 }
00662 
00663 #define is_zone_key(key) ((dst_key_flags(key) & DNS_KEYFLAG_OWNERMASK) \
00664                           == DNS_KEYOWNER_ZONE)
00665 
00666 isc_result_t
00667 dns_dnssec_findzonekeys2(dns_db_t *db, dns_dbversion_t *ver,
00668                          dns_dbnode_t *node, dns_name_t *name,
00669                          const char *directory, isc_mem_t *mctx,
00670                          unsigned int maxkeys, dst_key_t **keys,
00671                          unsigned int *nkeys)
00672 {
00673         dns_rdataset_t rdataset;
00674         dns_rdata_t rdata = DNS_RDATA_INIT;
00675         isc_result_t result;
00676         dst_key_t *pubkey = NULL;
00677         unsigned int count = 0;
00678         isc_stdtime_t now;
00679 
00680         REQUIRE(nkeys != NULL);
00681         REQUIRE(keys != NULL);
00682 
00683         isc_stdtime_get(&now);
00684 
00685         *nkeys = 0;
00686         memset(keys, 0, sizeof(*keys) * maxkeys);
00687         dns_rdataset_init(&rdataset);
00688         RETERR(dns_db_findrdataset(db, node, ver, dns_rdatatype_dnskey, 0, 0,
00689                                    &rdataset, NULL));
00690         RETERR(dns_rdataset_first(&rdataset));
00691         while (result == ISC_R_SUCCESS && count < maxkeys) {
00692                 pubkey = NULL;
00693                 dns_rdataset_current(&rdataset, &rdata);
00694                 RETERR(dns_dnssec_keyfromrdata(name, &rdata, mctx, &pubkey));
00695                 dst_key_setttl(pubkey, rdataset.ttl);
00696 
00697                 if (!is_zone_key(pubkey) ||
00698                     (dst_key_flags(pubkey) & DNS_KEYTYPE_NOAUTH) != 0)
00699                         goto next;
00700                 /* Corrupted .key file? */
00701                 if (!dns_name_equal(name, dst_key_name(pubkey)))
00702                         goto next;
00703                 keys[count] = NULL;
00704                 result = dst_key_fromfile(dst_key_name(pubkey),
00705                                           dst_key_id(pubkey),
00706                                           dst_key_alg(pubkey),
00707                                           DST_TYPE_PUBLIC|DST_TYPE_PRIVATE,
00708                                           directory,
00709                                           mctx, &keys[count]);
00710 
00711                 /*
00712                  * If the key was revoked and the private file
00713                  * doesn't exist, maybe it was revoked internally
00714                  * by named.  Try loading the unrevoked version.
00715                  */
00716                 if (result == ISC_R_FILENOTFOUND) {
00717                         isc_uint32_t flags;
00718                         flags = dst_key_flags(pubkey);
00719                         if ((flags & DNS_KEYFLAG_REVOKE) != 0) {
00720                                 dst_key_setflags(pubkey,
00721                                                  flags & ~DNS_KEYFLAG_REVOKE);
00722                                 result = dst_key_fromfile(dst_key_name(pubkey),
00723                                                           dst_key_id(pubkey),
00724                                                           dst_key_alg(pubkey),
00725                                                           DST_TYPE_PUBLIC|
00726                                                           DST_TYPE_PRIVATE,
00727                                                           directory,
00728                                                           mctx, &keys[count]);
00729                                 if (result == ISC_R_SUCCESS &&
00730                                     dst_key_pubcompare(pubkey, keys[count],
00731                                                        ISC_FALSE)) {
00732                                         dst_key_setflags(keys[count], flags);
00733                                 }
00734                                 dst_key_setflags(pubkey, flags);
00735                         }
00736                 }
00737 
00738                 if (result != ISC_R_SUCCESS) {
00739                         char filename[ISC_DIR_NAMEMAX];
00740                         isc_result_t result2;
00741                         isc_buffer_t buf;
00742 
00743                         isc_buffer_init(&buf, filename, ISC_DIR_NAMEMAX);
00744                         result2 = dst_key_getfilename(dst_key_name(pubkey),
00745                                                       dst_key_id(pubkey),
00746                                                       dst_key_alg(pubkey),
00747                                                       (DST_TYPE_PUBLIC |
00748                                                        DST_TYPE_PRIVATE),
00749                                                       directory, mctx,
00750                                                       &buf);
00751                         if (result2 != ISC_R_SUCCESS) {
00752                                 char namebuf[DNS_NAME_FORMATSIZE];
00753                                 char algbuf[DNS_SECALG_FORMATSIZE];
00754 
00755                                 dns_name_format(dst_key_name(pubkey),
00756                                                 namebuf, sizeof(namebuf));
00757                                 dns_secalg_format(dst_key_alg(pubkey),
00758                                                   algbuf, sizeof(algbuf));
00759                                 snprintf(filename, sizeof(filename) - 1,
00760                                          "key file for %s/%s/%d",
00761                                          namebuf, algbuf, dst_key_id(pubkey));
00762                         }
00763 
00764                         isc_log_write(dns_lctx, DNS_LOGCATEGORY_GENERAL,
00765                                       DNS_LOGMODULE_DNSSEC, ISC_LOG_WARNING,
00766                                       "dns_dnssec_findzonekeys2: error "
00767                                       "reading %s: %s",
00768                                       filename, isc_result_totext(result));
00769                 }
00770 
00771                 if (result == ISC_R_FILENOTFOUND || result == ISC_R_NOPERM) {
00772                         keys[count] = pubkey;
00773                         pubkey = NULL;
00774                         count++;
00775                         goto next;
00776                 }
00777 
00778                 if (result != ISC_R_SUCCESS)
00779                         goto failure;
00780 
00781                 /*
00782                  * If a key is marked inactive, skip it
00783                  */
00784                 if (!dns_dnssec_keyactive(keys[count], now)) {
00785                         dst_key_setinactive(pubkey, ISC_TRUE);
00786                         dst_key_free(&keys[count]);
00787                         keys[count] = pubkey;
00788                         pubkey = NULL;
00789                         count++;
00790                         goto next;
00791                 }
00792 
00793                 /*
00794                  * Whatever the key's default TTL may have
00795                  * been, the rdataset TTL takes priority.
00796                  */
00797                 dst_key_setttl(keys[count], rdataset.ttl);
00798 
00799                 if ((dst_key_flags(keys[count]) & DNS_KEYTYPE_NOAUTH) != 0) {
00800                         /* We should never get here. */
00801                         dst_key_free(&keys[count]);
00802                         goto next;
00803                 }
00804                 count++;
00805  next:
00806                 if (pubkey != NULL)
00807                         dst_key_free(&pubkey);
00808                 dns_rdata_reset(&rdata);
00809                 result = dns_rdataset_next(&rdataset);
00810         }
00811         if (result != ISC_R_NOMORE)
00812                 goto failure;
00813         if (count == 0)
00814                 result = ISC_R_NOTFOUND;
00815         else
00816                 result = ISC_R_SUCCESS;
00817 
00818  failure:
00819         if (dns_rdataset_isassociated(&rdataset))
00820                 dns_rdataset_disassociate(&rdataset);
00821         if (pubkey != NULL)
00822                 dst_key_free(&pubkey);
00823         if (result != ISC_R_SUCCESS)
00824                 while (count > 0)
00825                         dst_key_free(&keys[--count]);
00826         *nkeys = count;
00827         return (result);
00828 }
00829 
00830 isc_result_t
00831 dns_dnssec_findzonekeys(dns_db_t *db, dns_dbversion_t *ver,
00832                         dns_dbnode_t *node, dns_name_t *name, isc_mem_t *mctx,
00833                         unsigned int maxkeys, dst_key_t **keys,
00834                         unsigned int *nkeys)
00835 {
00836         return (dns_dnssec_findzonekeys2(db, ver, node, name, NULL, mctx,
00837                                          maxkeys, keys, nkeys));
00838 }
00839 
00840 isc_result_t
00841 dns_dnssec_signmessage(dns_message_t *msg, dst_key_t *key) {
00842         dns_rdata_sig_t sig;    /* SIG(0) */
00843         unsigned char data[512];
00844         unsigned char header[DNS_MESSAGE_HEADERLEN];
00845         isc_buffer_t headerbuf, databuf, sigbuf;
00846         unsigned int sigsize;
00847         isc_buffer_t *dynbuf = NULL;
00848         dns_rdata_t *rdata;
00849         dns_rdatalist_t *datalist;
00850         dns_rdataset_t *dataset;
00851         isc_region_t r;
00852         isc_stdtime_t now;
00853         dst_context_t *ctx = NULL;
00854         isc_mem_t *mctx;
00855         isc_result_t result;
00856         isc_boolean_t signeedsfree = ISC_TRUE;
00857 
00858         REQUIRE(msg != NULL);
00859         REQUIRE(key != NULL);
00860 
00861         if (is_response(msg))
00862                 REQUIRE(msg->query.base != NULL);
00863 
00864         mctx = msg->mctx;
00865 
00866         memset(&sig, 0, sizeof(sig));
00867 
00868         sig.mctx = mctx;
00869         sig.common.rdclass = dns_rdataclass_any;
00870         sig.common.rdtype = dns_rdatatype_sig;  /* SIG(0) */
00871         ISC_LINK_INIT(&sig.common, link);
00872 
00873         sig.covered = 0;
00874         sig.algorithm = dst_key_alg(key);
00875         sig.labels = 0; /* the root name */
00876         sig.originalttl = 0;
00877 
00878         isc_stdtime_get(&now);
00879         sig.timesigned = now - DNS_TSIG_FUDGE;
00880         sig.timeexpire = now + DNS_TSIG_FUDGE;
00881 
00882         sig.keyid = dst_key_id(key);
00883 
00884         dns_name_init(&sig.signer, NULL);
00885         dns_name_clone(dst_key_name(key), &sig.signer);
00886 
00887         sig.siglen = 0;
00888         sig.signature = NULL;
00889 
00890         isc_buffer_init(&databuf, data, sizeof(data));
00891 
00892         RETERR(dst_context_create3(key, mctx,
00893                                    DNS_LOGCATEGORY_DNSSEC, ISC_TRUE, &ctx));
00894 
00895         /*
00896          * Digest the fields of the SIG - we can cheat and use
00897          * dns_rdata_fromstruct.  Since siglen is 0, the digested data
00898          * is identical to dns format.
00899          */
00900         RETERR(dns_rdata_fromstruct(NULL, dns_rdataclass_any,
00901                                     dns_rdatatype_sig /* SIG(0) */,
00902                                     &sig, &databuf));
00903         isc_buffer_usedregion(&databuf, &r);
00904         RETERR(dst_context_adddata(ctx, &r));
00905 
00906         /*
00907          * If this is a response, digest the query.
00908          */
00909         if (is_response(msg))
00910                 RETERR(dst_context_adddata(ctx, &msg->query));
00911 
00912         /*
00913          * Digest the header.
00914          */
00915         isc_buffer_init(&headerbuf, header, sizeof(header));
00916         dns_message_renderheader(msg, &headerbuf);
00917         isc_buffer_usedregion(&headerbuf, &r);
00918         RETERR(dst_context_adddata(ctx, &r));
00919 
00920         /*
00921          * Digest the remainder of the message.
00922          */
00923         isc_buffer_usedregion(msg->buffer, &r);
00924         isc_region_consume(&r, DNS_MESSAGE_HEADERLEN);
00925         RETERR(dst_context_adddata(ctx, &r));
00926 
00927         RETERR(dst_key_sigsize(key, &sigsize));
00928         sig.siglen = sigsize;
00929         sig.signature = (unsigned char *) isc_mem_get(mctx, sig.siglen);
00930         if (sig.signature == NULL) {
00931                 result = ISC_R_NOMEMORY;
00932                 goto failure;
00933         }
00934 
00935         isc_buffer_init(&sigbuf, sig.signature, sig.siglen);
00936         RETERR(dst_context_sign(ctx, &sigbuf));
00937         dst_context_destroy(&ctx);
00938 
00939         rdata = NULL;
00940         RETERR(dns_message_gettemprdata(msg, &rdata));
00941         RETERR(isc_buffer_allocate(msg->mctx, &dynbuf, 1024));
00942         RETERR(dns_rdata_fromstruct(rdata, dns_rdataclass_any,
00943                                     dns_rdatatype_sig /* SIG(0) */,
00944                                     &sig, dynbuf));
00945 
00946         isc_mem_put(mctx, sig.signature, sig.siglen);
00947         signeedsfree = ISC_FALSE;
00948 
00949         dns_message_takebuffer(msg, &dynbuf);
00950 
00951         datalist = NULL;
00952         RETERR(dns_message_gettemprdatalist(msg, &datalist));
00953         datalist->rdclass = dns_rdataclass_any;
00954         datalist->type = dns_rdatatype_sig;     /* SIG(0) */
00955         ISC_LIST_APPEND(datalist->rdata, rdata, link);
00956         dataset = NULL;
00957         RETERR(dns_message_gettemprdataset(msg, &dataset));
00958         dns_rdataset_init(dataset);
00959         RUNTIME_CHECK(dns_rdatalist_tordataset(datalist, dataset) == ISC_R_SUCCESS);
00960         msg->sig0 = dataset;
00961 
00962         return (ISC_R_SUCCESS);
00963 
00964 failure:
00965         if (dynbuf != NULL)
00966                 isc_buffer_free(&dynbuf);
00967         if (signeedsfree)
00968                 isc_mem_put(mctx, sig.signature, sig.siglen);
00969         if (ctx != NULL)
00970                 dst_context_destroy(&ctx);
00971 
00972         return (result);
00973 }
00974 
00975 isc_result_t
00976 dns_dnssec_verifymessage(isc_buffer_t *source, dns_message_t *msg,
00977                          dst_key_t *key)
00978 {
00979         dns_rdata_sig_t sig;    /* SIG(0) */
00980         unsigned char header[DNS_MESSAGE_HEADERLEN];
00981         dns_rdata_t rdata = DNS_RDATA_INIT;
00982         isc_region_t r, source_r, sig_r, header_r;
00983         isc_stdtime_t now;
00984         dst_context_t *ctx = NULL;
00985         isc_mem_t *mctx;
00986         isc_result_t result;
00987         isc_uint16_t addcount, addcount_n;
00988         isc_boolean_t signeedsfree = ISC_FALSE;
00989 
00990         REQUIRE(source != NULL);
00991         REQUIRE(msg != NULL);
00992         REQUIRE(key != NULL);
00993 
00994         mctx = msg->mctx;
00995 
00996         msg->verify_attempted = 1;
00997 
00998         if (is_response(msg)) {
00999                 if (msg->query.base == NULL)
01000                         return (DNS_R_UNEXPECTEDTSIG);
01001         }
01002 
01003         isc_buffer_usedregion(source, &source_r);
01004 
01005         RETERR(dns_rdataset_first(msg->sig0));
01006         dns_rdataset_current(msg->sig0, &rdata);
01007 
01008         RETERR(dns_rdata_tostruct(&rdata, &sig, NULL));
01009         signeedsfree = ISC_TRUE;
01010 
01011         if (sig.labels != 0) {
01012                 result = DNS_R_SIGINVALID;
01013                 goto failure;
01014         }
01015 
01016         if (isc_serial_lt(sig.timeexpire, sig.timesigned)) {
01017                 result = DNS_R_SIGINVALID;
01018                 msg->sig0status = dns_tsigerror_badtime;
01019                 goto failure;
01020         }
01021 
01022         isc_stdtime_get(&now);
01023         if (isc_serial_lt((isc_uint32_t)now, sig.timesigned)) {
01024                 result = DNS_R_SIGFUTURE;
01025                 msg->sig0status = dns_tsigerror_badtime;
01026                 goto failure;
01027         }
01028         else if (isc_serial_lt(sig.timeexpire, (isc_uint32_t)now)) {
01029                 result = DNS_R_SIGEXPIRED;
01030                 msg->sig0status = dns_tsigerror_badtime;
01031                 goto failure;
01032         }
01033 
01034         if (!dns_name_equal(dst_key_name(key), &sig.signer)) {
01035                 result = DNS_R_SIGINVALID;
01036                 msg->sig0status = dns_tsigerror_badkey;
01037                 goto failure;
01038         }
01039 
01040         RETERR(dst_context_create3(key, mctx,
01041                                    DNS_LOGCATEGORY_DNSSEC, ISC_FALSE, &ctx));
01042 
01043         /*
01044          * Digest the SIG(0) record, except for the signature.
01045          */
01046         dns_rdata_toregion(&rdata, &r);
01047         r.length -= sig.siglen;
01048         RETERR(dst_context_adddata(ctx, &r));
01049 
01050         /*
01051          * If this is a response, digest the query.
01052          */
01053         if (is_response(msg))
01054                 RETERR(dst_context_adddata(ctx, &msg->query));
01055 
01056         /*
01057          * Extract the header.
01058          */
01059         memmove(header, source_r.base, DNS_MESSAGE_HEADERLEN);
01060 
01061         /*
01062          * Decrement the additional field counter.
01063          */
01064         memmove(&addcount, &header[DNS_MESSAGE_HEADERLEN - 2], 2);
01065         addcount_n = ntohs(addcount);
01066         addcount = htons((isc_uint16_t)(addcount_n - 1));
01067         memmove(&header[DNS_MESSAGE_HEADERLEN - 2], &addcount, 2);
01068 
01069         /*
01070          * Digest the modified header.
01071          */
01072         header_r.base = (unsigned char *) header;
01073         header_r.length = DNS_MESSAGE_HEADERLEN;
01074         RETERR(dst_context_adddata(ctx, &header_r));
01075 
01076         /*
01077          * Digest all non-SIG(0) records.
01078          */
01079         r.base = source_r.base + DNS_MESSAGE_HEADERLEN;
01080         r.length = msg->sigstart - DNS_MESSAGE_HEADERLEN;
01081         RETERR(dst_context_adddata(ctx, &r));
01082 
01083         sig_r.base = sig.signature;
01084         sig_r.length = sig.siglen;
01085         result = dst_context_verify(ctx, &sig_r);
01086         if (result != ISC_R_SUCCESS) {
01087                 msg->sig0status = dns_tsigerror_badsig;
01088                 goto failure;
01089         }
01090 
01091         msg->verified_sig = 1;
01092 
01093         dst_context_destroy(&ctx);
01094         dns_rdata_freestruct(&sig);
01095 
01096         return (ISC_R_SUCCESS);
01097 
01098 failure:
01099         if (signeedsfree)
01100                 dns_rdata_freestruct(&sig);
01101         if (ctx != NULL)
01102                 dst_context_destroy(&ctx);
01103 
01104         return (result);
01105 }
01106 
01107 /*%
01108  * Does this key ('rdata') self sign the rrset ('rdataset')?
01109  */
01110 isc_boolean_t
01111 dns_dnssec_selfsigns(dns_rdata_t *rdata, dns_name_t *name,
01112                      dns_rdataset_t *rdataset, dns_rdataset_t *sigrdataset,
01113                      isc_boolean_t ignoretime, isc_mem_t *mctx)
01114 {
01115         INSIST(rdataset->type == dns_rdatatype_key ||
01116                rdataset->type == dns_rdatatype_dnskey);
01117         if (rdataset->type == dns_rdatatype_key) {
01118                 INSIST(sigrdataset->type == dns_rdatatype_sig);
01119                 INSIST(sigrdataset->covers == dns_rdatatype_key);
01120         } else {
01121                 INSIST(sigrdataset->type == dns_rdatatype_rrsig);
01122                 INSIST(sigrdataset->covers == dns_rdatatype_dnskey);
01123         }
01124 
01125         return (dns_dnssec_signs(rdata, name, rdataset, sigrdataset,
01126                                  ignoretime, mctx));
01127 
01128 }
01129 
01130 isc_boolean_t
01131 dns_dnssec_signs(dns_rdata_t *rdata, dns_name_t *name,
01132                      dns_rdataset_t *rdataset, dns_rdataset_t *sigrdataset,
01133                      isc_boolean_t ignoretime, isc_mem_t *mctx)
01134 {
01135         dst_key_t *dstkey = NULL;
01136         dns_keytag_t keytag;
01137         dns_rdata_dnskey_t key;
01138         dns_rdata_rrsig_t sig;
01139         dns_rdata_t sigrdata = DNS_RDATA_INIT;
01140         isc_result_t result;
01141 
01142         INSIST(sigrdataset->type == dns_rdatatype_rrsig);
01143         if (sigrdataset->covers != rdataset->type)
01144                 return (ISC_FALSE);
01145 
01146         result = dns_dnssec_keyfromrdata(name, rdata, mctx, &dstkey);
01147         if (result != ISC_R_SUCCESS)
01148                 return (ISC_FALSE);
01149         result = dns_rdata_tostruct(rdata, &key, NULL);
01150         RUNTIME_CHECK(result == ISC_R_SUCCESS);
01151 
01152         keytag = dst_key_id(dstkey);
01153         for (result = dns_rdataset_first(sigrdataset);
01154              result == ISC_R_SUCCESS;
01155              result = dns_rdataset_next(sigrdataset))
01156         {
01157                 dns_rdata_reset(&sigrdata);
01158                 dns_rdataset_current(sigrdataset, &sigrdata);
01159                 result = dns_rdata_tostruct(&sigrdata, &sig, NULL);
01160                 RUNTIME_CHECK(result == ISC_R_SUCCESS);
01161 
01162                 if (sig.algorithm == key.algorithm &&
01163                     sig.keyid == keytag) {
01164                         result = dns_dnssec_verify2(name, rdataset, dstkey,
01165                                                     ignoretime, mctx,
01166                                                     &sigrdata, NULL);
01167                         if (result == ISC_R_SUCCESS) {
01168                                 dst_key_free(&dstkey);
01169                                 return (ISC_TRUE);
01170                         }
01171                 }
01172         }
01173         dst_key_free(&dstkey);
01174         return (ISC_FALSE);
01175 }
01176 
01177 isc_result_t
01178 dns_dnsseckey_create(isc_mem_t *mctx, dst_key_t **dstkey,
01179                      dns_dnsseckey_t **dkp)
01180 {
01181         isc_result_t result;
01182         dns_dnsseckey_t *dk;
01183         int major, minor;
01184 
01185         REQUIRE(dkp != NULL && *dkp == NULL);
01186         dk = isc_mem_get(mctx, sizeof(dns_dnsseckey_t));
01187         if (dk == NULL)
01188                 return (ISC_R_NOMEMORY);
01189 
01190         dk->key = *dstkey;
01191         *dstkey = NULL;
01192         dk->force_publish = ISC_FALSE;
01193         dk->force_sign = ISC_FALSE;
01194         dk->hint_publish = ISC_FALSE;
01195         dk->hint_sign = ISC_FALSE;
01196         dk->hint_remove = ISC_FALSE;
01197         dk->first_sign = ISC_FALSE;
01198         dk->is_active = ISC_FALSE;
01199         dk->prepublish = 0;
01200         dk->source = dns_keysource_unknown;
01201         dk->index = 0;
01202 
01203         /* KSK or ZSK? */
01204         dk->ksk = ISC_TF((dst_key_flags(dk->key) & DNS_KEYFLAG_KSK) != 0);
01205 
01206         /* Is this an old-style key? */
01207         result = dst_key_getprivateformat(dk->key, &major, &minor);
01208         INSIST(result == ISC_R_SUCCESS);
01209 
01210         /* Smart signing started with key format 1.3 */
01211         dk->legacy = ISC_TF(major == 1 && minor <= 2);
01212 
01213         ISC_LINK_INIT(dk, link);
01214         *dkp = dk;
01215         return (ISC_R_SUCCESS);
01216 }
01217 
01218 void
01219 dns_dnsseckey_destroy(isc_mem_t *mctx, dns_dnsseckey_t **dkp) {
01220         dns_dnsseckey_t *dk;
01221 
01222         REQUIRE(dkp != NULL && *dkp != NULL);
01223         dk = *dkp;
01224         if (dk->key != NULL)
01225                 dst_key_free(&dk->key);
01226         isc_mem_put(mctx, dk, sizeof(dns_dnsseckey_t));
01227         *dkp = NULL;
01228 }
01229 
01230 static void
01231 get_hints(dns_dnsseckey_t *key, isc_stdtime_t now) {
01232         isc_result_t result;
01233         isc_stdtime_t publish, active, revoke, inactive, delete;
01234         isc_boolean_t pubset = ISC_FALSE, actset = ISC_FALSE;
01235         isc_boolean_t revset = ISC_FALSE, inactset = ISC_FALSE;
01236         isc_boolean_t delset = ISC_FALSE;
01237 
01238         REQUIRE(key != NULL && key->key != NULL);
01239 
01240         result = dst_key_gettime(key->key, DST_TIME_PUBLISH, &publish);
01241         if (result == ISC_R_SUCCESS)
01242                 pubset = ISC_TRUE;
01243 
01244         result = dst_key_gettime(key->key, DST_TIME_ACTIVATE, &active);
01245         if (result == ISC_R_SUCCESS)
01246                 actset = ISC_TRUE;
01247 
01248         result = dst_key_gettime(key->key, DST_TIME_REVOKE, &revoke);
01249         if (result == ISC_R_SUCCESS)
01250                 revset = ISC_TRUE;
01251 
01252         result = dst_key_gettime(key->key, DST_TIME_INACTIVE, &inactive);
01253         if (result == ISC_R_SUCCESS)
01254                 inactset = ISC_TRUE;
01255 
01256         result = dst_key_gettime(key->key, DST_TIME_DELETE, &delete);
01257         if (result == ISC_R_SUCCESS)
01258                 delset = ISC_TRUE;
01259 
01260         /* Metadata says publish (but possibly not activate) */
01261         if (pubset && publish <= now)
01262                 key->hint_publish = ISC_TRUE;
01263 
01264         /* Metadata says activate (so we must also publish) */
01265         if (actset && active <= now) {
01266                 key->hint_sign = ISC_TRUE;
01267 
01268                 /* Only publish if publish time has already passed. */
01269                 if (pubset && publish <= now)
01270                         key->hint_publish = ISC_TRUE;
01271         }
01272 
01273         /*
01274          * Activation date is set (maybe in the future), but
01275          * publication date isn't. Most likely the user wants to
01276          * publish now and activate later.
01277          */
01278         if (actset && !pubset)
01279                 key->hint_publish = ISC_TRUE;
01280 
01281         /*
01282          * If activation date is in the future, make note of how far off
01283          */
01284         if (key->hint_publish && actset && active > now) {
01285                 key->prepublish = active - now;
01286         }
01287 
01288         /*
01289          * Key has been marked inactive: we can continue publishing,
01290          * but don't sign.
01291          */
01292         if (key->hint_publish && inactset && inactive <= now) {
01293                 key->hint_sign = ISC_FALSE;
01294         }
01295 
01296         /*
01297          * Metadata says revoke.  If the key is published,
01298          * we *have to* sign with it per RFC5011--even if it was
01299          * not active before.
01300          *
01301          * If it hasn't already been done, we should also revoke it now.
01302          */
01303         if (key->hint_publish && (revset && revoke <= now)) {
01304                 isc_uint32_t flags;
01305                 key->hint_sign = ISC_TRUE;
01306                 flags = dst_key_flags(key->key);
01307                 if ((flags & DNS_KEYFLAG_REVOKE) == 0) {
01308                         flags |= DNS_KEYFLAG_REVOKE;
01309                         dst_key_setflags(key->key, flags);
01310                 }
01311         }
01312 
01313         /*
01314          * Metadata says delete, so don't publish this key or sign with it.
01315          */
01316         if (delset && delete <= now) {
01317                 key->hint_publish = ISC_FALSE;
01318                 key->hint_sign = ISC_FALSE;
01319                 key->hint_remove = ISC_TRUE;
01320         }
01321 }
01322 
01323 /*%
01324  * Get a list of DNSSEC keys from the key repository
01325  */
01326 isc_result_t
01327 dns_dnssec_findmatchingkeys(dns_name_t *origin, const char *directory,
01328                             isc_mem_t *mctx, dns_dnsseckeylist_t *keylist)
01329 {
01330         isc_result_t result = ISC_R_SUCCESS;
01331         isc_boolean_t dir_open = ISC_FALSE;
01332         dns_dnsseckeylist_t list;
01333         isc_dir_t dir;
01334         dns_dnsseckey_t *key = NULL;
01335         dst_key_t *dstkey = NULL;
01336         char namebuf[DNS_NAME_FORMATSIZE];
01337         isc_buffer_t b;
01338         unsigned int len, i;
01339         isc_stdtime_t now;
01340 
01341         REQUIRE(keylist != NULL);
01342         ISC_LIST_INIT(list);
01343         isc_dir_init(&dir);
01344 
01345         isc_buffer_init(&b, namebuf, sizeof(namebuf) - 1);
01346         RETERR(dns_name_tofilenametext(origin, ISC_FALSE, &b));
01347         len = isc_buffer_usedlength(&b);
01348         namebuf[len] = '\0';
01349 
01350         if (directory == NULL)
01351                 directory = ".";
01352         RETERR(isc_dir_open(&dir, directory));
01353         dir_open = ISC_TRUE;
01354 
01355         isc_stdtime_get(&now);
01356 
01357         while (isc_dir_read(&dir) == ISC_R_SUCCESS) {
01358                 if (dir.entry.name[0] != 'K' ||
01359                     dir.entry.length < len + 1 ||
01360                     dir.entry.name[len + 1] != '+' ||
01361                     strncasecmp(dir.entry.name + 1, namebuf, len) != 0)
01362                         continue;
01363 
01364                 for (i = len + 1 + 1; i < dir.entry.length ; i++)
01365                         if (dir.entry.name[i] < '0' || dir.entry.name[i] > '9')
01366                                 break;
01367 
01368                 if (i == len + 1 + 1 || i >= dir.entry.length ||
01369                     dir.entry.name[i] != '+')
01370                         continue;
01371 
01372                 for (i++ ; i < dir.entry.length ; i++)
01373                         if (dir.entry.name[i] < '0' || dir.entry.name[i] > '9')
01374                                 break;
01375 
01376                 if (strcmp(dir.entry.name + i, ".private") != 0)
01377                                 continue;
01378 
01379                 dstkey = NULL;
01380                 result = dst_key_fromnamedfile(dir.entry.name,
01381                                                directory,
01382                                                DST_TYPE_PUBLIC |
01383                                                DST_TYPE_PRIVATE,
01384                                                mctx, &dstkey);
01385 
01386                 if (result != ISC_R_SUCCESS) {
01387                         isc_log_write(dns_lctx,
01388                                       DNS_LOGCATEGORY_GENERAL,
01389                                       DNS_LOGMODULE_DNSSEC,
01390                                       ISC_LOG_WARNING,
01391                                       "dns_dnssec_findmatchingkeys: "
01392                                       "error reading key file %s: %s",
01393                                       dir.entry.name,
01394                                       isc_result_totext(result));
01395                         continue;
01396                 }
01397 
01398                 RETERR(dns_dnsseckey_create(mctx, &dstkey, &key));
01399                 key->source = dns_keysource_repository;
01400                 get_hints(key, now);
01401 
01402                 if (key->legacy) {
01403                         dns_dnsseckey_destroy(mctx, &key);
01404                 } else {
01405                         ISC_LIST_APPEND(list, key, link);
01406                         key = NULL;
01407                 }
01408         }
01409 
01410         if (!ISC_LIST_EMPTY(list)) {
01411                 result = ISC_R_SUCCESS;
01412                 ISC_LIST_APPENDLIST(*keylist, list, link);
01413         } else
01414                 result = ISC_R_NOTFOUND;
01415 
01416  failure:
01417         if (dir_open)
01418                 isc_dir_close(&dir);
01419         INSIST(key == NULL);
01420         while ((key = ISC_LIST_HEAD(list)) != NULL) {
01421                 ISC_LIST_UNLINK(list, key, link);
01422                 INSIST(key->key != NULL);
01423                 dst_key_free(&key->key);
01424                 dns_dnsseckey_destroy(mctx, &key);
01425         }
01426         if (dstkey != NULL)
01427                 dst_key_free(&dstkey);
01428         return (result);
01429 }
01430 
01431 /*%
01432  * Add 'newkey' to 'keylist' if it's not already there.
01433  *
01434  * If 'savekeys' is ISC_TRUE, then we need to preserve all
01435  * the keys in the keyset, regardless of whether they have
01436  * metadata indicating they should be deactivated or removed.
01437  */
01438 static isc_result_t
01439 addkey(dns_dnsseckeylist_t *keylist, dst_key_t **newkey,
01440        isc_boolean_t savekeys, isc_mem_t *mctx)
01441 {
01442         dns_dnsseckey_t *key;
01443         isc_result_t result;
01444 
01445         /* Skip duplicates */
01446         for (key = ISC_LIST_HEAD(*keylist);
01447              key != NULL;
01448              key = ISC_LIST_NEXT(key, link)) {
01449                 if (dst_key_id(key->key) == dst_key_id(*newkey) &&
01450                     dst_key_alg(key->key) == dst_key_alg(*newkey) &&
01451                     dns_name_equal(dst_key_name(key->key),
01452                                    dst_key_name(*newkey)))
01453                         break;
01454         }
01455 
01456         if (key != NULL) {
01457                 /*
01458                  * Found a match.  If the old key was only public and the
01459                  * new key is private, replace the old one; otherwise
01460                  * leave it.  But either way, mark the key as having
01461                  * been found in the zone.
01462                  */
01463                 if (dst_key_isprivate(key->key)) {
01464                         dst_key_free(newkey);
01465                 } else if (dst_key_isprivate(*newkey)) {
01466                         dst_key_free(&key->key);
01467                         key->key = *newkey;
01468                 }
01469 
01470                 key->source = dns_keysource_zoneapex;
01471                 return (ISC_R_SUCCESS);
01472         }
01473 
01474         result = dns_dnsseckey_create(mctx, newkey, &key);
01475         if (result != ISC_R_SUCCESS)
01476                 return (result);
01477         if (key->legacy || savekeys) {
01478                 key->force_publish = ISC_TRUE;
01479                 key->force_sign = dst_key_isprivate(key->key);
01480         }
01481         key->source = dns_keysource_zoneapex;
01482         ISC_LIST_APPEND(*keylist, key, link);
01483         *newkey = NULL;
01484         return (ISC_R_SUCCESS);
01485 }
01486 
01487 
01488 /*%
01489  * Mark all keys which signed the DNSKEY/SOA RRsets as "active",
01490  * for future reference.
01491  */
01492 static isc_result_t
01493 mark_active_keys(dns_dnsseckeylist_t *keylist, dns_rdataset_t *rrsigs) {
01494         isc_result_t result = ISC_R_SUCCESS;
01495         dns_rdata_t rdata = DNS_RDATA_INIT;
01496         dns_rdataset_t sigs;
01497         dns_dnsseckey_t *key;
01498 
01499         REQUIRE(rrsigs != NULL && dns_rdataset_isassociated(rrsigs));
01500 
01501         dns_rdataset_init(&sigs);
01502         dns_rdataset_clone(rrsigs, &sigs);
01503         for (key = ISC_LIST_HEAD(*keylist);
01504              key != NULL;
01505              key = ISC_LIST_NEXT(key, link)) {
01506                 isc_uint16_t keyid, sigid;
01507                 dns_secalg_t keyalg, sigalg;
01508                 keyid = dst_key_id(key->key);
01509                 keyalg = dst_key_alg(key->key);
01510 
01511                 for (result = dns_rdataset_first(&sigs);
01512                      result == ISC_R_SUCCESS;
01513                      result = dns_rdataset_next(&sigs)) {
01514                         dns_rdata_rrsig_t sig;
01515 
01516                         dns_rdata_reset(&rdata);
01517                         dns_rdataset_current(&sigs, &rdata);
01518                         result = dns_rdata_tostruct(&rdata, &sig, NULL);
01519                         RUNTIME_CHECK(result == ISC_R_SUCCESS);
01520                         sigalg = sig.algorithm;
01521                         sigid = sig.keyid;
01522                         if (keyid == sigid && keyalg == sigalg) {
01523                                 key->is_active = ISC_TRUE;
01524                                 break;
01525                         }
01526                 }
01527         }
01528 
01529         if (result == ISC_R_NOMORE)
01530                 result = ISC_R_SUCCESS;
01531 
01532         if (dns_rdataset_isassociated(&sigs))
01533                 dns_rdataset_disassociate(&sigs);
01534         return (result);
01535 }
01536 
01537 /*%
01538  * Add the contents of a DNSKEY rdataset 'keyset' to 'keylist'.
01539  */
01540 isc_result_t
01541 dns_dnssec_keylistfromrdataset(dns_name_t *origin,
01542                                const char *directory, isc_mem_t *mctx,
01543                                dns_rdataset_t *keyset, dns_rdataset_t *keysigs,
01544                                dns_rdataset_t *soasigs, isc_boolean_t savekeys,
01545                                isc_boolean_t publickey,
01546                                dns_dnsseckeylist_t *keylist)
01547 {
01548         dns_rdataset_t keys;
01549         dns_rdata_t rdata = DNS_RDATA_INIT;
01550         dst_key_t *pubkey = NULL, *privkey = NULL;
01551         isc_result_t result;
01552 
01553         REQUIRE(keyset != NULL && dns_rdataset_isassociated(keyset));
01554 
01555         dns_rdataset_init(&keys);
01556 
01557         dns_rdataset_clone(keyset, &keys);
01558         for (result = dns_rdataset_first(&keys);
01559              result == ISC_R_SUCCESS;
01560              result = dns_rdataset_next(&keys)) {
01561                 dns_rdata_reset(&rdata);
01562                 dns_rdataset_current(&keys, &rdata);
01563                 RETERR(dns_dnssec_keyfromrdata(origin, &rdata, mctx, &pubkey));
01564                 dst_key_setttl(pubkey, keys.ttl);
01565 
01566                 if (!is_zone_key(pubkey) ||
01567                     (dst_key_flags(pubkey) & DNS_KEYTYPE_NOAUTH) != 0)
01568                         goto skip;
01569 
01570                 /* Corrupted .key file? */
01571                 if (!dns_name_equal(origin, dst_key_name(pubkey)))
01572                         goto skip;
01573 
01574                 if (publickey) {
01575                         RETERR(addkey(keylist, &pubkey, savekeys, mctx));
01576                         goto skip;
01577                 }
01578 
01579                 result = dst_key_fromfile(dst_key_name(pubkey),
01580                                           dst_key_id(pubkey),
01581                                           dst_key_alg(pubkey),
01582                                           DST_TYPE_PUBLIC|DST_TYPE_PRIVATE,
01583                                           directory, mctx, &privkey);
01584 
01585                 /*
01586                  * If the key was revoked and the private file
01587                  * doesn't exist, maybe it was revoked internally
01588                  * by named.  Try loading the unrevoked version.
01589                  */
01590                 if (result == ISC_R_FILENOTFOUND) {
01591                         isc_uint32_t flags;
01592                         flags = dst_key_flags(pubkey);
01593                         if ((flags & DNS_KEYFLAG_REVOKE) != 0) {
01594                                 dst_key_setflags(pubkey,
01595                                                  flags & ~DNS_KEYFLAG_REVOKE);
01596                                 result = dst_key_fromfile(dst_key_name(pubkey),
01597                                                           dst_key_id(pubkey),
01598                                                           dst_key_alg(pubkey),
01599                                                           DST_TYPE_PUBLIC|
01600                                                           DST_TYPE_PRIVATE,
01601                                                           directory,
01602                                                           mctx, &privkey);
01603                                 if (result == ISC_R_SUCCESS &&
01604                                     dst_key_pubcompare(pubkey, privkey,
01605                                                        ISC_FALSE)) {
01606                                         dst_key_setflags(privkey, flags);
01607                                 }
01608                                 dst_key_setflags(pubkey, flags);
01609                         }
01610                 }
01611 
01612                 if (result != ISC_R_SUCCESS) {
01613                         char filename[ISC_DIR_NAMEMAX];
01614                         isc_result_t result2;
01615                         isc_buffer_t buf;
01616 
01617                         isc_buffer_init(&buf, filename, ISC_DIR_NAMEMAX);
01618                         result2 = dst_key_getfilename(dst_key_name(pubkey),
01619                                                       dst_key_id(pubkey),
01620                                                       dst_key_alg(pubkey),
01621                                                       (DST_TYPE_PUBLIC |
01622                                                        DST_TYPE_PRIVATE),
01623                                                       directory, mctx,
01624                                                       &buf);
01625                         if (result2 != ISC_R_SUCCESS) {
01626                                 char namebuf[DNS_NAME_FORMATSIZE];
01627                                 char algbuf[DNS_SECALG_FORMATSIZE];
01628 
01629                                 dns_name_format(dst_key_name(pubkey),
01630                                                 namebuf, sizeof(namebuf));
01631                                 dns_secalg_format(dst_key_alg(pubkey),
01632                                                   algbuf, sizeof(algbuf));
01633                                 snprintf(filename, sizeof(filename) - 1,
01634                                          "key file for %s/%s/%d",
01635                                          namebuf, algbuf, dst_key_id(pubkey));
01636                         }
01637 
01638                         isc_log_write(dns_lctx, DNS_LOGCATEGORY_GENERAL,
01639                                       DNS_LOGMODULE_DNSSEC, ISC_LOG_WARNING,
01640                                       "dns_dnssec_keylistfromrdataset: error "
01641                                       "reading %s: %s",
01642                                       filename, isc_result_totext(result));
01643                 }
01644 
01645                 if (result == ISC_R_FILENOTFOUND || result == ISC_R_NOPERM) {
01646                         RETERR(addkey(keylist, &pubkey, savekeys, mctx));
01647                         goto skip;
01648                 }
01649                 RETERR(result);
01650 
01651                 /* This should never happen. */
01652                 if ((dst_key_flags(privkey) & DNS_KEYTYPE_NOAUTH) != 0)
01653                         goto skip;
01654 
01655                 /*
01656                  * Whatever the key's default TTL may have
01657                  * been, the rdataset TTL takes priority.
01658                  */
01659                 dst_key_setttl(privkey, dst_key_getttl(pubkey));
01660 
01661                 RETERR(addkey(keylist, &privkey, savekeys, mctx));
01662  skip:
01663                 if (pubkey != NULL)
01664                         dst_key_free(&pubkey);
01665                 if (privkey != NULL)
01666                         dst_key_free(&privkey);
01667         }
01668 
01669         if (result != ISC_R_NOMORE)
01670                 RETERR(result);
01671 
01672         if (keysigs != NULL && dns_rdataset_isassociated(keysigs))
01673                 RETERR(mark_active_keys(keylist, keysigs));
01674 
01675         if (soasigs != NULL && dns_rdataset_isassociated(soasigs))
01676                 RETERR(mark_active_keys(keylist, soasigs));
01677 
01678         result = ISC_R_SUCCESS;
01679 
01680  failure:
01681         if (dns_rdataset_isassociated(&keys))
01682                 dns_rdataset_disassociate(&keys);
01683         if (pubkey != NULL)
01684                 dst_key_free(&pubkey);
01685         if (privkey != NULL)
01686                 dst_key_free(&privkey);
01687         return (result);
01688 }
01689 
01690 static isc_result_t
01691 make_dnskey(dst_key_t *key, unsigned char *buf, int bufsize,
01692             dns_rdata_t *target)
01693 {
01694         isc_result_t result;
01695         isc_buffer_t b;
01696         isc_region_t r;
01697 
01698         isc_buffer_init(&b, buf, bufsize);
01699         result = dst_key_todns(key, &b);
01700         if (result != ISC_R_SUCCESS)
01701                 return (result);
01702 
01703         dns_rdata_reset(target);
01704         isc_buffer_usedregion(&b, &r);
01705         dns_rdata_fromregion(target, dst_key_class(key),
01706                              dns_rdatatype_dnskey, &r);
01707         return (ISC_R_SUCCESS);
01708 }
01709 
01710 static isc_result_t
01711 publish_key(dns_diff_t *diff, dns_dnsseckey_t *key, dns_name_t *origin,
01712             dns_ttl_t ttl, isc_mem_t *mctx, isc_boolean_t allzsk,
01713             void (*report)(const char *, ...))
01714 {
01715         isc_result_t result;
01716         dns_difftuple_t *tuple = NULL;
01717         unsigned char buf[DST_KEY_MAXSIZE];
01718         dns_rdata_t dnskey = DNS_RDATA_INIT;
01719         char alg[80];
01720 
01721         dns_rdata_reset(&dnskey);
01722         RETERR(make_dnskey(key->key, buf, sizeof(buf), &dnskey));
01723 
01724         dns_secalg_format(dst_key_alg(key->key), alg, sizeof(alg));
01725         report("Fetching %s %d/%s from key %s.",
01726                key->ksk ?  (allzsk ?  "KSK/ZSK" : "KSK") : "ZSK",
01727                dst_key_id(key->key), alg,
01728                key->source == dns_keysource_user ?  "file" : "repository");
01729 
01730         if (key->prepublish && ttl > key->prepublish) {
01731                 char keystr[DST_KEY_FORMATSIZE];
01732                 isc_stdtime_t now;
01733 
01734                 dst_key_format(key->key, keystr, sizeof(keystr));
01735                 report("Key %s: Delaying activation to match the DNSKEY TTL.\n",
01736                        keystr, ttl);
01737 
01738                 isc_stdtime_get(&now);
01739                 dst_key_settime(key->key, DST_TIME_ACTIVATE, now + ttl);
01740         }
01741 
01742         /* publish key */
01743         RETERR(dns_difftuple_create(mctx, DNS_DIFFOP_ADD, origin, ttl,
01744                                     &dnskey, &tuple));
01745         dns_diff_appendminimal(diff, &tuple);
01746         result = ISC_R_SUCCESS;
01747 
01748  failure:
01749         return (result);
01750 }
01751 
01752 static isc_result_t
01753 remove_key(dns_diff_t *diff, dns_dnsseckey_t *key, dns_name_t *origin,
01754           dns_ttl_t ttl, isc_mem_t *mctx, const char *reason,
01755           void (*report)(const char *, ...))
01756 {
01757         isc_result_t result;
01758         dns_difftuple_t *tuple = NULL;
01759         unsigned char buf[DST_KEY_MAXSIZE];
01760         dns_rdata_t dnskey = DNS_RDATA_INIT;
01761         char alg[80];
01762 
01763         dns_secalg_format(dst_key_alg(key->key), alg, sizeof(alg));
01764         report("Removing %s key %d/%s from DNSKEY RRset.",
01765                reason, dst_key_id(key->key), alg);
01766 
01767         RETERR(make_dnskey(key->key, buf, sizeof(buf), &dnskey));
01768         RETERR(dns_difftuple_create(mctx, DNS_DIFFOP_DEL, origin, ttl, &dnskey,
01769                                     &tuple));
01770         dns_diff_appendminimal(diff, &tuple);
01771         result = ISC_R_SUCCESS;
01772 
01773  failure:
01774         return (result);
01775 }
01776 
01777 /*
01778  * Update 'keys' with information from 'newkeys'.
01779  *
01780  * If 'removed' is not NULL, any keys that are being removed from
01781  * the zone will be added to the list for post-removal processing.
01782  */
01783 isc_result_t
01784 dns_dnssec_updatekeys(dns_dnsseckeylist_t *keys, dns_dnsseckeylist_t *newkeys,
01785                       dns_dnsseckeylist_t *removed, dns_name_t *origin,
01786                       dns_ttl_t hint_ttl, dns_diff_t *diff,
01787                       isc_boolean_t allzsk, isc_mem_t *mctx,
01788                       void (*report)(const char *, ...))
01789 {
01790         isc_result_t result;
01791         dns_dnsseckey_t *key, *key1, *key2, *next;
01792         isc_boolean_t found_ttl = ISC_FALSE;
01793         dns_ttl_t ttl = hint_ttl;
01794 
01795         /*
01796          * First, look through the existing key list to find keys
01797          * supplied from the command line which are not in the zone.
01798          * Update the zone to include them.
01799          *
01800          * Also, if there are keys published in the zone already,
01801          * use their TTL for all subsequent published keys.
01802          */
01803         for (key = ISC_LIST_HEAD(*keys);
01804              key != NULL;
01805              key = ISC_LIST_NEXT(key, link)) {
01806                 if (key->source == dns_keysource_user &&
01807                     (key->hint_publish || key->force_publish)) {
01808                         RETERR(publish_key(diff, key, origin, ttl,
01809                                            mctx, allzsk, report));
01810                 }
01811                 if (key->source == dns_keysource_zoneapex) {
01812                         ttl = dst_key_getttl(key->key);
01813                         found_ttl = ISC_TRUE;
01814                 }
01815         }
01816 
01817         /*
01818          * If there were no existing keys, use the smallest nonzero
01819          * TTL of the keys found in the repository.
01820          */
01821         if (!found_ttl && !ISC_LIST_EMPTY(*newkeys)) {
01822                 dns_ttl_t shortest = 0;
01823 
01824                 for (key = ISC_LIST_HEAD(*newkeys);
01825                      key != NULL;
01826                      key = ISC_LIST_NEXT(key, link)) {
01827                         dns_ttl_t thisttl = dst_key_getttl(key->key);
01828                         if (thisttl != 0 &&
01829                             (shortest == 0 || thisttl < shortest))
01830                                 shortest = thisttl;
01831                 }
01832 
01833                 if (shortest != 0)
01834                         ttl = shortest;
01835         }
01836 
01837         /*
01838          * Second, scan the list of newly found keys looking for matches
01839          * with known keys, and update accordingly.
01840          */
01841         for (key1 = ISC_LIST_HEAD(*newkeys); key1 != NULL; key1 = next) {
01842                 isc_boolean_t key_revoked = ISC_FALSE;
01843 
01844                 next = ISC_LIST_NEXT(key1, link);
01845 
01846                 for (key2 = ISC_LIST_HEAD(*keys);
01847                      key2 != NULL;
01848                      key2 = ISC_LIST_NEXT(key2, link)) {
01849                         int f1 = dst_key_flags(key1->key);
01850                         int f2 = dst_key_flags(key2->key);
01851                         int nr1 = f1 & ~DNS_KEYFLAG_REVOKE;
01852                         int nr2 = f2 & ~DNS_KEYFLAG_REVOKE;
01853                         if (nr1 == nr2 &&
01854                             dst_key_alg(key1->key) == dst_key_alg(key2->key) &&
01855                             dst_key_pubcompare(key1->key, key2->key,
01856                                                ISC_TRUE)) {
01857                                 int r1, r2;
01858                                 r1 = dst_key_flags(key1->key) &
01859                                         DNS_KEYFLAG_REVOKE;
01860                                 r2 = dst_key_flags(key2->key) &
01861                                         DNS_KEYFLAG_REVOKE;
01862                                 key_revoked = ISC_TF(r1 != r2);
01863                                 break;
01864                         }
01865                 }
01866 
01867                 /* No match found in keys; add the new key. */
01868                 if (key2 == NULL) {
01869                         ISC_LIST_UNLINK(*newkeys, key1, link);
01870                         ISC_LIST_APPEND(*keys, key1, link);
01871 
01872                         if (key1->source != dns_keysource_zoneapex &&
01873                             (key1->hint_publish || key1->force_publish)) {
01874                                 RETERR(publish_key(diff, key1, origin, ttl,
01875                                                    mctx, allzsk, report));
01876                                 if (key1->hint_sign || key1->force_sign)
01877                                         key1->first_sign = ISC_TRUE;
01878                         }
01879 
01880                         continue;
01881                 }
01882 
01883                 /* Match found: remove or update it as needed */
01884                 if (key1->hint_remove) {
01885                         RETERR(remove_key(diff, key2, origin, ttl, mctx,
01886                                           "expired", report));
01887                         ISC_LIST_UNLINK(*keys, key2, link);
01888                         if (removed != NULL)
01889                                 ISC_LIST_APPEND(*removed, key2, link);
01890                         else
01891                                 dns_dnsseckey_destroy(mctx, &key2);
01892                 } else if (key_revoked &&
01893                          (dst_key_flags(key1->key) & DNS_KEYFLAG_REVOKE) != 0) {
01894 
01895                         /*
01896                          * A previously valid key has been revoked.
01897                          * We need to remove the old version and pull
01898                          * in the new one.
01899                          */
01900                         RETERR(remove_key(diff, key2, origin, ttl, mctx,
01901                                           "revoked", report));
01902                         ISC_LIST_UNLINK(*keys, key2, link);
01903                         if (removed != NULL)
01904                                 ISC_LIST_APPEND(*removed, key2, link);
01905                         else
01906                                 dns_dnsseckey_destroy(mctx, &key2);
01907 
01908                         RETERR(publish_key(diff, key1, origin, ttl,
01909                                            mctx, allzsk, report));
01910                         ISC_LIST_UNLINK(*newkeys, key1, link);
01911                         ISC_LIST_APPEND(*keys, key1, link);
01912 
01913                         /*
01914                          * XXX: The revoke flag is only defined for trust
01915                          * anchors.  Setting the flag on a non-KSK is legal,
01916                          * but not defined in any RFC.  It seems reasonable
01917                          * to treat it the same as a KSK: keep it in the
01918                          * zone, sign the DNSKEY set with it, but not
01919                          * sign other records with it.
01920                          */
01921                         key1->ksk = ISC_TRUE;
01922                         continue;
01923                 } else {
01924                         if (!key2->is_active &&
01925                             (key1->hint_sign || key1->force_sign))
01926                                 key2->first_sign = ISC_TRUE;
01927                         key2->hint_sign = key1->hint_sign;
01928                         key2->hint_publish = key1->hint_publish;
01929                 }
01930         }
01931 
01932         /* Free any leftover keys in newkeys */
01933         while (!ISC_LIST_EMPTY(*newkeys)) {
01934                 key1 = ISC_LIST_HEAD(*newkeys);
01935                 ISC_LIST_UNLINK(*newkeys, key1, link);
01936                 dns_dnsseckey_destroy(mctx, &key1);
01937         }
01938 
01939         result = ISC_R_SUCCESS;
01940 
01941  failure:
01942         return (result);
01943 }

Generated on Tue Apr 28 17:40:56 2015 by Doxygen 1.5.4 for BIND9 Internals 9.11.0pre-alpha