mirror of
https://github.com/isc-projects/bind9.git
synced 2026-02-27 03:51:16 -05:00
431 lines
14 KiB
C
431 lines
14 KiB
C
/*
|
|
* 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_make_dnskey(dst_key_t *key, unsigned char *buf, int bufsize,
|
|
dns_rdata_t *target);
|
|
/*%<
|
|
* Convert a DST key into a DNS record.
|
|
*
|
|
* Requires:
|
|
*\li 'key' is not NULL
|
|
*\li 'buf' is not NULL
|
|
*\li 'bufsize' equals DST_KEY_MAXSIZE
|
|
*\li 'target' is not NULL
|
|
*
|
|
* Returns:
|
|
*\li #ISC_R_SUCCESS
|
|
*\li various errors from dst_key_todns
|
|
*/
|
|
|
|
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.
|
|
*/
|
|
|
|
void
|
|
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.
|
|
*/
|
|
|
|
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_kasp_digestlist_t *digests,
|
|
bool gencdnskey, 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.
|
|
*
|
|
* For each key in 'keys', check if corresponding CDS and CDNSKEY records
|
|
* need to be published. If needed and 'gencdnskey' is true, there will be one
|
|
* CDNSKEY record added to the 'cdnskey' RRset. Also one CDS record will be
|
|
* added to the 'cds' RRset for each digest type in 'digests'.
|
|
*
|
|
* For each key in 'rmkeys', remove any associated CDS and CDNSKEY records from
|
|
* the RRsets 'cds' and 'cdnskey'.
|
|
*
|
|
* 'hint_ttl' is the TTL to use for the CDS and CDNSKEY RRsets if there is no
|
|
* existing RRset.
|
|
*
|
|
* Any changes made also cause a dns_difftuple to be added to 'diff'.
|
|
*
|
|
* Requires:
|
|
*\li 'keys' is not NULL.
|
|
*\li 'rmkeys' is not NULL.
|
|
*\li 'digests' is not NULL.
|
|
*
|
|
* 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
|