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#include "sldns/rrdef.h"
49struct val_env;
50struct module_env;
51struct module_qstate;
52struct ub_packed_rrset_key;
53struct rbtree_type;
54struct regional;
55struct sldns_buffer;
56
57/** number of entries in algorithm needs array */
58#define ALGO_NEEDS_MAX 256
59
60/**
61 * Storage for algorithm needs.  DNSKEY algorithms.
62 */
63struct algo_needs {
64	/** the algorithms (8-bit) with each a number.
65	 * 0: not marked.
66	 * 1: marked 'necessary but not yet fulfilled'
67	 * 2: marked bogus.
68	 * Indexed by algorithm number.
69	 */
70	uint8_t needs[ALGO_NEEDS_MAX];
71	/** the number of entries in the array that are unfulfilled */
72	size_t num;
73};
74
75/**
76 * Initialize algo needs structure, set algos from rrset as needed.
77 * Results are added to an existing need structure.
78 * @param n: struct with storage.
79 * @param dnskey: algos from this struct set as necessary. DNSKEY set.
80 * @param sigalg: adds to signalled algorithm list too.
81 */
82void algo_needs_init_dnskey_add(struct algo_needs* n,
83	struct ub_packed_rrset_key* dnskey, uint8_t* sigalg);
84
85/**
86 * Initialize algo needs structure from a signalled algo list.
87 * @param n: struct with storage.
88 * @param sigalg: signalled algorithm list, numbers ends with 0.
89 */
90void algo_needs_init_list(struct algo_needs* n, uint8_t* sigalg);
91
92/**
93 * Initialize algo needs structure, set algos from rrset as needed.
94 * @param n: struct with storage.
95 * @param ds: algos from this struct set as necessary. DS set.
96 * @param fav_ds_algo: filter to use only this DS algo.
97 * @param sigalg: list of signalled algos, constructed as output,
98 *	provide size ALGO_NEEDS_MAX+1. list of algonumbers, ends with a zero.
99 */
100void algo_needs_init_ds(struct algo_needs* n, struct ub_packed_rrset_key* ds,
101	int fav_ds_algo, uint8_t* sigalg);
102
103/**
104 * Mark this algorithm as a success, sec_secure, and see if we are done.
105 * @param n: storage structure processed.
106 * @param algo: the algorithm processed to be secure.
107 * @return if true, processing has finished successfully, we are satisfied.
108 */
109int algo_needs_set_secure(struct algo_needs* n, uint8_t algo);
110
111/**
112 * Mark this algorithm a failure, sec_bogus.  It can later be overridden
113 * by a success for this algorithm (with a different signature).
114 * @param n: storage structure processed.
115 * @param algo: the algorithm processed to be bogus.
116 */
117void algo_needs_set_bogus(struct algo_needs* n, uint8_t algo);
118
119/**
120 * See how many algorithms are missing (not bogus or secure, but not processed)
121 * @param n: storage structure processed.
122 * @return number of algorithms missing after processing.
123 */
124size_t algo_needs_num_missing(struct algo_needs* n);
125
126/**
127 * See which algo is missing.
128 * @param n: struct after processing.
129 * @return if 0 an algorithm was bogus, if a number, this algorithm was
130 *   missing.  So on 0, report why that was bogus, on number report a missing
131 *   algorithm.  There could be multiple missing, this reports the first one.
132 */
133int algo_needs_missing(struct algo_needs* n);
134
135/**
136 * Format error reason for algorithm missing.
137 * @param env: module env with scratch for temp storage of string.
138 * @param alg: DNSKEY-algorithm missing.
139 * @param reason: destination.
140 * @param s: string, appended with 'with algorithm ..'.
141 */
142void algo_needs_reason(struct module_env* env, int alg, char** reason, char* s);
143
144/**
145 * Check if dnskey matches a DS digest
146 * Does not check dnskey-keyid footprint, just the digest.
147 * @param env: module environment. Uses scratch space.
148 * @param dnskey_rrset: DNSKEY rrset.
149 * @param dnskey_idx: index of RR in rrset.
150 * @param ds_rrset: DS rrset
151 * @param ds_idx: index of RR in DS rrset.
152 * @return true if it matches, false on error, not supported or no match.
153 */
154int ds_digest_match_dnskey(struct module_env* env,
155	struct ub_packed_rrset_key* dnskey_rrset, size_t dnskey_idx,
156	struct ub_packed_rrset_key* ds_rrset, size_t ds_idx);
157
158/**
159 * Get dnskey keytag, footprint value
160 * @param dnskey_rrset: DNSKEY rrset.
161 * @param dnskey_idx: index of RR in rrset.
162 * @return the keytag or 0 for badly formatted DNSKEYs.
163 */
164uint16_t dnskey_calc_keytag(struct ub_packed_rrset_key* dnskey_rrset,
165	size_t dnskey_idx);
166
167/**
168 * Get DS keytag, footprint value that matches the DNSKEY keytag it signs.
169 * @param ds_rrset: DS rrset
170 * @param ds_idx: index of RR in DS rrset.
171 * @return the keytag or 0 for badly formatted DSs.
172 */
173uint16_t ds_get_keytag(struct ub_packed_rrset_key* ds_rrset, size_t ds_idx);
174
175/**
176 * See if DNSKEY algorithm is supported
177 * @param dnskey_rrset: DNSKEY rrset.
178 * @param dnskey_idx: index of RR in rrset.
179 * @return true if supported.
180 */
181int dnskey_algo_is_supported(struct ub_packed_rrset_key* dnskey_rrset,
182	size_t dnskey_idx);
183
184/**
185 * See if the DNSKEY size at that algorithm is supported.
186 * @param dnskey_rrset: DNSKEY rrset.
187 * @param dnskey_idx: index of RR in rrset.
188 * @return true if supported.
189 */
190int dnskey_size_is_supported(struct ub_packed_rrset_key* dnskey_rrset,
191	size_t dnskey_idx);
192
193/**
194 * See if the DNSKEY size at that algorithm is supported for all the
195 * RRs in the DNSKEY RRset.
196 * @param dnskey_rrset: DNSKEY rrset.
197 * @return true if supported.
198 */
199int dnskeyset_size_is_supported(struct ub_packed_rrset_key* dnskey_rrset);
200
201/**
202 * See if DS digest algorithm is supported
203 * @param ds_rrset: DS rrset
204 * @param ds_idx: index of RR in DS rrset.
205 * @return true if supported.
206 */
207int ds_digest_algo_is_supported(struct ub_packed_rrset_key* ds_rrset,
208	size_t ds_idx);
209
210/**
211 * Get DS RR digest algorithm
212 * @param ds_rrset: DS rrset.
213 * @param ds_idx: which DS.
214 * @return algorithm or 0 if DS too short.
215 */
216int ds_get_digest_algo(struct ub_packed_rrset_key* ds_rrset, size_t ds_idx);
217
218/**
219 * See if DS key algorithm is supported
220 * @param ds_rrset: DS rrset
221 * @param ds_idx: index of RR in DS rrset.
222 * @return true if supported.
223 */
224int ds_key_algo_is_supported(struct ub_packed_rrset_key* ds_rrset,
225	size_t ds_idx);
226
227/**
228 * Get DS RR key algorithm. This value should match with the DNSKEY algo.
229 * @param k: DS rrset.
230 * @param idx: which DS.
231 * @return algorithm or 0 if DS too short.
232 */
233int ds_get_key_algo(struct ub_packed_rrset_key* k, size_t idx);
234
235/**
236 * Get DNSKEY RR signature algorithm
237 * @param k: DNSKEY rrset.
238 * @param idx: which DNSKEY RR.
239 * @return algorithm or 0 if DNSKEY too short.
240 */
241int dnskey_get_algo(struct ub_packed_rrset_key* k, size_t idx);
242
243/**
244 * Get DNSKEY RR flags
245 * @param k: DNSKEY rrset.
246 * @param idx: which DNSKEY RR.
247 * @return flags or 0 if DNSKEY too short.
248 */
249uint16_t dnskey_get_flags(struct ub_packed_rrset_key* k, size_t idx);
250
251/**
252 * Verify rrset against dnskey rrset.
253 * @param env: module environment, scratch space is used.
254 * @param ve: validator environment, date settings.
255 * @param rrset: to be validated.
256 * @param dnskey: DNSKEY rrset, keyset to try.
257 * @param sigalg: if nonNULL provide downgrade protection otherwise one
258 *   algorithm is enough.
259 * @param reason: if bogus, a string returned, fixed or alloced in scratch.
260 * @param reason_bogus: EDE (RFC8914) code paired with the reason of failure.
261 * @param section: section of packet where this rrset comes from.
262 * @param qstate: qstate with region.
263 * @param verified: if not NULL the number of RRSIG validations is returned.
264 * @return SECURE if one key in the set verifies one rrsig.
265 *	UNCHECKED on allocation errors, unsupported algorithms, malformed data,
266 *	and BOGUS on verification failures (no keys match any signatures).
267 */
268enum sec_status dnskeyset_verify_rrset(struct module_env* env,
269	struct val_env* ve, struct ub_packed_rrset_key* rrset,
270	struct ub_packed_rrset_key* dnskey, uint8_t* sigalg,
271	char** reason, sldns_ede_code *reason_bogus,
272	sldns_pkt_section section, struct module_qstate* qstate, int* verified);
273
274
275/**
276 * verify rrset against one specific dnskey (from rrset)
277 * @param env: module environment, scratch space is used.
278 * @param ve: validator environment, date settings.
279 * @param rrset: to be validated.
280 * @param dnskey: DNSKEY rrset, keyset.
281 * @param dnskey_idx: which key from the rrset to try.
282 * @param reason: if bogus, a string returned, fixed or alloced in scratch.
283 * @param reason_bogus: EDE (RFC8914) code paired with the reason of failure.
284 * @param section: section of packet where this rrset comes from.
285 * @param qstate: qstate with region.
286 * @return secure if *this* key signs any of the signatures on rrset.
287 *	unchecked on error or and bogus on bad signature.
288 */
289enum sec_status dnskey_verify_rrset(struct module_env* env, struct val_env* ve,
290        struct ub_packed_rrset_key* rrset, struct ub_packed_rrset_key* dnskey,
291	size_t dnskey_idx, char** reason, sldns_ede_code *reason_bogus,
292	sldns_pkt_section section, struct module_qstate* qstate);
293
294/**
295 * verify rrset, with specific dnskey(from set), for a specific rrsig
296 * @param region: scratch region used for temporary allocation.
297 * @param buf: scratch buffer used for canonicalized rrset data.
298 * @param ve: validator environment, date settings.
299 * @param now: current time for validation (can be overridden).
300 * @param rrset: to be validated.
301 * @param dnskey: DNSKEY rrset, keyset.
302 * @param dnskey_idx: which key from the rrset to try.
303 * @param sig_idx: which signature to try to validate.
304 * @param sortree: pass NULL at start, the sorted rrset order is returned.
305 * 	pass it again for the same rrset.
306 * @param buf_canon: if true, the buffer is already canonical.
307 * 	pass false at start. pass old value only for same rrset and same
308 * 	signature (but perhaps different key) for reuse.
309 * @param reason: if bogus, a string returned, fixed or alloced in scratch.
310 * @param reason_bogus: EDE (8914) code paired with the reason of failure.
311 * @param section: section of packet where this rrset comes from.
312 * @param qstate: qstate with region.
313 * @return secure if this key signs this signature. unchecked on error or
314 *	bogus if it did not validate.
315 */
316enum sec_status dnskey_verify_rrset_sig(struct regional* region,
317        struct sldns_buffer* buf, struct val_env* ve, time_t now,
318        struct ub_packed_rrset_key* rrset, struct ub_packed_rrset_key* dnskey,
319        size_t dnskey_idx, size_t sig_idx,
320        struct rbtree_type** sortree, int* buf_canon,
321        char** reason, sldns_ede_code *reason_bogus,
322        sldns_pkt_section section, struct module_qstate* qstate);
323
324/**
325 * canonical compare for two tree entries
326 */
327int canonical_tree_compare(const void* k1, const void* k2);
328
329/**
330 * Compare two rrsets and see if they are the same, canonicalised.
331 * The rrsets are not altered.
332 * @param region: temporary region.
333 * @param k1: rrset1
334 * @param k2: rrset2
335 * @return true if equal.
336 */
337int rrset_canonical_equal(struct regional* region,
338	struct ub_packed_rrset_key* k1, struct ub_packed_rrset_key* k2);
339
340/**
341 * Canonicalize an rrset into the buffer.  For an auth zone record, so
342 * this does not use a signature, or the RRSIG TTL or the wildcard label
343 * count from the RRSIG.
344 * @param region: temporary region.
345 * @param buf: the buffer to use.
346 * @param k: the rrset to insert.
347 * @return false on alloc error.
348 */
349int rrset_canonicalize_to_buffer(struct regional* region,
350	struct sldns_buffer* buf, struct ub_packed_rrset_key* k);
351
352#endif /* VALIDATOR_VAL_SIGCRYPT_H */
353