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