1 /*	$NetBSD: dnssec.h,v 1.8 2022/09/23 12:15:30 christos Exp $	*/
2 
3 /*
4  * Copyright (C) Internet Systems Consortium, Inc. ("ISC")
5  *
6  * SPDX-License-Identifier: MPL-2.0
7  *
8  * This Source Code Form is subject to the terms of the Mozilla Public
9  * License, v. 2.0. If a copy of the MPL was not distributed with this
10  * file, you can obtain one at https://mozilla.org/MPL/2.0/.
11  *
12  * See the COPYRIGHT file distributed with this work for additional
13  * information regarding copyright ownership.
14  */
15 
16 #ifndef DNS_DNSSEC_H
17 #define DNS_DNSSEC_H 1
18 
19 /*! \file dns/dnssec.h */
20 
21 #include <stdbool.h>
22 
23 #include <isc/lang.h>
24 #include <isc/stats.h>
25 #include <isc/stdtime.h>
26 
27 #include <dns/diff.h>
28 #include <dns/types.h>
29 
30 #include <dst/dst.h>
31 
32 ISC_LANG_BEGINDECLS
33 
34 LIBDNS_EXTERNAL_DATA extern isc_stats_t *dns_dnssec_stats;
35 
36 /*%< Maximum number of keys supported in a zone. */
37 #define DNS_MAXZONEKEYS 32
38 
39 /*
40  * Indicates how the signer found this key: in the key repository, at the
41  * zone apex, or specified by the user.
42  */
43 typedef enum {
44 	dns_keysource_unknown,
45 	dns_keysource_repository,
46 	dns_keysource_zoneapex,
47 	dns_keysource_user
48 } dns_keysource_t;
49 
50 /*
51  * A DNSSEC key and hints about its intended use gleaned from metadata
52  */
53 struct dns_dnsseckey {
54 	dst_key_t *key;
55 	bool	   hint_publish;     /*% metadata says to publish */
56 	bool	   force_publish;    /*% publish regardless of metadata
57 				      * */
58 	bool hint_sign;		     /*% metadata says to sign with this
59 				      * key */
60 	bool force_sign;	     /*% sign with key regardless of
61 				      * metadata */
62 	bool		hint_revoke; /*% metadata says revoke key */
63 	bool		hint_remove; /*% metadata says *don't* publish */
64 	bool		is_active;   /*% key is already active */
65 	bool		first_sign;  /*% key is newly becoming active */
66 	bool		purge;	     /*% remove key files */
67 	unsigned int	prepublish;  /*% how long until active? */
68 	dns_keysource_t source;	     /*% how the key was found */
69 	bool		ksk;	     /*% this is a key-signing key */
70 	bool		zsk;	     /*% this is a zone-signing key */
71 	bool		legacy;	     /*% this is old-style key with no
72 				      *  metadata (possibly generated by
73 				      *  an older version of BIND9) and
74 				      *  should be ignored when searching
75 				      *  for keys to import into the zone */
76 	unsigned int index;	     /*% position in list */
77 	ISC_LINK(dns_dnsseckey_t) link;
78 };
79 
80 isc_result_t
81 dns_dnssec_keyfromrdata(const dns_name_t *name, const dns_rdata_t *rdata,
82 			isc_mem_t *mctx, dst_key_t **key);
83 /*%<
84  *	Creates a DST key from a DNS record.  Basically a wrapper around
85  *	dst_key_fromdns().
86  *
87  *	Requires:
88  *\li		'name' is not NULL
89  *\li		'rdata' is not NULL
90  *\li		'mctx' is not NULL
91  *\li		'key' is not NULL
92  *\li		'*key' is NULL
93  *
94  *	Returns:
95  *\li		#ISC_R_SUCCESS
96  *\li		#ISC_R_NOMEMORY
97  *\li		DST_R_INVALIDPUBLICKEY
98  *\li		various errors from dns_name_totext
99  */
100 
101 isc_result_t
102 dns_dnssec_sign(const dns_name_t *name, dns_rdataset_t *set, dst_key_t *key,
103 		isc_stdtime_t *inception, isc_stdtime_t *expire,
104 		isc_mem_t *mctx, isc_buffer_t *buffer, dns_rdata_t *sigrdata);
105 /*%<
106  *	Generates a RRSIG record covering this rdataset.  This has no effect
107  *	on existing RRSIG records.
108  *
109  *	Requires:
110  *\li		'name' (the owner name of the record) is a valid name
111  *\li		'set' is a valid rdataset
112  *\li		'key' is a valid key
113  *\li		'inception' is not NULL
114  *\li		'expire' is not NULL
115  *\li		'mctx' is not NULL
116  *\li		'buffer' is not NULL
117  *\li		'sigrdata' is not NULL
118  *
119  *	Returns:
120  *\li		#ISC_R_SUCCESS
121  *\li		#ISC_R_NOMEMORY
122  *\li		#ISC_R_NOSPACE
123  *\li		#DNS_R_INVALIDTIME - the expiration is before the inception
124  *\li		#DNS_R_KEYUNAUTHORIZED - the key cannot sign this data (either
125  *			it is not a zone key or its flags prevent
126  *			authentication)
127  *\li		DST_R_*
128  */
129 
130 isc_result_t
131 dns_dnssec_verify(const dns_name_t *name, dns_rdataset_t *set, dst_key_t *key,
132 		  bool ignoretime, unsigned int maxbits, isc_mem_t *mctx,
133 		  dns_rdata_t *sigrdata, dns_name_t *wild);
134 /*%<
135  *	Verifies the RRSIG record covering this rdataset signed by a specific
136  *	key.  This does not determine if the key's owner is authorized to sign
137  *	this record, as this requires a resolver or database.
138  *	If 'ignoretime' is true, temporal validity will not be checked.
139  *
140  *	'maxbits' specifies the maximum number of rsa exponent bits accepted.
141  *
142  *	Requires:
143  *\li		'name' (the owner name of the record) is a valid name
144  *\li		'set' is a valid rdataset
145  *\li		'key' is a valid key
146  *\li		'mctx' is not NULL
147  *\li		'sigrdata' is a valid rdata containing a SIG record
148  *\li		'wild' if non-NULL then is a valid and has a buffer.
149  *
150  *	Returns:
151  *\li		#ISC_R_SUCCESS
152  *\li		#ISC_R_NOMEMORY
153  *\li		#DNS_R_FROMWILDCARD - the signature is valid and is from
154  *			a wildcard expansion.  dns_dnssec_verify2() only.
155  *			'wild' contains the name of the wildcard if non-NULL.
156  *\li		#DNS_R_SIGINVALID - the signature fails to verify
157  *\li		#DNS_R_SIGEXPIRED - the signature has expired
158  *\li		#DNS_R_SIGFUTURE - the signature's validity period has not begun
159  *\li		#DNS_R_KEYUNAUTHORIZED - the key cannot sign this data (either
160  *			it is not a zone key or its flags prevent
161  *			authentication)
162  *\li		DST_R_*
163  */
164 
165 /*@{*/
166 isc_result_t
167 dns_dnssec_findzonekeys(dns_db_t *db, dns_dbversion_t *ver, dns_dbnode_t *node,
168 			const dns_name_t *name, const char *directory,
169 			isc_stdtime_t now, isc_mem_t *mctx,
170 			unsigned int maxkeys, dst_key_t **keys,
171 			unsigned int *nkeys);
172 
173 /*%<
174  * 	Finds a set of zone keys.
175  * 	XXX temporary - this should be handled in dns_zone_t.
176  */
177 /*@}*/
178 
179 bool
180 dns_dnssec_keyactive(dst_key_t *key, isc_stdtime_t now);
181 /*%<
182  *
183  * 	Returns true if 'key' is active as of the time specified
184  * 	in 'now' (i.e., if the activation date has passed, inactivation or
185  * 	deletion date has not yet been reached, and the key is not revoked
186  * 	-- or if it is a legacy key without metadata). Otherwise returns
187  * 	false.
188  *
189  *	Requires:
190  *\li		'key' is a valid key
191  */
192 
193 isc_result_t
194 dns_dnssec_signmessage(dns_message_t *msg, dst_key_t *key);
195 /*%<
196  *	Signs a message with a SIG(0) record.  This is implicitly called by
197  *	dns_message_renderend() if msg->sig0key is not NULL.
198  *
199  *	Requires:
200  *\li		'msg' is a valid message
201  *\li		'key' is a valid key that can be used for signing
202  *
203  *	Returns:
204  *\li		#ISC_R_SUCCESS
205  *\li		#ISC_R_NOMEMORY
206  *\li		DST_R_*
207  */
208 
209 isc_result_t
210 dns_dnssec_verifymessage(isc_buffer_t *source, dns_message_t *msg,
211 			 dst_key_t *key);
212 /*%<
213  *	Verifies a message signed by a SIG(0) record.  This is not
214  *	called implicitly by dns_message_parse().  If dns_message_signer()
215  *	is called before dns_dnssec_verifymessage(), it will return
216  *	#DNS_R_NOTVERIFIEDYET.  dns_dnssec_verifymessage() will set
217  *	the verified_sig0 flag in msg if the verify succeeds, and
218  *	the sig0status field otherwise.
219  *
220  *	Requires:
221  *\li		'source' is a valid buffer containing the unparsed message
222  *\li		'msg' is a valid message
223  *\li		'key' is a valid key
224  *
225  *	Returns:
226  *\li		#ISC_R_SUCCESS
227  *\li		#ISC_R_NOMEMORY
228  *\li		#ISC_R_NOTFOUND - no SIG(0) was found
229  *\li		#DNS_R_SIGINVALID - the SIG record is not well-formed or
230  *				   was not generated by the key.
231  *\li		DST_R_*
232  */
233 
234 bool
235 dns_dnssec_selfsigns(dns_rdata_t *rdata, const dns_name_t *name,
236 		     dns_rdataset_t *rdataset, dns_rdataset_t *sigrdataset,
237 		     bool ignoretime, isc_mem_t *mctx);
238 
239 bool
240 dns_dnssec_signs(dns_rdata_t *rdata, const dns_name_t *name,
241 		 dns_rdataset_t *rdataset, dns_rdataset_t *sigrdataset,
242 		 bool ignoretime, isc_mem_t *mctx);
243 /*%<
244  * Verify that 'rdataset' is validly signed in 'sigrdataset' by
245  * the key in 'rdata'.
246  *
247  * dns_dnssec_selfsigns() requires that rdataset be a DNSKEY or KEY
248  * rrset.  dns_dnssec_signs() works on any rrset.
249  */
250 
251 isc_result_t
252 dns_dnsseckey_create(isc_mem_t *mctx, dst_key_t **dstkey,
253 		     dns_dnsseckey_t **dkp);
254 /*%<
255  * Create and initialize a dns_dnsseckey_t structure.
256  *
257  *	Requires:
258  *\li		'dkp' is not NULL and '*dkp' is NULL.
259  *
260  *	Returns:
261  *\li		#ISC_R_SUCCESS
262  *\li		#ISC_R_NOMEMORY
263  */
264 
265 void
266 dns_dnsseckey_destroy(isc_mem_t *mctx, dns_dnsseckey_t **dkp);
267 /*%<
268  * Reclaim a dns_dnsseckey_t structure.
269  *
270  *	Requires:
271  *\li		'dkp' is not NULL and '*dkp' is not NULL.
272  *
273  *	Ensures:
274  *\li		'*dkp' is NULL.
275  */
276 
277 void
278 dns_dnssec_get_hints(dns_dnsseckey_t *key, isc_stdtime_t now);
279 /*%<
280  * Get hints on DNSSEC key whether this key can be published
281  * and/or is active.  Timing metadata is compared to 'now'.
282  *
283  *	Requires:
284  *\li		'key' is a pointer to a DNSSEC key and is not NULL.
285  */
286 
287 isc_result_t
288 dns_dnssec_findmatchingkeys(const dns_name_t *origin, const char *directory,
289 			    isc_stdtime_t now, isc_mem_t *mctx,
290 			    dns_dnsseckeylist_t *keylist);
291 /*%<
292  * Search 'directory' for K* key files matching the name in 'origin'.
293  * Append all such keys, along with use hints gleaned from their
294  * metadata, onto 'keylist'.  Skip any unsupported algorithms.
295  *
296  *	Requires:
297  *\li		'keylist' is not NULL
298  *
299  *	Returns:
300  *\li		#ISC_R_SUCCESS
301  *\li		#ISC_R_NOTFOUND
302  *\li		#ISC_R_NOMEMORY
303  *\li		any error returned by dns_name_totext(), isc_dir_open(), or
304  *              dst_key_fromnamedfile()
305  *
306  *	Ensures:
307  *\li		On error, keylist is unchanged
308  */
309 
310 isc_result_t
311 dns_dnssec_keylistfromrdataset(const dns_name_t *origin, const char *directory,
312 			       isc_mem_t *mctx, dns_rdataset_t *keyset,
313 			       dns_rdataset_t *keysigs, dns_rdataset_t *soasigs,
314 			       bool savekeys, bool publickey,
315 			       dns_dnsseckeylist_t *keylist);
316 /*%<
317  * Append the contents of a DNSKEY rdataset 'keyset' to 'keylist'.
318  * Omit duplicates.  If 'publickey' is false, search 'directory' for
319  * matching key files, and load the private keys that go with
320  * the public ones.  If 'savekeys' is true, mark the keys so
321  * they will not be deleted or inactivated regardless of metadata.
322  *
323  * 'keysigs' and 'soasigs', if not NULL and associated, contain the
324  * RRSIGS for the DNSKEY and SOA records respectively and are used to mark
325  * whether a key is already active in the zone.
326  */
327 
328 isc_result_t
329 dns_dnssec_updatekeys(dns_dnsseckeylist_t *keys, dns_dnsseckeylist_t *newkeys,
330 		      dns_dnsseckeylist_t *removed, const dns_name_t *origin,
331 		      dns_ttl_t hint_ttl, dns_diff_t *diff, isc_mem_t *mctx,
332 		      void (*report)(const char *, ...));
333 /*%<
334  * Update the list of keys in 'keys' with new key information in 'newkeys'.
335  *
336  * For each key in 'newkeys', see if it has a match in 'keys'.
337  * - If not, and if the metadata says the key should be published:
338  *   add it to 'keys', and place a dns_difftuple into 'diff' so
339  *   the key can be added to the DNSKEY set.  If the metadata says it
340  *   should be active, set the first_sign flag.
341  * - If so, and if the metadata says it should be removed:
342  *   remove it from 'keys', and place a dns_difftuple into 'diff' so
343  *   the key can be removed from the DNSKEY set.  if 'removed' is non-NULL,
344  *   copy the key into that list; otherwise destroy it.
345  * - Otherwise, make sure keys has current metadata.
346  *
347  * 'hint_ttl' is the TTL to use for the DNSKEY RRset if there is no
348  * existing RRset, and if none of the keys to be added has a default TTL
349  * (in which case we would use the shortest one).  If the TTL is longer
350  * than the time until a new key will be activated, then we have to delay
351  * the key's activation.
352  *
353  * 'report' points to a function for reporting status.
354  *
355  * On completion, any remaining keys in 'newkeys' are freed.
356  */
357 
358 isc_result_t
359 dns_dnssec_syncupdate(dns_dnsseckeylist_t *keys, dns_dnsseckeylist_t *rmkeys,
360 		      dns_rdataset_t *cds, dns_rdataset_t *cdnskey,
361 		      isc_stdtime_t now, dns_ttl_t hint_ttl, dns_diff_t *diff,
362 		      isc_mem_t *mctx);
363 /*%<
364  * Update the CDS and CDNSKEY RRsets, adding and removing keys as needed.
365  *
366  * Returns:
367  *\li   ISC_R_SUCCESS
368  *\li   Other values indicate error
369  */
370 
371 isc_result_t
372 dns_dnssec_syncdelete(dns_rdataset_t *cds, dns_rdataset_t *cdnskey,
373 		      dns_name_t *origin, dns_rdataclass_t zclass,
374 		      dns_ttl_t ttl, dns_diff_t *diff, isc_mem_t *mctx,
375 		      bool expect_cds_delete, bool expect_cdnskey_delete);
376 /*%<
377  * Add or remove the CDS DELETE record and the CDNSKEY DELETE record.
378  * If 'expect_cds_delete' is true, the CDS DELETE record should be present.
379  * Otherwise, the CDS DELETE record must be removed from the RRsets (if
380  * present). If 'expect_cdnskey_delete' is true, the CDNSKEY DELETE record
381  * should be present. Otherwise, the CDNSKEY DELETE record must be removed
382  * from the RRsets (if present).
383  *
384  * Returns:
385  *\li   ISC_R_SUCCESS
386  *\li   Other values indicate error
387  */
388 
389 isc_result_t
390 dns_dnssec_matchdskey(dns_name_t *name, dns_rdata_t *dsrdata,
391 		      dns_rdataset_t *keyset, dns_rdata_t *keyrdata);
392 /*%<
393  * Given a DS rdata and a DNSKEY RRset, find the DNSKEY rdata that matches
394  * the DS, and place it in 'keyrdata'.
395  *
396  * Returns:
397  *\li	ISC_R_SUCCESS
398  *\li	ISC_R_NOTFOUND
399  *\li	Other values indicate error
400  */
401 ISC_LANG_ENDDECLS
402 
403 #endif /* DNS_DNSSEC_H */
404