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