diff options
Diffstat (limited to 'lib/dns/include/dns/dnssec.h')
-rw-r--r-- | lib/dns/include/dns/dnssec.h | 399 |
1 files changed, 399 insertions, 0 deletions
diff --git a/lib/dns/include/dns/dnssec.h b/lib/dns/include/dns/dnssec.h new file mode 100644 index 0000000..6add7d5 --- /dev/null +++ b/lib/dns/include/dns/dnssec.h @@ -0,0 +1,399 @@ +/* + * Copyright (C) Internet Systems Consortium, Inc. ("ISC") + * + * SPDX-License-Identifier: MPL-2.0 + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, you can obtain one at https://mozilla.org/MPL/2.0/. + * + * See the COPYRIGHT file distributed with this work for additional + * information regarding copyright ownership. + */ + +#pragma once + +/*! \file dns/dnssec.h */ + +#include <stdbool.h> + +#include <isc/lang.h> +#include <isc/stats.h> +#include <isc/stdtime.h> + +#include <dns/diff.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; + bool hint_publish; /*% metadata says to publish */ + bool force_publish; /*% publish regardless of metadata + * */ + bool hint_sign; /*% metadata says to sign with this + * key */ + bool force_sign; /*% sign with key regardless of + * metadata */ + bool hint_revoke; /*% metadata says revoke key */ + bool hint_remove; /*% metadata says *don't* publish */ + bool is_active; /*% key is already active */ + bool first_sign; /*% key is newly becoming active */ + bool purge; /*% remove key files */ + unsigned int prepublish; /*% how long until active? */ + dns_keysource_t source; /*% how the key was found */ + bool ksk; /*% this is a key-signing key */ + bool zsk; /*% this is a zone-signing key */ + bool 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(const dns_name_t *name, const dns_rdata_t *rdata, + isc_mem_t *mctx, 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(const dns_name_t *name, dns_rdataset_t *set, dst_key_t *key, + isc_stdtime_t *inception, isc_stdtime_t *expire, + isc_mem_t *mctx, 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(const dns_name_t *name, dns_rdataset_t *set, dst_key_t *key, + bool ignoretime, unsigned int maxbits, isc_mem_t *mctx, + 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 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_result_t +dns_dnssec_findzonekeys(dns_db_t *db, dns_dbversion_t *ver, dns_dbnode_t *node, + const dns_name_t *name, const char *directory, + isc_stdtime_t now, isc_mem_t *mctx, + unsigned int maxkeys, dst_key_t **keys, + unsigned int *nkeys); + +/*%< + * Finds a set of zone keys. + * XXX temporary - this should be handled in dns_zone_t. + */ +/*@}*/ + +bool +dns_dnssec_keyactive(dst_key_t *key, isc_stdtime_t now); +/*%< + * + * Returns 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 + * 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_* + */ + +bool +dns_dnssec_selfsigns(dns_rdata_t *rdata, const dns_name_t *name, + dns_rdataset_t *rdataset, dns_rdataset_t *sigrdataset, + bool ignoretime, isc_mem_t *mctx); + +bool +dns_dnssec_signs(dns_rdata_t *rdata, const dns_name_t *name, + dns_rdataset_t *rdataset, dns_rdataset_t *sigrdataset, + bool ignoretime, isc_mem_t *mctx); +/*%< + * 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(isc_mem_t *mctx, 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(isc_mem_t *mctx, 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. + */ + +void +dns_dnssec_get_hints(dns_dnsseckey_t *key, isc_stdtime_t now); +/*%< + * Get hints on DNSSEC key whether this key can be published + * and/or is active. Timing metadata is compared to 'now'. + * + * Requires: + *\li 'key' is a pointer to a DNSSEC key and is not NULL. + */ + +isc_result_t +dns_dnssec_findmatchingkeys(const dns_name_t *origin, const char *directory, + isc_stdtime_t now, isc_mem_t *mctx, + 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'. Skip any unsupported algorithms. + * + * 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(const dns_name_t *origin, const char *directory, + isc_mem_t *mctx, dns_rdataset_t *keyset, + dns_rdataset_t *keysigs, dns_rdataset_t *soasigs, + bool savekeys, bool publickey, + dns_dnsseckeylist_t *keylist); +/*%< + * Append the contents of a DNSKEY rdataset 'keyset' to 'keylist'. + * Omit duplicates. If 'publickey' is false, search 'directory' for + * matching key files, and load the private keys that go with + * the public ones. If 'savekeys' is 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_result_t +dns_dnssec_updatekeys(dns_dnsseckeylist_t *keys, dns_dnsseckeylist_t *newkeys, + dns_dnsseckeylist_t *removed, const dns_name_t *origin, + dns_ttl_t hint_ttl, dns_diff_t *diff, isc_mem_t *mctx, + void (*report)(const char *, ...) + ISC_FORMAT_PRINTF(1, 2)); +/*%< + * Update the list of keys in 'keys' with new key information in 'newkeys'. + * + * For each key in 'newkeys', see if it has a match in 'keys'. + * - If not, and if the metadata says the key should be published: + * add it to 'keys', and place a dns_difftuple into 'diff' so + * the key can be added to the DNSKEY set. If the metadata says it + * should be active, set the first_sign flag. + * - If so, and if the metadata says it should be removed: + * remove it from 'keys', and place a dns_difftuple into 'diff' so + * the key can be removed from the DNSKEY set. if 'removed' is non-NULL, + * copy the key into that list; otherwise destroy it. + * - Otherwise, make sure keys has current metadata. + * + * 'hint_ttl' is the TTL to use for the DNSKEY RRset if there is no + * existing RRset, and if none of the keys to be added has a default TTL + * (in which case we would use the shortest one). If the TTL is longer + * than the time until a new key will be activated, then we have to delay + * the key's activation. + * + * 'report' points to a function for reporting status. + * + * On completion, any remaining keys in 'newkeys' are freed. + */ + +isc_result_t +dns_dnssec_syncupdate(dns_dnsseckeylist_t *keys, dns_dnsseckeylist_t *rmkeys, + dns_rdataset_t *cds, dns_rdataset_t *cdnskey, + isc_stdtime_t now, dns_ttl_t hint_ttl, dns_diff_t *diff, + isc_mem_t *mctx); +/*%< + * Update the CDS and CDNSKEY RRsets, adding and removing keys as needed. + * + * Returns: + *\li ISC_R_SUCCESS + *\li Other values indicate error + */ + +isc_result_t +dns_dnssec_syncdelete(dns_rdataset_t *cds, dns_rdataset_t *cdnskey, + dns_name_t *origin, dns_rdataclass_t zclass, + dns_ttl_t ttl, dns_diff_t *diff, isc_mem_t *mctx, + bool expect_cds_delete, bool expect_cdnskey_delete); +/*%< + * Add or remove the CDS DELETE record and the CDNSKEY DELETE record. + * If 'expect_cds_delete' is true, the CDS DELETE record should be present. + * Otherwise, the CDS DELETE record must be removed from the RRsets (if + * present). If 'expect_cdnskey_delete' is true, the CDNSKEY DELETE record + * should be present. Otherwise, the CDNSKEY DELETE record must be removed + * from the RRsets (if present). + * + * Returns: + *\li ISC_R_SUCCESS + *\li Other values indicate error + */ + +isc_result_t +dns_dnssec_matchdskey(dns_name_t *name, dns_rdata_t *dsrdata, + dns_rdataset_t *keyset, dns_rdata_t *keyrdata); +/*%< + * Given a DS rdata and a DNSKEY RRset, find the DNSKEY rdata that matches + * the DS, and place it in 'keyrdata'. + * + * Returns: + *\li ISC_R_SUCCESS + *\li ISC_R_NOTFOUND + *\li Other values indicate error + */ +ISC_LANG_ENDDECLS |