xref: /freebsd/contrib/unbound/validator/val_sigcrypt.h (revision 19261079b74319502c6ffa1249920079f0f69a72)
1 /*
2  * validator/val_sigcrypt.h - validator signature crypto functions.
3  *
4  * Copyright (c) 2007, NLnet Labs. All rights reserved.
5  *
6  * This software is open source.
7  *
8  * Redistribution and use in source and binary forms, with or without
9  * modification, are permitted provided that the following conditions
10  * are met:
11  *
12  * Redistributions of source code must retain the above copyright notice,
13  * this list of conditions and the following disclaimer.
14  *
15  * Redistributions in binary form must reproduce the above copyright notice,
16  * this list of conditions and the following disclaimer in the documentation
17  * and/or other materials provided with the distribution.
18  *
19  * Neither the name of the NLNET LABS nor the names of its contributors may
20  * be used to endorse or promote products derived from this software without
21  * specific prior written permission.
22  *
23  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
24  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
25  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
26  * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
27  * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
28  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
29  * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
30  * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
31  * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
32  * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
33  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
34  */
35 
36 /**
37  * \file
38  *
39  * This file contains helper functions for the validator module.
40  * The functions help with signature verification and checking, the
41  * bridging between RR wireformat data and crypto calls.
42  */
43 
44 #ifndef VALIDATOR_VAL_SIGCRYPT_H
45 #define VALIDATOR_VAL_SIGCRYPT_H
46 #include "util/data/packed_rrset.h"
47 #include "sldns/pkthdr.h"
48 struct val_env;
49 struct module_env;
50 struct module_qstate;
51 struct ub_packed_rrset_key;
52 struct rbtree_type;
53 struct regional;
54 struct sldns_buffer;
55 
56 /** number of entries in algorithm needs array */
57 #define ALGO_NEEDS_MAX 256
58 
59 /**
60  * Storage for algorithm needs.  DNSKEY algorithms.
61  */
62 struct algo_needs {
63 	/** the algorithms (8-bit) with each a number.
64 	 * 0: not marked.
65 	 * 1: marked 'necessary but not yet fulfilled'
66 	 * 2: marked bogus.
67 	 * Indexed by algorithm number.
68 	 */
69 	uint8_t needs[ALGO_NEEDS_MAX];
70 	/** the number of entries in the array that are unfulfilled */
71 	size_t num;
72 };
73 
74 /**
75  * Initialize algo needs structure, set algos from rrset as needed.
76  * Results are added to an existing need structure.
77  * @param n: struct with storage.
78  * @param dnskey: algos from this struct set as necessary. DNSKEY set.
79  * @param sigalg: adds to signalled algorithm list too.
80  */
81 void algo_needs_init_dnskey_add(struct algo_needs* n,
82 	struct ub_packed_rrset_key* dnskey, uint8_t* sigalg);
83 
84 /**
85  * Initialize algo needs structure from a signalled algo list.
86  * @param n: struct with storage.
87  * @param sigalg: signalled algorithm list, numbers ends with 0.
88  */
89 void algo_needs_init_list(struct algo_needs* n, uint8_t* sigalg);
90 
91 /**
92  * Initialize algo needs structure, set algos from rrset as needed.
93  * @param n: struct with storage.
94  * @param ds: algos from this struct set as necessary. DS set.
95  * @param fav_ds_algo: filter to use only this DS algo.
96  * @param sigalg: list of signalled algos, constructed as output,
97  *	provide size ALGO_NEEDS_MAX+1. list of algonumbers, ends with a zero.
98  */
99 void algo_needs_init_ds(struct algo_needs* n, struct ub_packed_rrset_key* ds,
100 	int fav_ds_algo, uint8_t* sigalg);
101 
102 /**
103  * Mark this algorithm as a success, sec_secure, and see if we are done.
104  * @param n: storage structure processed.
105  * @param algo: the algorithm processed to be secure.
106  * @return if true, processing has finished successfully, we are satisfied.
107  */
108 int algo_needs_set_secure(struct algo_needs* n, uint8_t algo);
109 
110 /**
111  * Mark this algorithm a failure, sec_bogus.  It can later be overridden
112  * by a success for this algorithm (with a different signature).
113  * @param n: storage structure processed.
114  * @param algo: the algorithm processed to be bogus.
115  */
116 void algo_needs_set_bogus(struct algo_needs* n, uint8_t algo);
117 
118 /**
119  * See how many algorithms are missing (not bogus or secure, but not processed)
120  * @param n: storage structure processed.
121  * @return number of algorithms missing after processing.
122  */
123 size_t algo_needs_num_missing(struct algo_needs* n);
124 
125 /**
126  * See which algo is missing.
127  * @param n: struct after processing.
128  * @return if 0 an algorithm was bogus, if a number, this algorithm was
129  *   missing.  So on 0, report why that was bogus, on number report a missing
130  *   algorithm.  There could be multiple missing, this reports the first one.
131  */
132 int algo_needs_missing(struct algo_needs* n);
133 
134 /**
135  * Format error reason for algorithm missing.
136  * @param env: module env with scratch for temp storage of string.
137  * @param alg: DNSKEY-algorithm missing.
138  * @param reason: destination.
139  * @param s: string, appended with 'with algorithm ..'.
140  */
141 void algo_needs_reason(struct module_env* env, int alg, char** reason, char* s);
142 
143 /**
144  * Check if dnskey matches a DS digest
145  * Does not check dnskey-keyid footprint, just the digest.
146  * @param env: module environment. Uses scratch space.
147  * @param dnskey_rrset: DNSKEY rrset.
148  * @param dnskey_idx: index of RR in rrset.
149  * @param ds_rrset: DS rrset
150  * @param ds_idx: index of RR in DS rrset.
151  * @return true if it matches, false on error, not supported or no match.
152  */
153 int ds_digest_match_dnskey(struct module_env* env,
154 	struct ub_packed_rrset_key* dnskey_rrset, size_t dnskey_idx,
155 	struct ub_packed_rrset_key* ds_rrset, size_t ds_idx);
156 
157 /**
158  * Get dnskey keytag, footprint value
159  * @param dnskey_rrset: DNSKEY rrset.
160  * @param dnskey_idx: index of RR in rrset.
161  * @return the keytag or 0 for badly formatted DNSKEYs.
162  */
163 uint16_t dnskey_calc_keytag(struct ub_packed_rrset_key* dnskey_rrset,
164 	size_t dnskey_idx);
165 
166 /**
167  * Get DS keytag, footprint value that matches the DNSKEY keytag it signs.
168  * @param ds_rrset: DS rrset
169  * @param ds_idx: index of RR in DS rrset.
170  * @return the keytag or 0 for badly formatted DSs.
171  */
172 uint16_t ds_get_keytag(struct ub_packed_rrset_key* ds_rrset, size_t ds_idx);
173 
174 /**
175  * See if DNSKEY algorithm is supported
176  * @param dnskey_rrset: DNSKEY rrset.
177  * @param dnskey_idx: index of RR in rrset.
178  * @return true if supported.
179  */
180 int dnskey_algo_is_supported(struct ub_packed_rrset_key* dnskey_rrset,
181 	size_t dnskey_idx);
182 
183 /**
184  * See if the DNSKEY size at that algorithm is supported.
185  * @param dnskey_rrset: DNSKEY rrset.
186  * @param dnskey_idx: index of RR in rrset.
187  * @return true if supported.
188  */
189 int dnskey_size_is_supported(struct ub_packed_rrset_key* dnskey_rrset,
190 	size_t dnskey_idx);
191 
192 /**
193  * See if the DNSKEY size at that algorithm is supported for all the
194  * RRs in the DNSKEY RRset.
195  * @param dnskey_rrset: DNSKEY rrset.
196  * @return true if supported.
197  */
198 int dnskeyset_size_is_supported(struct ub_packed_rrset_key* dnskey_rrset);
199 
200 /**
201  * See if DS digest algorithm is supported
202  * @param ds_rrset: DS rrset
203  * @param ds_idx: index of RR in DS rrset.
204  * @return true if supported.
205  */
206 int ds_digest_algo_is_supported(struct ub_packed_rrset_key* ds_rrset,
207 	size_t ds_idx);
208 
209 /**
210  * Get DS RR digest algorithm
211  * @param ds_rrset: DS rrset.
212  * @param ds_idx: which DS.
213  * @return algorithm or 0 if DS too short.
214  */
215 int ds_get_digest_algo(struct ub_packed_rrset_key* ds_rrset, size_t ds_idx);
216 
217 /**
218  * See if DS key algorithm is supported
219  * @param ds_rrset: DS rrset
220  * @param ds_idx: index of RR in DS rrset.
221  * @return true if supported.
222  */
223 int ds_key_algo_is_supported(struct ub_packed_rrset_key* ds_rrset,
224 	size_t ds_idx);
225 
226 /**
227  * Get DS RR key algorithm. This value should match with the DNSKEY algo.
228  * @param k: DS rrset.
229  * @param idx: which DS.
230  * @return algorithm or 0 if DS too short.
231  */
232 int ds_get_key_algo(struct ub_packed_rrset_key* k, size_t idx);
233 
234 /**
235  * Get DNSKEY RR signature algorithm
236  * @param k: DNSKEY rrset.
237  * @param idx: which DNSKEY RR.
238  * @return algorithm or 0 if DNSKEY too short.
239  */
240 int dnskey_get_algo(struct ub_packed_rrset_key* k, size_t idx);
241 
242 /**
243  * Get DNSKEY RR flags
244  * @param k: DNSKEY rrset.
245  * @param idx: which DNSKEY RR.
246  * @return flags or 0 if DNSKEY too short.
247  */
248 uint16_t dnskey_get_flags(struct ub_packed_rrset_key* k, size_t idx);
249 
250 /**
251  * Verify rrset against dnskey rrset.
252  * @param env: module environment, scratch space is used.
253  * @param ve: validator environment, date settings.
254  * @param rrset: to be validated.
255  * @param dnskey: DNSKEY rrset, keyset to try.
256  * @param sigalg: if nonNULL provide downgrade protection otherwise one
257  *   algorithm is enough.
258  * @param reason: if bogus, a string returned, fixed or alloced in scratch.
259  * @param section: section of packet where this rrset comes from.
260  * @param qstate: qstate with region.
261  * @return SECURE if one key in the set verifies one rrsig.
262  *	UNCHECKED on allocation errors, unsupported algorithms, malformed data,
263  *	and BOGUS on verification failures (no keys match any signatures).
264  */
265 enum sec_status dnskeyset_verify_rrset(struct module_env* env,
266 	struct val_env* ve, struct ub_packed_rrset_key* rrset,
267 	struct ub_packed_rrset_key* dnskey, uint8_t* sigalg, char** reason,
268 	sldns_pkt_section section, struct module_qstate* qstate);
269 
270 /**
271  * verify rrset against one specific dnskey (from rrset)
272  * @param env: module environment, scratch space is used.
273  * @param ve: validator environment, date settings.
274  * @param rrset: to be validated.
275  * @param dnskey: DNSKEY rrset, keyset.
276  * @param dnskey_idx: which key from the rrset to try.
277  * @param reason: if bogus, a string returned, fixed or alloced in scratch.
278  * @param section: section of packet where this rrset comes from.
279  * @param qstate: qstate with region.
280  * @return secure if *this* key signs any of the signatures on rrset.
281  *	unchecked on error or and bogus on bad signature.
282  */
283 enum sec_status dnskey_verify_rrset(struct module_env* env,
284 	struct val_env* ve, struct ub_packed_rrset_key* rrset,
285 	struct ub_packed_rrset_key* dnskey, size_t dnskey_idx, char** reason,
286 	sldns_pkt_section section, struct module_qstate* qstate);
287 
288 /**
289  * verify rrset, with dnskey rrset, for a specific rrsig in rrset
290  * @param env: module environment, scratch space is used.
291  * @param ve: validator environment, date settings.
292  * @param now: current time for validation (can be overridden).
293  * @param rrset: to be validated.
294  * @param dnskey: DNSKEY rrset, keyset to try.
295  * @param sig_idx: which signature to try to validate.
296  * @param sortree: reused sorted order. Stored in region. Pass NULL at start,
297  * 	and for a new rrset.
298  * @param reason: if bogus, a string returned, fixed or alloced in scratch.
299  * @param section: section of packet where this rrset comes from.
300  * @param qstate: qstate with region.
301  * @return secure if any key signs *this* signature. bogus if no key signs it,
302  *	or unchecked on error.
303  */
304 enum sec_status dnskeyset_verify_rrset_sig(struct module_env* env,
305 	struct val_env* ve, time_t now, struct ub_packed_rrset_key* rrset,
306 	struct ub_packed_rrset_key* dnskey, size_t sig_idx,
307 	struct rbtree_type** sortree, char** reason, sldns_pkt_section section,
308 	struct module_qstate* qstate);
309 
310 /**
311  * verify rrset, with specific dnskey(from set), for a specific rrsig
312  * @param region: scratch region used for temporary allocation.
313  * @param buf: scratch buffer used for canonicalized rrset data.
314  * @param ve: validator environment, date settings.
315  * @param now: current time for validation (can be overridden).
316  * @param rrset: to be validated.
317  * @param dnskey: DNSKEY rrset, keyset.
318  * @param dnskey_idx: which key from the rrset to try.
319  * @param sig_idx: which signature to try to validate.
320  * @param sortree: pass NULL at start, the sorted rrset order is returned.
321  * 	pass it again for the same rrset.
322  * @param buf_canon: if true, the buffer is already canonical.
323  * 	pass false at start. pass old value only for same rrset and same
324  * 	signature (but perhaps different key) for reuse.
325  * @param reason: if bogus, a string returned, fixed or alloced in scratch.
326  * @param section: section of packet where this rrset comes from.
327  * @param qstate: qstate with region.
328  * @return secure if this key signs this signature. unchecked on error or
329  *	bogus if it did not validate.
330  */
331 enum sec_status dnskey_verify_rrset_sig(struct regional* region,
332 	struct sldns_buffer* buf, struct val_env* ve, time_t now,
333 	struct ub_packed_rrset_key* rrset, struct ub_packed_rrset_key* dnskey,
334 	size_t dnskey_idx, size_t sig_idx,
335 	struct rbtree_type** sortree, int* buf_canon, char** reason,
336 	sldns_pkt_section section, struct module_qstate* qstate);
337 
338 /**
339  * canonical compare for two tree entries
340  */
341 int canonical_tree_compare(const void* k1, const void* k2);
342 
343 /**
344  * Compare two rrsets and see if they are the same, canonicalised.
345  * The rrsets are not altered.
346  * @param region: temporary region.
347  * @param k1: rrset1
348  * @param k2: rrset2
349  * @return true if equal.
350  */
351 int rrset_canonical_equal(struct regional* region,
352 	struct ub_packed_rrset_key* k1, struct ub_packed_rrset_key* k2);
353 
354 /**
355  * Canonicalize an rrset into the buffer.  For an auth zone record, so
356  * this does not use a signature, or the RRSIG TTL or the wildcard label
357  * count from the RRSIG.
358  * @param region: temporary region.
359  * @param buf: the buffer to use.
360  * @param k: the rrset to insert.
361  * @return false on alloc error.
362  */
363 int rrset_canonicalize_to_buffer(struct regional* region,
364 	struct sldns_buffer* buf, struct ub_packed_rrset_key* k);
365 
366 #endif /* VALIDATOR_VAL_SIGCRYPT_H */
367