1933707f3Ssthen /* 2933707f3Ssthen * validator/val_sigcrypt.c - validator signature crypto functions. 3933707f3Ssthen * 4933707f3Ssthen * Copyright (c) 2007, NLnet Labs. All rights reserved. 5933707f3Ssthen * 6933707f3Ssthen * This software is open source. 7933707f3Ssthen * 8933707f3Ssthen * Redistribution and use in source and binary forms, with or without 9933707f3Ssthen * modification, are permitted provided that the following conditions 10933707f3Ssthen * are met: 11933707f3Ssthen * 12933707f3Ssthen * Redistributions of source code must retain the above copyright notice, 13933707f3Ssthen * this list of conditions and the following disclaimer. 14933707f3Ssthen * 15933707f3Ssthen * Redistributions in binary form must reproduce the above copyright notice, 16933707f3Ssthen * this list of conditions and the following disclaimer in the documentation 17933707f3Ssthen * and/or other materials provided with the distribution. 18933707f3Ssthen * 19933707f3Ssthen * Neither the name of the NLNET LABS nor the names of its contributors may 20933707f3Ssthen * be used to endorse or promote products derived from this software without 21933707f3Ssthen * specific prior written permission. 22933707f3Ssthen * 23933707f3Ssthen * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 245d76a658Ssthen * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 255d76a658Ssthen * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 265d76a658Ssthen * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 275d76a658Ssthen * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 285d76a658Ssthen * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED 295d76a658Ssthen * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 305d76a658Ssthen * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF 315d76a658Ssthen * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 325d76a658Ssthen * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 335d76a658Ssthen * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 34933707f3Ssthen */ 35933707f3Ssthen 36933707f3Ssthen /** 37933707f3Ssthen * \file 38933707f3Ssthen * 39933707f3Ssthen * This file contains helper functions for the validator module. 40933707f3Ssthen * The functions help with signature verification and checking, the 41933707f3Ssthen * bridging between RR wireformat data and crypto calls. 42933707f3Ssthen */ 43933707f3Ssthen #include "config.h" 44933707f3Ssthen #include "validator/val_sigcrypt.h" 453dcb24b8Ssthen #include "validator/val_secalgo.h" 46933707f3Ssthen #include "validator/validator.h" 47933707f3Ssthen #include "util/data/msgreply.h" 48933707f3Ssthen #include "util/data/msgparse.h" 49933707f3Ssthen #include "util/data/dname.h" 50933707f3Ssthen #include "util/rbtree.h" 518b7325afSsthen #include "util/rfc_1982.h" 52933707f3Ssthen #include "util/module.h" 53933707f3Ssthen #include "util/net_help.h" 54933707f3Ssthen #include "util/regional.h" 552be9e038Ssthen #include "util/config_file.h" 56fdfb4ba6Ssthen #include "sldns/keyraw.h" 57fdfb4ba6Ssthen #include "sldns/sbuffer.h" 58fdfb4ba6Ssthen #include "sldns/parseutil.h" 59fdfb4ba6Ssthen #include "sldns/wire2str.h" 60933707f3Ssthen 615d76a658Ssthen #include <ctype.h> 6224893edcSsthen #if !defined(HAVE_SSL) && !defined(HAVE_NSS) && !defined(HAVE_NETTLE) 633dcb24b8Ssthen #error "Need crypto library to do digital signature cryptography" 64933707f3Ssthen #endif 65933707f3Ssthen 66933707f3Ssthen #ifdef HAVE_OPENSSL_ERR_H 67933707f3Ssthen #include <openssl/err.h> 68933707f3Ssthen #endif 69933707f3Ssthen 70933707f3Ssthen #ifdef HAVE_OPENSSL_RAND_H 71933707f3Ssthen #include <openssl/rand.h> 72933707f3Ssthen #endif 73933707f3Ssthen 74933707f3Ssthen #ifdef HAVE_OPENSSL_CONF_H 75933707f3Ssthen #include <openssl/conf.h> 76933707f3Ssthen #endif 77933707f3Ssthen 78933707f3Ssthen #ifdef HAVE_OPENSSL_ENGINE_H 79933707f3Ssthen #include <openssl/engine.h> 80933707f3Ssthen #endif 81933707f3Ssthen 82817bdb8fSflorian /** Maximum number of RRSIG validations for an RRset. */ 83817bdb8fSflorian #define MAX_VALIDATE_RRSIGS 8 84817bdb8fSflorian 85933707f3Ssthen /** return number of rrs in an rrset */ 86933707f3Ssthen static size_t 87933707f3Ssthen rrset_get_count(struct ub_packed_rrset_key* rrset) 88933707f3Ssthen { 89933707f3Ssthen struct packed_rrset_data* d = (struct packed_rrset_data*) 90933707f3Ssthen rrset->entry.data; 91933707f3Ssthen if(!d) return 0; 92933707f3Ssthen return d->count; 93933707f3Ssthen } 94933707f3Ssthen 95933707f3Ssthen /** 96933707f3Ssthen * Get RR signature count 97933707f3Ssthen */ 98933707f3Ssthen static size_t 99933707f3Ssthen rrset_get_sigcount(struct ub_packed_rrset_key* k) 100933707f3Ssthen { 101933707f3Ssthen struct packed_rrset_data* d = (struct packed_rrset_data*)k->entry.data; 102933707f3Ssthen return d->rrsig_count; 103933707f3Ssthen } 104933707f3Ssthen 105933707f3Ssthen /** 106933707f3Ssthen * Get signature keytag value 107933707f3Ssthen * @param k: rrset (with signatures) 108933707f3Ssthen * @param sig_idx: signature index. 109933707f3Ssthen * @return keytag or 0 if malformed rrsig. 110933707f3Ssthen */ 111933707f3Ssthen static uint16_t 112933707f3Ssthen rrset_get_sig_keytag(struct ub_packed_rrset_key* k, size_t sig_idx) 113933707f3Ssthen { 114933707f3Ssthen uint16_t t; 115933707f3Ssthen struct packed_rrset_data* d = (struct packed_rrset_data*)k->entry.data; 116933707f3Ssthen log_assert(sig_idx < d->rrsig_count); 117933707f3Ssthen if(d->rr_len[d->count + sig_idx] < 2+18) 118933707f3Ssthen return 0; 119933707f3Ssthen memmove(&t, d->rr_data[d->count + sig_idx]+2+16, 2); 120933707f3Ssthen return ntohs(t); 121933707f3Ssthen } 122933707f3Ssthen 123933707f3Ssthen /** 124933707f3Ssthen * Get signature signing algorithm value 125933707f3Ssthen * @param k: rrset (with signatures) 126933707f3Ssthen * @param sig_idx: signature index. 127933707f3Ssthen * @return algo or 0 if malformed rrsig. 128933707f3Ssthen */ 129933707f3Ssthen static int 130933707f3Ssthen rrset_get_sig_algo(struct ub_packed_rrset_key* k, size_t sig_idx) 131933707f3Ssthen { 132933707f3Ssthen struct packed_rrset_data* d = (struct packed_rrset_data*)k->entry.data; 133933707f3Ssthen log_assert(sig_idx < d->rrsig_count); 134933707f3Ssthen if(d->rr_len[d->count + sig_idx] < 2+3) 135933707f3Ssthen return 0; 136933707f3Ssthen return (int)d->rr_data[d->count + sig_idx][2+2]; 137933707f3Ssthen } 138933707f3Ssthen 139933707f3Ssthen /** get rdata pointer and size */ 140933707f3Ssthen static void 141933707f3Ssthen rrset_get_rdata(struct ub_packed_rrset_key* k, size_t idx, uint8_t** rdata, 142933707f3Ssthen size_t* len) 143933707f3Ssthen { 144933707f3Ssthen struct packed_rrset_data* d = (struct packed_rrset_data*)k->entry.data; 145933707f3Ssthen log_assert(d && idx < (d->count + d->rrsig_count)); 146933707f3Ssthen *rdata = d->rr_data[idx]; 147933707f3Ssthen *len = d->rr_len[idx]; 148933707f3Ssthen } 149933707f3Ssthen 150933707f3Ssthen uint16_t 151933707f3Ssthen dnskey_get_flags(struct ub_packed_rrset_key* k, size_t idx) 152933707f3Ssthen { 153933707f3Ssthen uint8_t* rdata; 154933707f3Ssthen size_t len; 155933707f3Ssthen uint16_t f; 156933707f3Ssthen rrset_get_rdata(k, idx, &rdata, &len); 157933707f3Ssthen if(len < 2+2) 158933707f3Ssthen return 0; 159933707f3Ssthen memmove(&f, rdata+2, 2); 160933707f3Ssthen f = ntohs(f); 161933707f3Ssthen return f; 162933707f3Ssthen } 163933707f3Ssthen 164933707f3Ssthen /** 165933707f3Ssthen * Get DNSKEY protocol value from rdata 166933707f3Ssthen * @param k: DNSKEY rrset. 167933707f3Ssthen * @param idx: which key. 168933707f3Ssthen * @return protocol octet value 169933707f3Ssthen */ 170933707f3Ssthen static int 171933707f3Ssthen dnskey_get_protocol(struct ub_packed_rrset_key* k, size_t idx) 172933707f3Ssthen { 173933707f3Ssthen uint8_t* rdata; 174933707f3Ssthen size_t len; 175933707f3Ssthen rrset_get_rdata(k, idx, &rdata, &len); 176933707f3Ssthen if(len < 2+4) 177933707f3Ssthen return 0; 178933707f3Ssthen return (int)rdata[2+2]; 179933707f3Ssthen } 180933707f3Ssthen 181933707f3Ssthen int 182933707f3Ssthen dnskey_get_algo(struct ub_packed_rrset_key* k, size_t idx) 183933707f3Ssthen { 184933707f3Ssthen uint8_t* rdata; 185933707f3Ssthen size_t len; 186933707f3Ssthen rrset_get_rdata(k, idx, &rdata, &len); 187933707f3Ssthen if(len < 2+4) 188933707f3Ssthen return 0; 189933707f3Ssthen return (int)rdata[2+3]; 190933707f3Ssthen } 191933707f3Ssthen 192933707f3Ssthen /** get public key rdata field from a dnskey RR and do some checks */ 193933707f3Ssthen static void 194933707f3Ssthen dnskey_get_pubkey(struct ub_packed_rrset_key* k, size_t idx, 195933707f3Ssthen unsigned char** pk, unsigned int* pklen) 196933707f3Ssthen { 197933707f3Ssthen uint8_t* rdata; 198933707f3Ssthen size_t len; 199933707f3Ssthen rrset_get_rdata(k, idx, &rdata, &len); 200933707f3Ssthen if(len < 2+5) { 201933707f3Ssthen *pk = NULL; 202933707f3Ssthen *pklen = 0; 203933707f3Ssthen return; 204933707f3Ssthen } 205933707f3Ssthen *pk = (unsigned char*)rdata+2+4; 206933707f3Ssthen *pklen = (unsigned)len-2-4; 207933707f3Ssthen } 208933707f3Ssthen 209933707f3Ssthen int 210933707f3Ssthen ds_get_key_algo(struct ub_packed_rrset_key* k, size_t idx) 211933707f3Ssthen { 212933707f3Ssthen uint8_t* rdata; 213933707f3Ssthen size_t len; 214933707f3Ssthen rrset_get_rdata(k, idx, &rdata, &len); 215933707f3Ssthen if(len < 2+3) 216933707f3Ssthen return 0; 217933707f3Ssthen return (int)rdata[2+2]; 218933707f3Ssthen } 219933707f3Ssthen 220933707f3Ssthen int 221933707f3Ssthen ds_get_digest_algo(struct ub_packed_rrset_key* k, size_t idx) 222933707f3Ssthen { 223933707f3Ssthen uint8_t* rdata; 224933707f3Ssthen size_t len; 225933707f3Ssthen rrset_get_rdata(k, idx, &rdata, &len); 226933707f3Ssthen if(len < 2+4) 227933707f3Ssthen return 0; 228933707f3Ssthen return (int)rdata[2+3]; 229933707f3Ssthen } 230933707f3Ssthen 231933707f3Ssthen uint16_t 232933707f3Ssthen ds_get_keytag(struct ub_packed_rrset_key* ds_rrset, size_t ds_idx) 233933707f3Ssthen { 234933707f3Ssthen uint16_t t; 235933707f3Ssthen uint8_t* rdata; 236933707f3Ssthen size_t len; 237933707f3Ssthen rrset_get_rdata(ds_rrset, ds_idx, &rdata, &len); 238933707f3Ssthen if(len < 2+2) 239933707f3Ssthen return 0; 240933707f3Ssthen memmove(&t, rdata+2, 2); 241933707f3Ssthen return ntohs(t); 242933707f3Ssthen } 243933707f3Ssthen 244933707f3Ssthen /** 245933707f3Ssthen * Return pointer to the digest in a DS RR. 246933707f3Ssthen * @param k: DS rrset. 247933707f3Ssthen * @param idx: which DS. 248933707f3Ssthen * @param digest: digest data is returned. 249933707f3Ssthen * on error, this is NULL. 250933707f3Ssthen * @param len: length of digest is returned. 251933707f3Ssthen * on error, the length is 0. 252933707f3Ssthen */ 253933707f3Ssthen static void 254933707f3Ssthen ds_get_sigdata(struct ub_packed_rrset_key* k, size_t idx, uint8_t** digest, 255933707f3Ssthen size_t* len) 256933707f3Ssthen { 257933707f3Ssthen uint8_t* rdata; 258933707f3Ssthen size_t rdlen; 259933707f3Ssthen rrset_get_rdata(k, idx, &rdata, &rdlen); 260933707f3Ssthen if(rdlen < 2+5) { 261933707f3Ssthen *digest = NULL; 262933707f3Ssthen *len = 0; 263933707f3Ssthen return; 264933707f3Ssthen } 265933707f3Ssthen *digest = rdata + 2 + 4; 266933707f3Ssthen *len = rdlen - 2 - 4; 267933707f3Ssthen } 268933707f3Ssthen 269933707f3Ssthen /** 270933707f3Ssthen * Return size of DS digest according to its hash algorithm. 271933707f3Ssthen * @param k: DS rrset. 272933707f3Ssthen * @param idx: which DS. 273933707f3Ssthen * @return size in bytes of digest, or 0 if not supported. 274933707f3Ssthen */ 275933707f3Ssthen static size_t 276933707f3Ssthen ds_digest_size_algo(struct ub_packed_rrset_key* k, size_t idx) 277933707f3Ssthen { 2783dcb24b8Ssthen return ds_digest_size_supported(ds_get_digest_algo(k, idx)); 279933707f3Ssthen } 280933707f3Ssthen 281933707f3Ssthen /** 282933707f3Ssthen * Create a DS digest for a DNSKEY entry. 283933707f3Ssthen * 284933707f3Ssthen * @param env: module environment. Uses scratch space. 285933707f3Ssthen * @param dnskey_rrset: DNSKEY rrset. 286933707f3Ssthen * @param dnskey_idx: index of RR in rrset. 287933707f3Ssthen * @param ds_rrset: DS rrset 288933707f3Ssthen * @param ds_idx: index of RR in DS rrset. 289933707f3Ssthen * @param digest: digest is returned in here (must be correctly sized). 290933707f3Ssthen * @return false on error. 291933707f3Ssthen */ 292933707f3Ssthen static int 293933707f3Ssthen ds_create_dnskey_digest(struct module_env* env, 294933707f3Ssthen struct ub_packed_rrset_key* dnskey_rrset, size_t dnskey_idx, 295933707f3Ssthen struct ub_packed_rrset_key* ds_rrset, size_t ds_idx, 296933707f3Ssthen uint8_t* digest) 297933707f3Ssthen { 2985d76a658Ssthen sldns_buffer* b = env->scratch_buffer; 299933707f3Ssthen uint8_t* dnskey_rdata; 300933707f3Ssthen size_t dnskey_len; 301933707f3Ssthen rrset_get_rdata(dnskey_rrset, dnskey_idx, &dnskey_rdata, &dnskey_len); 302933707f3Ssthen 303933707f3Ssthen /* create digest source material in buffer 304933707f3Ssthen * digest = digest_algorithm( DNSKEY owner name | DNSKEY RDATA); 305933707f3Ssthen * DNSKEY RDATA = Flags | Protocol | Algorithm | Public Key. */ 3065d76a658Ssthen sldns_buffer_clear(b); 3075d76a658Ssthen sldns_buffer_write(b, dnskey_rrset->rk.dname, 308933707f3Ssthen dnskey_rrset->rk.dname_len); 3095d76a658Ssthen query_dname_tolower(sldns_buffer_begin(b)); 3105d76a658Ssthen sldns_buffer_write(b, dnskey_rdata+2, dnskey_len-2); /* skip rdatalen*/ 3115d76a658Ssthen sldns_buffer_flip(b); 312933707f3Ssthen 3133dcb24b8Ssthen return secalgo_ds_digest(ds_get_digest_algo(ds_rrset, ds_idx), 3145d76a658Ssthen (unsigned char*)sldns_buffer_begin(b), sldns_buffer_limit(b), 3153dcb24b8Ssthen (unsigned char*)digest); 316933707f3Ssthen } 317933707f3Ssthen 318933707f3Ssthen int ds_digest_match_dnskey(struct module_env* env, 319933707f3Ssthen struct ub_packed_rrset_key* dnskey_rrset, size_t dnskey_idx, 320933707f3Ssthen struct ub_packed_rrset_key* ds_rrset, size_t ds_idx) 321933707f3Ssthen { 322933707f3Ssthen uint8_t* ds; /* DS digest */ 323933707f3Ssthen size_t dslen; 324933707f3Ssthen uint8_t* digest; /* generated digest */ 325933707f3Ssthen size_t digestlen = ds_digest_size_algo(ds_rrset, ds_idx); 326933707f3Ssthen 327933707f3Ssthen if(digestlen == 0) { 328933707f3Ssthen verbose(VERB_QUERY, "DS fail: not supported, or DS RR " 329933707f3Ssthen "format error"); 330933707f3Ssthen return 0; /* not supported, or DS RR format error */ 331933707f3Ssthen } 3322be9e038Ssthen #ifndef USE_SHA1 3332be9e038Ssthen if(fake_sha1 && ds_get_digest_algo(ds_rrset, ds_idx)==LDNS_SHA1) 3342be9e038Ssthen return 1; 3352be9e038Ssthen #endif 3362be9e038Ssthen 337933707f3Ssthen /* check digest length in DS with length from hash function */ 338933707f3Ssthen ds_get_sigdata(ds_rrset, ds_idx, &ds, &dslen); 339933707f3Ssthen if(!ds || dslen != digestlen) { 340933707f3Ssthen verbose(VERB_QUERY, "DS fail: DS RR algo and digest do not " 341933707f3Ssthen "match each other"); 342933707f3Ssthen return 0; /* DS algorithm and digest do not match */ 343933707f3Ssthen } 344933707f3Ssthen 345933707f3Ssthen digest = regional_alloc(env->scratch, digestlen); 346933707f3Ssthen if(!digest) { 347933707f3Ssthen verbose(VERB_QUERY, "DS fail: out of memory"); 348933707f3Ssthen return 0; /* mem error */ 349933707f3Ssthen } 350933707f3Ssthen if(!ds_create_dnskey_digest(env, dnskey_rrset, dnskey_idx, ds_rrset, 351933707f3Ssthen ds_idx, digest)) { 352933707f3Ssthen verbose(VERB_QUERY, "DS fail: could not calc key digest"); 353933707f3Ssthen return 0; /* digest algo failed */ 354933707f3Ssthen } 355933707f3Ssthen if(memcmp(digest, ds, dslen) != 0) { 356933707f3Ssthen verbose(VERB_QUERY, "DS fail: digest is different"); 357933707f3Ssthen return 0; /* digest different */ 358933707f3Ssthen } 359933707f3Ssthen return 1; 360933707f3Ssthen } 361933707f3Ssthen 362933707f3Ssthen int 363933707f3Ssthen ds_digest_algo_is_supported(struct ub_packed_rrset_key* ds_rrset, 364933707f3Ssthen size_t ds_idx) 365933707f3Ssthen { 366933707f3Ssthen return (ds_digest_size_algo(ds_rrset, ds_idx) != 0); 367933707f3Ssthen } 368933707f3Ssthen 369933707f3Ssthen int 370933707f3Ssthen ds_key_algo_is_supported(struct ub_packed_rrset_key* ds_rrset, 371933707f3Ssthen size_t ds_idx) 372933707f3Ssthen { 373933707f3Ssthen return dnskey_algo_id_is_supported(ds_get_key_algo(ds_rrset, ds_idx)); 374933707f3Ssthen } 375933707f3Ssthen 376933707f3Ssthen uint16_t 377933707f3Ssthen dnskey_calc_keytag(struct ub_packed_rrset_key* dnskey_rrset, size_t dnskey_idx) 378933707f3Ssthen { 379933707f3Ssthen uint8_t* data; 380933707f3Ssthen size_t len; 381933707f3Ssthen rrset_get_rdata(dnskey_rrset, dnskey_idx, &data, &len); 382933707f3Ssthen /* do not pass rdatalen to ldns */ 3835d76a658Ssthen return sldns_calc_keytag_raw(data+2, len-2); 384933707f3Ssthen } 385933707f3Ssthen 386933707f3Ssthen int dnskey_algo_is_supported(struct ub_packed_rrset_key* dnskey_rrset, 387933707f3Ssthen size_t dnskey_idx) 388933707f3Ssthen { 389933707f3Ssthen return dnskey_algo_id_is_supported(dnskey_get_algo(dnskey_rrset, 390933707f3Ssthen dnskey_idx)); 391933707f3Ssthen } 392933707f3Ssthen 393191f22c6Ssthen int dnskey_size_is_supported(struct ub_packed_rrset_key* dnskey_rrset, 394191f22c6Ssthen size_t dnskey_idx) 395191f22c6Ssthen { 396191f22c6Ssthen #ifdef DEPRECATE_RSA_1024 397191f22c6Ssthen uint8_t* rdata; 398191f22c6Ssthen size_t len; 399191f22c6Ssthen int alg = dnskey_get_algo(dnskey_rrset, dnskey_idx); 400191f22c6Ssthen size_t keysize; 401191f22c6Ssthen 402191f22c6Ssthen rrset_get_rdata(dnskey_rrset, dnskey_idx, &rdata, &len); 403191f22c6Ssthen if(len < 2+4) 404191f22c6Ssthen return 0; 405191f22c6Ssthen keysize = sldns_rr_dnskey_key_size_raw(rdata+2+4, len-2-4, alg); 406191f22c6Ssthen 407191f22c6Ssthen switch((sldns_algorithm)alg) { 408191f22c6Ssthen case LDNS_RSAMD5: 409191f22c6Ssthen case LDNS_RSASHA1: 410191f22c6Ssthen case LDNS_RSASHA1_NSEC3: 411191f22c6Ssthen case LDNS_RSASHA256: 412191f22c6Ssthen case LDNS_RSASHA512: 413191f22c6Ssthen /* reject RSA keys of 1024 bits and shorter */ 414191f22c6Ssthen if(keysize <= 1024) 415191f22c6Ssthen return 0; 416191f22c6Ssthen break; 417191f22c6Ssthen default: 418191f22c6Ssthen break; 419191f22c6Ssthen } 420191f22c6Ssthen #else 421191f22c6Ssthen (void)dnskey_rrset; (void)dnskey_idx; 422191f22c6Ssthen #endif /* DEPRECATE_RSA_1024 */ 423191f22c6Ssthen return 1; 424191f22c6Ssthen } 425191f22c6Ssthen 426191f22c6Ssthen int dnskeyset_size_is_supported(struct ub_packed_rrset_key* dnskey_rrset) 427191f22c6Ssthen { 428191f22c6Ssthen size_t i, num = rrset_get_count(dnskey_rrset); 429191f22c6Ssthen for(i=0; i<num; i++) { 430191f22c6Ssthen if(!dnskey_size_is_supported(dnskey_rrset, i)) 431191f22c6Ssthen return 0; 432191f22c6Ssthen } 433191f22c6Ssthen return 1; 434191f22c6Ssthen } 435191f22c6Ssthen 436933707f3Ssthen void algo_needs_init_dnskey_add(struct algo_needs* n, 437933707f3Ssthen struct ub_packed_rrset_key* dnskey, uint8_t* sigalg) 438933707f3Ssthen { 439933707f3Ssthen uint8_t algo; 440933707f3Ssthen size_t i, total = n->num; 441933707f3Ssthen size_t num = rrset_get_count(dnskey); 442933707f3Ssthen 443933707f3Ssthen for(i=0; i<num; i++) { 444933707f3Ssthen algo = (uint8_t)dnskey_get_algo(dnskey, i); 445933707f3Ssthen if(!dnskey_algo_id_is_supported((int)algo)) 446933707f3Ssthen continue; 447933707f3Ssthen if(n->needs[algo] == 0) { 448933707f3Ssthen n->needs[algo] = 1; 449933707f3Ssthen sigalg[total] = algo; 450933707f3Ssthen total++; 451933707f3Ssthen } 452933707f3Ssthen } 453933707f3Ssthen sigalg[total] = 0; 454933707f3Ssthen n->num = total; 455933707f3Ssthen } 456933707f3Ssthen 457933707f3Ssthen void algo_needs_init_list(struct algo_needs* n, uint8_t* sigalg) 458933707f3Ssthen { 459933707f3Ssthen uint8_t algo; 460933707f3Ssthen size_t total = 0; 461933707f3Ssthen 462933707f3Ssthen memset(n->needs, 0, sizeof(uint8_t)*ALGO_NEEDS_MAX); 463933707f3Ssthen while( (algo=*sigalg++) != 0) { 464933707f3Ssthen log_assert(dnskey_algo_id_is_supported((int)algo)); 465933707f3Ssthen log_assert(n->needs[algo] == 0); 466933707f3Ssthen n->needs[algo] = 1; 467933707f3Ssthen total++; 468933707f3Ssthen } 469933707f3Ssthen n->num = total; 470933707f3Ssthen } 471933707f3Ssthen 472933707f3Ssthen void algo_needs_init_ds(struct algo_needs* n, struct ub_packed_rrset_key* ds, 473933707f3Ssthen int fav_ds_algo, uint8_t* sigalg) 474933707f3Ssthen { 475933707f3Ssthen uint8_t algo; 476933707f3Ssthen size_t i, total = 0; 477933707f3Ssthen size_t num = rrset_get_count(ds); 478933707f3Ssthen 479933707f3Ssthen memset(n->needs, 0, sizeof(uint8_t)*ALGO_NEEDS_MAX); 480933707f3Ssthen for(i=0; i<num; i++) { 481933707f3Ssthen if(ds_get_digest_algo(ds, i) != fav_ds_algo) 482933707f3Ssthen continue; 483933707f3Ssthen algo = (uint8_t)ds_get_key_algo(ds, i); 484933707f3Ssthen if(!dnskey_algo_id_is_supported((int)algo)) 485933707f3Ssthen continue; 486933707f3Ssthen log_assert(algo != 0); /* we do not support 0 and is EOS */ 487933707f3Ssthen if(n->needs[algo] == 0) { 488933707f3Ssthen n->needs[algo] = 1; 489933707f3Ssthen sigalg[total] = algo; 490933707f3Ssthen total++; 491933707f3Ssthen } 492933707f3Ssthen } 493933707f3Ssthen sigalg[total] = 0; 494933707f3Ssthen n->num = total; 495933707f3Ssthen } 496933707f3Ssthen 497933707f3Ssthen int algo_needs_set_secure(struct algo_needs* n, uint8_t algo) 498933707f3Ssthen { 499933707f3Ssthen if(n->needs[algo]) { 500933707f3Ssthen n->needs[algo] = 0; 501933707f3Ssthen n->num --; 502933707f3Ssthen if(n->num == 0) /* done! */ 503933707f3Ssthen return 1; 504933707f3Ssthen } 505933707f3Ssthen return 0; 506933707f3Ssthen } 507933707f3Ssthen 508933707f3Ssthen void algo_needs_set_bogus(struct algo_needs* n, uint8_t algo) 509933707f3Ssthen { 510933707f3Ssthen if(n->needs[algo]) n->needs[algo] = 2; /* need it, but bogus */ 511933707f3Ssthen } 512933707f3Ssthen 513933707f3Ssthen size_t algo_needs_num_missing(struct algo_needs* n) 514933707f3Ssthen { 515933707f3Ssthen return n->num; 516933707f3Ssthen } 517933707f3Ssthen 518933707f3Ssthen int algo_needs_missing(struct algo_needs* n) 519933707f3Ssthen { 520d1e2768aSsthen int i, miss = -1; 521d1e2768aSsthen /* check if a needed algo was bogus - report that; 522d1e2768aSsthen * check the first missing algo - report that; 523d1e2768aSsthen * or return 0 */ 524d1e2768aSsthen for(i=0; i<ALGO_NEEDS_MAX; i++) { 525933707f3Ssthen if(n->needs[i] == 2) 526933707f3Ssthen return 0; 527d1e2768aSsthen if(n->needs[i] == 1 && miss == -1) 528d1e2768aSsthen miss = i; 529d1e2768aSsthen } 530d1e2768aSsthen if(miss != -1) return miss; 531933707f3Ssthen return 0; 532933707f3Ssthen } 533933707f3Ssthen 534d1e2768aSsthen /** 535d1e2768aSsthen * verify rrset, with dnskey rrset, for a specific rrsig in rrset 536d1e2768aSsthen * @param env: module environment, scratch space is used. 537d1e2768aSsthen * @param ve: validator environment, date settings. 538d1e2768aSsthen * @param now: current time for validation (can be overridden). 539d1e2768aSsthen * @param rrset: to be validated. 540d1e2768aSsthen * @param dnskey: DNSKEY rrset, keyset to try. 541d1e2768aSsthen * @param sig_idx: which signature to try to validate. 542d1e2768aSsthen * @param sortree: reused sorted order. Stored in region. Pass NULL at start, 543d1e2768aSsthen * and for a new rrset. 544d1e2768aSsthen * @param reason: if bogus, a string returned, fixed or alloced in scratch. 545d1e2768aSsthen * @param reason_bogus: EDE (RFC8914) code paired with the reason of failure. 546d1e2768aSsthen * @param section: section of packet where this rrset comes from. 547d1e2768aSsthen * @param qstate: qstate with region. 548817bdb8fSflorian * @param numverified: incremented when the number of RRSIG validations 549817bdb8fSflorian * increases. 550d1e2768aSsthen * @return secure if any key signs *this* signature. bogus if no key signs it, 551d1e2768aSsthen * unchecked on error, or indeterminate if all keys are not supported by 552d1e2768aSsthen * the crypto library (openssl3+ only). 553d1e2768aSsthen */ 5540bdb4f62Ssthen static enum sec_status 5550bdb4f62Ssthen dnskeyset_verify_rrset_sig(struct module_env* env, struct val_env* ve, 5560bdb4f62Ssthen time_t now, struct ub_packed_rrset_key* rrset, 5570bdb4f62Ssthen struct ub_packed_rrset_key* dnskey, size_t sig_idx, 5580bdb4f62Ssthen struct rbtree_type** sortree, 5590bdb4f62Ssthen char** reason, sldns_ede_code *reason_bogus, 560817bdb8fSflorian sldns_pkt_section section, struct module_qstate* qstate, 561817bdb8fSflorian int* numverified) 562d1e2768aSsthen { 563d1e2768aSsthen /* find matching keys and check them */ 564d1e2768aSsthen enum sec_status sec = sec_status_bogus; 565d1e2768aSsthen uint16_t tag = rrset_get_sig_keytag(rrset, sig_idx); 566d1e2768aSsthen int algo = rrset_get_sig_algo(rrset, sig_idx); 567d1e2768aSsthen size_t i, num = rrset_get_count(dnskey); 568d1e2768aSsthen size_t numchecked = 0; 569d1e2768aSsthen size_t numindeterminate = 0; 570d1e2768aSsthen int buf_canon = 0; 571d1e2768aSsthen verbose(VERB_ALGO, "verify sig %d %d", (int)tag, algo); 572d1e2768aSsthen if(!dnskey_algo_id_is_supported(algo)) { 573d1e2768aSsthen if(reason_bogus) 574d1e2768aSsthen *reason_bogus = LDNS_EDE_UNSUPPORTED_DNSKEY_ALG; 575d1e2768aSsthen verbose(VERB_QUERY, "verify sig: unknown algorithm"); 576d1e2768aSsthen return sec_status_insecure; 577d1e2768aSsthen } 578d1e2768aSsthen 579d1e2768aSsthen for(i=0; i<num; i++) { 580d1e2768aSsthen /* see if key matches keytag and algo */ 581d1e2768aSsthen if(algo != dnskey_get_algo(dnskey, i) || 582d1e2768aSsthen tag != dnskey_calc_keytag(dnskey, i)) 583d1e2768aSsthen continue; 584d1e2768aSsthen numchecked ++; 585817bdb8fSflorian (*numverified)++; 586d1e2768aSsthen 587d1e2768aSsthen /* see if key verifies */ 588d1e2768aSsthen sec = dnskey_verify_rrset_sig(env->scratch, 589d1e2768aSsthen env->scratch_buffer, ve, now, rrset, dnskey, i, 590d1e2768aSsthen sig_idx, sortree, &buf_canon, reason, reason_bogus, 591d1e2768aSsthen section, qstate); 592d1e2768aSsthen if(sec == sec_status_secure) 593d1e2768aSsthen return sec; 594d1e2768aSsthen else if(sec == sec_status_indeterminate) 595d1e2768aSsthen numindeterminate ++; 596817bdb8fSflorian if(*numverified > MAX_VALIDATE_RRSIGS) { 597817bdb8fSflorian *reason = "too many RRSIG validations"; 598817bdb8fSflorian if(reason_bogus) 599817bdb8fSflorian *reason_bogus = LDNS_EDE_DNSSEC_BOGUS; 600817bdb8fSflorian verbose(VERB_ALGO, "verify sig: too many RRSIG validations"); 601817bdb8fSflorian return sec_status_bogus; 602817bdb8fSflorian } 603d1e2768aSsthen } 604d1e2768aSsthen if(numchecked == 0) { 605d1e2768aSsthen *reason = "signatures from unknown keys"; 606d1e2768aSsthen if(reason_bogus) 607d1e2768aSsthen *reason_bogus = LDNS_EDE_DNSKEY_MISSING; 608d1e2768aSsthen verbose(VERB_QUERY, "verify: could not find appropriate key"); 609d1e2768aSsthen return sec_status_bogus; 610d1e2768aSsthen } 611d1e2768aSsthen if(numindeterminate == numchecked) { 612d1e2768aSsthen *reason = "unsupported algorithm by crypto library"; 613d1e2768aSsthen if(reason_bogus) 614d1e2768aSsthen *reason_bogus = LDNS_EDE_UNSUPPORTED_DNSKEY_ALG; 615d1e2768aSsthen verbose(VERB_ALGO, "verify sig: unsupported algorithm by " 616d1e2768aSsthen "crypto library"); 617d1e2768aSsthen return sec_status_indeterminate; 618d1e2768aSsthen } 619d1e2768aSsthen return sec_status_bogus; 620d1e2768aSsthen } 6210bdb4f62Ssthen 622933707f3Ssthen enum sec_status 623933707f3Ssthen dnskeyset_verify_rrset(struct module_env* env, struct val_env* ve, 624933707f3Ssthen struct ub_packed_rrset_key* rrset, struct ub_packed_rrset_key* dnskey, 6250bdb4f62Ssthen uint8_t* sigalg, char** reason, sldns_ede_code *reason_bogus, 626*98bc733bSsthen sldns_pkt_section section, struct module_qstate* qstate, int* verified, 627*98bc733bSsthen char* reasonbuf, size_t reasonlen) 628933707f3Ssthen { 629933707f3Ssthen enum sec_status sec; 630933707f3Ssthen size_t i, num; 63177079be7Ssthen rbtree_type* sortree = NULL; 632933707f3Ssthen /* make sure that for all DNSKEY algorithms there are valid sigs */ 633933707f3Ssthen struct algo_needs needs; 634933707f3Ssthen int alg; 635817bdb8fSflorian *verified = 0; 636933707f3Ssthen 637933707f3Ssthen num = rrset_get_sigcount(rrset); 638933707f3Ssthen if(num == 0) { 639933707f3Ssthen verbose(VERB_QUERY, "rrset failed to verify due to a lack of " 640933707f3Ssthen "signatures"); 641933707f3Ssthen *reason = "no signatures"; 6420bdb4f62Ssthen if(reason_bogus) 6430bdb4f62Ssthen *reason_bogus = LDNS_EDE_RRSIGS_MISSING; 644933707f3Ssthen return sec_status_bogus; 645933707f3Ssthen } 646933707f3Ssthen 647933707f3Ssthen if(sigalg) { 648933707f3Ssthen algo_needs_init_list(&needs, sigalg); 649933707f3Ssthen if(algo_needs_num_missing(&needs) == 0) { 650933707f3Ssthen verbose(VERB_QUERY, "zone has no known algorithms"); 651933707f3Ssthen *reason = "zone has no known algorithms"; 6520bdb4f62Ssthen if(reason_bogus) 6530bdb4f62Ssthen *reason_bogus = LDNS_EDE_UNSUPPORTED_DNSKEY_ALG; 654933707f3Ssthen return sec_status_insecure; 655933707f3Ssthen } 656933707f3Ssthen } 657933707f3Ssthen for(i=0; i<num; i++) { 658933707f3Ssthen sec = dnskeyset_verify_rrset_sig(env, ve, *env->now, rrset, 6590bdb4f62Ssthen dnskey, i, &sortree, reason, reason_bogus, 660817bdb8fSflorian section, qstate, verified); 661933707f3Ssthen /* see which algorithm has been fixed up */ 662933707f3Ssthen if(sec == sec_status_secure) { 663933707f3Ssthen if(!sigalg) 664933707f3Ssthen return sec; /* done! */ 665933707f3Ssthen else if(algo_needs_set_secure(&needs, 666933707f3Ssthen (uint8_t)rrset_get_sig_algo(rrset, i))) 667933707f3Ssthen return sec; /* done! */ 668933707f3Ssthen } else if(sigalg && sec == sec_status_bogus) { 669933707f3Ssthen algo_needs_set_bogus(&needs, 670933707f3Ssthen (uint8_t)rrset_get_sig_algo(rrset, i)); 671933707f3Ssthen } 672817bdb8fSflorian if(*verified > MAX_VALIDATE_RRSIGS) { 673817bdb8fSflorian verbose(VERB_QUERY, "rrset failed to verify, too many RRSIG validations"); 674817bdb8fSflorian *reason = "too many RRSIG validations"; 675817bdb8fSflorian if(reason_bogus) 676817bdb8fSflorian *reason_bogus = LDNS_EDE_DNSSEC_BOGUS; 677817bdb8fSflorian return sec_status_bogus; 678817bdb8fSflorian } 679933707f3Ssthen } 680933707f3Ssthen if(sigalg && (alg=algo_needs_missing(&needs)) != 0) { 6813dcb24b8Ssthen verbose(VERB_ALGO, "rrset failed to verify: " 6823dcb24b8Ssthen "no valid signatures for %d algorithms", 6833dcb24b8Ssthen (int)algo_needs_num_missing(&needs)); 684*98bc733bSsthen algo_needs_reason(alg, reason, "no signatures", reasonbuf, 685*98bc733bSsthen reasonlen); 6863dcb24b8Ssthen } else { 6873dcb24b8Ssthen verbose(VERB_ALGO, "rrset failed to verify: " 6883dcb24b8Ssthen "no valid signatures"); 689933707f3Ssthen } 690933707f3Ssthen return sec_status_bogus; 691933707f3Ssthen } 692933707f3Ssthen 693*98bc733bSsthen void algo_needs_reason(int alg, char** reason, char* s, char* reasonbuf, 694*98bc733bSsthen size_t reasonlen) 695933707f3Ssthen { 6965d76a658Ssthen sldns_lookup_table *t = sldns_lookup_by_id(sldns_algorithms, alg); 697933707f3Ssthen if(t&&t->name) 698*98bc733bSsthen snprintf(reasonbuf, reasonlen, "%s with algorithm %s", s, 699*98bc733bSsthen t->name); 700*98bc733bSsthen else snprintf(reasonbuf, reasonlen, "%s with algorithm ALG%u", s, 701933707f3Ssthen (unsigned)alg); 702*98bc733bSsthen *reason = reasonbuf; 703933707f3Ssthen } 704933707f3Ssthen 705933707f3Ssthen enum sec_status 706933707f3Ssthen dnskey_verify_rrset(struct module_env* env, struct val_env* ve, 707933707f3Ssthen struct ub_packed_rrset_key* rrset, struct ub_packed_rrset_key* dnskey, 7080bdb4f62Ssthen size_t dnskey_idx, char** reason, sldns_ede_code *reason_bogus, 7090bdb4f62Ssthen sldns_pkt_section section, struct module_qstate* qstate) 710933707f3Ssthen { 711933707f3Ssthen enum sec_status sec; 712d1e2768aSsthen size_t i, num, numchecked = 0, numindeterminate = 0; 71377079be7Ssthen rbtree_type* sortree = NULL; 714933707f3Ssthen int buf_canon = 0; 715933707f3Ssthen uint16_t tag = dnskey_calc_keytag(dnskey, dnskey_idx); 716933707f3Ssthen int algo = dnskey_get_algo(dnskey, dnskey_idx); 717817bdb8fSflorian int numverified = 0; 718933707f3Ssthen 719933707f3Ssthen num = rrset_get_sigcount(rrset); 720933707f3Ssthen if(num == 0) { 721933707f3Ssthen verbose(VERB_QUERY, "rrset failed to verify due to a lack of " 722933707f3Ssthen "signatures"); 723933707f3Ssthen *reason = "no signatures"; 7240bdb4f62Ssthen if(reason_bogus) 7250bdb4f62Ssthen *reason_bogus = LDNS_EDE_RRSIGS_MISSING; 726933707f3Ssthen return sec_status_bogus; 727933707f3Ssthen } 728933707f3Ssthen for(i=0; i<num; i++) { 729933707f3Ssthen /* see if sig matches keytag and algo */ 730933707f3Ssthen if(algo != rrset_get_sig_algo(rrset, i) || 731933707f3Ssthen tag != rrset_get_sig_keytag(rrset, i)) 732933707f3Ssthen continue; 733933707f3Ssthen buf_canon = 0; 734933707f3Ssthen sec = dnskey_verify_rrset_sig(env->scratch, 735933707f3Ssthen env->scratch_buffer, ve, *env->now, rrset, 736bdfc4d55Sflorian dnskey, dnskey_idx, i, &sortree, &buf_canon, reason, 7370bdb4f62Ssthen reason_bogus, section, qstate); 738933707f3Ssthen if(sec == sec_status_secure) 739933707f3Ssthen return sec; 740933707f3Ssthen numchecked ++; 741817bdb8fSflorian numverified ++; 742d1e2768aSsthen if(sec == sec_status_indeterminate) 743d1e2768aSsthen numindeterminate ++; 744817bdb8fSflorian if(numverified > MAX_VALIDATE_RRSIGS) { 745817bdb8fSflorian verbose(VERB_QUERY, "rrset failed to verify, too many RRSIG validations"); 746817bdb8fSflorian *reason = "too many RRSIG validations"; 747817bdb8fSflorian if(reason_bogus) 748817bdb8fSflorian *reason_bogus = LDNS_EDE_DNSSEC_BOGUS; 749817bdb8fSflorian return sec_status_bogus; 750817bdb8fSflorian } 751933707f3Ssthen } 752d1e2768aSsthen if(!numchecked) { 7538b7325afSsthen *reason = "signature for expected key and algorithm missing"; 754d1e2768aSsthen if(reason_bogus) 7558b7325afSsthen *reason_bogus = LDNS_EDE_DNSSEC_BOGUS; 756d1e2768aSsthen } else if(numchecked == numindeterminate) { 757d1e2768aSsthen verbose(VERB_ALGO, "rrset failed to verify due to algorithm " 758d1e2768aSsthen "refusal by cryptolib"); 7590bdb4f62Ssthen if(reason_bogus) 7600bdb4f62Ssthen *reason_bogus = LDNS_EDE_UNSUPPORTED_DNSKEY_ALG; 761d1e2768aSsthen *reason = "algorithm refused by cryptolib"; 762d1e2768aSsthen return sec_status_indeterminate; 763933707f3Ssthen } 764f46c52bfSsthen verbose(VERB_ALGO, "rrset failed to verify: all signatures are bogus"); 765933707f3Ssthen return sec_status_bogus; 766933707f3Ssthen } 767933707f3Ssthen 768933707f3Ssthen /** 769933707f3Ssthen * RR entries in a canonical sorted tree of RRs 770933707f3Ssthen */ 771933707f3Ssthen struct canon_rr { 772933707f3Ssthen /** rbtree node, key is this structure */ 77377079be7Ssthen rbnode_type node; 774933707f3Ssthen /** rrset the RR is in */ 775933707f3Ssthen struct ub_packed_rrset_key* rrset; 776933707f3Ssthen /** which RR in the rrset */ 777933707f3Ssthen size_t rr_idx; 778933707f3Ssthen }; 779933707f3Ssthen 780933707f3Ssthen /** 781933707f3Ssthen * Compare two RR for canonical order, in a field-style sweep. 782933707f3Ssthen * @param d: rrset data 783933707f3Ssthen * @param desc: ldns wireformat descriptor. 784933707f3Ssthen * @param i: first RR to compare 785933707f3Ssthen * @param j: first RR to compare 786933707f3Ssthen * @return comparison code. 787933707f3Ssthen */ 788933707f3Ssthen static int 789933707f3Ssthen canonical_compare_byfield(struct packed_rrset_data* d, 7905d76a658Ssthen const sldns_rr_descriptor* desc, size_t i, size_t j) 791933707f3Ssthen { 792933707f3Ssthen /* sweep across rdata, keep track of some state: 793933707f3Ssthen * which rr field, and bytes left in field. 794933707f3Ssthen * current position in rdata, length left. 795933707f3Ssthen * are we in a dname, length left in a label. 796933707f3Ssthen */ 797933707f3Ssthen int wfi = -1; /* current wireformat rdata field (rdf) */ 798933707f3Ssthen int wfj = -1; 799933707f3Ssthen uint8_t* di = d->rr_data[i]+2; /* ptr to current rdata byte */ 800933707f3Ssthen uint8_t* dj = d->rr_data[j]+2; 801933707f3Ssthen size_t ilen = d->rr_len[i]-2; /* length left in rdata */ 802933707f3Ssthen size_t jlen = d->rr_len[j]-2; 803933707f3Ssthen int dname_i = 0; /* true if these bytes are part of a name */ 804933707f3Ssthen int dname_j = 0; 805933707f3Ssthen size_t lablen_i = 0; /* 0 for label length byte,for first byte of rdf*/ 806933707f3Ssthen size_t lablen_j = 0; /* otherwise remaining length of rdf or label */ 807933707f3Ssthen int dname_num_i = (int)desc->_dname_count; /* decreased at root label */ 808933707f3Ssthen int dname_num_j = (int)desc->_dname_count; 809933707f3Ssthen 810933707f3Ssthen /* loop while there are rdata bytes available for both rrs, 811933707f3Ssthen * and still some lowercasing needs to be done; either the dnames 812933707f3Ssthen * have not been reached yet, or they are currently being processed */ 813933707f3Ssthen while(ilen > 0 && jlen > 0 && (dname_num_i > 0 || dname_num_j > 0)) { 814933707f3Ssthen /* compare these two bytes */ 815933707f3Ssthen /* lowercase if in a dname and not a label length byte */ 816933707f3Ssthen if( ((dname_i && lablen_i)?(uint8_t)tolower((int)*di):*di) 817933707f3Ssthen != ((dname_j && lablen_j)?(uint8_t)tolower((int)*dj):*dj) 818933707f3Ssthen ) { 819933707f3Ssthen if(((dname_i && lablen_i)?(uint8_t)tolower((int)*di):*di) 820933707f3Ssthen < ((dname_j && lablen_j)?(uint8_t)tolower((int)*dj):*dj)) 821933707f3Ssthen return -1; 822933707f3Ssthen return 1; 823933707f3Ssthen } 824933707f3Ssthen ilen--; 825933707f3Ssthen jlen--; 826933707f3Ssthen /* bytes are equal */ 827933707f3Ssthen 828933707f3Ssthen /* advance field i */ 829933707f3Ssthen /* lablen 0 means that this byte is the first byte of the 830933707f3Ssthen * next rdata field; inspect this rdata field and setup 831933707f3Ssthen * to process the rest of this rdata field. 832933707f3Ssthen * The reason to first read the byte, then setup the rdf, 833933707f3Ssthen * is that we are then sure the byte is available and short 834933707f3Ssthen * rdata is handled gracefully (even if it is a formerr). */ 835933707f3Ssthen if(lablen_i == 0) { 836933707f3Ssthen if(dname_i) { 837933707f3Ssthen /* scan this dname label */ 838933707f3Ssthen /* capture length to lowercase */ 839933707f3Ssthen lablen_i = (size_t)*di; 840933707f3Ssthen if(lablen_i == 0) { 841933707f3Ssthen /* end root label */ 842933707f3Ssthen dname_i = 0; 843933707f3Ssthen dname_num_i--; 844933707f3Ssthen /* if dname num is 0, then the 845933707f3Ssthen * remainder is binary only */ 846933707f3Ssthen if(dname_num_i == 0) 847933707f3Ssthen lablen_i = ilen; 848933707f3Ssthen } 849933707f3Ssthen } else { 850933707f3Ssthen /* scan this rdata field */ 851933707f3Ssthen wfi++; 852933707f3Ssthen if(desc->_wireformat[wfi] 853933707f3Ssthen == LDNS_RDF_TYPE_DNAME) { 854933707f3Ssthen dname_i = 1; 855933707f3Ssthen lablen_i = (size_t)*di; 856933707f3Ssthen if(lablen_i == 0) { 857933707f3Ssthen dname_i = 0; 858933707f3Ssthen dname_num_i--; 859933707f3Ssthen if(dname_num_i == 0) 860933707f3Ssthen lablen_i = ilen; 861933707f3Ssthen } 862933707f3Ssthen } else if(desc->_wireformat[wfi] 863933707f3Ssthen == LDNS_RDF_TYPE_STR) 864933707f3Ssthen lablen_i = (size_t)*di; 865933707f3Ssthen else lablen_i = get_rdf_size( 866933707f3Ssthen desc->_wireformat[wfi]) - 1; 867933707f3Ssthen } 868933707f3Ssthen } else lablen_i--; 869933707f3Ssthen 870933707f3Ssthen /* advance field j; same as for i */ 871933707f3Ssthen if(lablen_j == 0) { 872933707f3Ssthen if(dname_j) { 873933707f3Ssthen lablen_j = (size_t)*dj; 874933707f3Ssthen if(lablen_j == 0) { 875933707f3Ssthen dname_j = 0; 876933707f3Ssthen dname_num_j--; 877933707f3Ssthen if(dname_num_j == 0) 878933707f3Ssthen lablen_j = jlen; 879933707f3Ssthen } 880933707f3Ssthen } else { 881933707f3Ssthen wfj++; 882933707f3Ssthen if(desc->_wireformat[wfj] 883933707f3Ssthen == LDNS_RDF_TYPE_DNAME) { 884933707f3Ssthen dname_j = 1; 885933707f3Ssthen lablen_j = (size_t)*dj; 886933707f3Ssthen if(lablen_j == 0) { 887933707f3Ssthen dname_j = 0; 888933707f3Ssthen dname_num_j--; 889933707f3Ssthen if(dname_num_j == 0) 890933707f3Ssthen lablen_j = jlen; 891933707f3Ssthen } 892933707f3Ssthen } else if(desc->_wireformat[wfj] 893933707f3Ssthen == LDNS_RDF_TYPE_STR) 894933707f3Ssthen lablen_j = (size_t)*dj; 895933707f3Ssthen else lablen_j = get_rdf_size( 896933707f3Ssthen desc->_wireformat[wfj]) - 1; 897933707f3Ssthen } 898933707f3Ssthen } else lablen_j--; 899933707f3Ssthen di++; 900933707f3Ssthen dj++; 901933707f3Ssthen } 902933707f3Ssthen /* end of the loop; because we advanced byte by byte; now we have 903933707f3Ssthen * that the rdata has ended, or that there is a binary remainder */ 904933707f3Ssthen /* shortest first */ 905933707f3Ssthen if(ilen == 0 && jlen == 0) 906933707f3Ssthen return 0; 907933707f3Ssthen if(ilen == 0) 908933707f3Ssthen return -1; 909933707f3Ssthen if(jlen == 0) 910933707f3Ssthen return 1; 911933707f3Ssthen /* binary remainder, capture comparison in wfi variable */ 912933707f3Ssthen if((wfi = memcmp(di, dj, (ilen<jlen)?ilen:jlen)) != 0) 913933707f3Ssthen return wfi; 914933707f3Ssthen if(ilen < jlen) 915933707f3Ssthen return -1; 916933707f3Ssthen if(jlen < ilen) 917933707f3Ssthen return 1; 918933707f3Ssthen return 0; 919933707f3Ssthen } 920933707f3Ssthen 921933707f3Ssthen /** 922933707f3Ssthen * Compare two RRs in the same RRset and determine their relative 923933707f3Ssthen * canonical order. 924933707f3Ssthen * @param rrset: the rrset in which to perform compares. 925933707f3Ssthen * @param i: first RR to compare 926933707f3Ssthen * @param j: first RR to compare 927933707f3Ssthen * @return 0 if RR i== RR j, -1 if <, +1 if >. 928933707f3Ssthen */ 929933707f3Ssthen static int 930933707f3Ssthen canonical_compare(struct ub_packed_rrset_key* rrset, size_t i, size_t j) 931933707f3Ssthen { 932933707f3Ssthen struct packed_rrset_data* d = (struct packed_rrset_data*) 933933707f3Ssthen rrset->entry.data; 9345d76a658Ssthen const sldns_rr_descriptor* desc; 935933707f3Ssthen uint16_t type = ntohs(rrset->rk.type); 936933707f3Ssthen size_t minlen; 937933707f3Ssthen int c; 938933707f3Ssthen 939933707f3Ssthen if(i==j) 940933707f3Ssthen return 0; 941933707f3Ssthen 942933707f3Ssthen switch(type) { 943933707f3Ssthen /* These RR types have only a name as RDATA. 944933707f3Ssthen * This name has to be canonicalized.*/ 945933707f3Ssthen case LDNS_RR_TYPE_NS: 946933707f3Ssthen case LDNS_RR_TYPE_MD: 947933707f3Ssthen case LDNS_RR_TYPE_MF: 948933707f3Ssthen case LDNS_RR_TYPE_CNAME: 949933707f3Ssthen case LDNS_RR_TYPE_MB: 950933707f3Ssthen case LDNS_RR_TYPE_MG: 951933707f3Ssthen case LDNS_RR_TYPE_MR: 952933707f3Ssthen case LDNS_RR_TYPE_PTR: 953933707f3Ssthen case LDNS_RR_TYPE_DNAME: 954229e174cSsthen /* the wireread function has already checked these 955229e174cSsthen * dname's for correctness, and this double checks */ 956229e174cSsthen if(!dname_valid(d->rr_data[i]+2, d->rr_len[i]-2) || 957229e174cSsthen !dname_valid(d->rr_data[j]+2, d->rr_len[j]-2)) 958229e174cSsthen return 0; 959933707f3Ssthen return query_dname_compare(d->rr_data[i]+2, 960933707f3Ssthen d->rr_data[j]+2); 961933707f3Ssthen 962933707f3Ssthen /* These RR types have STR and fixed size rdata fields 963933707f3Ssthen * before one or more name fields that need canonicalizing, 964933707f3Ssthen * and after that a byte-for byte remainder can be compared. 965933707f3Ssthen */ 966933707f3Ssthen /* type starts with the name; remainder is binary compared */ 967933707f3Ssthen case LDNS_RR_TYPE_NXT: 968933707f3Ssthen /* use rdata field formats */ 969933707f3Ssthen case LDNS_RR_TYPE_MINFO: 970933707f3Ssthen case LDNS_RR_TYPE_RP: 971933707f3Ssthen case LDNS_RR_TYPE_SOA: 972933707f3Ssthen case LDNS_RR_TYPE_RT: 973933707f3Ssthen case LDNS_RR_TYPE_AFSDB: 974933707f3Ssthen case LDNS_RR_TYPE_KX: 975933707f3Ssthen case LDNS_RR_TYPE_MX: 976933707f3Ssthen case LDNS_RR_TYPE_SIG: 977933707f3Ssthen /* RRSIG signer name has to be downcased */ 978933707f3Ssthen case LDNS_RR_TYPE_RRSIG: 979933707f3Ssthen case LDNS_RR_TYPE_PX: 980933707f3Ssthen case LDNS_RR_TYPE_NAPTR: 981933707f3Ssthen case LDNS_RR_TYPE_SRV: 9825d76a658Ssthen desc = sldns_rr_descript(type); 983933707f3Ssthen log_assert(desc); 984933707f3Ssthen /* this holds for the types that need canonicalizing */ 985933707f3Ssthen log_assert(desc->_minimum == desc->_maximum); 986933707f3Ssthen return canonical_compare_byfield(d, desc, i, j); 987933707f3Ssthen 988933707f3Ssthen case LDNS_RR_TYPE_HINFO: /* no longer downcased */ 989933707f3Ssthen case LDNS_RR_TYPE_NSEC: 990933707f3Ssthen default: 991933707f3Ssthen /* For unknown RR types, or types not listed above, 992933707f3Ssthen * no canonicalization is needed, do binary compare */ 993933707f3Ssthen /* byte for byte compare, equal means shortest first*/ 994933707f3Ssthen minlen = d->rr_len[i]-2; 995933707f3Ssthen if(minlen > d->rr_len[j]-2) 996933707f3Ssthen minlen = d->rr_len[j]-2; 997933707f3Ssthen c = memcmp(d->rr_data[i]+2, d->rr_data[j]+2, minlen); 998933707f3Ssthen if(c!=0) 999933707f3Ssthen return c; 1000933707f3Ssthen /* rdata equal, shortest is first */ 1001933707f3Ssthen if(d->rr_len[i] < d->rr_len[j]) 1002933707f3Ssthen return -1; 1003933707f3Ssthen if(d->rr_len[i] > d->rr_len[j]) 1004933707f3Ssthen return 1; 1005933707f3Ssthen /* rdata equal, length equal */ 1006933707f3Ssthen break; 1007933707f3Ssthen } 1008933707f3Ssthen return 0; 1009933707f3Ssthen } 1010933707f3Ssthen 1011933707f3Ssthen int 1012933707f3Ssthen canonical_tree_compare(const void* k1, const void* k2) 1013933707f3Ssthen { 1014933707f3Ssthen struct canon_rr* r1 = (struct canon_rr*)k1; 1015933707f3Ssthen struct canon_rr* r2 = (struct canon_rr*)k2; 1016933707f3Ssthen log_assert(r1->rrset == r2->rrset); 1017933707f3Ssthen return canonical_compare(r1->rrset, r1->rr_idx, r2->rr_idx); 1018933707f3Ssthen } 1019933707f3Ssthen 1020933707f3Ssthen /** 1021933707f3Ssthen * Sort RRs for rrset in canonical order. 1022933707f3Ssthen * Does not actually canonicalize the RR rdatas. 1023933707f3Ssthen * Does not touch rrsigs. 1024933707f3Ssthen * @param rrset: to sort. 1025933707f3Ssthen * @param d: rrset data. 1026933707f3Ssthen * @param sortree: tree to sort into. 1027933707f3Ssthen * @param rrs: rr storage. 1028933707f3Ssthen */ 1029933707f3Ssthen static void 1030933707f3Ssthen canonical_sort(struct ub_packed_rrset_key* rrset, struct packed_rrset_data* d, 103177079be7Ssthen rbtree_type* sortree, struct canon_rr* rrs) 1032933707f3Ssthen { 1033933707f3Ssthen size_t i; 1034933707f3Ssthen /* insert into rbtree to sort and detect duplicates */ 1035933707f3Ssthen for(i=0; i<d->count; i++) { 1036933707f3Ssthen rrs[i].node.key = &rrs[i]; 1037933707f3Ssthen rrs[i].rrset = rrset; 1038933707f3Ssthen rrs[i].rr_idx = i; 1039933707f3Ssthen if(!rbtree_insert(sortree, &rrs[i].node)) { 1040933707f3Ssthen /* this was a duplicate */ 1041933707f3Ssthen } 1042933707f3Ssthen } 1043933707f3Ssthen } 1044933707f3Ssthen 1045933707f3Ssthen /** 1046bdfc4d55Sflorian * Insert canonical owner name into buffer. 1047933707f3Ssthen * @param buf: buffer to insert into at current position. 1048933707f3Ssthen * @param k: rrset with its owner name. 1049933707f3Ssthen * @param sig: signature with signer name and label count. 1050933707f3Ssthen * must be length checked, at least 18 bytes long. 1051933707f3Ssthen * @param can_owner: position in buffer returned for future use. 1052933707f3Ssthen * @param can_owner_len: length of canonical owner name. 1053933707f3Ssthen */ 1054933707f3Ssthen static void 10555d76a658Ssthen insert_can_owner(sldns_buffer* buf, struct ub_packed_rrset_key* k, 1056933707f3Ssthen uint8_t* sig, uint8_t** can_owner, size_t* can_owner_len) 1057933707f3Ssthen { 1058933707f3Ssthen int rrsig_labels = (int)sig[3]; 1059933707f3Ssthen int fqdn_labels = dname_signame_label_count(k->rk.dname); 10605d76a658Ssthen *can_owner = sldns_buffer_current(buf); 1061933707f3Ssthen if(rrsig_labels == fqdn_labels) { 1062933707f3Ssthen /* no change */ 10635d76a658Ssthen sldns_buffer_write(buf, k->rk.dname, k->rk.dname_len); 1064933707f3Ssthen query_dname_tolower(*can_owner); 1065933707f3Ssthen *can_owner_len = k->rk.dname_len; 1066933707f3Ssthen return; 1067933707f3Ssthen } 1068933707f3Ssthen log_assert(rrsig_labels < fqdn_labels); 1069933707f3Ssthen /* *. | fqdn(rightmost rrsig_labels) */ 1070933707f3Ssthen if(rrsig_labels < fqdn_labels) { 1071933707f3Ssthen int i; 1072933707f3Ssthen uint8_t* nm = k->rk.dname; 1073933707f3Ssthen size_t len = k->rk.dname_len; 1074933707f3Ssthen /* so skip fqdn_labels-rrsig_labels */ 1075933707f3Ssthen for(i=0; i<fqdn_labels-rrsig_labels; i++) { 1076933707f3Ssthen dname_remove_label(&nm, &len); 1077933707f3Ssthen } 1078933707f3Ssthen *can_owner_len = len+2; 10795d76a658Ssthen sldns_buffer_write(buf, (uint8_t*)"\001*", 2); 10805d76a658Ssthen sldns_buffer_write(buf, nm, len); 1081933707f3Ssthen query_dname_tolower(*can_owner); 1082933707f3Ssthen } 1083933707f3Ssthen } 1084933707f3Ssthen 1085933707f3Ssthen /** 1086933707f3Ssthen * Canonicalize Rdata in buffer. 1087933707f3Ssthen * @param buf: buffer at position just after the rdata. 1088933707f3Ssthen * @param rrset: rrset with type. 1089933707f3Ssthen * @param len: length of the rdata (including rdatalen uint16). 1090933707f3Ssthen */ 1091933707f3Ssthen static void 10925d76a658Ssthen canonicalize_rdata(sldns_buffer* buf, struct ub_packed_rrset_key* rrset, 1093933707f3Ssthen size_t len) 1094933707f3Ssthen { 10955d76a658Ssthen uint8_t* datstart = sldns_buffer_current(buf)-len+2; 1096933707f3Ssthen switch(ntohs(rrset->rk.type)) { 1097933707f3Ssthen case LDNS_RR_TYPE_NXT: 1098933707f3Ssthen case LDNS_RR_TYPE_NS: 1099933707f3Ssthen case LDNS_RR_TYPE_MD: 1100933707f3Ssthen case LDNS_RR_TYPE_MF: 1101933707f3Ssthen case LDNS_RR_TYPE_CNAME: 1102933707f3Ssthen case LDNS_RR_TYPE_MB: 1103933707f3Ssthen case LDNS_RR_TYPE_MG: 1104933707f3Ssthen case LDNS_RR_TYPE_MR: 1105933707f3Ssthen case LDNS_RR_TYPE_PTR: 1106933707f3Ssthen case LDNS_RR_TYPE_DNAME: 1107933707f3Ssthen /* type only has a single argument, the name */ 1108933707f3Ssthen query_dname_tolower(datstart); 1109933707f3Ssthen return; 1110933707f3Ssthen case LDNS_RR_TYPE_MINFO: 1111933707f3Ssthen case LDNS_RR_TYPE_RP: 1112933707f3Ssthen case LDNS_RR_TYPE_SOA: 1113933707f3Ssthen /* two names after another */ 1114933707f3Ssthen query_dname_tolower(datstart); 1115933707f3Ssthen query_dname_tolower(datstart + 1116933707f3Ssthen dname_valid(datstart, len-2)); 1117933707f3Ssthen return; 1118933707f3Ssthen case LDNS_RR_TYPE_RT: 1119933707f3Ssthen case LDNS_RR_TYPE_AFSDB: 1120933707f3Ssthen case LDNS_RR_TYPE_KX: 1121933707f3Ssthen case LDNS_RR_TYPE_MX: 1122933707f3Ssthen /* skip fixed part */ 1123933707f3Ssthen if(len < 2+2+1) /* rdlen, skiplen, 1byteroot */ 1124933707f3Ssthen return; 1125933707f3Ssthen datstart += 2; 1126933707f3Ssthen query_dname_tolower(datstart); 1127933707f3Ssthen return; 1128933707f3Ssthen case LDNS_RR_TYPE_SIG: 1129933707f3Ssthen /* downcase the RRSIG, compat with BIND (kept it from SIG) */ 1130933707f3Ssthen case LDNS_RR_TYPE_RRSIG: 1131933707f3Ssthen /* skip fixed part */ 1132933707f3Ssthen if(len < 2+18+1) 1133933707f3Ssthen return; 1134933707f3Ssthen datstart += 18; 1135933707f3Ssthen query_dname_tolower(datstart); 1136933707f3Ssthen return; 1137933707f3Ssthen case LDNS_RR_TYPE_PX: 1138933707f3Ssthen /* skip, then two names after another */ 1139933707f3Ssthen if(len < 2+2+1) 1140933707f3Ssthen return; 1141933707f3Ssthen datstart += 2; 1142933707f3Ssthen query_dname_tolower(datstart); 1143933707f3Ssthen query_dname_tolower(datstart + 1144933707f3Ssthen dname_valid(datstart, len-2-2)); 1145933707f3Ssthen return; 1146933707f3Ssthen case LDNS_RR_TYPE_NAPTR: 1147933707f3Ssthen if(len < 2+4) 1148933707f3Ssthen return; 1149933707f3Ssthen len -= 2+4; 1150933707f3Ssthen datstart += 4; 1151933707f3Ssthen if(len < (size_t)datstart[0]+1) /* skip text field */ 1152933707f3Ssthen return; 1153933707f3Ssthen len -= (size_t)datstart[0]+1; 1154933707f3Ssthen datstart += (size_t)datstart[0]+1; 1155933707f3Ssthen if(len < (size_t)datstart[0]+1) /* skip text field */ 1156933707f3Ssthen return; 1157933707f3Ssthen len -= (size_t)datstart[0]+1; 1158933707f3Ssthen datstart += (size_t)datstart[0]+1; 1159933707f3Ssthen if(len < (size_t)datstart[0]+1) /* skip text field */ 1160933707f3Ssthen return; 1161933707f3Ssthen len -= (size_t)datstart[0]+1; 1162933707f3Ssthen datstart += (size_t)datstart[0]+1; 1163933707f3Ssthen if(len < 1) /* check name is at least 1 byte*/ 1164933707f3Ssthen return; 1165933707f3Ssthen query_dname_tolower(datstart); 1166933707f3Ssthen return; 1167933707f3Ssthen case LDNS_RR_TYPE_SRV: 1168933707f3Ssthen /* skip fixed part */ 1169933707f3Ssthen if(len < 2+6+1) 1170933707f3Ssthen return; 1171933707f3Ssthen datstart += 6; 1172933707f3Ssthen query_dname_tolower(datstart); 1173933707f3Ssthen return; 1174933707f3Ssthen 1175933707f3Ssthen /* do not canonicalize NSEC rdata name, compat with 1176933707f3Ssthen * from bind 9.4 signer, where it does not do so */ 1177933707f3Ssthen case LDNS_RR_TYPE_NSEC: /* type starts with the name */ 1178933707f3Ssthen case LDNS_RR_TYPE_HINFO: /* not downcased */ 1179933707f3Ssthen /* A6 not supported */ 1180933707f3Ssthen default: 1181933707f3Ssthen /* nothing to do for unknown types */ 1182933707f3Ssthen return; 1183933707f3Ssthen } 1184933707f3Ssthen } 1185933707f3Ssthen 11865d76a658Ssthen int rrset_canonical_equal(struct regional* region, 11875d76a658Ssthen struct ub_packed_rrset_key* k1, struct ub_packed_rrset_key* k2) 11885d76a658Ssthen { 118977079be7Ssthen struct rbtree_type sortree1, sortree2; 11905d76a658Ssthen struct canon_rr *rrs1, *rrs2, *p1, *p2; 11915d76a658Ssthen struct packed_rrset_data* d1=(struct packed_rrset_data*)k1->entry.data; 11925d76a658Ssthen struct packed_rrset_data* d2=(struct packed_rrset_data*)k2->entry.data; 11935d76a658Ssthen struct ub_packed_rrset_key fk; 11945d76a658Ssthen struct packed_rrset_data fd; 11955d76a658Ssthen size_t flen[2]; 11965d76a658Ssthen uint8_t* fdata[2]; 11975d76a658Ssthen 11985d76a658Ssthen /* basic compare */ 11995d76a658Ssthen if(k1->rk.dname_len != k2->rk.dname_len || 12005d76a658Ssthen k1->rk.flags != k2->rk.flags || 12015d76a658Ssthen k1->rk.type != k2->rk.type || 12025d76a658Ssthen k1->rk.rrset_class != k2->rk.rrset_class || 12035d76a658Ssthen query_dname_compare(k1->rk.dname, k2->rk.dname) != 0) 12045d76a658Ssthen return 0; 12055d76a658Ssthen if(d1->ttl != d2->ttl || 12065d76a658Ssthen d1->count != d2->count || 12075d76a658Ssthen d1->rrsig_count != d2->rrsig_count || 12085d76a658Ssthen d1->trust != d2->trust || 12095d76a658Ssthen d1->security != d2->security) 12105d76a658Ssthen return 0; 12115d76a658Ssthen 12125d76a658Ssthen /* init */ 12135d76a658Ssthen memset(&fk, 0, sizeof(fk)); 12145d76a658Ssthen memset(&fd, 0, sizeof(fd)); 12155d76a658Ssthen fk.entry.data = &fd; 12165d76a658Ssthen fd.count = 2; 12175d76a658Ssthen fd.rr_len = flen; 12185d76a658Ssthen fd.rr_data = fdata; 12195d76a658Ssthen rbtree_init(&sortree1, &canonical_tree_compare); 12205d76a658Ssthen rbtree_init(&sortree2, &canonical_tree_compare); 1221fdfb4ba6Ssthen if(d1->count > RR_COUNT_MAX || d2->count > RR_COUNT_MAX) 1222fdfb4ba6Ssthen return 1; /* protection against integer overflow */ 12235d76a658Ssthen rrs1 = regional_alloc(region, sizeof(struct canon_rr)*d1->count); 12245d76a658Ssthen rrs2 = regional_alloc(region, sizeof(struct canon_rr)*d2->count); 12255d76a658Ssthen if(!rrs1 || !rrs2) return 1; /* alloc failure */ 12265d76a658Ssthen 12275d76a658Ssthen /* sort */ 12285d76a658Ssthen canonical_sort(k1, d1, &sortree1, rrs1); 12295d76a658Ssthen canonical_sort(k2, d2, &sortree2, rrs2); 12305d76a658Ssthen 12315d76a658Ssthen /* compare canonical-sorted RRs for canonical-equality */ 12325d76a658Ssthen if(sortree1.count != sortree2.count) 12335d76a658Ssthen return 0; 12345d76a658Ssthen p1 = (struct canon_rr*)rbtree_first(&sortree1); 12355d76a658Ssthen p2 = (struct canon_rr*)rbtree_first(&sortree2); 12365d76a658Ssthen while(p1 != (struct canon_rr*)RBTREE_NULL && 12375d76a658Ssthen p2 != (struct canon_rr*)RBTREE_NULL) { 12385d76a658Ssthen flen[0] = d1->rr_len[p1->rr_idx]; 12395d76a658Ssthen flen[1] = d2->rr_len[p2->rr_idx]; 12405d76a658Ssthen fdata[0] = d1->rr_data[p1->rr_idx]; 12415d76a658Ssthen fdata[1] = d2->rr_data[p2->rr_idx]; 12425d76a658Ssthen 12435d76a658Ssthen if(canonical_compare(&fk, 0, 1) != 0) 12445d76a658Ssthen return 0; 12455d76a658Ssthen p1 = (struct canon_rr*)rbtree_next(&p1->node); 12465d76a658Ssthen p2 = (struct canon_rr*)rbtree_next(&p2->node); 12475d76a658Ssthen } 12485d76a658Ssthen return 1; 12495d76a658Ssthen } 12505d76a658Ssthen 1251933707f3Ssthen /** 1252933707f3Ssthen * Create canonical form of rrset in the scratch buffer. 1253933707f3Ssthen * @param region: temporary region. 1254933707f3Ssthen * @param buf: the buffer to use. 1255933707f3Ssthen * @param k: the rrset to insert. 1256933707f3Ssthen * @param sig: RRSIG rdata to include. 1257933707f3Ssthen * @param siglen: RRSIG rdata len excluding signature field, but inclusive 1258933707f3Ssthen * signer name length. 1259933707f3Ssthen * @param sortree: if NULL is passed a new sorted rrset tree is built. 1260933707f3Ssthen * Otherwise it is reused. 1261bdfc4d55Sflorian * @param section: section of packet where this rrset comes from. 1262bdfc4d55Sflorian * @param qstate: qstate with region. 1263933707f3Ssthen * @return false on alloc error. 1264933707f3Ssthen */ 1265933707f3Ssthen static int 12665d76a658Ssthen rrset_canonical(struct regional* region, sldns_buffer* buf, 1267933707f3Ssthen struct ub_packed_rrset_key* k, uint8_t* sig, size_t siglen, 1268bdfc4d55Sflorian struct rbtree_type** sortree, sldns_pkt_section section, 1269bdfc4d55Sflorian struct module_qstate* qstate) 1270933707f3Ssthen { 1271933707f3Ssthen struct packed_rrset_data* d = (struct packed_rrset_data*)k->entry.data; 1272933707f3Ssthen uint8_t* can_owner = NULL; 1273933707f3Ssthen size_t can_owner_len = 0; 1274933707f3Ssthen struct canon_rr* walk; 1275933707f3Ssthen struct canon_rr* rrs; 1276933707f3Ssthen 1277933707f3Ssthen if(!*sortree) { 127877079be7Ssthen *sortree = (struct rbtree_type*)regional_alloc(region, 127977079be7Ssthen sizeof(rbtree_type)); 1280933707f3Ssthen if(!*sortree) 1281933707f3Ssthen return 0; 1282fdfb4ba6Ssthen if(d->count > RR_COUNT_MAX) 1283fdfb4ba6Ssthen return 0; /* integer overflow protection */ 1284933707f3Ssthen rrs = regional_alloc(region, sizeof(struct canon_rr)*d->count); 1285933707f3Ssthen if(!rrs) { 1286933707f3Ssthen *sortree = NULL; 1287933707f3Ssthen return 0; 1288933707f3Ssthen } 1289933707f3Ssthen rbtree_init(*sortree, &canonical_tree_compare); 1290933707f3Ssthen canonical_sort(k, d, *sortree, rrs); 1291933707f3Ssthen } 1292933707f3Ssthen 12935d76a658Ssthen sldns_buffer_clear(buf); 12945d76a658Ssthen sldns_buffer_write(buf, sig, siglen); 1295933707f3Ssthen /* canonicalize signer name */ 12965d76a658Ssthen query_dname_tolower(sldns_buffer_begin(buf)+18); 1297933707f3Ssthen RBTREE_FOR(walk, struct canon_rr*, (*sortree)) { 1298933707f3Ssthen /* see if there is enough space left in the buffer */ 12995d76a658Ssthen if(sldns_buffer_remaining(buf) < can_owner_len + 2 + 2 + 4 1300933707f3Ssthen + d->rr_len[walk->rr_idx]) { 1301933707f3Ssthen log_err("verify: failed to canonicalize, " 1302933707f3Ssthen "rrset too big"); 1303933707f3Ssthen return 0; 1304933707f3Ssthen } 1305933707f3Ssthen /* determine canonical owner name */ 1306933707f3Ssthen if(can_owner) 13075d76a658Ssthen sldns_buffer_write(buf, can_owner, can_owner_len); 1308933707f3Ssthen else insert_can_owner(buf, k, sig, &can_owner, 1309933707f3Ssthen &can_owner_len); 13105d76a658Ssthen sldns_buffer_write(buf, &k->rk.type, 2); 13115d76a658Ssthen sldns_buffer_write(buf, &k->rk.rrset_class, 2); 13125d76a658Ssthen sldns_buffer_write(buf, sig+4, 4); 13135d76a658Ssthen sldns_buffer_write(buf, d->rr_data[walk->rr_idx], 1314933707f3Ssthen d->rr_len[walk->rr_idx]); 1315933707f3Ssthen canonicalize_rdata(buf, k, d->rr_len[walk->rr_idx]); 1316933707f3Ssthen } 13175d76a658Ssthen sldns_buffer_flip(buf); 1318bdfc4d55Sflorian 1319bdfc4d55Sflorian /* Replace RR owner with canonical owner for NSEC records in authority 1320bdfc4d55Sflorian * section, to prevent that a wildcard synthesized NSEC can be used in 1321bdfc4d55Sflorian * the non-existence proves. */ 1322bdfc4d55Sflorian if(ntohs(k->rk.type) == LDNS_RR_TYPE_NSEC && 1323191f22c6Ssthen section == LDNS_SECTION_AUTHORITY && qstate) { 1324bdfc4d55Sflorian k->rk.dname = regional_alloc_init(qstate->region, can_owner, 1325bdfc4d55Sflorian can_owner_len); 1326bdfc4d55Sflorian if(!k->rk.dname) 1327bdfc4d55Sflorian return 0; 1328bdfc4d55Sflorian k->rk.dname_len = can_owner_len; 1329bdfc4d55Sflorian } 1330bdfc4d55Sflorian 1331bdfc4d55Sflorian 1332933707f3Ssthen return 1; 1333933707f3Ssthen } 1334933707f3Ssthen 1335191f22c6Ssthen int 1336191f22c6Ssthen rrset_canonicalize_to_buffer(struct regional* region, sldns_buffer* buf, 1337191f22c6Ssthen struct ub_packed_rrset_key* k) 1338191f22c6Ssthen { 1339191f22c6Ssthen struct rbtree_type* sortree = NULL; 1340191f22c6Ssthen struct packed_rrset_data* d = (struct packed_rrset_data*)k->entry.data; 1341191f22c6Ssthen uint8_t* can_owner = NULL; 1342191f22c6Ssthen size_t can_owner_len = 0; 1343191f22c6Ssthen struct canon_rr* walk; 1344191f22c6Ssthen struct canon_rr* rrs; 1345191f22c6Ssthen 1346191f22c6Ssthen sortree = (struct rbtree_type*)regional_alloc(region, 1347191f22c6Ssthen sizeof(rbtree_type)); 1348191f22c6Ssthen if(!sortree) 1349191f22c6Ssthen return 0; 1350191f22c6Ssthen if(d->count > RR_COUNT_MAX) 1351191f22c6Ssthen return 0; /* integer overflow protection */ 1352191f22c6Ssthen rrs = regional_alloc(region, sizeof(struct canon_rr)*d->count); 1353191f22c6Ssthen if(!rrs) { 1354191f22c6Ssthen return 0; 1355191f22c6Ssthen } 1356191f22c6Ssthen rbtree_init(sortree, &canonical_tree_compare); 1357191f22c6Ssthen canonical_sort(k, d, sortree, rrs); 1358191f22c6Ssthen 1359191f22c6Ssthen sldns_buffer_clear(buf); 1360191f22c6Ssthen RBTREE_FOR(walk, struct canon_rr*, sortree) { 1361191f22c6Ssthen /* see if there is enough space left in the buffer */ 1362191f22c6Ssthen if(sldns_buffer_remaining(buf) < can_owner_len + 2 + 2 + 4 1363191f22c6Ssthen + d->rr_len[walk->rr_idx]) { 1364191f22c6Ssthen log_err("verify: failed to canonicalize, " 1365191f22c6Ssthen "rrset too big"); 1366191f22c6Ssthen return 0; 1367191f22c6Ssthen } 1368191f22c6Ssthen /* determine canonical owner name */ 1369191f22c6Ssthen if(can_owner) 1370191f22c6Ssthen sldns_buffer_write(buf, can_owner, can_owner_len); 1371191f22c6Ssthen else { 1372191f22c6Ssthen can_owner = sldns_buffer_current(buf); 1373191f22c6Ssthen sldns_buffer_write(buf, k->rk.dname, k->rk.dname_len); 1374191f22c6Ssthen query_dname_tolower(can_owner); 1375191f22c6Ssthen can_owner_len = k->rk.dname_len; 1376191f22c6Ssthen } 1377191f22c6Ssthen sldns_buffer_write(buf, &k->rk.type, 2); 1378191f22c6Ssthen sldns_buffer_write(buf, &k->rk.rrset_class, 2); 1379191f22c6Ssthen sldns_buffer_write_u32(buf, d->rr_ttl[walk->rr_idx]); 1380191f22c6Ssthen sldns_buffer_write(buf, d->rr_data[walk->rr_idx], 1381191f22c6Ssthen d->rr_len[walk->rr_idx]); 1382191f22c6Ssthen canonicalize_rdata(buf, k, d->rr_len[walk->rr_idx]); 1383191f22c6Ssthen } 1384191f22c6Ssthen sldns_buffer_flip(buf); 1385191f22c6Ssthen return 1; 1386191f22c6Ssthen } 1387191f22c6Ssthen 1388933707f3Ssthen /** pretty print rrsig error with dates */ 1389933707f3Ssthen static void 1390933707f3Ssthen sigdate_error(const char* str, int32_t expi, int32_t incep, int32_t now) 1391933707f3Ssthen { 1392933707f3Ssthen struct tm tm; 1393933707f3Ssthen char expi_buf[16]; 1394933707f3Ssthen char incep_buf[16]; 1395933707f3Ssthen char now_buf[16]; 1396933707f3Ssthen time_t te, ti, tn; 1397933707f3Ssthen 1398933707f3Ssthen if(verbosity < VERB_QUERY) 1399933707f3Ssthen return; 1400933707f3Ssthen te = (time_t)expi; 1401933707f3Ssthen ti = (time_t)incep; 1402933707f3Ssthen tn = (time_t)now; 1403933707f3Ssthen memset(&tm, 0, sizeof(tm)); 1404933707f3Ssthen if(gmtime_r(&te, &tm) && strftime(expi_buf, 15, "%Y%m%d%H%M%S", &tm) 1405933707f3Ssthen &&gmtime_r(&ti, &tm) && strftime(incep_buf, 15, "%Y%m%d%H%M%S", &tm) 1406933707f3Ssthen &&gmtime_r(&tn, &tm) && strftime(now_buf, 15, "%Y%m%d%H%M%S", &tm)) { 1407933707f3Ssthen log_info("%s expi=%s incep=%s now=%s", str, expi_buf, 1408933707f3Ssthen incep_buf, now_buf); 1409933707f3Ssthen } else 1410933707f3Ssthen log_info("%s expi=%u incep=%u now=%u", str, (unsigned)expi, 1411933707f3Ssthen (unsigned)incep, (unsigned)now); 1412933707f3Ssthen } 1413933707f3Ssthen 1414933707f3Ssthen /** check rrsig dates */ 1415933707f3Ssthen static int 14160bdb4f62Ssthen check_dates(struct val_env* ve, uint32_t unow, uint8_t* expi_p, 14170bdb4f62Ssthen uint8_t* incep_p, char** reason, sldns_ede_code *reason_bogus) 1418933707f3Ssthen { 1419933707f3Ssthen /* read out the dates */ 1420bdfc4d55Sflorian uint32_t expi, incep, now; 1421933707f3Ssthen memmove(&expi, expi_p, sizeof(expi)); 1422933707f3Ssthen memmove(&incep, incep_p, sizeof(incep)); 1423933707f3Ssthen expi = ntohl(expi); 1424933707f3Ssthen incep = ntohl(incep); 1425933707f3Ssthen 1426933707f3Ssthen /* get current date */ 1427933707f3Ssthen if(ve->date_override) { 1428933707f3Ssthen if(ve->date_override == -1) { 1429933707f3Ssthen verbose(VERB_ALGO, "date override: ignore date"); 1430933707f3Ssthen return 1; 1431933707f3Ssthen } 1432933707f3Ssthen now = ve->date_override; 1433933707f3Ssthen verbose(VERB_ALGO, "date override option %d", (int)now); 1434bdfc4d55Sflorian } else now = unow; 1435933707f3Ssthen 1436933707f3Ssthen /* check them */ 1437ebf5bb73Ssthen if(compare_1982(incep, expi) > 0) { 1438933707f3Ssthen sigdate_error("verify: inception after expiration, " 1439933707f3Ssthen "signature bad", expi, incep, now); 1440933707f3Ssthen *reason = "signature inception after expiration"; 14410bdb4f62Ssthen if(reason_bogus){ 14420bdb4f62Ssthen /* from RFC8914 on Signature Not Yet Valid: The resolver 14430bdb4f62Ssthen * attempted to perform DNSSEC validation, but no 14440bdb4f62Ssthen * signatures are presently valid and at least some are 14450bdb4f62Ssthen * not yet valid. */ 14460bdb4f62Ssthen *reason_bogus = LDNS_EDE_SIGNATURE_NOT_YET_VALID; 14470bdb4f62Ssthen } 14480bdb4f62Ssthen 1449933707f3Ssthen return 0; 1450933707f3Ssthen } 1451ebf5bb73Ssthen if(compare_1982(incep, now) > 0) { 1452933707f3Ssthen /* within skew ? (calc here to avoid calculation normally) */ 1453ebf5bb73Ssthen uint32_t skew = subtract_1982(incep, expi)/10; 1454bdfc4d55Sflorian if(skew < (uint32_t)ve->skew_min) skew = ve->skew_min; 1455bdfc4d55Sflorian if(skew > (uint32_t)ve->skew_max) skew = ve->skew_max; 1456ebf5bb73Ssthen if(subtract_1982(now, incep) > skew) { 1457933707f3Ssthen sigdate_error("verify: signature bad, current time is" 1458933707f3Ssthen " before inception date", expi, incep, now); 1459933707f3Ssthen *reason = "signature before inception date"; 14600bdb4f62Ssthen if(reason_bogus) 14610bdb4f62Ssthen *reason_bogus = LDNS_EDE_SIGNATURE_NOT_YET_VALID; 1462933707f3Ssthen return 0; 1463933707f3Ssthen } 1464933707f3Ssthen sigdate_error("verify warning suspicious signature inception " 1465933707f3Ssthen " or bad local clock", expi, incep, now); 1466933707f3Ssthen } 1467ebf5bb73Ssthen if(compare_1982(now, expi) > 0) { 1468ebf5bb73Ssthen uint32_t skew = subtract_1982(incep, expi)/10; 1469bdfc4d55Sflorian if(skew < (uint32_t)ve->skew_min) skew = ve->skew_min; 1470bdfc4d55Sflorian if(skew > (uint32_t)ve->skew_max) skew = ve->skew_max; 1471ebf5bb73Ssthen if(subtract_1982(expi, now) > skew) { 1472933707f3Ssthen sigdate_error("verify: signature expired", expi, 1473933707f3Ssthen incep, now); 1474933707f3Ssthen *reason = "signature expired"; 14750bdb4f62Ssthen if(reason_bogus) 14760bdb4f62Ssthen *reason_bogus = LDNS_EDE_SIGNATURE_EXPIRED; 1477933707f3Ssthen return 0; 1478933707f3Ssthen } 1479933707f3Ssthen sigdate_error("verify warning suspicious signature expiration " 1480933707f3Ssthen " or bad local clock", expi, incep, now); 1481933707f3Ssthen } 1482933707f3Ssthen return 1; 1483933707f3Ssthen } 1484933707f3Ssthen 1485933707f3Ssthen /** adjust rrset TTL for verified rrset, compare to original TTL and expi */ 1486933707f3Ssthen static void 1487933707f3Ssthen adjust_ttl(struct val_env* ve, uint32_t unow, 1488933707f3Ssthen struct ub_packed_rrset_key* rrset, uint8_t* orig_p, 1489933707f3Ssthen uint8_t* expi_p, uint8_t* incep_p) 1490933707f3Ssthen { 1491933707f3Ssthen struct packed_rrset_data* d = 1492933707f3Ssthen (struct packed_rrset_data*)rrset->entry.data; 1493933707f3Ssthen /* read out the dates */ 1494933707f3Ssthen int32_t origttl, expittl, expi, incep, now; 1495933707f3Ssthen memmove(&origttl, orig_p, sizeof(origttl)); 1496933707f3Ssthen memmove(&expi, expi_p, sizeof(expi)); 1497933707f3Ssthen memmove(&incep, incep_p, sizeof(incep)); 1498933707f3Ssthen expi = ntohl(expi); 1499933707f3Ssthen incep = ntohl(incep); 1500933707f3Ssthen origttl = ntohl(origttl); 1501933707f3Ssthen 1502933707f3Ssthen /* get current date */ 1503933707f3Ssthen if(ve->date_override) { 1504933707f3Ssthen now = ve->date_override; 1505933707f3Ssthen } else now = (int32_t)unow; 1506a3167c07Ssthen expittl = (int32_t)((uint32_t)expi - (uint32_t)now); 1507933707f3Ssthen 1508933707f3Ssthen /* so now: 1509933707f3Ssthen * d->ttl: rrset ttl read from message or cache. May be reduced 1510933707f3Ssthen * origttl: original TTL from signature, authoritative TTL max. 151177079be7Ssthen * MIN_TTL: minimum TTL from config. 1512933707f3Ssthen * expittl: TTL until the signature expires. 1513933707f3Ssthen * 151477079be7Ssthen * Use the smallest of these, but don't let origttl set the TTL 151577079be7Ssthen * below the minimum. 1516933707f3Ssthen */ 151777079be7Ssthen if(MIN_TTL > (time_t)origttl && d->ttl > MIN_TTL) { 151877079be7Ssthen verbose(VERB_QUERY, "rrset TTL larger than original and minimum" 151977079be7Ssthen " TTL, adjusting TTL downwards to minimum ttl"); 152077079be7Ssthen d->ttl = MIN_TTL; 152177079be7Ssthen } 152277079be7Ssthen else if(MIN_TTL <= origttl && d->ttl > (time_t)origttl) { 1523933707f3Ssthen verbose(VERB_QUERY, "rrset TTL larger than original TTL, " 152477079be7Ssthen "adjusting TTL downwards to original ttl"); 1525933707f3Ssthen d->ttl = origttl; 1526933707f3Ssthen } 152777079be7Ssthen 1528229e174cSsthen if(expittl > 0 && d->ttl > (time_t)expittl) { 1529933707f3Ssthen verbose(VERB_ALGO, "rrset TTL larger than sig expiration ttl," 1530933707f3Ssthen " adjusting TTL downwards"); 1531933707f3Ssthen d->ttl = expittl; 1532933707f3Ssthen } 1533933707f3Ssthen } 1534933707f3Ssthen 1535933707f3Ssthen enum sec_status 15365d76a658Ssthen dnskey_verify_rrset_sig(struct regional* region, sldns_buffer* buf, 1537229e174cSsthen struct val_env* ve, time_t now, 1538933707f3Ssthen struct ub_packed_rrset_key* rrset, struct ub_packed_rrset_key* dnskey, 1539933707f3Ssthen size_t dnskey_idx, size_t sig_idx, 15400bdb4f62Ssthen struct rbtree_type** sortree, int* buf_canon, 15410bdb4f62Ssthen char** reason, sldns_ede_code *reason_bogus, 1542bdfc4d55Sflorian sldns_pkt_section section, struct module_qstate* qstate) 1543933707f3Ssthen { 1544933707f3Ssthen enum sec_status sec; 1545933707f3Ssthen uint8_t* sig; /* RRSIG rdata */ 1546933707f3Ssthen size_t siglen; 1547933707f3Ssthen size_t rrnum = rrset_get_count(rrset); 1548933707f3Ssthen uint8_t* signer; /* rrsig signer name */ 1549933707f3Ssthen size_t signer_len; 1550933707f3Ssthen unsigned char* sigblock; /* signature rdata field */ 1551933707f3Ssthen unsigned int sigblock_len; 1552933707f3Ssthen uint16_t ktag; /* DNSKEY key tag */ 1553933707f3Ssthen unsigned char* key; /* public key rdata field */ 1554933707f3Ssthen unsigned int keylen; 1555933707f3Ssthen rrset_get_rdata(rrset, rrnum + sig_idx, &sig, &siglen); 1556933707f3Ssthen /* min length of rdatalen, fixed rrsig, root signer, 1 byte sig */ 1557933707f3Ssthen if(siglen < 2+20) { 1558933707f3Ssthen verbose(VERB_QUERY, "verify: signature too short"); 1559933707f3Ssthen *reason = "signature too short"; 15600bdb4f62Ssthen if(reason_bogus) 15610bdb4f62Ssthen *reason_bogus = LDNS_EDE_DNSSEC_BOGUS; 1562933707f3Ssthen return sec_status_bogus; 1563933707f3Ssthen } 1564933707f3Ssthen 1565933707f3Ssthen if(!(dnskey_get_flags(dnskey, dnskey_idx) & DNSKEY_BIT_ZSK)) { 1566933707f3Ssthen verbose(VERB_QUERY, "verify: dnskey without ZSK flag"); 1567933707f3Ssthen *reason = "dnskey without ZSK flag"; 15680bdb4f62Ssthen if(reason_bogus) 15690bdb4f62Ssthen *reason_bogus = LDNS_EDE_NO_ZONE_KEY_BIT_SET; 1570933707f3Ssthen return sec_status_bogus; 1571933707f3Ssthen } 1572933707f3Ssthen 1573933707f3Ssthen if(dnskey_get_protocol(dnskey, dnskey_idx) != LDNS_DNSSEC_KEYPROTO) { 1574933707f3Ssthen /* RFC 4034 says DNSKEY PROTOCOL MUST be 3 */ 1575933707f3Ssthen verbose(VERB_QUERY, "verify: dnskey has wrong key protocol"); 1576933707f3Ssthen *reason = "dnskey has wrong protocolnumber"; 15770bdb4f62Ssthen if(reason_bogus) 15780bdb4f62Ssthen *reason_bogus = LDNS_EDE_DNSSEC_BOGUS; 1579933707f3Ssthen return sec_status_bogus; 1580933707f3Ssthen } 1581933707f3Ssthen 1582933707f3Ssthen /* verify as many fields in rrsig as possible */ 1583933707f3Ssthen signer = sig+2+18; 1584933707f3Ssthen signer_len = dname_valid(signer, siglen-2-18); 1585933707f3Ssthen if(!signer_len) { 1586933707f3Ssthen verbose(VERB_QUERY, "verify: malformed signer name"); 1587933707f3Ssthen *reason = "signer name malformed"; 15880bdb4f62Ssthen if(reason_bogus) 15890bdb4f62Ssthen *reason_bogus = LDNS_EDE_DNSSEC_BOGUS; 1590933707f3Ssthen return sec_status_bogus; /* signer name invalid */ 1591933707f3Ssthen } 1592933707f3Ssthen if(!dname_subdomain_c(rrset->rk.dname, signer)) { 1593933707f3Ssthen verbose(VERB_QUERY, "verify: signer name is off-tree"); 1594933707f3Ssthen *reason = "signer name off-tree"; 15950bdb4f62Ssthen if(reason_bogus) 15960bdb4f62Ssthen *reason_bogus = LDNS_EDE_DNSSEC_BOGUS; 1597933707f3Ssthen return sec_status_bogus; /* signer name offtree */ 1598933707f3Ssthen } 1599933707f3Ssthen sigblock = (unsigned char*)signer+signer_len; 1600933707f3Ssthen if(siglen < 2+18+signer_len+1) { 1601933707f3Ssthen verbose(VERB_QUERY, "verify: too short, no signature data"); 1602933707f3Ssthen *reason = "signature too short, no signature data"; 16030bdb4f62Ssthen if(reason_bogus) 16040bdb4f62Ssthen *reason_bogus = LDNS_EDE_DNSSEC_BOGUS; 1605933707f3Ssthen return sec_status_bogus; /* sig rdf is < 1 byte */ 1606933707f3Ssthen } 1607933707f3Ssthen sigblock_len = (unsigned int)(siglen - 2 - 18 - signer_len); 1608933707f3Ssthen 1609933707f3Ssthen /* verify key dname == sig signer name */ 1610933707f3Ssthen if(query_dname_compare(signer, dnskey->rk.dname) != 0) { 1611933707f3Ssthen verbose(VERB_QUERY, "verify: wrong key for rrsig"); 1612933707f3Ssthen log_nametypeclass(VERB_QUERY, "RRSIG signername is", 1613933707f3Ssthen signer, 0, 0); 1614933707f3Ssthen log_nametypeclass(VERB_QUERY, "the key name is", 1615933707f3Ssthen dnskey->rk.dname, 0, 0); 1616933707f3Ssthen *reason = "signer name mismatches key name"; 16170bdb4f62Ssthen if(reason_bogus) 16180bdb4f62Ssthen *reason_bogus = LDNS_EDE_DNSSEC_BOGUS; 1619933707f3Ssthen return sec_status_bogus; 1620933707f3Ssthen } 1621933707f3Ssthen 1622933707f3Ssthen /* verify covered type */ 1623933707f3Ssthen /* memcmp works because type is in network format for rrset */ 1624933707f3Ssthen if(memcmp(sig+2, &rrset->rk.type, 2) != 0) { 1625933707f3Ssthen verbose(VERB_QUERY, "verify: wrong type covered"); 1626933707f3Ssthen *reason = "signature covers wrong type"; 16270bdb4f62Ssthen if(reason_bogus) 16280bdb4f62Ssthen *reason_bogus = LDNS_EDE_DNSSEC_BOGUS; 1629933707f3Ssthen return sec_status_bogus; 1630933707f3Ssthen } 1631933707f3Ssthen /* verify keytag and sig algo (possibly again) */ 1632933707f3Ssthen if((int)sig[2+2] != dnskey_get_algo(dnskey, dnskey_idx)) { 1633933707f3Ssthen verbose(VERB_QUERY, "verify: wrong algorithm"); 1634933707f3Ssthen *reason = "signature has wrong algorithm"; 16350bdb4f62Ssthen if(reason_bogus) 16360bdb4f62Ssthen *reason_bogus = LDNS_EDE_DNSSEC_BOGUS; 1637933707f3Ssthen return sec_status_bogus; 1638933707f3Ssthen } 1639933707f3Ssthen ktag = htons(dnskey_calc_keytag(dnskey, dnskey_idx)); 1640933707f3Ssthen if(memcmp(sig+2+16, &ktag, 2) != 0) { 1641933707f3Ssthen verbose(VERB_QUERY, "verify: wrong keytag"); 1642933707f3Ssthen *reason = "signature has wrong keytag"; 16430bdb4f62Ssthen if(reason_bogus) 16440bdb4f62Ssthen *reason_bogus = LDNS_EDE_DNSSEC_BOGUS; 1645933707f3Ssthen return sec_status_bogus; 1646933707f3Ssthen } 1647933707f3Ssthen 1648933707f3Ssthen /* verify labels is in a valid range */ 1649933707f3Ssthen if((int)sig[2+3] > dname_signame_label_count(rrset->rk.dname)) { 1650933707f3Ssthen verbose(VERB_QUERY, "verify: labelcount out of range"); 1651933707f3Ssthen *reason = "signature labelcount out of range"; 16520bdb4f62Ssthen if(reason_bogus) 16530bdb4f62Ssthen *reason_bogus = LDNS_EDE_DNSSEC_BOGUS; 1654933707f3Ssthen return sec_status_bogus; 1655933707f3Ssthen } 1656933707f3Ssthen 1657933707f3Ssthen /* original ttl, always ok */ 1658933707f3Ssthen 1659933707f3Ssthen if(!*buf_canon) { 1660933707f3Ssthen /* create rrset canonical format in buffer, ready for 1661933707f3Ssthen * signature */ 1662933707f3Ssthen if(!rrset_canonical(region, buf, rrset, sig+2, 1663bdfc4d55Sflorian 18 + signer_len, sortree, section, qstate)) { 1664933707f3Ssthen log_err("verify: failed due to alloc error"); 1665933707f3Ssthen return sec_status_unchecked; 1666933707f3Ssthen } 1667933707f3Ssthen *buf_canon = 1; 1668933707f3Ssthen } 1669933707f3Ssthen 1670933707f3Ssthen /* check that dnskey is available */ 1671933707f3Ssthen dnskey_get_pubkey(dnskey, dnskey_idx, &key, &keylen); 1672933707f3Ssthen if(!key) { 1673933707f3Ssthen verbose(VERB_QUERY, "verify: short DNSKEY RR"); 1674933707f3Ssthen return sec_status_unchecked; 1675933707f3Ssthen } 1676933707f3Ssthen 1677933707f3Ssthen /* verify */ 1678933707f3Ssthen sec = verify_canonrrset(buf, (int)sig[2+2], 1679933707f3Ssthen sigblock, sigblock_len, key, keylen, reason); 1680933707f3Ssthen 1681933707f3Ssthen if(sec == sec_status_secure) { 1682933707f3Ssthen /* check if TTL is too high - reduce if so */ 1683933707f3Ssthen adjust_ttl(ve, now, rrset, sig+2+4, sig+2+8, sig+2+12); 1684933707f3Ssthen 1685933707f3Ssthen /* verify inception, expiration dates 1686933707f3Ssthen * Do this last so that if you ignore expired-sigs the 1687933707f3Ssthen * rest is sure to be OK. */ 16880bdb4f62Ssthen if(!check_dates(ve, now, sig+2+8, sig+2+12, 16890bdb4f62Ssthen reason, reason_bogus)) { 1690933707f3Ssthen return sec_status_bogus; 1691933707f3Ssthen } 1692933707f3Ssthen } 1693933707f3Ssthen 1694933707f3Ssthen return sec; 1695933707f3Ssthen } 1696