1238106Sdes/* 2238106Sdes * validator/val_sigcrypt.c - validator signature crypto 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 24269257Sdes * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 25269257Sdes * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 26269257Sdes * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 27269257Sdes * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 28269257Sdes * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED 29269257Sdes * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 30269257Sdes * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF 31269257Sdes * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 32269257Sdes * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 33269257Sdes * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 34238106Sdes */ 35238106Sdes 36238106Sdes/** 37238106Sdes * \file 38238106Sdes * 39238106Sdes * This file contains helper functions for the validator module. 40238106Sdes * The functions help with signature verification and checking, the 41238106Sdes * bridging between RR wireformat data and crypto calls. 42238106Sdes */ 43238106Sdes#include "config.h" 44238106Sdes#include "validator/val_sigcrypt.h" 45249141Sdes#include "validator/val_secalgo.h" 46238106Sdes#include "validator/validator.h" 47238106Sdes#include "util/data/msgreply.h" 48238106Sdes#include "util/data/msgparse.h" 49238106Sdes#include "util/data/dname.h" 50238106Sdes#include "util/rbtree.h" 51238106Sdes#include "util/module.h" 52238106Sdes#include "util/net_help.h" 53238106Sdes#include "util/regional.h" 54269257Sdes#include "ldns/keyraw.h" 55269257Sdes#include "ldns/sbuffer.h" 56269257Sdes#include "ldns/parseutil.h" 57269257Sdes#include "ldns/wire2str.h" 58238106Sdes 59269257Sdes#include <ctype.h> 60249141Sdes#if !defined(HAVE_SSL) && !defined(HAVE_NSS) 61249141Sdes#error "Need crypto library to do digital signature cryptography" 62238106Sdes#endif 63238106Sdes 64238106Sdes#ifdef HAVE_OPENSSL_ERR_H 65238106Sdes#include <openssl/err.h> 66238106Sdes#endif 67238106Sdes 68238106Sdes#ifdef HAVE_OPENSSL_RAND_H 69238106Sdes#include <openssl/rand.h> 70238106Sdes#endif 71238106Sdes 72238106Sdes#ifdef HAVE_OPENSSL_CONF_H 73238106Sdes#include <openssl/conf.h> 74238106Sdes#endif 75238106Sdes 76238106Sdes#ifdef HAVE_OPENSSL_ENGINE_H 77238106Sdes#include <openssl/engine.h> 78238106Sdes#endif 79238106Sdes 80238106Sdes/** return number of rrs in an rrset */ 81238106Sdesstatic size_t 82238106Sdesrrset_get_count(struct ub_packed_rrset_key* rrset) 83238106Sdes{ 84238106Sdes struct packed_rrset_data* d = (struct packed_rrset_data*) 85238106Sdes rrset->entry.data; 86238106Sdes if(!d) return 0; 87238106Sdes return d->count; 88238106Sdes} 89238106Sdes 90238106Sdes/** 91238106Sdes * Get RR signature count 92238106Sdes */ 93238106Sdesstatic size_t 94238106Sdesrrset_get_sigcount(struct ub_packed_rrset_key* k) 95238106Sdes{ 96238106Sdes struct packed_rrset_data* d = (struct packed_rrset_data*)k->entry.data; 97238106Sdes return d->rrsig_count; 98238106Sdes} 99238106Sdes 100238106Sdes/** 101238106Sdes * Get signature keytag value 102238106Sdes * @param k: rrset (with signatures) 103238106Sdes * @param sig_idx: signature index. 104238106Sdes * @return keytag or 0 if malformed rrsig. 105238106Sdes */ 106238106Sdesstatic uint16_t 107238106Sdesrrset_get_sig_keytag(struct ub_packed_rrset_key* k, size_t sig_idx) 108238106Sdes{ 109238106Sdes uint16_t t; 110238106Sdes struct packed_rrset_data* d = (struct packed_rrset_data*)k->entry.data; 111238106Sdes log_assert(sig_idx < d->rrsig_count); 112238106Sdes if(d->rr_len[d->count + sig_idx] < 2+18) 113238106Sdes return 0; 114238106Sdes memmove(&t, d->rr_data[d->count + sig_idx]+2+16, 2); 115238106Sdes return ntohs(t); 116238106Sdes} 117238106Sdes 118238106Sdes/** 119238106Sdes * Get signature signing algorithm value 120238106Sdes * @param k: rrset (with signatures) 121238106Sdes * @param sig_idx: signature index. 122238106Sdes * @return algo or 0 if malformed rrsig. 123238106Sdes */ 124238106Sdesstatic int 125238106Sdesrrset_get_sig_algo(struct ub_packed_rrset_key* k, size_t sig_idx) 126238106Sdes{ 127238106Sdes struct packed_rrset_data* d = (struct packed_rrset_data*)k->entry.data; 128238106Sdes log_assert(sig_idx < d->rrsig_count); 129238106Sdes if(d->rr_len[d->count + sig_idx] < 2+3) 130238106Sdes return 0; 131238106Sdes return (int)d->rr_data[d->count + sig_idx][2+2]; 132238106Sdes} 133238106Sdes 134238106Sdes/** get rdata pointer and size */ 135238106Sdesstatic void 136238106Sdesrrset_get_rdata(struct ub_packed_rrset_key* k, size_t idx, uint8_t** rdata, 137238106Sdes size_t* len) 138238106Sdes{ 139238106Sdes struct packed_rrset_data* d = (struct packed_rrset_data*)k->entry.data; 140238106Sdes log_assert(d && idx < (d->count + d->rrsig_count)); 141238106Sdes *rdata = d->rr_data[idx]; 142238106Sdes *len = d->rr_len[idx]; 143238106Sdes} 144238106Sdes 145238106Sdesuint16_t 146238106Sdesdnskey_get_flags(struct ub_packed_rrset_key* k, size_t idx) 147238106Sdes{ 148238106Sdes uint8_t* rdata; 149238106Sdes size_t len; 150238106Sdes uint16_t f; 151238106Sdes rrset_get_rdata(k, idx, &rdata, &len); 152238106Sdes if(len < 2+2) 153238106Sdes return 0; 154238106Sdes memmove(&f, rdata+2, 2); 155238106Sdes f = ntohs(f); 156238106Sdes return f; 157238106Sdes} 158238106Sdes 159238106Sdes/** 160238106Sdes * Get DNSKEY protocol value from rdata 161238106Sdes * @param k: DNSKEY rrset. 162238106Sdes * @param idx: which key. 163238106Sdes * @return protocol octet value 164238106Sdes */ 165238106Sdesstatic int 166238106Sdesdnskey_get_protocol(struct ub_packed_rrset_key* k, size_t idx) 167238106Sdes{ 168238106Sdes uint8_t* rdata; 169238106Sdes size_t len; 170238106Sdes rrset_get_rdata(k, idx, &rdata, &len); 171238106Sdes if(len < 2+4) 172238106Sdes return 0; 173238106Sdes return (int)rdata[2+2]; 174238106Sdes} 175238106Sdes 176238106Sdesint 177238106Sdesdnskey_get_algo(struct ub_packed_rrset_key* k, size_t idx) 178238106Sdes{ 179238106Sdes uint8_t* rdata; 180238106Sdes size_t len; 181238106Sdes rrset_get_rdata(k, idx, &rdata, &len); 182238106Sdes if(len < 2+4) 183238106Sdes return 0; 184238106Sdes return (int)rdata[2+3]; 185238106Sdes} 186238106Sdes 187238106Sdes/** get public key rdata field from a dnskey RR and do some checks */ 188238106Sdesstatic void 189238106Sdesdnskey_get_pubkey(struct ub_packed_rrset_key* k, size_t idx, 190238106Sdes unsigned char** pk, unsigned int* pklen) 191238106Sdes{ 192238106Sdes uint8_t* rdata; 193238106Sdes size_t len; 194238106Sdes rrset_get_rdata(k, idx, &rdata, &len); 195238106Sdes if(len < 2+5) { 196238106Sdes *pk = NULL; 197238106Sdes *pklen = 0; 198238106Sdes return; 199238106Sdes } 200238106Sdes *pk = (unsigned char*)rdata+2+4; 201238106Sdes *pklen = (unsigned)len-2-4; 202238106Sdes} 203238106Sdes 204238106Sdesint 205238106Sdesds_get_key_algo(struct ub_packed_rrset_key* k, size_t idx) 206238106Sdes{ 207238106Sdes uint8_t* rdata; 208238106Sdes size_t len; 209238106Sdes rrset_get_rdata(k, idx, &rdata, &len); 210238106Sdes if(len < 2+3) 211238106Sdes return 0; 212238106Sdes return (int)rdata[2+2]; 213238106Sdes} 214238106Sdes 215238106Sdesint 216238106Sdesds_get_digest_algo(struct ub_packed_rrset_key* k, size_t idx) 217238106Sdes{ 218238106Sdes uint8_t* rdata; 219238106Sdes size_t len; 220238106Sdes rrset_get_rdata(k, idx, &rdata, &len); 221238106Sdes if(len < 2+4) 222238106Sdes return 0; 223238106Sdes return (int)rdata[2+3]; 224238106Sdes} 225238106Sdes 226238106Sdesuint16_t 227238106Sdesds_get_keytag(struct ub_packed_rrset_key* ds_rrset, size_t ds_idx) 228238106Sdes{ 229238106Sdes uint16_t t; 230238106Sdes uint8_t* rdata; 231238106Sdes size_t len; 232238106Sdes rrset_get_rdata(ds_rrset, ds_idx, &rdata, &len); 233238106Sdes if(len < 2+2) 234238106Sdes return 0; 235238106Sdes memmove(&t, rdata+2, 2); 236238106Sdes return ntohs(t); 237238106Sdes} 238238106Sdes 239238106Sdes/** 240238106Sdes * Return pointer to the digest in a DS RR. 241238106Sdes * @param k: DS rrset. 242238106Sdes * @param idx: which DS. 243238106Sdes * @param digest: digest data is returned. 244238106Sdes * on error, this is NULL. 245238106Sdes * @param len: length of digest is returned. 246238106Sdes * on error, the length is 0. 247238106Sdes */ 248238106Sdesstatic void 249238106Sdesds_get_sigdata(struct ub_packed_rrset_key* k, size_t idx, uint8_t** digest, 250238106Sdes size_t* len) 251238106Sdes{ 252238106Sdes uint8_t* rdata; 253238106Sdes size_t rdlen; 254238106Sdes rrset_get_rdata(k, idx, &rdata, &rdlen); 255238106Sdes if(rdlen < 2+5) { 256238106Sdes *digest = NULL; 257238106Sdes *len = 0; 258238106Sdes return; 259238106Sdes } 260238106Sdes *digest = rdata + 2 + 4; 261238106Sdes *len = rdlen - 2 - 4; 262238106Sdes} 263238106Sdes 264238106Sdes/** 265238106Sdes * Return size of DS digest according to its hash algorithm. 266238106Sdes * @param k: DS rrset. 267238106Sdes * @param idx: which DS. 268238106Sdes * @return size in bytes of digest, or 0 if not supported. 269238106Sdes */ 270238106Sdesstatic size_t 271238106Sdesds_digest_size_algo(struct ub_packed_rrset_key* k, size_t idx) 272238106Sdes{ 273249141Sdes return ds_digest_size_supported(ds_get_digest_algo(k, idx)); 274238106Sdes} 275238106Sdes 276238106Sdes/** 277238106Sdes * Create a DS digest for a DNSKEY entry. 278238106Sdes * 279238106Sdes * @param env: module environment. Uses scratch space. 280238106Sdes * @param dnskey_rrset: DNSKEY rrset. 281238106Sdes * @param dnskey_idx: index of RR in rrset. 282238106Sdes * @param ds_rrset: DS rrset 283238106Sdes * @param ds_idx: index of RR in DS rrset. 284238106Sdes * @param digest: digest is returned in here (must be correctly sized). 285238106Sdes * @return false on error. 286238106Sdes */ 287238106Sdesstatic int 288238106Sdesds_create_dnskey_digest(struct module_env* env, 289238106Sdes struct ub_packed_rrset_key* dnskey_rrset, size_t dnskey_idx, 290238106Sdes struct ub_packed_rrset_key* ds_rrset, size_t ds_idx, 291238106Sdes uint8_t* digest) 292238106Sdes{ 293269257Sdes sldns_buffer* b = env->scratch_buffer; 294238106Sdes uint8_t* dnskey_rdata; 295238106Sdes size_t dnskey_len; 296238106Sdes rrset_get_rdata(dnskey_rrset, dnskey_idx, &dnskey_rdata, &dnskey_len); 297238106Sdes 298238106Sdes /* create digest source material in buffer 299238106Sdes * digest = digest_algorithm( DNSKEY owner name | DNSKEY RDATA); 300238106Sdes * DNSKEY RDATA = Flags | Protocol | Algorithm | Public Key. */ 301269257Sdes sldns_buffer_clear(b); 302269257Sdes sldns_buffer_write(b, dnskey_rrset->rk.dname, 303238106Sdes dnskey_rrset->rk.dname_len); 304269257Sdes query_dname_tolower(sldns_buffer_begin(b)); 305269257Sdes sldns_buffer_write(b, dnskey_rdata+2, dnskey_len-2); /* skip rdatalen*/ 306269257Sdes sldns_buffer_flip(b); 307238106Sdes 308249141Sdes return secalgo_ds_digest(ds_get_digest_algo(ds_rrset, ds_idx), 309269257Sdes (unsigned char*)sldns_buffer_begin(b), sldns_buffer_limit(b), 310249141Sdes (unsigned char*)digest); 311238106Sdes} 312238106Sdes 313238106Sdesint ds_digest_match_dnskey(struct module_env* env, 314238106Sdes struct ub_packed_rrset_key* dnskey_rrset, size_t dnskey_idx, 315238106Sdes struct ub_packed_rrset_key* ds_rrset, size_t ds_idx) 316238106Sdes{ 317238106Sdes uint8_t* ds; /* DS digest */ 318238106Sdes size_t dslen; 319238106Sdes uint8_t* digest; /* generated digest */ 320238106Sdes size_t digestlen = ds_digest_size_algo(ds_rrset, ds_idx); 321238106Sdes 322238106Sdes if(digestlen == 0) { 323238106Sdes verbose(VERB_QUERY, "DS fail: not supported, or DS RR " 324238106Sdes "format error"); 325238106Sdes return 0; /* not supported, or DS RR format error */ 326238106Sdes } 327238106Sdes /* check digest length in DS with length from hash function */ 328238106Sdes ds_get_sigdata(ds_rrset, ds_idx, &ds, &dslen); 329238106Sdes if(!ds || dslen != digestlen) { 330238106Sdes verbose(VERB_QUERY, "DS fail: DS RR algo and digest do not " 331238106Sdes "match each other"); 332238106Sdes return 0; /* DS algorithm and digest do not match */ 333238106Sdes } 334238106Sdes 335238106Sdes digest = regional_alloc(env->scratch, digestlen); 336238106Sdes if(!digest) { 337238106Sdes verbose(VERB_QUERY, "DS fail: out of memory"); 338238106Sdes return 0; /* mem error */ 339238106Sdes } 340238106Sdes if(!ds_create_dnskey_digest(env, dnskey_rrset, dnskey_idx, ds_rrset, 341238106Sdes ds_idx, digest)) { 342238106Sdes verbose(VERB_QUERY, "DS fail: could not calc key digest"); 343238106Sdes return 0; /* digest algo failed */ 344238106Sdes } 345238106Sdes if(memcmp(digest, ds, dslen) != 0) { 346238106Sdes verbose(VERB_QUERY, "DS fail: digest is different"); 347238106Sdes return 0; /* digest different */ 348238106Sdes } 349238106Sdes return 1; 350238106Sdes} 351238106Sdes 352238106Sdesint 353238106Sdesds_digest_algo_is_supported(struct ub_packed_rrset_key* ds_rrset, 354238106Sdes size_t ds_idx) 355238106Sdes{ 356238106Sdes return (ds_digest_size_algo(ds_rrset, ds_idx) != 0); 357238106Sdes} 358238106Sdes 359238106Sdesint 360238106Sdesds_key_algo_is_supported(struct ub_packed_rrset_key* ds_rrset, 361238106Sdes size_t ds_idx) 362238106Sdes{ 363238106Sdes return dnskey_algo_id_is_supported(ds_get_key_algo(ds_rrset, ds_idx)); 364238106Sdes} 365238106Sdes 366238106Sdesuint16_t 367238106Sdesdnskey_calc_keytag(struct ub_packed_rrset_key* dnskey_rrset, size_t dnskey_idx) 368238106Sdes{ 369238106Sdes uint8_t* data; 370238106Sdes size_t len; 371238106Sdes rrset_get_rdata(dnskey_rrset, dnskey_idx, &data, &len); 372238106Sdes /* do not pass rdatalen to ldns */ 373269257Sdes return sldns_calc_keytag_raw(data+2, len-2); 374238106Sdes} 375238106Sdes 376238106Sdesint dnskey_algo_is_supported(struct ub_packed_rrset_key* dnskey_rrset, 377238106Sdes size_t dnskey_idx) 378238106Sdes{ 379238106Sdes return dnskey_algo_id_is_supported(dnskey_get_algo(dnskey_rrset, 380238106Sdes dnskey_idx)); 381238106Sdes} 382238106Sdes 383238106Sdesvoid algo_needs_init_dnskey_add(struct algo_needs* n, 384238106Sdes struct ub_packed_rrset_key* dnskey, uint8_t* sigalg) 385238106Sdes{ 386238106Sdes uint8_t algo; 387238106Sdes size_t i, total = n->num; 388238106Sdes size_t num = rrset_get_count(dnskey); 389238106Sdes 390238106Sdes for(i=0; i<num; i++) { 391238106Sdes algo = (uint8_t)dnskey_get_algo(dnskey, i); 392238106Sdes if(!dnskey_algo_id_is_supported((int)algo)) 393238106Sdes continue; 394238106Sdes if(n->needs[algo] == 0) { 395238106Sdes n->needs[algo] = 1; 396238106Sdes sigalg[total] = algo; 397238106Sdes total++; 398238106Sdes } 399238106Sdes } 400238106Sdes sigalg[total] = 0; 401238106Sdes n->num = total; 402238106Sdes} 403238106Sdes 404238106Sdesvoid algo_needs_init_list(struct algo_needs* n, uint8_t* sigalg) 405238106Sdes{ 406238106Sdes uint8_t algo; 407238106Sdes size_t total = 0; 408238106Sdes 409238106Sdes memset(n->needs, 0, sizeof(uint8_t)*ALGO_NEEDS_MAX); 410238106Sdes while( (algo=*sigalg++) != 0) { 411238106Sdes log_assert(dnskey_algo_id_is_supported((int)algo)); 412238106Sdes log_assert(n->needs[algo] == 0); 413238106Sdes n->needs[algo] = 1; 414238106Sdes total++; 415238106Sdes } 416238106Sdes n->num = total; 417238106Sdes} 418238106Sdes 419238106Sdesvoid algo_needs_init_ds(struct algo_needs* n, struct ub_packed_rrset_key* ds, 420238106Sdes int fav_ds_algo, uint8_t* sigalg) 421238106Sdes{ 422238106Sdes uint8_t algo; 423238106Sdes size_t i, total = 0; 424238106Sdes size_t num = rrset_get_count(ds); 425238106Sdes 426238106Sdes memset(n->needs, 0, sizeof(uint8_t)*ALGO_NEEDS_MAX); 427238106Sdes for(i=0; i<num; i++) { 428238106Sdes if(ds_get_digest_algo(ds, i) != fav_ds_algo) 429238106Sdes continue; 430238106Sdes algo = (uint8_t)ds_get_key_algo(ds, i); 431238106Sdes if(!dnskey_algo_id_is_supported((int)algo)) 432238106Sdes continue; 433238106Sdes log_assert(algo != 0); /* we do not support 0 and is EOS */ 434238106Sdes if(n->needs[algo] == 0) { 435238106Sdes n->needs[algo] = 1; 436238106Sdes sigalg[total] = algo; 437238106Sdes total++; 438238106Sdes } 439238106Sdes } 440238106Sdes sigalg[total] = 0; 441238106Sdes n->num = total; 442238106Sdes} 443238106Sdes 444238106Sdesint algo_needs_set_secure(struct algo_needs* n, uint8_t algo) 445238106Sdes{ 446238106Sdes if(n->needs[algo]) { 447238106Sdes n->needs[algo] = 0; 448238106Sdes n->num --; 449238106Sdes if(n->num == 0) /* done! */ 450238106Sdes return 1; 451238106Sdes } 452238106Sdes return 0; 453238106Sdes} 454238106Sdes 455238106Sdesvoid algo_needs_set_bogus(struct algo_needs* n, uint8_t algo) 456238106Sdes{ 457238106Sdes if(n->needs[algo]) n->needs[algo] = 2; /* need it, but bogus */ 458238106Sdes} 459238106Sdes 460238106Sdessize_t algo_needs_num_missing(struct algo_needs* n) 461238106Sdes{ 462238106Sdes return n->num; 463238106Sdes} 464238106Sdes 465238106Sdesint algo_needs_missing(struct algo_needs* n) 466238106Sdes{ 467238106Sdes int i; 468238106Sdes /* first check if a needed algo was bogus - report that */ 469238106Sdes for(i=0; i<ALGO_NEEDS_MAX; i++) 470238106Sdes if(n->needs[i] == 2) 471238106Sdes return 0; 472238106Sdes /* now check which algo is missing */ 473238106Sdes for(i=0; i<ALGO_NEEDS_MAX; i++) 474238106Sdes if(n->needs[i] == 1) 475238106Sdes return i; 476238106Sdes return 0; 477238106Sdes} 478238106Sdes 479238106Sdesenum sec_status 480238106Sdesdnskeyset_verify_rrset(struct module_env* env, struct val_env* ve, 481238106Sdes struct ub_packed_rrset_key* rrset, struct ub_packed_rrset_key* dnskey, 482238106Sdes uint8_t* sigalg, char** reason) 483238106Sdes{ 484238106Sdes enum sec_status sec; 485238106Sdes size_t i, num; 486238106Sdes rbtree_t* sortree = NULL; 487238106Sdes /* make sure that for all DNSKEY algorithms there are valid sigs */ 488238106Sdes struct algo_needs needs; 489238106Sdes int alg; 490238106Sdes 491238106Sdes num = rrset_get_sigcount(rrset); 492238106Sdes if(num == 0) { 493238106Sdes verbose(VERB_QUERY, "rrset failed to verify due to a lack of " 494238106Sdes "signatures"); 495238106Sdes *reason = "no signatures"; 496238106Sdes return sec_status_bogus; 497238106Sdes } 498238106Sdes 499238106Sdes if(sigalg) { 500238106Sdes algo_needs_init_list(&needs, sigalg); 501238106Sdes if(algo_needs_num_missing(&needs) == 0) { 502238106Sdes verbose(VERB_QUERY, "zone has no known algorithms"); 503238106Sdes *reason = "zone has no known algorithms"; 504238106Sdes return sec_status_insecure; 505238106Sdes } 506238106Sdes } 507238106Sdes for(i=0; i<num; i++) { 508238106Sdes sec = dnskeyset_verify_rrset_sig(env, ve, *env->now, rrset, 509238106Sdes dnskey, i, &sortree, reason); 510238106Sdes /* see which algorithm has been fixed up */ 511238106Sdes if(sec == sec_status_secure) { 512238106Sdes if(!sigalg) 513238106Sdes return sec; /* done! */ 514238106Sdes else if(algo_needs_set_secure(&needs, 515238106Sdes (uint8_t)rrset_get_sig_algo(rrset, i))) 516238106Sdes return sec; /* done! */ 517238106Sdes } else if(sigalg && sec == sec_status_bogus) { 518238106Sdes algo_needs_set_bogus(&needs, 519238106Sdes (uint8_t)rrset_get_sig_algo(rrset, i)); 520238106Sdes } 521238106Sdes } 522238106Sdes if(sigalg && (alg=algo_needs_missing(&needs)) != 0) { 523249141Sdes verbose(VERB_ALGO, "rrset failed to verify: " 524249141Sdes "no valid signatures for %d algorithms", 525249141Sdes (int)algo_needs_num_missing(&needs)); 526238106Sdes algo_needs_reason(env, alg, reason, "no signatures"); 527249141Sdes } else { 528249141Sdes verbose(VERB_ALGO, "rrset failed to verify: " 529249141Sdes "no valid signatures"); 530238106Sdes } 531238106Sdes return sec_status_bogus; 532238106Sdes} 533238106Sdes 534238106Sdesvoid algo_needs_reason(struct module_env* env, int alg, char** reason, char* s) 535238106Sdes{ 536238106Sdes char buf[256]; 537269257Sdes sldns_lookup_table *t = sldns_lookup_by_id(sldns_algorithms, alg); 538238106Sdes if(t&&t->name) 539238106Sdes snprintf(buf, sizeof(buf), "%s with algorithm %s", s, t->name); 540238106Sdes else snprintf(buf, sizeof(buf), "%s with algorithm ALG%u", s, 541238106Sdes (unsigned)alg); 542238106Sdes *reason = regional_strdup(env->scratch, buf); 543238106Sdes if(!*reason) 544238106Sdes *reason = s; 545238106Sdes} 546238106Sdes 547238106Sdesenum sec_status 548238106Sdesdnskey_verify_rrset(struct module_env* env, struct val_env* ve, 549238106Sdes struct ub_packed_rrset_key* rrset, struct ub_packed_rrset_key* dnskey, 550238106Sdes size_t dnskey_idx, char** reason) 551238106Sdes{ 552238106Sdes enum sec_status sec; 553238106Sdes size_t i, num, numchecked = 0; 554238106Sdes rbtree_t* sortree = NULL; 555238106Sdes int buf_canon = 0; 556238106Sdes uint16_t tag = dnskey_calc_keytag(dnskey, dnskey_idx); 557238106Sdes int algo = dnskey_get_algo(dnskey, dnskey_idx); 558238106Sdes 559238106Sdes num = rrset_get_sigcount(rrset); 560238106Sdes if(num == 0) { 561238106Sdes verbose(VERB_QUERY, "rrset failed to verify due to a lack of " 562238106Sdes "signatures"); 563238106Sdes *reason = "no signatures"; 564238106Sdes return sec_status_bogus; 565238106Sdes } 566238106Sdes for(i=0; i<num; i++) { 567238106Sdes /* see if sig matches keytag and algo */ 568238106Sdes if(algo != rrset_get_sig_algo(rrset, i) || 569238106Sdes tag != rrset_get_sig_keytag(rrset, i)) 570238106Sdes continue; 571238106Sdes buf_canon = 0; 572238106Sdes sec = dnskey_verify_rrset_sig(env->scratch, 573238106Sdes env->scratch_buffer, ve, *env->now, rrset, 574238106Sdes dnskey, dnskey_idx, i, &sortree, &buf_canon, reason); 575238106Sdes if(sec == sec_status_secure) 576238106Sdes return sec; 577238106Sdes numchecked ++; 578238106Sdes } 579238106Sdes verbose(VERB_ALGO, "rrset failed to verify: all signatures are bogus"); 580238106Sdes if(!numchecked) *reason = "signature missing"; 581238106Sdes return sec_status_bogus; 582238106Sdes} 583238106Sdes 584238106Sdesenum sec_status 585238106Sdesdnskeyset_verify_rrset_sig(struct module_env* env, struct val_env* ve, 586269257Sdes time_t now, struct ub_packed_rrset_key* rrset, 587238106Sdes struct ub_packed_rrset_key* dnskey, size_t sig_idx, 588238106Sdes struct rbtree_t** sortree, char** reason) 589238106Sdes{ 590238106Sdes /* find matching keys and check them */ 591238106Sdes enum sec_status sec = sec_status_bogus; 592238106Sdes uint16_t tag = rrset_get_sig_keytag(rrset, sig_idx); 593238106Sdes int algo = rrset_get_sig_algo(rrset, sig_idx); 594238106Sdes size_t i, num = rrset_get_count(dnskey); 595238106Sdes size_t numchecked = 0; 596238106Sdes int buf_canon = 0; 597238106Sdes verbose(VERB_ALGO, "verify sig %d %d", (int)tag, algo); 598238106Sdes if(!dnskey_algo_id_is_supported(algo)) { 599238106Sdes verbose(VERB_QUERY, "verify sig: unknown algorithm"); 600238106Sdes return sec_status_insecure; 601238106Sdes } 602238106Sdes 603238106Sdes for(i=0; i<num; i++) { 604238106Sdes /* see if key matches keytag and algo */ 605238106Sdes if(algo != dnskey_get_algo(dnskey, i) || 606238106Sdes tag != dnskey_calc_keytag(dnskey, i)) 607238106Sdes continue; 608238106Sdes numchecked ++; 609238106Sdes 610238106Sdes /* see if key verifies */ 611238106Sdes sec = dnskey_verify_rrset_sig(env->scratch, 612238106Sdes env->scratch_buffer, ve, now, rrset, dnskey, i, 613238106Sdes sig_idx, sortree, &buf_canon, reason); 614238106Sdes if(sec == sec_status_secure) 615238106Sdes return sec; 616238106Sdes } 617238106Sdes if(numchecked == 0) { 618238106Sdes *reason = "signatures from unknown keys"; 619238106Sdes verbose(VERB_QUERY, "verify: could not find appropriate key"); 620238106Sdes return sec_status_bogus; 621238106Sdes } 622238106Sdes return sec_status_bogus; 623238106Sdes} 624238106Sdes 625238106Sdes/** 626238106Sdes * RR entries in a canonical sorted tree of RRs 627238106Sdes */ 628238106Sdesstruct canon_rr { 629238106Sdes /** rbtree node, key is this structure */ 630238106Sdes rbnode_t node; 631238106Sdes /** rrset the RR is in */ 632238106Sdes struct ub_packed_rrset_key* rrset; 633238106Sdes /** which RR in the rrset */ 634238106Sdes size_t rr_idx; 635238106Sdes}; 636238106Sdes 637238106Sdes/** 638238106Sdes * Compare two RR for canonical order, in a field-style sweep. 639238106Sdes * @param d: rrset data 640238106Sdes * @param desc: ldns wireformat descriptor. 641238106Sdes * @param i: first RR to compare 642238106Sdes * @param j: first RR to compare 643238106Sdes * @return comparison code. 644238106Sdes */ 645238106Sdesstatic int 646238106Sdescanonical_compare_byfield(struct packed_rrset_data* d, 647269257Sdes const sldns_rr_descriptor* desc, size_t i, size_t j) 648238106Sdes{ 649238106Sdes /* sweep across rdata, keep track of some state: 650238106Sdes * which rr field, and bytes left in field. 651238106Sdes * current position in rdata, length left. 652238106Sdes * are we in a dname, length left in a label. 653238106Sdes */ 654238106Sdes int wfi = -1; /* current wireformat rdata field (rdf) */ 655238106Sdes int wfj = -1; 656238106Sdes uint8_t* di = d->rr_data[i]+2; /* ptr to current rdata byte */ 657238106Sdes uint8_t* dj = d->rr_data[j]+2; 658238106Sdes size_t ilen = d->rr_len[i]-2; /* length left in rdata */ 659238106Sdes size_t jlen = d->rr_len[j]-2; 660238106Sdes int dname_i = 0; /* true if these bytes are part of a name */ 661238106Sdes int dname_j = 0; 662238106Sdes size_t lablen_i = 0; /* 0 for label length byte,for first byte of rdf*/ 663238106Sdes size_t lablen_j = 0; /* otherwise remaining length of rdf or label */ 664238106Sdes int dname_num_i = (int)desc->_dname_count; /* decreased at root label */ 665238106Sdes int dname_num_j = (int)desc->_dname_count; 666238106Sdes 667238106Sdes /* loop while there are rdata bytes available for both rrs, 668238106Sdes * and still some lowercasing needs to be done; either the dnames 669238106Sdes * have not been reached yet, or they are currently being processed */ 670238106Sdes while(ilen > 0 && jlen > 0 && (dname_num_i > 0 || dname_num_j > 0)) { 671238106Sdes /* compare these two bytes */ 672238106Sdes /* lowercase if in a dname and not a label length byte */ 673238106Sdes if( ((dname_i && lablen_i)?(uint8_t)tolower((int)*di):*di) 674238106Sdes != ((dname_j && lablen_j)?(uint8_t)tolower((int)*dj):*dj) 675238106Sdes ) { 676238106Sdes if(((dname_i && lablen_i)?(uint8_t)tolower((int)*di):*di) 677238106Sdes < ((dname_j && lablen_j)?(uint8_t)tolower((int)*dj):*dj)) 678238106Sdes return -1; 679238106Sdes return 1; 680238106Sdes } 681238106Sdes ilen--; 682238106Sdes jlen--; 683238106Sdes /* bytes are equal */ 684238106Sdes 685238106Sdes /* advance field i */ 686238106Sdes /* lablen 0 means that this byte is the first byte of the 687238106Sdes * next rdata field; inspect this rdata field and setup 688238106Sdes * to process the rest of this rdata field. 689238106Sdes * The reason to first read the byte, then setup the rdf, 690238106Sdes * is that we are then sure the byte is available and short 691238106Sdes * rdata is handled gracefully (even if it is a formerr). */ 692238106Sdes if(lablen_i == 0) { 693238106Sdes if(dname_i) { 694238106Sdes /* scan this dname label */ 695238106Sdes /* capture length to lowercase */ 696238106Sdes lablen_i = (size_t)*di; 697238106Sdes if(lablen_i == 0) { 698238106Sdes /* end root label */ 699238106Sdes dname_i = 0; 700238106Sdes dname_num_i--; 701238106Sdes /* if dname num is 0, then the 702238106Sdes * remainder is binary only */ 703238106Sdes if(dname_num_i == 0) 704238106Sdes lablen_i = ilen; 705238106Sdes } 706238106Sdes } else { 707238106Sdes /* scan this rdata field */ 708238106Sdes wfi++; 709238106Sdes if(desc->_wireformat[wfi] 710238106Sdes == LDNS_RDF_TYPE_DNAME) { 711238106Sdes dname_i = 1; 712238106Sdes lablen_i = (size_t)*di; 713238106Sdes if(lablen_i == 0) { 714238106Sdes dname_i = 0; 715238106Sdes dname_num_i--; 716238106Sdes if(dname_num_i == 0) 717238106Sdes lablen_i = ilen; 718238106Sdes } 719238106Sdes } else if(desc->_wireformat[wfi] 720238106Sdes == LDNS_RDF_TYPE_STR) 721238106Sdes lablen_i = (size_t)*di; 722238106Sdes else lablen_i = get_rdf_size( 723238106Sdes desc->_wireformat[wfi]) - 1; 724238106Sdes } 725238106Sdes } else lablen_i--; 726238106Sdes 727238106Sdes /* advance field j; same as for i */ 728238106Sdes if(lablen_j == 0) { 729238106Sdes if(dname_j) { 730238106Sdes lablen_j = (size_t)*dj; 731238106Sdes if(lablen_j == 0) { 732238106Sdes dname_j = 0; 733238106Sdes dname_num_j--; 734238106Sdes if(dname_num_j == 0) 735238106Sdes lablen_j = jlen; 736238106Sdes } 737238106Sdes } else { 738238106Sdes wfj++; 739238106Sdes if(desc->_wireformat[wfj] 740238106Sdes == LDNS_RDF_TYPE_DNAME) { 741238106Sdes dname_j = 1; 742238106Sdes lablen_j = (size_t)*dj; 743238106Sdes if(lablen_j == 0) { 744238106Sdes dname_j = 0; 745238106Sdes dname_num_j--; 746238106Sdes if(dname_num_j == 0) 747238106Sdes lablen_j = jlen; 748238106Sdes } 749238106Sdes } else if(desc->_wireformat[wfj] 750238106Sdes == LDNS_RDF_TYPE_STR) 751238106Sdes lablen_j = (size_t)*dj; 752238106Sdes else lablen_j = get_rdf_size( 753238106Sdes desc->_wireformat[wfj]) - 1; 754238106Sdes } 755238106Sdes } else lablen_j--; 756238106Sdes di++; 757238106Sdes dj++; 758238106Sdes } 759238106Sdes /* end of the loop; because we advanced byte by byte; now we have 760238106Sdes * that the rdata has ended, or that there is a binary remainder */ 761238106Sdes /* shortest first */ 762238106Sdes if(ilen == 0 && jlen == 0) 763238106Sdes return 0; 764238106Sdes if(ilen == 0) 765238106Sdes return -1; 766238106Sdes if(jlen == 0) 767238106Sdes return 1; 768238106Sdes /* binary remainder, capture comparison in wfi variable */ 769238106Sdes if((wfi = memcmp(di, dj, (ilen<jlen)?ilen:jlen)) != 0) 770238106Sdes return wfi; 771238106Sdes if(ilen < jlen) 772238106Sdes return -1; 773238106Sdes if(jlen < ilen) 774238106Sdes return 1; 775238106Sdes return 0; 776238106Sdes} 777238106Sdes 778238106Sdes/** 779238106Sdes * Compare two RRs in the same RRset and determine their relative 780238106Sdes * canonical order. 781238106Sdes * @param rrset: the rrset in which to perform compares. 782238106Sdes * @param i: first RR to compare 783238106Sdes * @param j: first RR to compare 784238106Sdes * @return 0 if RR i== RR j, -1 if <, +1 if >. 785238106Sdes */ 786238106Sdesstatic int 787238106Sdescanonical_compare(struct ub_packed_rrset_key* rrset, size_t i, size_t j) 788238106Sdes{ 789238106Sdes struct packed_rrset_data* d = (struct packed_rrset_data*) 790238106Sdes rrset->entry.data; 791269257Sdes const sldns_rr_descriptor* desc; 792238106Sdes uint16_t type = ntohs(rrset->rk.type); 793238106Sdes size_t minlen; 794238106Sdes int c; 795238106Sdes 796238106Sdes if(i==j) 797238106Sdes return 0; 798238106Sdes /* in case rdata-len is to be compared for canonical order 799238106Sdes c = memcmp(d->rr_data[i], d->rr_data[j], 2); 800238106Sdes if(c != 0) 801238106Sdes return c; */ 802238106Sdes 803238106Sdes switch(type) { 804238106Sdes /* These RR types have only a name as RDATA. 805238106Sdes * This name has to be canonicalized.*/ 806238106Sdes case LDNS_RR_TYPE_NS: 807238106Sdes case LDNS_RR_TYPE_MD: 808238106Sdes case LDNS_RR_TYPE_MF: 809238106Sdes case LDNS_RR_TYPE_CNAME: 810238106Sdes case LDNS_RR_TYPE_MB: 811238106Sdes case LDNS_RR_TYPE_MG: 812238106Sdes case LDNS_RR_TYPE_MR: 813238106Sdes case LDNS_RR_TYPE_PTR: 814238106Sdes case LDNS_RR_TYPE_DNAME: 815269257Sdes /* the wireread function has already checked these 816269257Sdes * dname's for correctness, and this double checks */ 817269257Sdes if(!dname_valid(d->rr_data[i]+2, d->rr_len[i]-2) || 818269257Sdes !dname_valid(d->rr_data[j]+2, d->rr_len[j]-2)) 819269257Sdes return 0; 820269257Sdes return query_dname_compare(d->rr_data[i]+2, 821238106Sdes d->rr_data[j]+2); 822238106Sdes 823238106Sdes /* These RR types have STR and fixed size rdata fields 824238106Sdes * before one or more name fields that need canonicalizing, 825238106Sdes * and after that a byte-for byte remainder can be compared. 826238106Sdes */ 827238106Sdes /* type starts with the name; remainder is binary compared */ 828238106Sdes case LDNS_RR_TYPE_NXT: 829238106Sdes /* use rdata field formats */ 830238106Sdes case LDNS_RR_TYPE_MINFO: 831238106Sdes case LDNS_RR_TYPE_RP: 832238106Sdes case LDNS_RR_TYPE_SOA: 833238106Sdes case LDNS_RR_TYPE_RT: 834238106Sdes case LDNS_RR_TYPE_AFSDB: 835238106Sdes case LDNS_RR_TYPE_KX: 836238106Sdes case LDNS_RR_TYPE_MX: 837238106Sdes case LDNS_RR_TYPE_SIG: 838238106Sdes /* RRSIG signer name has to be downcased */ 839238106Sdes case LDNS_RR_TYPE_RRSIG: 840238106Sdes case LDNS_RR_TYPE_PX: 841238106Sdes case LDNS_RR_TYPE_NAPTR: 842238106Sdes case LDNS_RR_TYPE_SRV: 843269257Sdes desc = sldns_rr_descript(type); 844238106Sdes log_assert(desc); 845238106Sdes /* this holds for the types that need canonicalizing */ 846238106Sdes log_assert(desc->_minimum == desc->_maximum); 847238106Sdes return canonical_compare_byfield(d, desc, i, j); 848238106Sdes 849238106Sdes case LDNS_RR_TYPE_HINFO: /* no longer downcased */ 850238106Sdes case LDNS_RR_TYPE_NSEC: 851238106Sdes default: 852238106Sdes /* For unknown RR types, or types not listed above, 853238106Sdes * no canonicalization is needed, do binary compare */ 854238106Sdes /* byte for byte compare, equal means shortest first*/ 855238106Sdes minlen = d->rr_len[i]-2; 856238106Sdes if(minlen > d->rr_len[j]-2) 857238106Sdes minlen = d->rr_len[j]-2; 858238106Sdes c = memcmp(d->rr_data[i]+2, d->rr_data[j]+2, minlen); 859238106Sdes if(c!=0) 860238106Sdes return c; 861238106Sdes /* rdata equal, shortest is first */ 862238106Sdes if(d->rr_len[i] < d->rr_len[j]) 863238106Sdes return -1; 864238106Sdes if(d->rr_len[i] > d->rr_len[j]) 865238106Sdes return 1; 866238106Sdes /* rdata equal, length equal */ 867238106Sdes break; 868238106Sdes } 869238106Sdes return 0; 870238106Sdes} 871238106Sdes 872238106Sdesint 873238106Sdescanonical_tree_compare(const void* k1, const void* k2) 874238106Sdes{ 875238106Sdes struct canon_rr* r1 = (struct canon_rr*)k1; 876238106Sdes struct canon_rr* r2 = (struct canon_rr*)k2; 877238106Sdes log_assert(r1->rrset == r2->rrset); 878238106Sdes return canonical_compare(r1->rrset, r1->rr_idx, r2->rr_idx); 879238106Sdes} 880238106Sdes 881238106Sdes/** 882238106Sdes * Sort RRs for rrset in canonical order. 883238106Sdes * Does not actually canonicalize the RR rdatas. 884238106Sdes * Does not touch rrsigs. 885238106Sdes * @param rrset: to sort. 886238106Sdes * @param d: rrset data. 887238106Sdes * @param sortree: tree to sort into. 888238106Sdes * @param rrs: rr storage. 889238106Sdes */ 890238106Sdesstatic void 891238106Sdescanonical_sort(struct ub_packed_rrset_key* rrset, struct packed_rrset_data* d, 892238106Sdes rbtree_t* sortree, struct canon_rr* rrs) 893238106Sdes{ 894238106Sdes size_t i; 895238106Sdes /* insert into rbtree to sort and detect duplicates */ 896238106Sdes for(i=0; i<d->count; i++) { 897238106Sdes rrs[i].node.key = &rrs[i]; 898238106Sdes rrs[i].rrset = rrset; 899238106Sdes rrs[i].rr_idx = i; 900238106Sdes if(!rbtree_insert(sortree, &rrs[i].node)) { 901238106Sdes /* this was a duplicate */ 902238106Sdes } 903238106Sdes } 904238106Sdes} 905238106Sdes 906238106Sdes/** 907238106Sdes * Inser canonical owner name into buffer. 908238106Sdes * @param buf: buffer to insert into at current position. 909238106Sdes * @param k: rrset with its owner name. 910238106Sdes * @param sig: signature with signer name and label count. 911238106Sdes * must be length checked, at least 18 bytes long. 912238106Sdes * @param can_owner: position in buffer returned for future use. 913238106Sdes * @param can_owner_len: length of canonical owner name. 914238106Sdes */ 915238106Sdesstatic void 916269257Sdesinsert_can_owner(sldns_buffer* buf, struct ub_packed_rrset_key* k, 917238106Sdes uint8_t* sig, uint8_t** can_owner, size_t* can_owner_len) 918238106Sdes{ 919238106Sdes int rrsig_labels = (int)sig[3]; 920238106Sdes int fqdn_labels = dname_signame_label_count(k->rk.dname); 921269257Sdes *can_owner = sldns_buffer_current(buf); 922238106Sdes if(rrsig_labels == fqdn_labels) { 923238106Sdes /* no change */ 924269257Sdes sldns_buffer_write(buf, k->rk.dname, k->rk.dname_len); 925238106Sdes query_dname_tolower(*can_owner); 926238106Sdes *can_owner_len = k->rk.dname_len; 927238106Sdes return; 928238106Sdes } 929238106Sdes log_assert(rrsig_labels < fqdn_labels); 930238106Sdes /* *. | fqdn(rightmost rrsig_labels) */ 931238106Sdes if(rrsig_labels < fqdn_labels) { 932238106Sdes int i; 933238106Sdes uint8_t* nm = k->rk.dname; 934238106Sdes size_t len = k->rk.dname_len; 935238106Sdes /* so skip fqdn_labels-rrsig_labels */ 936238106Sdes for(i=0; i<fqdn_labels-rrsig_labels; i++) { 937238106Sdes dname_remove_label(&nm, &len); 938238106Sdes } 939238106Sdes *can_owner_len = len+2; 940269257Sdes sldns_buffer_write(buf, (uint8_t*)"\001*", 2); 941269257Sdes sldns_buffer_write(buf, nm, len); 942238106Sdes query_dname_tolower(*can_owner); 943238106Sdes } 944238106Sdes} 945238106Sdes 946238106Sdes/** 947238106Sdes * Canonicalize Rdata in buffer. 948238106Sdes * @param buf: buffer at position just after the rdata. 949238106Sdes * @param rrset: rrset with type. 950238106Sdes * @param len: length of the rdata (including rdatalen uint16). 951238106Sdes */ 952238106Sdesstatic void 953269257Sdescanonicalize_rdata(sldns_buffer* buf, struct ub_packed_rrset_key* rrset, 954238106Sdes size_t len) 955238106Sdes{ 956269257Sdes uint8_t* datstart = sldns_buffer_current(buf)-len+2; 957238106Sdes switch(ntohs(rrset->rk.type)) { 958238106Sdes case LDNS_RR_TYPE_NXT: 959238106Sdes case LDNS_RR_TYPE_NS: 960238106Sdes case LDNS_RR_TYPE_MD: 961238106Sdes case LDNS_RR_TYPE_MF: 962238106Sdes case LDNS_RR_TYPE_CNAME: 963238106Sdes case LDNS_RR_TYPE_MB: 964238106Sdes case LDNS_RR_TYPE_MG: 965238106Sdes case LDNS_RR_TYPE_MR: 966238106Sdes case LDNS_RR_TYPE_PTR: 967238106Sdes case LDNS_RR_TYPE_DNAME: 968238106Sdes /* type only has a single argument, the name */ 969238106Sdes query_dname_tolower(datstart); 970238106Sdes return; 971238106Sdes case LDNS_RR_TYPE_MINFO: 972238106Sdes case LDNS_RR_TYPE_RP: 973238106Sdes case LDNS_RR_TYPE_SOA: 974238106Sdes /* two names after another */ 975238106Sdes query_dname_tolower(datstart); 976238106Sdes query_dname_tolower(datstart + 977238106Sdes dname_valid(datstart, len-2)); 978238106Sdes return; 979238106Sdes case LDNS_RR_TYPE_RT: 980238106Sdes case LDNS_RR_TYPE_AFSDB: 981238106Sdes case LDNS_RR_TYPE_KX: 982238106Sdes case LDNS_RR_TYPE_MX: 983238106Sdes /* skip fixed part */ 984238106Sdes if(len < 2+2+1) /* rdlen, skiplen, 1byteroot */ 985238106Sdes return; 986238106Sdes datstart += 2; 987238106Sdes query_dname_tolower(datstart); 988238106Sdes return; 989238106Sdes case LDNS_RR_TYPE_SIG: 990238106Sdes /* downcase the RRSIG, compat with BIND (kept it from SIG) */ 991238106Sdes case LDNS_RR_TYPE_RRSIG: 992238106Sdes /* skip fixed part */ 993238106Sdes if(len < 2+18+1) 994238106Sdes return; 995238106Sdes datstart += 18; 996238106Sdes query_dname_tolower(datstart); 997238106Sdes return; 998238106Sdes case LDNS_RR_TYPE_PX: 999238106Sdes /* skip, then two names after another */ 1000238106Sdes if(len < 2+2+1) 1001238106Sdes return; 1002238106Sdes datstart += 2; 1003238106Sdes query_dname_tolower(datstart); 1004238106Sdes query_dname_tolower(datstart + 1005238106Sdes dname_valid(datstart, len-2-2)); 1006238106Sdes return; 1007238106Sdes case LDNS_RR_TYPE_NAPTR: 1008238106Sdes if(len < 2+4) 1009238106Sdes return; 1010238106Sdes len -= 2+4; 1011238106Sdes datstart += 4; 1012238106Sdes if(len < (size_t)datstart[0]+1) /* skip text field */ 1013238106Sdes return; 1014238106Sdes len -= (size_t)datstart[0]+1; 1015238106Sdes datstart += (size_t)datstart[0]+1; 1016238106Sdes if(len < (size_t)datstart[0]+1) /* skip text field */ 1017238106Sdes return; 1018238106Sdes len -= (size_t)datstart[0]+1; 1019238106Sdes datstart += (size_t)datstart[0]+1; 1020238106Sdes if(len < (size_t)datstart[0]+1) /* skip text field */ 1021238106Sdes return; 1022238106Sdes len -= (size_t)datstart[0]+1; 1023238106Sdes datstart += (size_t)datstart[0]+1; 1024238106Sdes if(len < 1) /* check name is at least 1 byte*/ 1025238106Sdes return; 1026238106Sdes query_dname_tolower(datstart); 1027238106Sdes return; 1028238106Sdes case LDNS_RR_TYPE_SRV: 1029238106Sdes /* skip fixed part */ 1030238106Sdes if(len < 2+6+1) 1031238106Sdes return; 1032238106Sdes datstart += 6; 1033238106Sdes query_dname_tolower(datstart); 1034238106Sdes return; 1035238106Sdes 1036238106Sdes /* do not canonicalize NSEC rdata name, compat with 1037238106Sdes * from bind 9.4 signer, where it does not do so */ 1038238106Sdes case LDNS_RR_TYPE_NSEC: /* type starts with the name */ 1039238106Sdes case LDNS_RR_TYPE_HINFO: /* not downcased */ 1040238106Sdes /* A6 not supported */ 1041238106Sdes default: 1042238106Sdes /* nothing to do for unknown types */ 1043238106Sdes return; 1044238106Sdes } 1045238106Sdes} 1046238106Sdes 1047269257Sdesint rrset_canonical_equal(struct regional* region, 1048269257Sdes struct ub_packed_rrset_key* k1, struct ub_packed_rrset_key* k2) 1049269257Sdes{ 1050269257Sdes struct rbtree_t sortree1, sortree2; 1051269257Sdes struct canon_rr *rrs1, *rrs2, *p1, *p2; 1052269257Sdes struct packed_rrset_data* d1=(struct packed_rrset_data*)k1->entry.data; 1053269257Sdes struct packed_rrset_data* d2=(struct packed_rrset_data*)k2->entry.data; 1054269257Sdes struct ub_packed_rrset_key fk; 1055269257Sdes struct packed_rrset_data fd; 1056269257Sdes size_t flen[2]; 1057269257Sdes uint8_t* fdata[2]; 1058269257Sdes 1059269257Sdes /* basic compare */ 1060269257Sdes if(k1->rk.dname_len != k2->rk.dname_len || 1061269257Sdes k1->rk.flags != k2->rk.flags || 1062269257Sdes k1->rk.type != k2->rk.type || 1063269257Sdes k1->rk.rrset_class != k2->rk.rrset_class || 1064269257Sdes query_dname_compare(k1->rk.dname, k2->rk.dname) != 0) 1065269257Sdes return 0; 1066269257Sdes if(d1->ttl != d2->ttl || 1067269257Sdes d1->count != d2->count || 1068269257Sdes d1->rrsig_count != d2->rrsig_count || 1069269257Sdes d1->trust != d2->trust || 1070269257Sdes d1->security != d2->security) 1071269257Sdes return 0; 1072269257Sdes 1073269257Sdes /* init */ 1074269257Sdes memset(&fk, 0, sizeof(fk)); 1075269257Sdes memset(&fd, 0, sizeof(fd)); 1076269257Sdes fk.entry.data = &fd; 1077269257Sdes fd.count = 2; 1078269257Sdes fd.rr_len = flen; 1079269257Sdes fd.rr_data = fdata; 1080269257Sdes rbtree_init(&sortree1, &canonical_tree_compare); 1081269257Sdes rbtree_init(&sortree2, &canonical_tree_compare); 1082269257Sdes rrs1 = regional_alloc(region, sizeof(struct canon_rr)*d1->count); 1083269257Sdes rrs2 = regional_alloc(region, sizeof(struct canon_rr)*d2->count); 1084269257Sdes if(!rrs1 || !rrs2) return 1; /* alloc failure */ 1085269257Sdes 1086269257Sdes /* sort */ 1087269257Sdes canonical_sort(k1, d1, &sortree1, rrs1); 1088269257Sdes canonical_sort(k2, d2, &sortree2, rrs2); 1089269257Sdes 1090269257Sdes /* compare canonical-sorted RRs for canonical-equality */ 1091269257Sdes if(sortree1.count != sortree2.count) 1092269257Sdes return 0; 1093269257Sdes p1 = (struct canon_rr*)rbtree_first(&sortree1); 1094269257Sdes p2 = (struct canon_rr*)rbtree_first(&sortree2); 1095269257Sdes while(p1 != (struct canon_rr*)RBTREE_NULL && 1096269257Sdes p2 != (struct canon_rr*)RBTREE_NULL) { 1097269257Sdes flen[0] = d1->rr_len[p1->rr_idx]; 1098269257Sdes flen[1] = d2->rr_len[p2->rr_idx]; 1099269257Sdes fdata[0] = d1->rr_data[p1->rr_idx]; 1100269257Sdes fdata[1] = d2->rr_data[p2->rr_idx]; 1101269257Sdes 1102269257Sdes if(canonical_compare(&fk, 0, 1) != 0) 1103269257Sdes return 0; 1104269257Sdes p1 = (struct canon_rr*)rbtree_next(&p1->node); 1105269257Sdes p2 = (struct canon_rr*)rbtree_next(&p2->node); 1106269257Sdes } 1107269257Sdes return 1; 1108269257Sdes} 1109269257Sdes 1110238106Sdes/** 1111238106Sdes * Create canonical form of rrset in the scratch buffer. 1112238106Sdes * @param region: temporary region. 1113238106Sdes * @param buf: the buffer to use. 1114238106Sdes * @param k: the rrset to insert. 1115238106Sdes * @param sig: RRSIG rdata to include. 1116238106Sdes * @param siglen: RRSIG rdata len excluding signature field, but inclusive 1117238106Sdes * signer name length. 1118238106Sdes * @param sortree: if NULL is passed a new sorted rrset tree is built. 1119238106Sdes * Otherwise it is reused. 1120238106Sdes * @return false on alloc error. 1121238106Sdes */ 1122238106Sdesstatic int 1123269257Sdesrrset_canonical(struct regional* region, sldns_buffer* buf, 1124238106Sdes struct ub_packed_rrset_key* k, uint8_t* sig, size_t siglen, 1125238106Sdes struct rbtree_t** sortree) 1126238106Sdes{ 1127238106Sdes struct packed_rrset_data* d = (struct packed_rrset_data*)k->entry.data; 1128238106Sdes uint8_t* can_owner = NULL; 1129238106Sdes size_t can_owner_len = 0; 1130238106Sdes struct canon_rr* walk; 1131238106Sdes struct canon_rr* rrs; 1132238106Sdes 1133238106Sdes if(!*sortree) { 1134238106Sdes *sortree = (struct rbtree_t*)regional_alloc(region, 1135238106Sdes sizeof(rbtree_t)); 1136238106Sdes if(!*sortree) 1137238106Sdes return 0; 1138238106Sdes rrs = regional_alloc(region, sizeof(struct canon_rr)*d->count); 1139238106Sdes if(!rrs) { 1140238106Sdes *sortree = NULL; 1141238106Sdes return 0; 1142238106Sdes } 1143238106Sdes rbtree_init(*sortree, &canonical_tree_compare); 1144238106Sdes canonical_sort(k, d, *sortree, rrs); 1145238106Sdes } 1146238106Sdes 1147269257Sdes sldns_buffer_clear(buf); 1148269257Sdes sldns_buffer_write(buf, sig, siglen); 1149238106Sdes /* canonicalize signer name */ 1150269257Sdes query_dname_tolower(sldns_buffer_begin(buf)+18); 1151238106Sdes RBTREE_FOR(walk, struct canon_rr*, (*sortree)) { 1152238106Sdes /* see if there is enough space left in the buffer */ 1153269257Sdes if(sldns_buffer_remaining(buf) < can_owner_len + 2 + 2 + 4 1154238106Sdes + d->rr_len[walk->rr_idx]) { 1155238106Sdes log_err("verify: failed to canonicalize, " 1156238106Sdes "rrset too big"); 1157238106Sdes return 0; 1158238106Sdes } 1159238106Sdes /* determine canonical owner name */ 1160238106Sdes if(can_owner) 1161269257Sdes sldns_buffer_write(buf, can_owner, can_owner_len); 1162238106Sdes else insert_can_owner(buf, k, sig, &can_owner, 1163238106Sdes &can_owner_len); 1164269257Sdes sldns_buffer_write(buf, &k->rk.type, 2); 1165269257Sdes sldns_buffer_write(buf, &k->rk.rrset_class, 2); 1166269257Sdes sldns_buffer_write(buf, sig+4, 4); 1167269257Sdes sldns_buffer_write(buf, d->rr_data[walk->rr_idx], 1168238106Sdes d->rr_len[walk->rr_idx]); 1169238106Sdes canonicalize_rdata(buf, k, d->rr_len[walk->rr_idx]); 1170238106Sdes } 1171269257Sdes sldns_buffer_flip(buf); 1172238106Sdes return 1; 1173238106Sdes} 1174238106Sdes 1175238106Sdes/** pretty print rrsig error with dates */ 1176238106Sdesstatic void 1177238106Sdessigdate_error(const char* str, int32_t expi, int32_t incep, int32_t now) 1178238106Sdes{ 1179238106Sdes struct tm tm; 1180238106Sdes char expi_buf[16]; 1181238106Sdes char incep_buf[16]; 1182238106Sdes char now_buf[16]; 1183238106Sdes time_t te, ti, tn; 1184238106Sdes 1185238106Sdes if(verbosity < VERB_QUERY) 1186238106Sdes return; 1187238106Sdes te = (time_t)expi; 1188238106Sdes ti = (time_t)incep; 1189238106Sdes tn = (time_t)now; 1190238106Sdes memset(&tm, 0, sizeof(tm)); 1191238106Sdes if(gmtime_r(&te, &tm) && strftime(expi_buf, 15, "%Y%m%d%H%M%S", &tm) 1192238106Sdes &&gmtime_r(&ti, &tm) && strftime(incep_buf, 15, "%Y%m%d%H%M%S", &tm) 1193238106Sdes &&gmtime_r(&tn, &tm) && strftime(now_buf, 15, "%Y%m%d%H%M%S", &tm)) { 1194238106Sdes log_info("%s expi=%s incep=%s now=%s", str, expi_buf, 1195238106Sdes incep_buf, now_buf); 1196238106Sdes } else 1197238106Sdes log_info("%s expi=%u incep=%u now=%u", str, (unsigned)expi, 1198238106Sdes (unsigned)incep, (unsigned)now); 1199238106Sdes} 1200238106Sdes 1201238106Sdes/** check rrsig dates */ 1202238106Sdesstatic int 1203238106Sdescheck_dates(struct val_env* ve, uint32_t unow, 1204238106Sdes uint8_t* expi_p, uint8_t* incep_p, char** reason) 1205238106Sdes{ 1206238106Sdes /* read out the dates */ 1207238106Sdes int32_t expi, incep, now; 1208238106Sdes memmove(&expi, expi_p, sizeof(expi)); 1209238106Sdes memmove(&incep, incep_p, sizeof(incep)); 1210238106Sdes expi = ntohl(expi); 1211238106Sdes incep = ntohl(incep); 1212238106Sdes 1213238106Sdes /* get current date */ 1214238106Sdes if(ve->date_override) { 1215238106Sdes if(ve->date_override == -1) { 1216238106Sdes verbose(VERB_ALGO, "date override: ignore date"); 1217238106Sdes return 1; 1218238106Sdes } 1219238106Sdes now = ve->date_override; 1220238106Sdes verbose(VERB_ALGO, "date override option %d", (int)now); 1221238106Sdes } else now = (int32_t)unow; 1222238106Sdes 1223238106Sdes /* check them */ 1224238106Sdes if(incep - expi > 0) { 1225238106Sdes sigdate_error("verify: inception after expiration, " 1226238106Sdes "signature bad", expi, incep, now); 1227238106Sdes *reason = "signature inception after expiration"; 1228238106Sdes return 0; 1229238106Sdes } 1230238106Sdes if(incep - now > 0) { 1231238106Sdes /* within skew ? (calc here to avoid calculation normally) */ 1232238106Sdes int32_t skew = (expi-incep)/10; 1233238106Sdes if(skew < ve->skew_min) skew = ve->skew_min; 1234238106Sdes if(skew > ve->skew_max) skew = ve->skew_max; 1235238106Sdes if(incep - now > skew) { 1236238106Sdes sigdate_error("verify: signature bad, current time is" 1237238106Sdes " before inception date", expi, incep, now); 1238238106Sdes *reason = "signature before inception date"; 1239238106Sdes return 0; 1240238106Sdes } 1241238106Sdes sigdate_error("verify warning suspicious signature inception " 1242238106Sdes " or bad local clock", expi, incep, now); 1243238106Sdes } 1244238106Sdes if(now - expi > 0) { 1245238106Sdes int32_t skew = (expi-incep)/10; 1246238106Sdes if(skew < ve->skew_min) skew = ve->skew_min; 1247238106Sdes if(skew > ve->skew_max) skew = ve->skew_max; 1248238106Sdes if(now - expi > skew) { 1249238106Sdes sigdate_error("verify: signature expired", expi, 1250238106Sdes incep, now); 1251238106Sdes *reason = "signature expired"; 1252238106Sdes return 0; 1253238106Sdes } 1254238106Sdes sigdate_error("verify warning suspicious signature expiration " 1255238106Sdes " or bad local clock", expi, incep, now); 1256238106Sdes } 1257238106Sdes return 1; 1258238106Sdes} 1259238106Sdes 1260238106Sdes/** adjust rrset TTL for verified rrset, compare to original TTL and expi */ 1261238106Sdesstatic void 1262238106Sdesadjust_ttl(struct val_env* ve, uint32_t unow, 1263238106Sdes struct ub_packed_rrset_key* rrset, uint8_t* orig_p, 1264238106Sdes uint8_t* expi_p, uint8_t* incep_p) 1265238106Sdes{ 1266238106Sdes struct packed_rrset_data* d = 1267238106Sdes (struct packed_rrset_data*)rrset->entry.data; 1268238106Sdes /* read out the dates */ 1269238106Sdes int32_t origttl, expittl, expi, incep, now; 1270238106Sdes memmove(&origttl, orig_p, sizeof(origttl)); 1271238106Sdes memmove(&expi, expi_p, sizeof(expi)); 1272238106Sdes memmove(&incep, incep_p, sizeof(incep)); 1273238106Sdes expi = ntohl(expi); 1274238106Sdes incep = ntohl(incep); 1275238106Sdes origttl = ntohl(origttl); 1276238106Sdes 1277238106Sdes /* get current date */ 1278238106Sdes if(ve->date_override) { 1279238106Sdes now = ve->date_override; 1280238106Sdes } else now = (int32_t)unow; 1281238106Sdes expittl = expi - now; 1282238106Sdes 1283238106Sdes /* so now: 1284238106Sdes * d->ttl: rrset ttl read from message or cache. May be reduced 1285238106Sdes * origttl: original TTL from signature, authoritative TTL max. 1286238106Sdes * expittl: TTL until the signature expires. 1287238106Sdes * 1288238106Sdes * Use the smallest of these. 1289238106Sdes */ 1290269257Sdes if(d->ttl > (time_t)origttl) { 1291238106Sdes verbose(VERB_QUERY, "rrset TTL larger than original TTL," 1292238106Sdes " adjusting TTL downwards"); 1293238106Sdes d->ttl = origttl; 1294238106Sdes } 1295269257Sdes if(expittl > 0 && d->ttl > (time_t)expittl) { 1296238106Sdes verbose(VERB_ALGO, "rrset TTL larger than sig expiration ttl," 1297238106Sdes " adjusting TTL downwards"); 1298238106Sdes d->ttl = expittl; 1299238106Sdes } 1300238106Sdes} 1301238106Sdes 1302238106Sdesenum sec_status 1303269257Sdesdnskey_verify_rrset_sig(struct regional* region, sldns_buffer* buf, 1304269257Sdes struct val_env* ve, time_t now, 1305238106Sdes struct ub_packed_rrset_key* rrset, struct ub_packed_rrset_key* dnskey, 1306238106Sdes size_t dnskey_idx, size_t sig_idx, 1307238106Sdes struct rbtree_t** sortree, int* buf_canon, char** reason) 1308238106Sdes{ 1309238106Sdes enum sec_status sec; 1310238106Sdes uint8_t* sig; /* RRSIG rdata */ 1311238106Sdes size_t siglen; 1312238106Sdes size_t rrnum = rrset_get_count(rrset); 1313238106Sdes uint8_t* signer; /* rrsig signer name */ 1314238106Sdes size_t signer_len; 1315238106Sdes unsigned char* sigblock; /* signature rdata field */ 1316238106Sdes unsigned int sigblock_len; 1317238106Sdes uint16_t ktag; /* DNSKEY key tag */ 1318238106Sdes unsigned char* key; /* public key rdata field */ 1319238106Sdes unsigned int keylen; 1320238106Sdes rrset_get_rdata(rrset, rrnum + sig_idx, &sig, &siglen); 1321238106Sdes /* min length of rdatalen, fixed rrsig, root signer, 1 byte sig */ 1322238106Sdes if(siglen < 2+20) { 1323238106Sdes verbose(VERB_QUERY, "verify: signature too short"); 1324238106Sdes *reason = "signature too short"; 1325238106Sdes return sec_status_bogus; 1326238106Sdes } 1327238106Sdes 1328238106Sdes if(!(dnskey_get_flags(dnskey, dnskey_idx) & DNSKEY_BIT_ZSK)) { 1329238106Sdes verbose(VERB_QUERY, "verify: dnskey without ZSK flag"); 1330238106Sdes *reason = "dnskey without ZSK flag"; 1331238106Sdes return sec_status_bogus; 1332238106Sdes } 1333238106Sdes 1334238106Sdes if(dnskey_get_protocol(dnskey, dnskey_idx) != LDNS_DNSSEC_KEYPROTO) { 1335238106Sdes /* RFC 4034 says DNSKEY PROTOCOL MUST be 3 */ 1336238106Sdes verbose(VERB_QUERY, "verify: dnskey has wrong key protocol"); 1337238106Sdes *reason = "dnskey has wrong protocolnumber"; 1338238106Sdes return sec_status_bogus; 1339238106Sdes } 1340238106Sdes 1341238106Sdes /* verify as many fields in rrsig as possible */ 1342238106Sdes signer = sig+2+18; 1343238106Sdes signer_len = dname_valid(signer, siglen-2-18); 1344238106Sdes if(!signer_len) { 1345238106Sdes verbose(VERB_QUERY, "verify: malformed signer name"); 1346238106Sdes *reason = "signer name malformed"; 1347238106Sdes return sec_status_bogus; /* signer name invalid */ 1348238106Sdes } 1349238106Sdes if(!dname_subdomain_c(rrset->rk.dname, signer)) { 1350238106Sdes verbose(VERB_QUERY, "verify: signer name is off-tree"); 1351238106Sdes *reason = "signer name off-tree"; 1352238106Sdes return sec_status_bogus; /* signer name offtree */ 1353238106Sdes } 1354238106Sdes sigblock = (unsigned char*)signer+signer_len; 1355238106Sdes if(siglen < 2+18+signer_len+1) { 1356238106Sdes verbose(VERB_QUERY, "verify: too short, no signature data"); 1357238106Sdes *reason = "signature too short, no signature data"; 1358238106Sdes return sec_status_bogus; /* sig rdf is < 1 byte */ 1359238106Sdes } 1360238106Sdes sigblock_len = (unsigned int)(siglen - 2 - 18 - signer_len); 1361238106Sdes 1362238106Sdes /* verify key dname == sig signer name */ 1363238106Sdes if(query_dname_compare(signer, dnskey->rk.dname) != 0) { 1364238106Sdes verbose(VERB_QUERY, "verify: wrong key for rrsig"); 1365238106Sdes log_nametypeclass(VERB_QUERY, "RRSIG signername is", 1366238106Sdes signer, 0, 0); 1367238106Sdes log_nametypeclass(VERB_QUERY, "the key name is", 1368238106Sdes dnskey->rk.dname, 0, 0); 1369238106Sdes *reason = "signer name mismatches key name"; 1370238106Sdes return sec_status_bogus; 1371238106Sdes } 1372238106Sdes 1373238106Sdes /* verify covered type */ 1374238106Sdes /* memcmp works because type is in network format for rrset */ 1375238106Sdes if(memcmp(sig+2, &rrset->rk.type, 2) != 0) { 1376238106Sdes verbose(VERB_QUERY, "verify: wrong type covered"); 1377238106Sdes *reason = "signature covers wrong type"; 1378238106Sdes return sec_status_bogus; 1379238106Sdes } 1380238106Sdes /* verify keytag and sig algo (possibly again) */ 1381238106Sdes if((int)sig[2+2] != dnskey_get_algo(dnskey, dnskey_idx)) { 1382238106Sdes verbose(VERB_QUERY, "verify: wrong algorithm"); 1383238106Sdes *reason = "signature has wrong algorithm"; 1384238106Sdes return sec_status_bogus; 1385238106Sdes } 1386238106Sdes ktag = htons(dnskey_calc_keytag(dnskey, dnskey_idx)); 1387238106Sdes if(memcmp(sig+2+16, &ktag, 2) != 0) { 1388238106Sdes verbose(VERB_QUERY, "verify: wrong keytag"); 1389238106Sdes *reason = "signature has wrong keytag"; 1390238106Sdes return sec_status_bogus; 1391238106Sdes } 1392238106Sdes 1393238106Sdes /* verify labels is in a valid range */ 1394238106Sdes if((int)sig[2+3] > dname_signame_label_count(rrset->rk.dname)) { 1395238106Sdes verbose(VERB_QUERY, "verify: labelcount out of range"); 1396238106Sdes *reason = "signature labelcount out of range"; 1397238106Sdes return sec_status_bogus; 1398238106Sdes } 1399238106Sdes 1400238106Sdes /* original ttl, always ok */ 1401238106Sdes 1402238106Sdes if(!*buf_canon) { 1403238106Sdes /* create rrset canonical format in buffer, ready for 1404238106Sdes * signature */ 1405238106Sdes if(!rrset_canonical(region, buf, rrset, sig+2, 1406238106Sdes 18 + signer_len, sortree)) { 1407238106Sdes log_err("verify: failed due to alloc error"); 1408238106Sdes return sec_status_unchecked; 1409238106Sdes } 1410238106Sdes *buf_canon = 1; 1411238106Sdes } 1412238106Sdes 1413238106Sdes /* check that dnskey is available */ 1414238106Sdes dnskey_get_pubkey(dnskey, dnskey_idx, &key, &keylen); 1415238106Sdes if(!key) { 1416238106Sdes verbose(VERB_QUERY, "verify: short DNSKEY RR"); 1417238106Sdes return sec_status_unchecked; 1418238106Sdes } 1419238106Sdes 1420238106Sdes /* verify */ 1421238106Sdes sec = verify_canonrrset(buf, (int)sig[2+2], 1422238106Sdes sigblock, sigblock_len, key, keylen, reason); 1423238106Sdes 1424238106Sdes if(sec == sec_status_secure) { 1425238106Sdes /* check if TTL is too high - reduce if so */ 1426238106Sdes adjust_ttl(ve, now, rrset, sig+2+4, sig+2+8, sig+2+12); 1427238106Sdes 1428238106Sdes /* verify inception, expiration dates 1429238106Sdes * Do this last so that if you ignore expired-sigs the 1430238106Sdes * rest is sure to be OK. */ 1431238106Sdes if(!check_dates(ve, now, sig+2+8, sig+2+12, reason)) { 1432238106Sdes return sec_status_bogus; 1433238106Sdes } 1434238106Sdes } 1435238106Sdes 1436238106Sdes return sec; 1437238106Sdes} 1438