1238106Sdes/*
2238106Sdes * validator/val_utils.h - validator utility functions.
3238106Sdes *
4238106Sdes * Copyright (c) 2007, NLnet Labs. All rights reserved.
5238106Sdes *
6238106Sdes * This software is open source.
7238106Sdes *
8238106Sdes * Redistribution and use in source and binary forms, with or without
9238106Sdes * modification, are permitted provided that the following conditions
10238106Sdes * are met:
11238106Sdes *
12238106Sdes * Redistributions of source code must retain the above copyright notice,
13238106Sdes * this list of conditions and the following disclaimer.
14238106Sdes *
15238106Sdes * Redistributions in binary form must reproduce the above copyright notice,
16238106Sdes * this list of conditions and the following disclaimer in the documentation
17238106Sdes * and/or other materials provided with the distribution.
18238106Sdes *
19238106Sdes * Neither the name of the NLNET LABS nor the names of its contributors may
20238106Sdes * be used to endorse or promote products derived from this software without
21238106Sdes * specific prior written permission.
22238106Sdes *
23238106Sdes * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
24238106Sdes * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
25238106Sdes * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
26238106Sdes * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE
27238106Sdes * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
28238106Sdes * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
29238106Sdes * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
30238106Sdes * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
31238106Sdes * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
32238106Sdes * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
33238106Sdes * POSSIBILITY OF SUCH DAMAGE.
34238106Sdes */
35238106Sdes
36238106Sdes/**
37238106Sdes * \file
38238106Sdes *
39238106Sdes * This file contains helper functions for the validator module.
40238106Sdes */
41238106Sdes
42238106Sdes#ifndef VALIDATOR_VAL_UTILS_H
43238106Sdes#define VALIDATOR_VAL_UTILS_H
44238106Sdes#include "util/data/packed_rrset.h"
45238106Sdesstruct query_info;
46238106Sdesstruct reply_info;
47238106Sdesstruct val_env;
48238106Sdesstruct module_env;
49238106Sdesstruct ub_packed_rrset_key;
50238106Sdesstruct key_entry_key;
51238106Sdesstruct regional;
52238106Sdesstruct val_anchors;
53238106Sdesstruct rrset_cache;
54238106Sdesstruct sock_list;
55238106Sdes
56238106Sdes/**
57238106Sdes * Response classifications for the validator. The different types of proofs.
58238106Sdes */
59238106Sdesenum val_classification {
60238106Sdes	/** Not subtyped yet. */
61238106Sdes	VAL_CLASS_UNTYPED = 0,
62238106Sdes	/** Not a recognized subtype. */
63238106Sdes	VAL_CLASS_UNKNOWN,
64238106Sdes	/** A positive, direct, response */
65238106Sdes	VAL_CLASS_POSITIVE,
66238106Sdes	/** A positive response, with a CNAME/DNAME chain. */
67238106Sdes	VAL_CLASS_CNAME,
68238106Sdes	/** A NOERROR/NODATA response. */
69238106Sdes	VAL_CLASS_NODATA,
70238106Sdes	/** A NXDOMAIN response. */
71238106Sdes	VAL_CLASS_NAMEERROR,
72238106Sdes	/** A CNAME/DNAME chain, and the offset is at the end of it,
73238106Sdes	 * but there is no answer here, it can be NAMERROR or NODATA. */
74238106Sdes	VAL_CLASS_CNAMENOANSWER,
75238106Sdes	/** A referral, from cache with a nonRD query. */
76238106Sdes	VAL_CLASS_REFERRAL,
77238106Sdes	/** A response to a qtype=ANY query. */
78238106Sdes	VAL_CLASS_ANY
79238106Sdes};
80238106Sdes
81238106Sdes/**
82238106Sdes * Given a response, classify ANSWER responses into a subtype.
83238106Sdes * @param query_flags: query flags for the original query.
84238106Sdes * @param origqinf: query info. The original query name.
85238106Sdes * @param qinf: query info. The chased query name.
86238106Sdes * @param rep: response. The original response.
87238106Sdes * @param skip: offset into the original response answer section.
88238106Sdes * @return A subtype, all values possible except UNTYPED .
89238106Sdes * 	Once CNAME type is returned you can increase skip.
90238106Sdes * 	Then, another CNAME type, CNAME_NOANSWER or POSITIVE are possible.
91238106Sdes */
92238106Sdesenum val_classification val_classify_response(uint16_t query_flags,
93238106Sdes	struct query_info* origqinf, struct query_info* qinf,
94238106Sdes	struct reply_info* rep, size_t skip);
95238106Sdes
96238106Sdes/**
97238106Sdes * Given a response, determine the name of the "signer". This is primarily
98238106Sdes * to determine if the response is, in fact, signed at all, and, if so, what
99238106Sdes * is the name of the most pertinent keyset.
100238106Sdes *
101238106Sdes * @param subtype: the type from classify.
102238106Sdes * @param qinf: query, the chased query name.
103238106Sdes * @param rep: response to that, original response.
104238106Sdes * @param cname_skip: how many answer rrsets have been skipped due to CNAME
105238106Sdes * 	chains being chased around.
106238106Sdes * @param signer_name:  signer name, if the response is signed
107238106Sdes * 	(even partially), or null if the response isn't signed.
108238106Sdes * @param signer_len: length of signer_name of 0 if signer_name is NULL.
109238106Sdes */
110238106Sdesvoid val_find_signer(enum val_classification subtype,
111238106Sdes	struct query_info* qinf, struct reply_info* rep,
112238106Sdes	size_t cname_skip, uint8_t** signer_name, size_t* signer_len);
113238106Sdes
114238106Sdes/**
115238106Sdes * Verify RRset with keys
116238106Sdes * @param env: module environment (scratch buffer)
117238106Sdes * @param ve: validator environment (verification settings)
118238106Sdes * @param rrset: what to verify
119238106Sdes * @param keys: dnskey rrset to verify with.
120238106Sdes * @param sigalg: if nonNULL provide downgrade protection otherwise one
121238106Sdes *   algorithm is enough.  Algo list is constructed in here.
122238106Sdes * @param reason: reason of failure. Fixed string or alloced in scratch.
123238106Sdes * @return security status of verification.
124238106Sdes */
125238106Sdesenum sec_status val_verify_rrset(struct module_env* env, struct val_env* ve,
126238106Sdes	struct ub_packed_rrset_key* rrset, struct ub_packed_rrset_key* keys,
127238106Sdes	uint8_t* sigalg, char** reason);
128238106Sdes
129238106Sdes/**
130238106Sdes * Verify RRset with keys from a keyset.
131238106Sdes * @param env: module environment (scratch buffer)
132238106Sdes * @param ve: validator environment (verification settings)
133238106Sdes * @param rrset: what to verify
134238106Sdes * @param kkey: key_entry to verify with.
135238106Sdes * @param reason: reason of failure. Fixed string or alloced in scratch.
136238106Sdes * @return security status of verification.
137238106Sdes */
138238106Sdesenum sec_status val_verify_rrset_entry(struct module_env* env,
139238106Sdes	struct val_env* ve, struct ub_packed_rrset_key* rrset,
140238106Sdes	struct key_entry_key* kkey, char** reason);
141238106Sdes
142238106Sdes/**
143238106Sdes * Verify DNSKEYs with DS rrset. Like val_verify_new_DNSKEYs but
144238106Sdes * returns a sec_status instead of a key_entry.
145238106Sdes * @param env: module environment (scratch buffer)
146238106Sdes * @param ve: validator environment (verification settings)
147238106Sdes * @param dnskey_rrset: DNSKEY rrset to verify
148238106Sdes * @param ds_rrset: DS rrset to verify with.
149238106Sdes * @param sigalg: if nonNULL provide downgrade protection otherwise one
150238106Sdes *   algorithm is enough.  The list of signalled algorithms is returned,
151238106Sdes *   must have enough space for ALGO_NEEDS_MAX+1.
152238106Sdes * @param reason: reason of failure. Fixed string or alloced in scratch.
153238106Sdes * @return: sec_status_secure if a DS matches.
154238106Sdes *     sec_status_insecure if end of trust (i.e., unknown algorithms).
155238106Sdes *     sec_status_bogus if it fails.
156238106Sdes */
157238106Sdesenum sec_status val_verify_DNSKEY_with_DS(struct module_env* env,
158238106Sdes	struct val_env* ve, struct ub_packed_rrset_key* dnskey_rrset,
159238106Sdes	struct ub_packed_rrset_key* ds_rrset, uint8_t* sigalg, char** reason);
160238106Sdes
161238106Sdes/**
162238106Sdes * Verify DNSKEYs with DS and DNSKEY rrset.  Like val_verify_DNSKEY_with_DS
163238106Sdes * but for a trust anchor.
164238106Sdes * @param env: module environment (scratch buffer)
165238106Sdes * @param ve: validator environment (verification settings)
166238106Sdes * @param dnskey_rrset: DNSKEY rrset to verify
167238106Sdes * @param ta_ds: DS rrset to verify with.
168238106Sdes * @param ta_dnskey: DNSKEY rrset to verify with.
169238106Sdes * @param sigalg: if nonNULL provide downgrade protection otherwise one
170238106Sdes *   algorithm is enough.  The list of signalled algorithms is returned,
171238106Sdes *   must have enough space for ALGO_NEEDS_MAX+1.
172238106Sdes * @param reason: reason of failure. Fixed string or alloced in scratch.
173238106Sdes * @return: sec_status_secure if a DS matches.
174238106Sdes *     sec_status_insecure if end of trust (i.e., unknown algorithms).
175238106Sdes *     sec_status_bogus if it fails.
176238106Sdes */
177238106Sdesenum sec_status val_verify_DNSKEY_with_TA(struct module_env* env,
178238106Sdes	struct val_env* ve, struct ub_packed_rrset_key* dnskey_rrset,
179238106Sdes	struct ub_packed_rrset_key* ta_ds,
180238106Sdes	struct ub_packed_rrset_key* ta_dnskey, uint8_t* sigalg, char** reason);
181238106Sdes
182238106Sdes/**
183238106Sdes * Verify new DNSKEYs with DS rrset. The DS contains hash values that should
184238106Sdes * match the DNSKEY keys.
185238106Sdes * match the DS to a DNSKEY and verify the DNSKEY rrset with that key.
186238106Sdes *
187238106Sdes * @param region: where to allocate key entry result.
188238106Sdes * @param env: module environment (scratch buffer)
189238106Sdes * @param ve: validator environment (verification settings)
190238106Sdes * @param dnskey_rrset: DNSKEY rrset to verify
191238106Sdes * @param ds_rrset: DS rrset to verify with.
192238106Sdes * @param downprot: if true provide downgrade protection otherwise one
193238106Sdes *   algorithm is enough.
194238106Sdes * @param reason: reason of failure. Fixed string or alloced in scratch.
195238106Sdes * @return a KeyEntry. This will either contain the now trusted
196238106Sdes *         dnskey_rrset, a "null" key entry indicating that this DS
197238106Sdes *         rrset/DNSKEY pair indicate an secure end to the island of trust
198238106Sdes *         (i.e., unknown algorithms), or a "bad" KeyEntry if the dnskey
199238106Sdes *         rrset fails to verify. Note that the "null" response should
200238106Sdes *         generally only occur in a private algorithm scenario: normally
201238106Sdes *         this sort of thing is checked before fetching the matching DNSKEY
202238106Sdes *         rrset.
203238106Sdes *         if downprot is set, a key entry with an algo list is made.
204238106Sdes */
205238106Sdesstruct key_entry_key* val_verify_new_DNSKEYs(struct regional* region,
206238106Sdes	struct module_env* env, struct val_env* ve,
207238106Sdes	struct ub_packed_rrset_key* dnskey_rrset,
208238106Sdes	struct ub_packed_rrset_key* ds_rrset, int downprot, char** reason);
209238106Sdes
210238106Sdes
211238106Sdes/**
212238106Sdes * Verify rrset with trust anchor: DS and DNSKEY rrset.
213238106Sdes *
214238106Sdes * @param region: where to allocate key entry result.
215238106Sdes * @param env: module environment (scratch buffer)
216238106Sdes * @param ve: validator environment (verification settings)
217238106Sdes * @param dnskey_rrset: DNSKEY rrset to verify
218238106Sdes * @param ta_ds_rrset: DS rrset to verify with.
219238106Sdes * @param ta_dnskey_rrset: the DNSKEY rrset to verify with.
220238106Sdes * @param downprot: if true provide downgrade protection otherwise one
221238106Sdes *   algorithm is enough.
222238106Sdes * @param reason: reason of failure. Fixed string or alloced in scratch.
223238106Sdes * @return a KeyEntry. This will either contain the now trusted
224238106Sdes *         dnskey_rrset, a "null" key entry indicating that this DS
225238106Sdes *         rrset/DNSKEY pair indicate an secure end to the island of trust
226238106Sdes *         (i.e., unknown algorithms), or a "bad" KeyEntry if the dnskey
227238106Sdes *         rrset fails to verify. Note that the "null" response should
228238106Sdes *         generally only occur in a private algorithm scenario: normally
229238106Sdes *         this sort of thing is checked before fetching the matching DNSKEY
230238106Sdes *         rrset.
231238106Sdes *         if downprot is set, a key entry with an algo list is made.
232238106Sdes */
233238106Sdesstruct key_entry_key* val_verify_new_DNSKEYs_with_ta(struct regional* region,
234238106Sdes	struct module_env* env, struct val_env* ve,
235238106Sdes	struct ub_packed_rrset_key* dnskey_rrset,
236238106Sdes	struct ub_packed_rrset_key* ta_ds_rrset,
237238106Sdes	struct ub_packed_rrset_key* ta_dnskey_rrset,
238238106Sdes	int downprot, char** reason);
239238106Sdes
240238106Sdes/**
241238106Sdes * Determine if DS rrset is usable for validator or not.
242238106Sdes * Returns true if the algorithms for key and DShash are supported,
243238106Sdes * for at least one RR.
244238106Sdes *
245238106Sdes * @param ds_rrset: the newly received DS rrset.
246238106Sdes * @return true or false if not usable.
247238106Sdes */
248238106Sdesint val_dsset_isusable(struct ub_packed_rrset_key* ds_rrset);
249238106Sdes
250238106Sdes/**
251238106Sdes * Determine by looking at a signed RRset whether or not the RRset name was
252238106Sdes * the result of a wildcard expansion. If so, return the name of the
253238106Sdes * generating wildcard.
254238106Sdes *
255238106Sdes * @param rrset The rrset to chedck.
256238106Sdes * @param wc: the wildcard name, if the rrset was synthesized from a wildcard.
257238106Sdes *         unchanged if not.  The wildcard name, without "*." in front, is
258238106Sdes *         returned. This is a pointer into the rrset owner name.
259238106Sdes * @return false if the signatures are inconsistent in indicating the
260238106Sdes * 	wildcard status; possible spoofing of wildcard response for other
261238106Sdes * 	responses is being tried. We lost the status which rrsig was verified
262238106Sdes * 	after the verification routine finished, so we simply check if
263238106Sdes * 	the signatures are consistent; inserting a fake signature is a denial
264238106Sdes * 	of service; but in that you could also have removed the real
265238106Sdes * 	signature anyway.
266238106Sdes */
267238106Sdesint val_rrset_wildcard(struct ub_packed_rrset_key* rrset, uint8_t** wc);
268238106Sdes
269238106Sdes/**
270238106Sdes * Chase the cname to the next query name.
271238106Sdes * @param qchase: the current query name, updated to next target.
272238106Sdes * @param rep: original message reply to look at CNAMEs.
273238106Sdes * @param cname_skip: the skip into the answer section. Updated to skip
274238106Sdes * 	DNAME and CNAME to the next part of the answer.
275238106Sdes * @return false on error (bad rdata).
276238106Sdes */
277238106Sdesint val_chase_cname(struct query_info* qchase, struct reply_info* rep,
278238106Sdes	size_t* cname_skip);
279238106Sdes
280238106Sdes/**
281238106Sdes * Fill up the chased reply with the content from the original reply;
282238106Sdes * as pointers to those rrsets. Select the part after the cname_skip into
283238106Sdes * the answer section, NS and AR sections that are signed with same signer.
284238106Sdes *
285238106Sdes * @param chase: chased reply, filled up.
286238106Sdes * @param orig: original reply.
287238106Sdes * @param cname_skip: which part of the answer section to skip.
288238106Sdes * 	The skipped part contains CNAME(and DNAME)s that have been chased.
289238106Sdes * @param name: the signer name to look for.
290238106Sdes * @param len: length of name.
291238106Sdes * @param signer: signer name or NULL if an unsigned RRset is considered.
292238106Sdes *	If NULL, rrsets with the lookup name are copied over.
293238106Sdes */
294238106Sdesvoid val_fill_reply(struct reply_info* chase, struct reply_info* orig,
295238106Sdes	size_t cname_skip, uint8_t* name, size_t len, uint8_t* signer);
296238106Sdes
297238106Sdes/**
298238106Sdes * Remove all unsigned or non-secure status rrsets from NS and AR sections.
299238106Sdes * So that unsigned data does not get let through to clients, when we have
300238106Sdes * found the data to be secure.
301238106Sdes *
302238106Sdes * @param ve: validator environment with cleaning options.
303238106Sdes * @param rep: reply to dump all nonsecure stuff out of.
304238106Sdes */
305238106Sdesvoid val_check_nonsecure(struct val_env* ve, struct reply_info* rep);
306238106Sdes
307238106Sdes/**
308238106Sdes * Mark all unchecked rrset entries not below a trust anchor as indeterminate.
309238106Sdes * Only security==unchecked rrsets are updated.
310238106Sdes * @param rep: the reply with rrsets.
311238106Sdes * @param anchors: the trust anchors.
312238106Sdes * @param r: rrset cache to store updated security status into.
313238106Sdes * @param env: module environment
314238106Sdes */
315238106Sdesvoid val_mark_indeterminate(struct reply_info* rep,
316238106Sdes	struct val_anchors* anchors, struct rrset_cache* r,
317238106Sdes	struct module_env* env);
318238106Sdes
319238106Sdes/**
320238106Sdes * Mark all unchecked rrset entries below a NULL key entry as insecure.
321238106Sdes * Only security==unchecked rrsets are updated.
322238106Sdes * @param rep: the reply with rrsets.
323238106Sdes * @param kname: end of secure space name.
324238106Sdes * @param r: rrset cache to store updated security status into.
325238106Sdes * @param env: module environment
326238106Sdes */
327238106Sdesvoid val_mark_insecure(struct reply_info* rep, uint8_t* kname,
328238106Sdes	struct rrset_cache* r, struct module_env* env);
329238106Sdes
330238106Sdes/**
331238106Sdes * Find next unchecked rrset position, return it for skip.
332238106Sdes * @param rep: the original reply to look into.
333238106Sdes * @param skip: the skip now.
334238106Sdes * @return new skip, which may be at the rep->rrset_count position to signal
335238106Sdes * 	there are no unchecked items.
336238106Sdes */
337238106Sdessize_t val_next_unchecked(struct reply_info* rep, size_t skip);
338238106Sdes
339238106Sdes/**
340238106Sdes * Find the signer name for an RRset.
341238106Sdes * @param rrset: the rrset.
342238106Sdes * @param sname: signer name is returned or NULL if not signed.
343238106Sdes * @param slen: length of sname (or 0).
344238106Sdes */
345238106Sdesvoid val_find_rrset_signer(struct ub_packed_rrset_key* rrset, uint8_t** sname,
346238106Sdes	size_t* slen);
347238106Sdes
348238106Sdes/**
349238106Sdes * Get string to denote the classification result.
350238106Sdes * @param subtype: from classification function.
351238106Sdes * @return static string to describe the classification.
352238106Sdes */
353238106Sdesconst char* val_classification_to_string(enum val_classification subtype);
354238106Sdes
355238106Sdes/**
356238106Sdes * Add existing list to blacklist.
357238106Sdes * @param blacklist: the blacklist with result
358238106Sdes * @param region: the region where blacklist is allocated.
359238106Sdes *	Allocation failures are logged.
360238106Sdes * @param origin: origin list to add, if NULL, a cache-entry is added to
361238106Sdes *   the blacklist to stop cache from being used.
362238106Sdes * @param cross: if true this is a cross-qstate copy, and the 'origin'
363238106Sdes *   list is not allocated in the same region as the blacklist.
364238106Sdes */
365238106Sdesvoid val_blacklist(struct sock_list** blacklist, struct regional* region,
366238106Sdes	struct sock_list* origin, int cross);
367238106Sdes
368238106Sdes/**
369238106Sdes * check if has dnssec info, and if it has signed nsecs. gives error reason.
370238106Sdes * @param rep: reply to check.
371238106Sdes * @param reason: returned on fail.
372238106Sdes * @return false if message has no signed nsecs.  Can not prove negatives.
373238106Sdes */
374238106Sdesint val_has_signed_nsecs(struct reply_info* rep, char** reason);
375238106Sdes
376238106Sdes/**
377238106Sdes * Return algo number for favorite (best) algorithm that we support in DS.
378238106Sdes * @param ds_rrset: the DSes in this rrset are inspected and best algo chosen.
379238106Sdes * @return algo number or 0 if none supported. 0 is unused as algo number.
380238106Sdes */
381238106Sdesint val_favorite_ds_algo(struct ub_packed_rrset_key* ds_rrset);
382238106Sdes
383238106Sdes/**
384238106Sdes * Find DS denial message in cache.  Saves new qstate allocation and allows
385238106Sdes * the validator to use partial content which is not enough to construct a
386238106Sdes * message for network (or user) consumption.  Without SOA for example,
387238106Sdes * which is a common occurence in the unbound code since the referrals contain
388238106Sdes * NSEC/NSEC3 rrs without the SOA element, thus do not allow synthesis of a
389238106Sdes * full negative reply, but do allow synthesis of sufficient proof.
390238106Sdes * @param env: query env with caches and time.
391238106Sdes * @param nm: name of DS record sought.
392238106Sdes * @param nmlen: length of name.
393238106Sdes * @param c: class of DS RR.
394238106Sdes * @param region: where to allocate result.
395238106Sdes * @param topname: name of the key that is currently in use, that will get
396238106Sdes *	used to validate the result, and thus no higher entries from the
397238106Sdes *	negative cache need to be examined.
398238106Sdes * @return a dns_msg on success. NULL on failure.
399238106Sdes */
400238106Sdesstruct dns_msg* val_find_DS(struct module_env* env, uint8_t* nm, size_t nmlen,
401238106Sdes	uint16_t c, struct regional* region, uint8_t* topname);
402238106Sdes
403238106Sdes#endif /* VALIDATOR_VAL_UTILS_H */
404