diff options
Diffstat (limited to 'usr.sbin/bind/lib')
| -rw-r--r-- | usr.sbin/bind/lib/dns/Makefile.inc | 4 | ||||
| -rw-r--r-- | usr.sbin/bind/lib/dns/dnssec.c | 1495 | ||||
| -rw-r--r-- | usr.sbin/bind/lib/dns/include/dns/dnssec.h | 313 | ||||
| -rw-r--r-- | usr.sbin/bind/lib/dns/include/dns/message.h | 30 | ||||
| -rw-r--r-- | usr.sbin/bind/lib/dns/message.c | 94 |
5 files changed, 5 insertions, 1931 deletions
diff --git a/usr.sbin/bind/lib/dns/Makefile.inc b/usr.sbin/bind/lib/dns/Makefile.inc index 51cce21230f..f3ab8a3f5da 100644 --- a/usr.sbin/bind/lib/dns/Makefile.inc +++ b/usr.sbin/bind/lib/dns/Makefile.inc @@ -1,9 +1,9 @@ -# $OpenBSD: Makefile.inc,v 1.1 2020/01/28 17:17:05 florian Exp $ +# $OpenBSD: Makefile.inc,v 1.2 2020/02/04 18:42:51 florian Exp $ .PATH: ${.CURDIR}/lib/dns SRCS+= byaddr.c callbacks.c compress.c dns_log.c dns_result.c dns_time.c -SRCS+= dnssec.c ds.c dst_api.c dst_parse.c dst_result.c masterdump.c +SRCS+= ds.c dst_api.c dst_parse.c dst_result.c masterdump.c SRCS+= hmac_link.c key.c keydata.c lib.c name.c openssl_link.c message.c SRCS+= ncache.c nsec.c nsec3.c openssldh_link.c openssldsa_link.c SRCS+= opensslecdsa_link.c opensslrsa_link.c rcode.c rdata.c rdatalist.c diff --git a/usr.sbin/bind/lib/dns/dnssec.c b/usr.sbin/bind/lib/dns/dnssec.c deleted file mode 100644 index 4a98aba15e4..00000000000 --- a/usr.sbin/bind/lib/dns/dnssec.c +++ /dev/null @@ -1,1495 +0,0 @@ -/* - * Copyright (C) Internet Systems Consortium, Inc. ("ISC") - * - * Permission to use, copy, modify, and/or distribute this software for any - * purpose with or without fee is hereby granted, provided that the above - * copyright notice and this permission notice appear in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH - * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY - * AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT, - * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM - * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE - * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR - * PERFORMANCE OF THIS SOFTWARE. - */ - -/* - * $Id: dnssec.c,v 1.16 2020/01/28 17:17:05 florian Exp $ - */ - -/*! \file */ - - - -#include <stdlib.h> - -#include <isc/buffer.h> -#include <isc/dir.h> - -#include <isc/serial.h> -#include <string.h> -#include <isc/util.h> - - - - - -#include <dns/dnssec.h> -#include <dns/fixedname.h> -#include <dns/keyvalues.h> -#include <dns/log.h> -#include <dns/message.h> -#include <dns/rdata.h> -#include <dns/rdatalist.h> -#include <dns/rdataset.h> -#include "rdatastruct.h" -#include <dns/result.h> - -#include <dns/tsig.h> /* for DNS_TSIG_FUDGE */ - -#include <dst/result.h> - -#define is_response(msg) (msg->flags & DNS_MESSAGEFLAG_QR) - -#define RETERR(x) do { \ - result = (x); \ - if (result != ISC_R_SUCCESS) \ - goto failure; \ - } while (0) - - -#define TYPE_SIGN 0 -#define TYPE_VERIFY 1 - -static isc_result_t -digest_callback(void *arg, isc_region_t *data); - -static int -rdata_compare_wrapper(const void *rdata1, const void *rdata2); - -static isc_result_t -rdataset_to_sortedarray(dns_rdataset_t *set, - dns_rdata_t **rdata, int *nrdata); - -static isc_result_t -digest_callback(void *arg, isc_region_t *data) { - dst_context_t *ctx = arg; - - return (dst_context_adddata(ctx, data)); -} - -/* - * Make qsort happy. - */ -static int -rdata_compare_wrapper(const void *rdata1, const void *rdata2) { - return (dns_rdata_compare((const dns_rdata_t *)rdata1, - (const dns_rdata_t *)rdata2)); -} - -/* - * Sort the rdataset into an array. - */ -static isc_result_t -rdataset_to_sortedarray(dns_rdataset_t *set, - dns_rdata_t **rdata, int *nrdata) -{ - isc_result_t ret; - int i = 0, n; - dns_rdata_t *data; - dns_rdataset_t rdataset; - - n = dns_rdataset_count(set); - - data = malloc(n * sizeof(dns_rdata_t)); - if (data == NULL) - return (ISC_R_NOMEMORY); - - dns_rdataset_init(&rdataset); - dns_rdataset_clone(set, &rdataset); - ret = dns_rdataset_first(&rdataset); - if (ret != ISC_R_SUCCESS) { - dns_rdataset_disassociate(&rdataset); - free(data); - return (ret); - } - - /* - * Put them in the array. - */ - do { - dns_rdata_init(&data[i]); - dns_rdataset_current(&rdataset, &data[i++]); - } while (dns_rdataset_next(&rdataset) == ISC_R_SUCCESS); - - /* - * Sort the array. - */ - qsort(data, n, sizeof(dns_rdata_t), rdata_compare_wrapper); - *rdata = data; - *nrdata = n; - dns_rdataset_disassociate(&rdataset); - return (ISC_R_SUCCESS); -} - -isc_result_t -dns_dnssec_keyfromrdata(dns_name_t *name, dns_rdata_t *rdata, - dst_key_t **key) -{ - isc_buffer_t b; - isc_region_t r; - - INSIST(name != NULL); - INSIST(rdata != NULL); - INSIST(key != NULL); - INSIST(*key == NULL); - REQUIRE(rdata->type == dns_rdatatype_key || - rdata->type == dns_rdatatype_dnskey); - - dns_rdata_toregion(rdata, &r); - isc_buffer_init(&b, r.base, r.length); - isc_buffer_add(&b, r.length); - return (dst_key_fromdns(name, rdata->rdclass, &b, key)); -} - -static isc_result_t -digest_sig(dst_context_t *ctx, isc_boolean_t downcase, dns_rdata_t *sigrdata, - dns_rdata_rrsig_t *rrsig) -{ - isc_region_t r; - isc_result_t ret; - dns_fixedname_t fname; - - dns_rdata_toregion(sigrdata, &r); - INSIST(r.length >= 19); - - r.length = 18; - ret = dst_context_adddata(ctx, &r); - if (ret != ISC_R_SUCCESS) - return (ret); - if (downcase) { - dns_fixedname_init(&fname); - - RUNTIME_CHECK(dns_name_downcase(&rrsig->signer, - dns_fixedname_name(&fname), - NULL) == ISC_R_SUCCESS); - dns_name_toregion(dns_fixedname_name(&fname), &r); - } else - dns_name_toregion(&rrsig->signer, &r); - - return (dst_context_adddata(ctx, &r)); -} - -isc_result_t -dns_dnssec_sign(dns_name_t *name, dns_rdataset_t *set, dst_key_t *key, - isc_stdtime_t *inception, isc_stdtime_t *expire, - isc_buffer_t *buffer, dns_rdata_t *sigrdata) -{ - dns_rdata_rrsig_t sig; - dns_rdata_t tmpsigrdata; - dns_rdata_t *rdatas; - int nrdatas, i; - isc_buffer_t sigbuf, envbuf; - isc_region_t r; - dst_context_t *ctx = NULL; - isc_result_t ret; - isc_buffer_t *databuf = NULL; - char data[256 + 8]; - uint32_t flags; - unsigned int sigsize; - dns_fixedname_t fnewname; - dns_fixedname_t fsigner; - - REQUIRE(name != NULL); - REQUIRE(dns_name_countlabels(name) <= 255); - REQUIRE(set != NULL); - REQUIRE(key != NULL); - REQUIRE(inception != NULL); - REQUIRE(expire != NULL); - REQUIRE(sigrdata != NULL); - - if (*inception >= *expire) - return (DNS_R_INVALIDTIME); - - /* - * Is the key allowed to sign data? - */ - flags = dst_key_flags(key); - if (flags & DNS_KEYTYPE_NOAUTH) - return (DNS_R_KEYUNAUTHORIZED); - if ((flags & DNS_KEYFLAG_OWNERMASK) != DNS_KEYOWNER_ZONE) - return (DNS_R_KEYUNAUTHORIZED); - - sig.common.rdclass = set->rdclass; - sig.common.rdtype = dns_rdatatype_rrsig; - ISC_LINK_INIT(&sig.common, link); - - /* - * Downcase signer. - */ - dns_name_init(&sig.signer, NULL); - dns_fixedname_init(&fsigner); - RUNTIME_CHECK(dns_name_downcase(dst_key_name(key), - dns_fixedname_name(&fsigner), NULL) == ISC_R_SUCCESS); - dns_name_clone(dns_fixedname_name(&fsigner), &sig.signer); - - sig.covered = set->type; - sig.algorithm = dst_key_alg(key); - sig.labels = dns_name_countlabels(name) - 1; - if (dns_name_iswildcard(name)) - sig.labels--; - sig.originalttl = set->ttl; - sig.timesigned = *inception; - sig.timeexpire = *expire; - sig.keyid = dst_key_id(key); - ret = dst_key_sigsize(key, &sigsize); - if (ret != ISC_R_SUCCESS) - return (ret); - sig.siglen = sigsize; - /* - * The actual contents of sig.signature are not important yet, since - * they're not used in digest_sig(). - */ - sig.signature = malloc(sig.siglen); - if (sig.signature == NULL) - return (ISC_R_NOMEMORY); - - ret = isc_buffer_allocate(&databuf, sigsize + 256 + 18); - if (ret != ISC_R_SUCCESS) - goto cleanup_signature; - - dns_rdata_init(&tmpsigrdata); - ret = dns_rdata_fromstruct(&tmpsigrdata, sig.common.rdclass, - sig.common.rdtype, &sig, databuf); - if (ret != ISC_R_SUCCESS) - goto cleanup_databuf; - - ret = dst_context_create3(key, - DNS_LOGCATEGORY_DNSSEC, ISC_TRUE, &ctx); - if (ret != ISC_R_SUCCESS) - goto cleanup_databuf; - - /* - * Digest the SIG rdata. - */ - ret = digest_sig(ctx, ISC_FALSE, &tmpsigrdata, &sig); - if (ret != ISC_R_SUCCESS) - goto cleanup_context; - - dns_fixedname_init(&fnewname); - RUNTIME_CHECK(dns_name_downcase(name, dns_fixedname_name(&fnewname), - NULL) == ISC_R_SUCCESS); - dns_name_toregion(dns_fixedname_name(&fnewname), &r); - - /* - * Create an envelope for each rdata: <name|type|class|ttl>. - */ - isc_buffer_init(&envbuf, data, sizeof(data)); - memmove(data, r.base, r.length); - isc_buffer_add(&envbuf, r.length); - isc_buffer_putuint16(&envbuf, set->type); - isc_buffer_putuint16(&envbuf, set->rdclass); - isc_buffer_putuint32(&envbuf, set->ttl); - - ret = rdataset_to_sortedarray(set, &rdatas, &nrdatas); - if (ret != ISC_R_SUCCESS) - goto cleanup_context; - isc_buffer_usedregion(&envbuf, &r); - - for (i = 0; i < nrdatas; i++) { - uint16_t len; - isc_buffer_t lenbuf; - isc_region_t lenr; - - /* - * Skip duplicates. - */ - if (i > 0 && dns_rdata_compare(&rdatas[i], &rdatas[i-1]) == 0) - continue; - - /* - * Digest the envelope. - */ - ret = dst_context_adddata(ctx, &r); - if (ret != ISC_R_SUCCESS) - goto cleanup_array; - - /* - * Digest the length of the rdata. - */ - isc_buffer_init(&lenbuf, &len, sizeof(len)); - INSIST(rdatas[i].length < 65536); - isc_buffer_putuint16(&lenbuf, (uint16_t)rdatas[i].length); - isc_buffer_usedregion(&lenbuf, &lenr); - ret = dst_context_adddata(ctx, &lenr); - if (ret != ISC_R_SUCCESS) - goto cleanup_array; - - /* - * Digest the rdata. - */ - ret = dns_rdata_digest(&rdatas[i], digest_callback, ctx); - if (ret != ISC_R_SUCCESS) - goto cleanup_array; - } - - isc_buffer_init(&sigbuf, sig.signature, sig.siglen); - ret = dst_context_sign(ctx, &sigbuf); - if (ret != ISC_R_SUCCESS) - goto cleanup_array; - isc_buffer_usedregion(&sigbuf, &r); - if (r.length != sig.siglen) { - ret = ISC_R_NOSPACE; - goto cleanup_array; - } - - ret = dns_rdata_fromstruct(sigrdata, sig.common.rdclass, - sig.common.rdtype, &sig, buffer); - -cleanup_array: - free(rdatas); -cleanup_context: - dst_context_destroy(&ctx); -cleanup_databuf: - isc_buffer_free(&databuf); -cleanup_signature: - free(sig.signature); - - return (ret); -} - -isc_result_t -dns_dnssec_verify2(dns_name_t *name, dns_rdataset_t *set, dst_key_t *key, - isc_boolean_t ignoretime, - dns_rdata_t *sigrdata, dns_name_t *wild) -{ - return (dns_dnssec_verify3(name, set, key, ignoretime, 0, - sigrdata, wild)); -} - -isc_result_t -dns_dnssec_verify3(dns_name_t *name, dns_rdataset_t *set, dst_key_t *key, - isc_boolean_t ignoretime, unsigned int maxbits, - dns_rdata_t *sigrdata, dns_name_t *wild) -{ - dns_rdata_rrsig_t sig; - dns_fixedname_t fnewname; - isc_region_t r; - isc_buffer_t envbuf; - dns_rdata_t *rdatas; - int nrdatas, i; - isc_stdtime_t now; - isc_result_t ret; - unsigned char data[300]; - dst_context_t *ctx = NULL; - int labels = 0; - uint32_t flags; - isc_boolean_t downcase = ISC_FALSE; - - REQUIRE(name != NULL); - REQUIRE(set != NULL); - REQUIRE(key != NULL); - REQUIRE(sigrdata != NULL && sigrdata->type == dns_rdatatype_rrsig); - - ret = dns_rdata_tostruct(sigrdata, &sig); - if (ret != ISC_R_SUCCESS) - return (ret); - - if (set->type != sig.covered) - return (DNS_R_SIGINVALID); - - if (isc_serial_lt(sig.timeexpire, sig.timesigned)) { - return (DNS_R_SIGINVALID); - } - - if (!ignoretime) { - isc_stdtime_get(&now); - - /* - * Is SIG temporally valid? - */ - if (isc_serial_lt((uint32_t)now, sig.timesigned)) { - return (DNS_R_SIGFUTURE); - } else if (isc_serial_lt(sig.timeexpire, (uint32_t)now)) { - return (DNS_R_SIGEXPIRED); - } - } - - /* - * NS, SOA and DNSSKEY records are signed by their owner. - * DS records are signed by the parent. - */ - switch (set->type) { - case dns_rdatatype_ns: - case dns_rdatatype_soa: - case dns_rdatatype_dnskey: - if (!dns_name_equal(name, &sig.signer)) { - return (DNS_R_SIGINVALID); - } - break; - case dns_rdatatype_ds: - if (dns_name_equal(name, &sig.signer)) { - return (DNS_R_SIGINVALID); - } - /* FALLTHROUGH */ - default: - if (!dns_name_issubdomain(name, &sig.signer)) { - return (DNS_R_SIGINVALID); - } - break; - } - - /* - * Is the key allowed to sign data? - */ - flags = dst_key_flags(key); - if (flags & DNS_KEYTYPE_NOAUTH) { - return (DNS_R_KEYUNAUTHORIZED); - } - if ((flags & DNS_KEYFLAG_OWNERMASK) != DNS_KEYOWNER_ZONE) { - return (DNS_R_KEYUNAUTHORIZED); - } - - again: - ret = dst_context_create4(key, DNS_LOGCATEGORY_DNSSEC, - ISC_FALSE, maxbits, &ctx); - if (ret != ISC_R_SUCCESS) - goto cleanup_struct; - - /* - * Digest the SIG rdata (not including the signature). - */ - ret = digest_sig(ctx, downcase, sigrdata, &sig); - if (ret != ISC_R_SUCCESS) - goto cleanup_context; - - /* - * If the name is an expanded wildcard, use the wildcard name. - */ - dns_fixedname_init(&fnewname); - labels = dns_name_countlabels(name) - 1; - RUNTIME_CHECK(dns_name_downcase(name, dns_fixedname_name(&fnewname), - NULL) == ISC_R_SUCCESS); - if (labels - sig.labels > 0) - dns_name_split(dns_fixedname_name(&fnewname), sig.labels + 1, - NULL, dns_fixedname_name(&fnewname)); - - dns_name_toregion(dns_fixedname_name(&fnewname), &r); - - /* - * Create an envelope for each rdata: <name|type|class|ttl>. - */ - isc_buffer_init(&envbuf, data, sizeof(data)); - if (labels - sig.labels > 0) { - isc_buffer_putuint8(&envbuf, 1); - isc_buffer_putuint8(&envbuf, '*'); - memmove(data + 2, r.base, r.length); - } - else - memmove(data, r.base, r.length); - isc_buffer_add(&envbuf, r.length); - isc_buffer_putuint16(&envbuf, set->type); - isc_buffer_putuint16(&envbuf, set->rdclass); - isc_buffer_putuint32(&envbuf, sig.originalttl); - - ret = rdataset_to_sortedarray(set, &rdatas, &nrdatas); - if (ret != ISC_R_SUCCESS) - goto cleanup_context; - - isc_buffer_usedregion(&envbuf, &r); - - for (i = 0; i < nrdatas; i++) { - uint16_t len; - isc_buffer_t lenbuf; - isc_region_t lenr; - - /* - * Skip duplicates. - */ - if (i > 0 && dns_rdata_compare(&rdatas[i], &rdatas[i-1]) == 0) - continue; - - /* - * Digest the envelope. - */ - ret = dst_context_adddata(ctx, &r); - if (ret != ISC_R_SUCCESS) - goto cleanup_array; - - /* - * Digest the rdata length. - */ - isc_buffer_init(&lenbuf, &len, sizeof(len)); - INSIST(rdatas[i].length < 65536); - isc_buffer_putuint16(&lenbuf, (uint16_t)rdatas[i].length); - isc_buffer_usedregion(&lenbuf, &lenr); - - /* - * Digest the rdata. - */ - ret = dst_context_adddata(ctx, &lenr); - if (ret != ISC_R_SUCCESS) - goto cleanup_array; - ret = dns_rdata_digest(&rdatas[i], digest_callback, ctx); - if (ret != ISC_R_SUCCESS) - goto cleanup_array; - } - - r.base = sig.signature; - r.length = sig.siglen; - ret = dst_context_verify2(ctx, maxbits, &r); - if (ret == ISC_R_SUCCESS && downcase) { - char namebuf[DNS_NAME_FORMATSIZE]; - dns_name_format(&sig.signer, namebuf, sizeof(namebuf)); - isc_log_write(dns_lctx, DNS_LOGCATEGORY_DNSSEC, - DNS_LOGMODULE_DNSSEC, ISC_LOG_DEBUG(1), - "successfully validated after lower casing " - "signer '%s'", namebuf); - } - -cleanup_array: - free(rdatas); -cleanup_context: - dst_context_destroy(&ctx); - if (ret == DST_R_VERIFYFAILURE && !downcase) { - downcase = ISC_TRUE; - goto again; - } -cleanup_struct: - dns_rdata_freestruct(&sig); - - if (ret == DST_R_VERIFYFAILURE) - ret = DNS_R_SIGINVALID; - - if (ret == ISC_R_SUCCESS && labels - sig.labels > 0) { - if (wild != NULL) - RUNTIME_CHECK(dns_name_concatenate(dns_wildcardname, - dns_fixedname_name(&fnewname), - wild, NULL) == ISC_R_SUCCESS); - ret = DNS_R_FROMWILDCARD; - } - return (ret); -} - -isc_result_t -dns_dnssec_verify(dns_name_t *name, dns_rdataset_t *set, dst_key_t *key, - isc_boolean_t ignoretime, - dns_rdata_t *sigrdata) -{ - isc_result_t result; - - result = dns_dnssec_verify2(name, set, key, ignoretime, - sigrdata, NULL); - if (result == DNS_R_FROMWILDCARD) - result = ISC_R_SUCCESS; - return (result); -} - -isc_boolean_t -dns_dnssec_keyactive(dst_key_t *key, isc_stdtime_t now) { - isc_result_t result; - isc_stdtime_t publish, active, revoke, inactive, deltime; - isc_boolean_t pubset = ISC_FALSE, actset = ISC_FALSE; - isc_boolean_t revset = ISC_FALSE, inactset = ISC_FALSE; - isc_boolean_t delset = ISC_FALSE; - int major, minor; - - /* Is this an old-style key? */ - result = dst_key_getprivateformat(key, &major, &minor); - RUNTIME_CHECK(result == ISC_R_SUCCESS); - - /* - * Smart signing started with key format 1.3; prior to that, all - * keys are assumed active - */ - if (major == 1 && minor <= 2) - return (ISC_TRUE); - - result = dst_key_gettime(key, DST_TIME_PUBLISH, &publish); - if (result == ISC_R_SUCCESS) - pubset = ISC_TRUE; - - result = dst_key_gettime(key, DST_TIME_ACTIVATE, &active); - if (result == ISC_R_SUCCESS) - actset = ISC_TRUE; - - result = dst_key_gettime(key, DST_TIME_REVOKE, &revoke); - if (result == ISC_R_SUCCESS) - revset = ISC_TRUE; - - result = dst_key_gettime(key, DST_TIME_INACTIVE, &inactive); - if (result == ISC_R_SUCCESS) - inactset = ISC_TRUE; - - result = dst_key_gettime(key, DST_TIME_DELETE, &deltime); - if (result == ISC_R_SUCCESS) - delset = ISC_TRUE; - - if ((inactset && inactive <= now) || (delset && deltime <= now)) - return (ISC_FALSE); - - if (revset && revoke <= now && pubset && publish <= now) - return (ISC_TRUE); - - if (actset && active <= now) - return (ISC_TRUE); - - return (ISC_FALSE); -} - -#define is_zone_key(key) ((dst_key_flags(key) & DNS_KEYFLAG_OWNERMASK) \ - == DNS_KEYOWNER_ZONE) - -isc_result_t -dns_dnssec_signmessage(dns_message_t *msg, dst_key_t *key) { - dns_rdata_sig_t sig; /* SIG(0) */ - unsigned char data[512]; - unsigned char header[DNS_MESSAGE_HEADERLEN]; - isc_buffer_t headerbuf, databuf, sigbuf; - unsigned int sigsize; - isc_buffer_t *dynbuf = NULL; - dns_rdata_t *rdata; - dns_rdatalist_t *datalist; - dns_rdataset_t *dataset; - isc_region_t r; - isc_stdtime_t now; - dst_context_t *ctx = NULL; - isc_result_t result; - isc_boolean_t signeedsfree = ISC_TRUE; - - REQUIRE(msg != NULL); - REQUIRE(key != NULL); - - if (is_response(msg)) - REQUIRE(msg->query.base != NULL); - - memset(&sig, 0, sizeof(sig)); - - sig.common.rdclass = dns_rdataclass_any; - sig.common.rdtype = dns_rdatatype_sig; /* SIG(0) */ - ISC_LINK_INIT(&sig.common, link); - - sig.covered = 0; - sig.algorithm = dst_key_alg(key); - sig.labels = 0; /* the root name */ - sig.originalttl = 0; - - isc_stdtime_get(&now); - sig.timesigned = now - DNS_TSIG_FUDGE; - sig.timeexpire = now + DNS_TSIG_FUDGE; - - sig.keyid = dst_key_id(key); - - dns_name_init(&sig.signer, NULL); - dns_name_clone(dst_key_name(key), &sig.signer); - - sig.siglen = 0; - sig.signature = NULL; - - isc_buffer_init(&databuf, data, sizeof(data)); - - RETERR(dst_context_create3(key, - DNS_LOGCATEGORY_DNSSEC, ISC_TRUE, &ctx)); - - /* - * Digest the fields of the SIG - we can cheat and use - * dns_rdata_fromstruct. Since siglen is 0, the digested data - * is identical to dns format. - */ - RETERR(dns_rdata_fromstruct(NULL, dns_rdataclass_any, - dns_rdatatype_sig /* SIG(0) */, - &sig, &databuf)); - isc_buffer_usedregion(&databuf, &r); - RETERR(dst_context_adddata(ctx, &r)); - - /* - * If this is a response, digest the query. - */ - if (is_response(msg)) - RETERR(dst_context_adddata(ctx, &msg->query)); - - /* - * Digest the header. - */ - isc_buffer_init(&headerbuf, header, sizeof(header)); - dns_message_renderheader(msg, &headerbuf); - isc_buffer_usedregion(&headerbuf, &r); - RETERR(dst_context_adddata(ctx, &r)); - - /* - * Digest the remainder of the message. - */ - isc_buffer_usedregion(msg->buffer, &r); - isc_region_consume(&r, DNS_MESSAGE_HEADERLEN); - RETERR(dst_context_adddata(ctx, &r)); - - RETERR(dst_key_sigsize(key, &sigsize)); - sig.siglen = sigsize; - sig.signature = (unsigned char *) malloc(sig.siglen); - if (sig.signature == NULL) { - result = ISC_R_NOMEMORY; - goto failure; - } - - isc_buffer_init(&sigbuf, sig.signature, sig.siglen); - RETERR(dst_context_sign(ctx, &sigbuf)); - dst_context_destroy(&ctx); - - rdata = NULL; - RETERR(dns_message_gettemprdata(msg, &rdata)); - RETERR(isc_buffer_allocate( &dynbuf, 1024)); - RETERR(dns_rdata_fromstruct(rdata, dns_rdataclass_any, - dns_rdatatype_sig /* SIG(0) */, - &sig, dynbuf)); - - free(sig.signature); - signeedsfree = ISC_FALSE; - - dns_message_takebuffer(msg, &dynbuf); - - datalist = NULL; - RETERR(dns_message_gettemprdatalist(msg, &datalist)); - datalist->rdclass = dns_rdataclass_any; - datalist->type = dns_rdatatype_sig; /* SIG(0) */ - ISC_LIST_APPEND(datalist->rdata, rdata, link); - dataset = NULL; - RETERR(dns_message_gettemprdataset(msg, &dataset)); - RUNTIME_CHECK(dns_rdatalist_tordataset(datalist, dataset) == ISC_R_SUCCESS); - msg->sig0 = dataset; - - return (ISC_R_SUCCESS); - -failure: - if (dynbuf != NULL) - isc_buffer_free(&dynbuf); - if (signeedsfree) - free(sig.signature); - if (ctx != NULL) - dst_context_destroy(&ctx); - - return (result); -} - -isc_result_t -dns_dnssec_verifymessage(isc_buffer_t *source, dns_message_t *msg, - dst_key_t *key) -{ - dns_rdata_sig_t sig; /* SIG(0) */ - unsigned char header[DNS_MESSAGE_HEADERLEN]; - dns_rdata_t rdata = DNS_RDATA_INIT; - isc_region_t r, source_r, sig_r, header_r; - isc_stdtime_t now; - dst_context_t *ctx = NULL; - isc_result_t result; - uint16_t addcount, addcount_n; - isc_boolean_t signeedsfree = ISC_FALSE; - - REQUIRE(source != NULL); - REQUIRE(msg != NULL); - REQUIRE(key != NULL); - - - msg->verify_attempted = 1; - msg->verified_sig = 0; - msg->sig0status = dns_tsigerror_badsig; - - if (is_response(msg)) { - if (msg->query.base == NULL) - return (DNS_R_UNEXPECTEDTSIG); - } - - isc_buffer_usedregion(source, &source_r); - - RETERR(dns_rdataset_first(msg->sig0)); - dns_rdataset_current(msg->sig0, &rdata); - - RETERR(dns_rdata_tostruct(&rdata, &sig)); - signeedsfree = ISC_TRUE; - - if (sig.labels != 0) { - result = DNS_R_SIGINVALID; - goto failure; - } - - if (isc_serial_lt(sig.timeexpire, sig.timesigned)) { - result = DNS_R_SIGINVALID; - msg->sig0status = dns_tsigerror_badtime; - goto failure; - } - - isc_stdtime_get(&now); - if (isc_serial_lt((uint32_t)now, sig.timesigned)) { - result = DNS_R_SIGFUTURE; - msg->sig0status = dns_tsigerror_badtime; - goto failure; - } - else if (isc_serial_lt(sig.timeexpire, (uint32_t)now)) { - result = DNS_R_SIGEXPIRED; - msg->sig0status = dns_tsigerror_badtime; - goto failure; - } - - if (!dns_name_equal(dst_key_name(key), &sig.signer)) { - result = DNS_R_SIGINVALID; - msg->sig0status = dns_tsigerror_badkey; - goto failure; - } - - RETERR(dst_context_create3(key, - DNS_LOGCATEGORY_DNSSEC, ISC_FALSE, &ctx)); - - /* - * Digest the SIG(0) record, except for the signature. - */ - dns_rdata_toregion(&rdata, &r); - r.length -= sig.siglen; - RETERR(dst_context_adddata(ctx, &r)); - - /* - * If this is a response, digest the query. - */ - if (is_response(msg)) - RETERR(dst_context_adddata(ctx, &msg->query)); - - /* - * Extract the header. - */ - memmove(header, source_r.base, DNS_MESSAGE_HEADERLEN); - - /* - * Decrement the additional field counter. - */ - memmove(&addcount, &header[DNS_MESSAGE_HEADERLEN - 2], 2); - addcount_n = ntohs(addcount); - addcount = htons((uint16_t)(addcount_n - 1)); - memmove(&header[DNS_MESSAGE_HEADERLEN - 2], &addcount, 2); - - /* - * Digest the modified header. - */ - header_r.base = (unsigned char *) header; - header_r.length = DNS_MESSAGE_HEADERLEN; - RETERR(dst_context_adddata(ctx, &header_r)); - - /* - * Digest all non-SIG(0) records. - */ - r.base = source_r.base + DNS_MESSAGE_HEADERLEN; - r.length = msg->sigstart - DNS_MESSAGE_HEADERLEN; - RETERR(dst_context_adddata(ctx, &r)); - - sig_r.base = sig.signature; - sig_r.length = sig.siglen; - result = dst_context_verify(ctx, &sig_r); - if (result != ISC_R_SUCCESS) { - msg->sig0status = dns_tsigerror_badsig; - goto failure; - } - - msg->verified_sig = 1; - msg->sig0status = dns_rcode_noerror; - - dst_context_destroy(&ctx); - dns_rdata_freestruct(&sig); - - return (ISC_R_SUCCESS); - -failure: - if (signeedsfree) - dns_rdata_freestruct(&sig); - if (ctx != NULL) - dst_context_destroy(&ctx); - - return (result); -} - -/*% - * Does this key ('rdata') self sign the rrset ('rdataset')? - */ -isc_boolean_t -dns_dnssec_selfsigns(dns_rdata_t *rdata, dns_name_t *name, - dns_rdataset_t *rdataset, dns_rdataset_t *sigrdataset, - isc_boolean_t ignoretime) -{ - INSIST(rdataset->type == dns_rdatatype_key || - rdataset->type == dns_rdatatype_dnskey); - if (rdataset->type == dns_rdatatype_key) { - INSIST(sigrdataset->type == dns_rdatatype_sig); - INSIST(sigrdataset->covers == dns_rdatatype_key); - } else { - INSIST(sigrdataset->type == dns_rdatatype_rrsig); - INSIST(sigrdataset->covers == dns_rdatatype_dnskey); - } - - return (dns_dnssec_signs(rdata, name, rdataset, sigrdataset, - ignoretime)); - -} - -isc_boolean_t -dns_dnssec_signs(dns_rdata_t *rdata, dns_name_t *name, - dns_rdataset_t *rdataset, dns_rdataset_t *sigrdataset, - isc_boolean_t ignoretime) -{ - dst_key_t *dstkey = NULL; - dns_keytag_t keytag; - dns_rdata_dnskey_t key; - dns_rdata_rrsig_t sig; - dns_rdata_t sigrdata = DNS_RDATA_INIT; - isc_result_t result; - - INSIST(sigrdataset->type == dns_rdatatype_rrsig); - if (sigrdataset->covers != rdataset->type) - return (ISC_FALSE); - - result = dns_dnssec_keyfromrdata(name, rdata, &dstkey); - if (result != ISC_R_SUCCESS) - return (ISC_FALSE); - result = dns_rdata_tostruct(rdata, &key); - RUNTIME_CHECK(result == ISC_R_SUCCESS); - - keytag = dst_key_id(dstkey); - for (result = dns_rdataset_first(sigrdataset); - result == ISC_R_SUCCESS; - result = dns_rdataset_next(sigrdataset)) - { - dns_rdata_reset(&sigrdata); - dns_rdataset_current(sigrdataset, &sigrdata); - result = dns_rdata_tostruct(&sigrdata, &sig); - RUNTIME_CHECK(result == ISC_R_SUCCESS); - - if (sig.algorithm == key.algorithm && - sig.keyid == keytag) { - result = dns_dnssec_verify2(name, rdataset, dstkey, - ignoretime, - &sigrdata, NULL); - if (result == ISC_R_SUCCESS) { - dst_key_free(&dstkey); - return (ISC_TRUE); - } - } - } - dst_key_free(&dstkey); - return (ISC_FALSE); -} - -isc_result_t -dns_dnsseckey_create(dst_key_t **dstkey, - dns_dnsseckey_t **dkp) -{ - isc_result_t result; - dns_dnsseckey_t *dk; - int major, minor; - - REQUIRE(dkp != NULL && *dkp == NULL); - dk = malloc(sizeof(dns_dnsseckey_t)); - if (dk == NULL) - return (ISC_R_NOMEMORY); - - dk->key = *dstkey; - *dstkey = NULL; - dk->force_publish = ISC_FALSE; - dk->force_sign = ISC_FALSE; - dk->hint_publish = ISC_FALSE; - dk->hint_sign = ISC_FALSE; - dk->hint_remove = ISC_FALSE; - dk->first_sign = ISC_FALSE; - dk->is_active = ISC_FALSE; - dk->prepublish = 0; - dk->source = dns_keysource_unknown; - dk->index = 0; - - /* KSK or ZSK? */ - dk->ksk = ISC_TF((dst_key_flags(dk->key) & DNS_KEYFLAG_KSK) != 0); - - /* Is this an old-style key? */ - result = dst_key_getprivateformat(dk->key, &major, &minor); - INSIST(result == ISC_R_SUCCESS); - - /* Smart signing started with key format 1.3 */ - dk->legacy = ISC_TF(major == 1 && minor <= 2); - - ISC_LINK_INIT(dk, link); - *dkp = dk; - return (ISC_R_SUCCESS); -} - -void -dns_dnsseckey_destroy(dns_dnsseckey_t **dkp) { - dns_dnsseckey_t *dk; - - REQUIRE(dkp != NULL && *dkp != NULL); - dk = *dkp; - if (dk->key != NULL) - dst_key_free(&dk->key); - free(dk); - *dkp = NULL; -} - -static void -get_hints(dns_dnsseckey_t *key, isc_stdtime_t now) { - isc_result_t result; - isc_stdtime_t publish, active, revoke, inactive, deltime; - isc_boolean_t pubset = ISC_FALSE, actset = ISC_FALSE; - isc_boolean_t revset = ISC_FALSE, inactset = ISC_FALSE; - isc_boolean_t delset = ISC_FALSE; - - REQUIRE(key != NULL && key->key != NULL); - - result = dst_key_gettime(key->key, DST_TIME_PUBLISH, &publish); - if (result == ISC_R_SUCCESS) - pubset = ISC_TRUE; - - result = dst_key_gettime(key->key, DST_TIME_ACTIVATE, &active); - if (result == ISC_R_SUCCESS) - actset = ISC_TRUE; - - result = dst_key_gettime(key->key, DST_TIME_REVOKE, &revoke); - if (result == ISC_R_SUCCESS) - revset = ISC_TRUE; - - result = dst_key_gettime(key->key, DST_TIME_INACTIVE, &inactive); - if (result == ISC_R_SUCCESS) - inactset = ISC_TRUE; - - result = dst_key_gettime(key->key, DST_TIME_DELETE, &deltime); - if (result == ISC_R_SUCCESS) - delset = ISC_TRUE; - - /* Metadata says publish (but possibly not activate) */ - if (pubset && publish <= now) - key->hint_publish = ISC_TRUE; - - /* Metadata says activate (so we must also publish) */ - if (actset && active <= now) { - key->hint_sign = ISC_TRUE; - - /* Only publish if publish time has already passed. */ - if (pubset && publish <= now) - key->hint_publish = ISC_TRUE; - } - - /* - * Activation date is set (maybe in the future), but - * publication date isn't. Most likely the user wants to - * publish now and activate later. - */ - if (actset && !pubset) - key->hint_publish = ISC_TRUE; - - /* - * If activation date is in the future, make note of how far off - */ - if (key->hint_publish && actset && active > now) { - key->prepublish = active - now; - } - - /* - * Key has been marked inactive: we can continue publishing, - * but don't sign. - */ - if (key->hint_publish && inactset && inactive <= now) { - key->hint_sign = ISC_FALSE; - } - - /* - * Metadata says revoke. If the key is published, - * we *have to* sign with it per RFC5011--even if it was - * not active before. - * - * If it hasn't already been done, we should also revoke it now. - */ - if (key->hint_publish && (revset && revoke <= now)) { - uint32_t flags; - key->hint_sign = ISC_TRUE; - flags = dst_key_flags(key->key); - if ((flags & DNS_KEYFLAG_REVOKE) == 0) { - flags |= DNS_KEYFLAG_REVOKE; - dst_key_setflags(key->key, flags); - } - } - - /* - * Metadata says delete, so don't publish this key or sign with it. - */ - if (delset && deltime <= now) { - key->hint_publish = ISC_FALSE; - key->hint_sign = ISC_FALSE; - key->hint_remove = ISC_TRUE; - } -} - -/*% - * Get a list of DNSSEC keys from the key repository - */ -isc_result_t -dns_dnssec_findmatchingkeys(dns_name_t *origin, const char *directory, - dns_dnsseckeylist_t *keylist) -{ - isc_result_t result = ISC_R_SUCCESS; - isc_boolean_t dir_open = ISC_FALSE; - dns_dnsseckeylist_t list; - isc_dir_t dir; - dns_dnsseckey_t *key = NULL; - dst_key_t *dstkey = NULL; - char namebuf[DNS_NAME_FORMATSIZE]; - isc_buffer_t b; - unsigned int len, i, alg; - isc_stdtime_t now; - - REQUIRE(keylist != NULL); - ISC_LIST_INIT(list); - isc_dir_init(&dir); - - isc_buffer_init(&b, namebuf, sizeof(namebuf) - 1); - RETERR(dns_name_tofilenametext(origin, ISC_FALSE, &b)); - len = isc_buffer_usedlength(&b); - namebuf[len] = '\0'; - - if (directory == NULL) - directory = "."; - RETERR(isc_dir_open(&dir, directory)); - dir_open = ISC_TRUE; - - isc_stdtime_get(&now); - - while (isc_dir_read(&dir) == ISC_R_SUCCESS) { - if (dir.entry.name[0] != 'K' || - dir.entry.length < len + 1 || - dir.entry.name[len + 1] != '+' || - strncasecmp(dir.entry.name + 1, namebuf, len) != 0) - continue; - - alg = 0; - for (i = len + 1 + 1; i < dir.entry.length ; i++) { - if (dir.entry.name[i] < '0' || dir.entry.name[i] > '9') - break; - alg *= 10; - alg += dir.entry.name[i] - '0'; - } - - /* - * Did we not read exactly 3 digits? - * Did we overflow? - * Did we correctly terminate? - */ - if (i != len + 1 + 1 + 3 || i >= dir.entry.length || - dir.entry.name[i] != '+') - continue; - - for (i++ ; i < dir.entry.length ; i++) - if (dir.entry.name[i] < '0' || dir.entry.name[i] > '9') - break; - - /* - * Did we not read exactly 5 more digits? - * Did we overflow? - * Did we correctly terminate? - */ - if (i != len + 1 + 1 + 3 + 1 + 5 || i >= dir.entry.length || - strcmp(dir.entry.name + i, ".private") != 0) - continue; - - dstkey = NULL; - result = dst_key_fromnamedfile(dir.entry.name, - directory, - DST_TYPE_PUBLIC | - DST_TYPE_PRIVATE, - &dstkey); - - switch (alg) { - case DST_ALG_HMACSHA1: - case DST_ALG_HMACSHA224: - case DST_ALG_HMACSHA256: - case DST_ALG_HMACSHA384: - case DST_ALG_HMACSHA512: - if (result == DST_R_BADKEYTYPE) - continue; - } - - if (result != ISC_R_SUCCESS) { - isc_log_write(dns_lctx, - DNS_LOGCATEGORY_GENERAL, - DNS_LOGMODULE_DNSSEC, - ISC_LOG_WARNING, - "dns_dnssec_findmatchingkeys: " - "error reading key file %s: %s", - dir.entry.name, - isc_result_totext(result)); - continue; - } - - RETERR(dns_dnsseckey_create(&dstkey, &key)); - key->source = dns_keysource_repository; - get_hints(key, now); - - if (key->legacy) { - dns_dnsseckey_destroy(&key); - } else { - ISC_LIST_APPEND(list, key, link); - key = NULL; - } - } - - if (!ISC_LIST_EMPTY(list)) { - result = ISC_R_SUCCESS; - ISC_LIST_APPENDLIST(*keylist, list, link); - } else - result = ISC_R_NOTFOUND; - - failure: - if (dir_open) - isc_dir_close(&dir); - INSIST(key == NULL); - while ((key = ISC_LIST_HEAD(list)) != NULL) { - ISC_LIST_UNLINK(list, key, link); - INSIST(key->key != NULL); - dst_key_free(&key->key); - dns_dnsseckey_destroy(&key); - } - if (dstkey != NULL) - dst_key_free(&dstkey); - return (result); -} - -/*% - * Add 'newkey' to 'keylist' if it's not already there. - * - * If 'savekeys' is ISC_TRUE, then we need to preserve all - * the keys in the keyset, regardless of whether they have - * metadata indicating they should be deactivated or removed. - */ -static isc_result_t -addkey(dns_dnsseckeylist_t *keylist, dst_key_t **newkey, - isc_boolean_t savekeys) -{ - dns_dnsseckey_t *key; - isc_result_t result; - - /* Skip duplicates */ - for (key = ISC_LIST_HEAD(*keylist); - key != NULL; - key = ISC_LIST_NEXT(key, link)) { - if (dst_key_id(key->key) == dst_key_id(*newkey) && - dst_key_alg(key->key) == dst_key_alg(*newkey) && - dns_name_equal(dst_key_name(key->key), - dst_key_name(*newkey))) - break; - } - - if (key != NULL) { - /* - * Found a match. If the old key was only public and the - * new key is private, replace the old one; otherwise - * leave it. But either way, mark the key as having - * been found in the zone. - */ - if (dst_key_isprivate(key->key)) { - dst_key_free(newkey); - } else if (dst_key_isprivate(*newkey)) { - dst_key_free(&key->key); - key->key = *newkey; - } - - key->source = dns_keysource_zoneapex; - return (ISC_R_SUCCESS); - } - - result = dns_dnsseckey_create(newkey, &key); - if (result != ISC_R_SUCCESS) - return (result); - if (key->legacy || savekeys) { - key->force_publish = ISC_TRUE; - key->force_sign = dst_key_isprivate(key->key); - } - key->source = dns_keysource_zoneapex; - ISC_LIST_APPEND(*keylist, key, link); - *newkey = NULL; - return (ISC_R_SUCCESS); -} - - -/*% - * Mark all keys which signed the DNSKEY/SOA RRsets as "active", - * for future reference. - */ -static isc_result_t -mark_active_keys(dns_dnsseckeylist_t *keylist, dns_rdataset_t *rrsigs) { - isc_result_t result = ISC_R_SUCCESS; - dns_rdata_t rdata = DNS_RDATA_INIT; - dns_rdataset_t sigs; - dns_dnsseckey_t *key; - - REQUIRE(rrsigs != NULL && dns_rdataset_isassociated(rrsigs)); - - dns_rdataset_init(&sigs); - dns_rdataset_clone(rrsigs, &sigs); - for (key = ISC_LIST_HEAD(*keylist); - key != NULL; - key = ISC_LIST_NEXT(key, link)) { - uint16_t keyid, sigid; - dns_secalg_t keyalg, sigalg; - keyid = dst_key_id(key->key); - keyalg = dst_key_alg(key->key); - - for (result = dns_rdataset_first(&sigs); - result == ISC_R_SUCCESS; - result = dns_rdataset_next(&sigs)) { - dns_rdata_rrsig_t sig; - - dns_rdata_reset(&rdata); - dns_rdataset_current(&sigs, &rdata); - result = dns_rdata_tostruct(&rdata, &sig); - RUNTIME_CHECK(result == ISC_R_SUCCESS); - sigalg = sig.algorithm; - sigid = sig.keyid; - if (keyid == sigid && keyalg == sigalg) { - key->is_active = ISC_TRUE; - break; - } - } - } - - if (result == ISC_R_NOMORE) - result = ISC_R_SUCCESS; - - if (dns_rdataset_isassociated(&sigs)) - dns_rdataset_disassociate(&sigs); - return (result); -} - -/*% - * Add the contents of a DNSKEY rdataset 'keyset' to 'keylist'. - */ -isc_result_t -dns_dnssec_keylistfromrdataset(dns_name_t *origin, - const char *directory, - dns_rdataset_t *keyset, dns_rdataset_t *keysigs, - dns_rdataset_t *soasigs, isc_boolean_t savekeys, - isc_boolean_t publickey, - dns_dnsseckeylist_t *keylist) -{ - dns_rdataset_t keys; - dns_rdata_t rdata = DNS_RDATA_INIT; - dst_key_t *pubkey = NULL, *privkey = NULL; - isc_result_t result; - - REQUIRE(keyset != NULL && dns_rdataset_isassociated(keyset)); - - dns_rdataset_init(&keys); - - dns_rdataset_clone(keyset, &keys); - for (result = dns_rdataset_first(&keys); - result == ISC_R_SUCCESS; - result = dns_rdataset_next(&keys)) { - dns_rdata_reset(&rdata); - dns_rdataset_current(&keys, &rdata); - RETERR(dns_dnssec_keyfromrdata(origin, &rdata, &pubkey)); - dst_key_setttl(pubkey, keys.ttl); - - if (!is_zone_key(pubkey) || - (dst_key_flags(pubkey) & DNS_KEYTYPE_NOAUTH) != 0) - goto skip; - - /* Corrupted .key file? */ - if (!dns_name_equal(origin, dst_key_name(pubkey))) - goto skip; - - if (publickey) { - RETERR(addkey(keylist, &pubkey, savekeys)); - goto skip; - } - - result = dst_key_fromfile(dst_key_name(pubkey), - dst_key_id(pubkey), - dst_key_alg(pubkey), - DST_TYPE_PUBLIC|DST_TYPE_PRIVATE, - directory, &privkey); - - /* - * If the key was revoked and the private file - * doesn't exist, maybe it was revoked internally - * by named. Try loading the unrevoked version. - */ - if (result == ISC_R_FILENOTFOUND) { - uint32_t flags; - flags = dst_key_flags(pubkey); - if ((flags & DNS_KEYFLAG_REVOKE) != 0) { - dst_key_setflags(pubkey, - flags & ~DNS_KEYFLAG_REVOKE); - result = dst_key_fromfile(dst_key_name(pubkey), - dst_key_id(pubkey), - dst_key_alg(pubkey), - DST_TYPE_PUBLIC| - DST_TYPE_PRIVATE, - directory, - &privkey); - if (result == ISC_R_SUCCESS && - dst_key_pubcompare(pubkey, privkey, - ISC_FALSE)) { - dst_key_setflags(privkey, flags); - } - dst_key_setflags(pubkey, flags); - } - } - - if (result != ISC_R_SUCCESS) { - char keybuf[DNS_NAME_FORMATSIZE]; - char algbuf[DNS_SECALG_FORMATSIZE]; - dns_name_format(dst_key_name(pubkey), keybuf, - sizeof(keybuf)); - dns_secalg_format(dst_key_alg(pubkey), algbuf, - sizeof(algbuf)); - isc_log_write(dns_lctx, DNS_LOGCATEGORY_GENERAL, - DNS_LOGMODULE_DNSSEC, ISC_LOG_WARNING, - "dns_dnssec_keylistfromrdataset: error " - "reading private key file %s/%s/%d: %s", - keybuf, algbuf, dst_key_id(pubkey), - isc_result_totext(result)); - } - - if (result == ISC_R_FILENOTFOUND || result == ISC_R_NOPERM) { - RETERR(addkey(keylist, &pubkey, savekeys)); - goto skip; - } - RETERR(result); - - /* This should never happen. */ - if ((dst_key_flags(privkey) & DNS_KEYTYPE_NOAUTH) != 0) - goto skip; - - /* - * Whatever the key's default TTL may have - * been, the rdataset TTL takes priority. - */ - dst_key_setttl(privkey, dst_key_getttl(pubkey)); - - RETERR(addkey(keylist, &privkey, savekeys)); - skip: - if (pubkey != NULL) - dst_key_free(&pubkey); - if (privkey != NULL) - dst_key_free(&privkey); - } - - if (result != ISC_R_NOMORE) - RETERR(result); - - if (keysigs != NULL && dns_rdataset_isassociated(keysigs)) - RETERR(mark_active_keys(keylist, keysigs)); - - if (soasigs != NULL && dns_rdataset_isassociated(soasigs)) - RETERR(mark_active_keys(keylist, soasigs)); - - result = ISC_R_SUCCESS; - - failure: - if (dns_rdataset_isassociated(&keys)) - dns_rdataset_disassociate(&keys); - if (pubkey != NULL) - dst_key_free(&pubkey); - if (privkey != NULL) - dst_key_free(&privkey); - return (result); -} diff --git a/usr.sbin/bind/lib/dns/include/dns/dnssec.h b/usr.sbin/bind/lib/dns/include/dns/dnssec.h deleted file mode 100644 index 4ad5b61e6c9..00000000000 --- a/usr.sbin/bind/lib/dns/include/dns/dnssec.h +++ /dev/null @@ -1,313 +0,0 @@ -/* - * Copyright (C) Internet Systems Consortium, Inc. ("ISC") - * - * Permission to use, copy, modify, and/or distribute this software for any - * purpose with or without fee is hereby granted, provided that the above - * copyright notice and this permission notice appear in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH - * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY - * AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT, - * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM - * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE - * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR - * PERFORMANCE OF THIS SOFTWARE. - */ - -/* $Id: dnssec.h,v 1.7 2020/01/20 18:51:52 florian Exp $ */ - -#ifndef DNS_DNSSEC_H -#define DNS_DNSSEC_H 1 - -/*! \file dns/dnssec.h */ - -#include <isc/lang.h> -#include <isc/stdtime.h> - - - -#include <dns/types.h> - -#include <dst/dst.h> - -ISC_LANG_BEGINDECLS - -extern isc_stats_t *dns_dnssec_stats; - -/*%< Maximum number of keys supported in a zone. */ -#define DNS_MAXZONEKEYS 32 - -/* - * Indicates how the signer found this key: in the key repository, at the - * zone apex, or specified by the user. - */ -typedef enum { - dns_keysource_unknown, - dns_keysource_repository, - dns_keysource_zoneapex, - dns_keysource_user -} dns_keysource_t; - -/* - * A DNSSEC key and hints about its intended use gleaned from metadata - */ -struct dns_dnsseckey { - dst_key_t *key; - isc_boolean_t hint_publish; /*% metadata says to publish */ - isc_boolean_t force_publish; /*% publish regardless of metadata */ - isc_boolean_t hint_sign; /*% metadata says to sign with this key */ - isc_boolean_t force_sign; /*% sign with key regardless of metadata */ - isc_boolean_t hint_remove; /*% metadata says *don't* publish */ - isc_boolean_t is_active; /*% key is already active */ - isc_boolean_t first_sign; /*% key is newly becoming active */ - unsigned int prepublish; /*% how long until active? */ - dns_keysource_t source; /*% how the key was found */ - isc_boolean_t ksk; /*% this is a key-signing key */ - isc_boolean_t legacy; /*% this is old-style key with no - metadata (possibly generated by - an older version of BIND9) and - should be ignored when searching - for keys to import into the zone */ - unsigned int index; /*% position in list */ - ISC_LINK(dns_dnsseckey_t) link; -}; - -isc_result_t -dns_dnssec_keyfromrdata(dns_name_t *name, dns_rdata_t *rdata, - dst_key_t **key); -/*%< - * Creates a DST key from a DNS record. Basically a wrapper around - * dst_key_fromdns(). - * - * Requires: - *\li 'name' is not NULL - *\li 'rdata' is not NULL - *\li 'mctx' is not NULL - *\li 'key' is not NULL - *\li '*key' is NULL - * - * Returns: - *\li #ISC_R_SUCCESS - *\li #ISC_R_NOMEMORY - *\li DST_R_INVALIDPUBLICKEY - *\li various errors from dns_name_totext - */ - -isc_result_t -dns_dnssec_sign(dns_name_t *name, dns_rdataset_t *set, dst_key_t *key, - isc_stdtime_t *inception, isc_stdtime_t *expire, - isc_buffer_t *buffer, dns_rdata_t *sigrdata); -/*%< - * Generates a RRSIG record covering this rdataset. This has no effect - * on existing RRSIG records. - * - * Requires: - *\li 'name' (the owner name of the record) is a valid name - *\li 'set' is a valid rdataset - *\li 'key' is a valid key - *\li 'inception' is not NULL - *\li 'expire' is not NULL - *\li 'mctx' is not NULL - *\li 'buffer' is not NULL - *\li 'sigrdata' is not NULL - * - * Returns: - *\li #ISC_R_SUCCESS - *\li #ISC_R_NOMEMORY - *\li #ISC_R_NOSPACE - *\li #DNS_R_INVALIDTIME - the expiration is before the inception - *\li #DNS_R_KEYUNAUTHORIZED - the key cannot sign this data (either - * it is not a zone key or its flags prevent - * authentication) - *\li DST_R_* - */ - -isc_result_t -dns_dnssec_verify(dns_name_t *name, dns_rdataset_t *set, dst_key_t *key, - isc_boolean_t ignoretime, - dns_rdata_t *sigrdata); - -isc_result_t -dns_dnssec_verify2(dns_name_t *name, dns_rdataset_t *set, dst_key_t *key, - isc_boolean_t ignoretime, - dns_rdata_t *sigrdata, dns_name_t *wild); - -isc_result_t -dns_dnssec_verify3(dns_name_t *name, dns_rdataset_t *set, dst_key_t *key, - isc_boolean_t ignoretime, unsigned int maxbits, - dns_rdata_t *sigrdata, dns_name_t *wild); -/*%< - * Verifies the RRSIG record covering this rdataset signed by a specific - * key. This does not determine if the key's owner is authorized to sign - * this record, as this requires a resolver or database. - * If 'ignoretime' is ISC_TRUE, temporal validity will not be checked. - * - * 'maxbits' specifies the maximum number of rsa exponent bits accepted. - * - * Requires: - *\li 'name' (the owner name of the record) is a valid name - *\li 'set' is a valid rdataset - *\li 'key' is a valid key - *\li 'mctx' is not NULL - *\li 'sigrdata' is a valid rdata containing a SIG record - *\li 'wild' if non-NULL then is a valid and has a buffer. - * - * Returns: - *\li #ISC_R_SUCCESS - *\li #ISC_R_NOMEMORY - *\li #DNS_R_FROMWILDCARD - the signature is valid and is from - * a wildcard expansion. dns_dnssec_verify2() only. - * 'wild' contains the name of the wildcard if non-NULL. - *\li #DNS_R_SIGINVALID - the signature fails to verify - *\li #DNS_R_SIGEXPIRED - the signature has expired - *\li #DNS_R_SIGFUTURE - the signature's validity period has not begun - *\li #DNS_R_KEYUNAUTHORIZED - the key cannot sign this data (either - * it is not a zone key or its flags prevent - * authentication) - *\li DST_R_* - */ - -isc_boolean_t -dns_dnssec_keyactive(dst_key_t *key, isc_stdtime_t now); -/*%< - * - * Returns ISC_TRUE if 'key' is active as of the time specified - * in 'now' (i.e., if the activation date has passed, inactivation or - * deletion date has not yet been reached, and the key is not revoked - * -- or if it is a legacy key without metadata). Otherwise returns - * ISC_FALSE. - * - * Requires: - *\li 'key' is a valid key - */ - -isc_result_t -dns_dnssec_signmessage(dns_message_t *msg, dst_key_t *key); -/*%< - * Signs a message with a SIG(0) record. This is implicitly called by - * dns_message_renderend() if msg->sig0key is not NULL. - * - * Requires: - *\li 'msg' is a valid message - *\li 'key' is a valid key that can be used for signing - * - * Returns: - *\li #ISC_R_SUCCESS - *\li #ISC_R_NOMEMORY - *\li DST_R_* - */ - -isc_result_t -dns_dnssec_verifymessage(isc_buffer_t *source, dns_message_t *msg, - dst_key_t *key); -/*%< - * Verifies a message signed by a SIG(0) record. This is not - * called implicitly by dns_message_parse(). If dns_message_signer() - * is called before dns_dnssec_verifymessage(), it will return - * #DNS_R_NOTVERIFIEDYET. dns_dnssec_verifymessage() will set - * the verified_sig0 flag in msg if the verify succeeds, and - * the sig0status field otherwise. - * - * Requires: - *\li 'source' is a valid buffer containing the unparsed message - *\li 'msg' is a valid message - *\li 'key' is a valid key - * - * Returns: - *\li #ISC_R_SUCCESS - *\li #ISC_R_NOMEMORY - *\li #ISC_R_NOTFOUND - no SIG(0) was found - *\li #DNS_R_SIGINVALID - the SIG record is not well-formed or - * was not generated by the key. - *\li DST_R_* - */ - -isc_boolean_t -dns_dnssec_selfsigns(dns_rdata_t *rdata, dns_name_t *name, - dns_rdataset_t *rdataset, dns_rdataset_t *sigrdataset, - isc_boolean_t ignoretime); - - -isc_boolean_t -dns_dnssec_signs(dns_rdata_t *rdata, dns_name_t *name, - dns_rdataset_t *rdataset, dns_rdataset_t *sigrdataset, - isc_boolean_t ignoretime); -/*%< - * Verify that 'rdataset' is validly signed in 'sigrdataset' by - * the key in 'rdata'. - * - * dns_dnssec_selfsigns() requires that rdataset be a DNSKEY or KEY - * rrset. dns_dnssec_signs() works on any rrset. - */ - - -isc_result_t -dns_dnsseckey_create(dst_key_t **dstkey, - dns_dnsseckey_t **dkp); -/*%< - * Create and initialize a dns_dnsseckey_t structure. - * - * Requires: - *\li 'dkp' is not NULL and '*dkp' is NULL. - * - * Returns: - *\li #ISC_R_SUCCESS - *\li #ISC_R_NOMEMORY - */ - -void -dns_dnsseckey_destroy(dns_dnsseckey_t **dkp); -/*%< - * Reclaim a dns_dnsseckey_t structure. - * - * Requires: - *\li 'dkp' is not NULL and '*dkp' is not NULL. - * - * Ensures: - *\li '*dkp' is NULL. - */ - -isc_result_t -dns_dnssec_findmatchingkeys(dns_name_t *origin, const char *directory, - dns_dnsseckeylist_t *keylist); -/*%< - * Search 'directory' for K* key files matching the name in 'origin'. - * Append all such keys, along with use hints gleaned from their - * metadata, onto 'keylist'. - * - * Requires: - *\li 'keylist' is not NULL - * - * Returns: - *\li #ISC_R_SUCCESS - *\li #ISC_R_NOTFOUND - *\li #ISC_R_NOMEMORY - *\li any error returned by dns_name_totext(), isc_dir_open(), or - * dst_key_fromnamedfile() - * - * Ensures: - *\li On error, keylist is unchanged - */ - -isc_result_t -dns_dnssec_keylistfromrdataset(dns_name_t *origin, - const char *directory, - dns_rdataset_t *keyset, dns_rdataset_t *keysigs, - dns_rdataset_t *soasigs, isc_boolean_t savekeys, - isc_boolean_t publickey, - dns_dnsseckeylist_t *keylist); -/*%< - * Append the contents of a DNSKEY rdataset 'keyset' to 'keylist'. - * Omit duplicates. If 'publickey' is ISC_FALSE, search 'directory' for - * matching key files, and load the private keys that go with - * the public ones. If 'savekeys' is ISC_TRUE, mark the keys so - * they will not be deleted or inactivated regardless of metadata. - * - * 'keysigs' and 'soasigs', if not NULL and associated, contain the - * RRSIGS for the DNSKEY and SOA records respectively and are used to mark - * whether a key is already active in the zone. - */ - -ISC_LANG_ENDDECLS - -#endif /* DNS_DNSSEC_H */ diff --git a/usr.sbin/bind/lib/dns/include/dns/message.h b/usr.sbin/bind/lib/dns/include/dns/message.h index 755c75a96f7..deabf4ad413 100644 --- a/usr.sbin/bind/lib/dns/include/dns/message.h +++ b/usr.sbin/bind/lib/dns/include/dns/message.h @@ -244,7 +244,6 @@ struct dns_message { int timeadjust; dns_name_t *sig0name; /* Owner name of SIG0, if any */ - dst_key_t *sig0key; dns_rcode_t sig0status; isc_region_t query; isc_region_t saved; @@ -1176,35 +1175,6 @@ dns_message_getsig0(dns_message_t *msg, dns_name_t **owner); * \li If 'owner' is not NULL, it will point to the owner name. */ -isc_result_t -dns_message_setsig0key(dns_message_t *msg, dst_key_t *key); -/*%< - * Set the SIG(0) key for 'msg'. - * - * Requires: - * - *\li 'msg' is a valid message with rendering intent, - * dns_message_renderbegin() has been called, and no sections have been - * rendered. - *\li 'key' is a valid sig key or NULL. - * - * Returns: - * - *\li #ISC_R_SUCCESS -- all is well. - * - *\li #ISC_R_NOSPACE -- there is no space for the SIG(0) record. - */ - -dst_key_t * -dns_message_getsig0key(dns_message_t *msg); -/*%< - * Gets the SIG(0) key for 'msg'. - * - * Requires: - * - *\li 'msg' is a valid message - */ - void dns_message_takebuffer(dns_message_t *msg, isc_buffer_t **buffer); /*%< diff --git a/usr.sbin/bind/lib/dns/message.c b/usr.sbin/bind/lib/dns/message.c index 4d36ee8f237..7c8a5c90431 100644 --- a/usr.sbin/bind/lib/dns/message.c +++ b/usr.sbin/bind/lib/dns/message.c @@ -14,7 +14,7 @@ * PERFORMANCE OF THIS SOFTWARE. */ -/* $Id: message.c,v 1.18 2020/01/28 17:17:05 florian Exp $ */ +/* $Id: message.c,v 1.19 2020/02/04 18:42:51 florian Exp $ */ /*! \file */ @@ -32,7 +32,6 @@ #include <string.h> /* Required for HP/UX (and others?) */ #include <isc/util.h> -#include <dns/dnssec.h> #include <dns/keyvalues.h> #include <dns/log.h> #include <dns/masterdump.h> @@ -390,7 +389,6 @@ msginittsig(dns_message_t *m) { m->tsigkey = NULL; m->tsigctx = NULL; m->sigstart = -1; - m->sig0key = NULL; m->sig0status = dns_rcode_noerror; m->timeadjust = 0; } @@ -2159,7 +2157,7 @@ dns_message_renderend(dns_message_t *msg) { * before adding the OPT, TSIG or SIG(0). If the question doesn't * fit, don't include it. */ - if ((msg->tsigkey != NULL || msg->sig0key != NULL || msg->opt) && + if ((msg->tsigkey != NULL || msg->opt) && (msg->flags & DNS_MESSAGEFLAG_TC) != 0) { isc_buffer_t *buf; @@ -2217,28 +2215,6 @@ dns_message_renderend(dns_message_t *msg) { return (result); } - /* - * If we're adding a SIG(0) record, generate and render it. - */ - if (msg->sig0key != NULL) { - dns_message_renderrelease(msg, msg->sig_reserved); - msg->sig_reserved = 0; - result = dns_dnssec_signmessage(msg, msg->sig0key); - if (result != ISC_R_SUCCESS) - return (result); - count = 0; - /* - * Note: dns_rootname is used here, not msg->sig0name, since - * the owner name of a SIG(0) is irrelevant, and will not - * be set in a message being rendered. - */ - result = renderset(msg->sig0, dns_rootname, msg->cctx, - msg->buffer, msg->reserved, 0, &count); - msg->counts[DNS_SECTION_ADDITIONAL] += count; - if (result != ISC_R_SUCCESS) - return (result); - } - isc_buffer_usedregion(msg->buffer, &r); isc_buffer_init(&tmpbuf, r.base, r.length); @@ -2713,7 +2689,7 @@ dns_message_settsigkey(dns_message_t *msg, dns_tsigkey_t *key) { dns_tsigkey_detach(&msg->tsigkey); } if (key != NULL) { - REQUIRE(msg->tsigkey == NULL && msg->sig0key == NULL); + REQUIRE(msg->tsigkey == NULL); dns_tsigkey_attach(key, &msg->tsigkey); if (msg->from_to_wire == DNS_MESSAGE_INTENTRENDER) { msg->sig_reserved = spacefortsig(msg->tsigkey, 0); @@ -2843,70 +2819,6 @@ dns_message_getsig0(dns_message_t *msg, dns_name_t **owner) { return (msg->sig0); } -isc_result_t -dns_message_setsig0key(dns_message_t *msg, dst_key_t *key) { - isc_region_t r; - unsigned int x; - isc_result_t result; - - /* - * Set the SIG(0) key for 'msg' - */ - - /* - * The space required for an SIG(0) record is: - * - * 1 byte for the name - * 2 bytes for the type - * 2 bytes for the class - * 4 bytes for the ttl - * 2 bytes for the type covered - * 1 byte for the algorithm - * 1 bytes for the labels - * 4 bytes for the original ttl - * 4 bytes for the signature expiration - * 4 bytes for the signature inception - * 2 bytes for the key tag - * n bytes for the signer's name - * x bytes for the signature - * --------------------------------- - * 27 + n + x bytes - */ - REQUIRE(DNS_MESSAGE_VALID(msg)); - REQUIRE(msg->from_to_wire == DNS_MESSAGE_INTENTRENDER); - REQUIRE(msg->state == DNS_SECTION_ANY); - - if (key != NULL) { - REQUIRE(msg->sig0key == NULL && msg->tsigkey == NULL); - dns_name_toregion(dst_key_name(key), &r); - result = dst_key_sigsize(key, &x); - if (result != ISC_R_SUCCESS) { - msg->sig_reserved = 0; - return (result); - } - msg->sig_reserved = 27 + r.length + x; - result = dns_message_renderreserve(msg, msg->sig_reserved); - if (result != ISC_R_SUCCESS) { - msg->sig_reserved = 0; - return (result); - } - msg->sig0key = key; - } - return (ISC_R_SUCCESS); -} - -dst_key_t * -dns_message_getsig0key(dns_message_t *msg) { - - /* - * Get the SIG(0) key for 'msg' - */ - - REQUIRE(DNS_MESSAGE_VALID(msg)); - - return (msg->sig0key); -} - void dns_message_takebuffer(dns_message_t *msg, isc_buffer_t **buffer) { REQUIRE(DNS_MESSAGE_VALID(msg)); |
