diff options
Diffstat (limited to 'external/unbound/validator')
-rw-r--r-- | external/unbound/validator/autotrust.c | 10 | ||||
-rw-r--r-- | external/unbound/validator/val_neg.c | 2 | ||||
-rw-r--r-- | external/unbound/validator/val_neg.h | 2 | ||||
-rw-r--r-- | external/unbound/validator/val_nsec.c | 28 | ||||
-rw-r--r-- | external/unbound/validator/val_nsec.h | 6 | ||||
-rw-r--r-- | external/unbound/validator/val_nsec3.c | 136 | ||||
-rw-r--r-- | external/unbound/validator/val_nsec3.h | 6 | ||||
-rw-r--r-- | external/unbound/validator/val_secalgo.c | 520 | ||||
-rw-r--r-- | external/unbound/validator/val_secalgo.h | 15 | ||||
-rw-r--r-- | external/unbound/validator/val_sigcrypt.c | 6 | ||||
-rw-r--r-- | external/unbound/validator/val_utils.h | 2 | ||||
-rw-r--r-- | external/unbound/validator/validator.c | 6 |
12 files changed, 620 insertions, 119 deletions
diff --git a/external/unbound/validator/autotrust.c b/external/unbound/validator/autotrust.c index e63b086e6..f8c9c8c63 100644 --- a/external/unbound/validator/autotrust.c +++ b/external/unbound/validator/autotrust.c @@ -1195,6 +1195,14 @@ void autr_write_file(struct module_env* env, struct trust_anchor* tp) fatal_exit("could not completely write: %s", fname); return; } + if(fflush(out) != 0) + log_err("could not fflush(%s): %s", fname, strerror(errno)); +#ifdef HAVE_FSYNC + if(fsync(fileno(out)) != 0) + log_err("could not fsync(%s): %s", fname, strerror(errno)); +#else + FlushFileBuffers((HANDLE)_fileno(out)); +#endif if(fclose(out) != 0) { fatal_exit("could not complete write: %s: %s", fname, strerror(errno)); @@ -2162,7 +2170,7 @@ int autr_process_prime(struct module_env* env, struct val_env* ve, if(!verify_dnskey(env, ve, tp, dnskey_rrset)) { verbose(VERB_ALGO, "autotrust: dnskey did not verify."); /* only increase failure count if this is not the first prime, - * this means there was a previous succesful probe */ + * this means there was a previous successful probe */ if(tp->autr->last_success) { tp->autr->query_failed += 1; autr_write_file(env, tp); diff --git a/external/unbound/validator/val_neg.c b/external/unbound/validator/val_neg.c index b1ff8d9a1..ab31f483e 100644 --- a/external/unbound/validator/val_neg.c +++ b/external/unbound/validator/val_neg.c @@ -38,7 +38,7 @@ * * This file contains helper functions for the validator module. * The functions help with aggressive negative caching. - * This creates new denials of existance, and proofs for absence of types + * This creates new denials of existence, and proofs for absence of types * from cached NSEC records. */ #include "config.h" diff --git a/external/unbound/validator/val_neg.h b/external/unbound/validator/val_neg.h index 967d1a70f..bf3a2471c 100644 --- a/external/unbound/validator/val_neg.h +++ b/external/unbound/validator/val_neg.h @@ -38,7 +38,7 @@ * * This file contains helper functions for the validator module. * The functions help with aggressive negative caching. - * This creates new denials of existance, and proofs for absence of types + * This creates new denials of existence, and proofs for absence of types * from cached NSEC records. */ diff --git a/external/unbound/validator/val_nsec.c b/external/unbound/validator/val_nsec.c index bdfe3c8fa..f104a347c 100644 --- a/external/unbound/validator/val_nsec.c +++ b/external/unbound/validator/val_nsec.c @@ -1,5 +1,5 @@ /* - * validator/val_nsec.c - validator NSEC denial of existance functions. + * validator/val_nsec.c - validator NSEC denial of existence functions. * * Copyright (c) 2007, NLnet Labs. All rights reserved. * @@ -38,7 +38,7 @@ * * This file contains helper functions for the validator module. * The functions help with NSEC checking, the different NSEC proofs - * for denial of existance, and proofs for presence of types. + * for denial of existence, and proofs for presence of types. */ #include "config.h" #include "validator/val_nsec.h" @@ -279,7 +279,7 @@ val_nsec_prove_nodata_dsreply(struct module_env* env, struct val_env* ve, return sec_status_insecure; } - /* NSEC proof did not conlusively point to DS or no DS */ + /* NSEC proof did not conclusively point to DS or no DS */ return sec_status_unchecked; } @@ -340,6 +340,28 @@ int nsec_proves_nodata(struct ub_packed_rrset_key* nsec, *wc = ce; return 1; } + } else { + /* See if the next owner name covers a wildcard + * empty non-terminal. */ + while (dname_strict_subdomain_c(nm, nsec->rk.dname)) { + /* wildcard does not apply if qname below + * the name that exists under the '*' */ + if (dname_subdomain_c(qinfo->qname, nm)) + break; + /* but if it is a wildcard and qname is below + * it, then the wildcard applies. The wildcard + * is an empty nonterminal. nodata proven. */ + if (dname_is_wild(nm)) { + size_t ce_len = ln; + uint8_t* ce = nm; + dname_remove_label(&ce, &ce_len); + if(dname_strict_subdomain_c(qinfo->qname, ce)) { + *wc = ce; + return 1; + } + } + dname_remove_label(&nm, &ln); + } } /* Otherwise, this NSEC does not prove ENT and is not a diff --git a/external/unbound/validator/val_nsec.h b/external/unbound/validator/val_nsec.h index f680d08c0..c031c9a3b 100644 --- a/external/unbound/validator/val_nsec.h +++ b/external/unbound/validator/val_nsec.h @@ -1,5 +1,5 @@ /* - * validator/val_nsec.h - validator NSEC denial of existance functions. + * validator/val_nsec.h - validator NSEC denial of existence functions. * * Copyright (c) 2007, NLnet Labs. All rights reserved. * @@ -38,7 +38,7 @@ * * This file contains helper functions for the validator module. * The functions help with NSEC checking, the different NSEC proofs - * for denial of existance, and proofs for presence of types. + * for denial of existence, and proofs for presence of types. */ #ifndef VALIDATOR_VAL_NSEC_H @@ -54,7 +54,7 @@ struct key_entry_key; /** * Check DS absence. * There is a NODATA reply to a DS that needs checking. - * NSECs can prove this is not a delegation point, or sucessfully prove + * NSECs can prove this is not a delegation point, or successfully prove * that there is no DS. Or this fails. * * @param env: module env for rrsig verification routines. diff --git a/external/unbound/validator/val_nsec3.c b/external/unbound/validator/val_nsec3.c index 80ca4d0ba..22867d170 100644 --- a/external/unbound/validator/val_nsec3.c +++ b/external/unbound/validator/val_nsec3.c @@ -1,5 +1,5 @@ /* - * validator/val_nsec3.c - validator NSEC3 denial of existance functions. + * validator/val_nsec3.c - validator NSEC3 denial of existence functions. * * Copyright (c) 2007, NLnet Labs. All rights reserved. * @@ -38,18 +38,12 @@ * * This file contains helper functions for the validator module. * The functions help with NSEC3 checking, the different NSEC3 proofs - * for denial of existance, and proofs for presence of types. + * for denial of existence, and proofs for presence of types. */ #include "config.h" #include <ctype.h> -#ifdef HAVE_OPENSSL_SSL_H -#include "openssl/ssl.h" -#endif -#ifdef HAVE_NSS -/* nss3 */ -#include "sechash.h" -#endif #include "validator/val_nsec3.h" +#include "validator/val_secalgo.h" #include "validator/validator.h" #include "validator/val_kentry.h" #include "services/cache/rrset.h" @@ -370,8 +364,8 @@ filter_next(struct nsec3_filter* filter, size_t* rrsetnum, int* rrnum) /** * Start iterating over NSEC3 records. * @param filter: the filter structure, must have been filter_init-ed. - * @param rrsetnum: can be undefined on call, inited. - * @param rrnum: can be undefined on call, inited. + * @param rrsetnum: can be undefined on call, initialised. + * @param rrnum: can be undefined on call, initialised. * @return first rrset of an NSEC3, together with rrnum this points to * the first RR to examine. Is NULL on empty list. */ @@ -545,46 +539,24 @@ nsec3_get_hashed(sldns_buffer* buf, uint8_t* nm, size_t nmlen, int algo, query_dname_tolower(sldns_buffer_begin(buf)); sldns_buffer_write(buf, salt, saltlen); sldns_buffer_flip(buf); - switch(algo) { -#if defined(HAVE_EVP_SHA1) || defined(HAVE_NSS) - case NSEC3_HASH_SHA1: -#ifdef HAVE_SSL - hash_len = SHA_DIGEST_LENGTH; -#else - hash_len = SHA1_LENGTH; -#endif - if(hash_len > max) - return 0; -# ifdef HAVE_SSL - (void)SHA1((unsigned char*)sldns_buffer_begin(buf), - (unsigned long)sldns_buffer_limit(buf), - (unsigned char*)res); -# else - (void)HASH_HashBuf(HASH_AlgSHA1, (unsigned char*)res, - (unsigned char*)sldns_buffer_begin(buf), - (unsigned long)sldns_buffer_limit(buf)); -# endif - for(i=0; i<iter; i++) { - sldns_buffer_clear(buf); - sldns_buffer_write(buf, res, hash_len); - sldns_buffer_write(buf, salt, saltlen); - sldns_buffer_flip(buf); -# ifdef HAVE_SSL - (void)SHA1( - (unsigned char*)sldns_buffer_begin(buf), - (unsigned long)sldns_buffer_limit(buf), - (unsigned char*)res); -# else - (void)HASH_HashBuf(HASH_AlgSHA1, - (unsigned char*)res, - (unsigned char*)sldns_buffer_begin(buf), - (unsigned long)sldns_buffer_limit(buf)); -# endif - } - break; -#endif /* HAVE_EVP_SHA1 or NSS */ - default: - log_err("nsec3 hash of unknown algo %d", algo); + hash_len = nsec3_hash_algo_size_supported(algo); + if(hash_len == 0) { + log_err("nsec3 hash of unknown algo %d", algo); + return 0; + } + if(hash_len > max) + return 0; + if(!secalgo_nsec3_hash(algo, (unsigned char*)sldns_buffer_begin(buf), + sldns_buffer_limit(buf), (unsigned char*)res)) + return 0; + for(i=0; i<iter; i++) { + sldns_buffer_clear(buf); + sldns_buffer_write(buf, res, hash_len); + sldns_buffer_write(buf, salt, saltlen); + sldns_buffer_flip(buf); + if(!secalgo_nsec3_hash(algo, + (unsigned char*)sldns_buffer_begin(buf), + sldns_buffer_limit(buf), (unsigned char*)res)) return 0; } return hash_len; @@ -607,50 +579,24 @@ nsec3_calc_hash(struct regional* region, sldns_buffer* buf, query_dname_tolower(sldns_buffer_begin(buf)); sldns_buffer_write(buf, salt, saltlen); sldns_buffer_flip(buf); - switch(algo) { -#if defined(HAVE_EVP_SHA1) || defined(HAVE_NSS) - case NSEC3_HASH_SHA1: -#ifdef HAVE_SSL - c->hash_len = SHA_DIGEST_LENGTH; -#else - c->hash_len = SHA1_LENGTH; -#endif - c->hash = (uint8_t*)regional_alloc(region, - c->hash_len); - if(!c->hash) - return 0; -# ifdef HAVE_SSL - (void)SHA1((unsigned char*)sldns_buffer_begin(buf), - (unsigned long)sldns_buffer_limit(buf), - (unsigned char*)c->hash); -# else - (void)HASH_HashBuf(HASH_AlgSHA1, - (unsigned char*)c->hash, - (unsigned char*)sldns_buffer_begin(buf), - (unsigned long)sldns_buffer_limit(buf)); -# endif - for(i=0; i<iter; i++) { - sldns_buffer_clear(buf); - sldns_buffer_write(buf, c->hash, c->hash_len); - sldns_buffer_write(buf, salt, saltlen); - sldns_buffer_flip(buf); -# ifdef HAVE_SSL - (void)SHA1( - (unsigned char*)sldns_buffer_begin(buf), - (unsigned long)sldns_buffer_limit(buf), - (unsigned char*)c->hash); -# else - (void)HASH_HashBuf(HASH_AlgSHA1, - (unsigned char*)c->hash, - (unsigned char*)sldns_buffer_begin(buf), - (unsigned long)sldns_buffer_limit(buf)); -# endif - } - break; -#endif /* HAVE_EVP_SHA1 or NSS */ - default: - log_err("nsec3 hash of unknown algo %d", algo); - return -1; + c->hash_len = nsec3_hash_algo_size_supported(algo); + if(c->hash_len == 0) { + log_err("nsec3 hash of unknown algo %d", algo); + return -1; + } + c->hash = (uint8_t*)regional_alloc(region, c->hash_len); + if(!c->hash) + return 0; + (void)secalgo_nsec3_hash(algo, (unsigned char*)sldns_buffer_begin(buf), + sldns_buffer_limit(buf), (unsigned char*)c->hash); + for(i=0; i<iter; i++) { + sldns_buffer_clear(buf); + sldns_buffer_write(buf, c->hash, c->hash_len); + sldns_buffer_write(buf, salt, saltlen); + sldns_buffer_flip(buf); + (void)secalgo_nsec3_hash(algo, + (unsigned char*)sldns_buffer_begin(buf), + sldns_buffer_limit(buf), (unsigned char*)c->hash); } return 1; } diff --git a/external/unbound/validator/val_nsec3.h b/external/unbound/validator/val_nsec3.h index d619d672d..69ba78d83 100644 --- a/external/unbound/validator/val_nsec3.h +++ b/external/unbound/validator/val_nsec3.h @@ -1,5 +1,5 @@ /* - * validator/val_nsec3.h - validator NSEC3 denial of existance functions. + * validator/val_nsec3.h - validator NSEC3 denial of existence functions. * * Copyright (c) 2007, NLnet Labs. All rights reserved. * @@ -38,7 +38,7 @@ * * This file contains helper functions for the validator module. * The functions help with NSEC3 checking, the different NSEC3 proofs - * for denial of existance, and proofs for presence of types. + * for denial of existence, and proofs for presence of types. * * NSEC3 * 1 1 1 1 1 1 1 1 1 1 2 2 2 2 2 2 2 2 2 2 3 3 @@ -256,7 +256,7 @@ int nsec3_hash_cmp(const void* c1, const void* c2); * Used internally by the nsec3 proof functions in this file. * published to enable unit testing of hash algorithms and cache. * - * @param table: the cache table. Must be inited at start. + * @param table: the cache table. Must be initialised at start. * @param region: scratch region to use for allocation. * This region holds the tree, if you wipe the region, reinit the tree. * @param buf: temporary buffer. diff --git a/external/unbound/validator/val_secalgo.c b/external/unbound/validator/val_secalgo.c index 8ed403dfc..7c8d7b287 100644 --- a/external/unbound/validator/val_secalgo.c +++ b/external/unbound/validator/val_secalgo.c @@ -44,12 +44,13 @@ /* packed_rrset on top to define enum types (forced by c99 standard) */ #include "util/data/packed_rrset.h" #include "validator/val_secalgo.h" +#include "validator/val_nsec3.h" #include "util/log.h" #include "sldns/rrdef.h" #include "sldns/keyraw.h" #include "sldns/sbuffer.h" -#if !defined(HAVE_SSL) && !defined(HAVE_NSS) +#if !defined(HAVE_SSL) && !defined(HAVE_NSS) && !defined(HAVE_NETTLE) #error "Need crypto library to do digital signature cryptography" #endif @@ -71,10 +72,36 @@ #include <openssl/engine.h> #endif +/* return size of digest if supported, or 0 otherwise */ +size_t +nsec3_hash_algo_size_supported(int id) +{ + switch(id) { + case NSEC3_HASH_SHA1: + return SHA_DIGEST_LENGTH; + default: + return 0; + } +} + +/* perform nsec3 hash. return false on failure */ +int +secalgo_nsec3_hash(int algo, unsigned char* buf, size_t len, + unsigned char* res) +{ + switch(algo) { + case NSEC3_HASH_SHA1: + (void)SHA1(buf, len, res); + return 1; + default: + return 0; + } +} + /** * Return size of DS digest according to its hash algorithm. * @param algo: DS digest algo. - * @return size in bytes of digest, or 0 if not supported. + * @return size in bytes of digest, or 0 if not supported. */ size_t ds_digest_size_supported(int algo) @@ -565,6 +592,32 @@ verify_canonrrset(sldns_buffer* buf, int algo, unsigned char* sigblock, /* nspr4 */ #include "prerror.h" +/* return size of digest if supported, or 0 otherwise */ +size_t +nsec3_hash_algo_size_supported(int id) +{ + switch(id) { + case NSEC3_HASH_SHA1: + return SHA1_LENGTH; + default: + return 0; + } +} + +/* perform nsec3 hash. return false on failure */ +int +secalgo_nsec3_hash(int algo, unsigned char* buf, size_t len, + unsigned char* res) +{ + switch(algo) { + case NSEC3_HASH_SHA1: + (void)HASH_HashBuf(HASH_AlgSHA1, res, buf, (unsigned long)len); + return 1; + default: + return 0; + } +} + size_t ds_digest_size_supported(int algo) { @@ -1069,5 +1122,466 @@ verify_canonrrset(sldns_buffer* buf, int algo, unsigned char* sigblock, return sec_status_bogus; } +#elif defined(HAVE_NETTLE) + +#include "sha.h" +#include "bignum.h" +#include "macros.h" +#include "rsa.h" +#include "dsa.h" +#include "asn1.h" +#ifdef USE_ECDSA +#include "ecdsa.h" +#include "ecc-curve.h" +#endif + +static int +_digest_nettle(int algo, uint8_t* buf, size_t len, + unsigned char* res) +{ + switch(algo) { + case SHA1_DIGEST_SIZE: + { + struct sha1_ctx ctx; + sha1_init(&ctx); + sha1_update(&ctx, len, buf); + sha1_digest(&ctx, SHA1_DIGEST_SIZE, res); + return 1; + } + case SHA256_DIGEST_SIZE: + { + struct sha256_ctx ctx; + sha256_init(&ctx); + sha256_update(&ctx, len, buf); + sha256_digest(&ctx, SHA256_DIGEST_SIZE, res); + return 1; + } + case SHA384_DIGEST_SIZE: + { + struct sha384_ctx ctx; + sha384_init(&ctx); + sha384_update(&ctx, len, buf); + sha384_digest(&ctx, SHA384_DIGEST_SIZE, res); + return 1; + } + case SHA512_DIGEST_SIZE: + { + struct sha512_ctx ctx; + sha512_init(&ctx); + sha512_update(&ctx, len, buf); + sha512_digest(&ctx, SHA512_DIGEST_SIZE, res); + return 1; + } + default: + break; + } + return 0; +} + +/* return size of digest if supported, or 0 otherwise */ +size_t +nsec3_hash_algo_size_supported(int id) +{ + switch(id) { + case NSEC3_HASH_SHA1: + return SHA1_DIGEST_SIZE; + default: + return 0; + } +} + +/* perform nsec3 hash. return false on failure */ +int +secalgo_nsec3_hash(int algo, unsigned char* buf, size_t len, + unsigned char* res) +{ + switch(algo) { + case NSEC3_HASH_SHA1: + return _digest_nettle(SHA1_DIGEST_SIZE, (uint8_t*)buf, len, + res); + default: + return 0; + } +} + +/** + * Return size of DS digest according to its hash algorithm. + * @param algo: DS digest algo. + * @return size in bytes of digest, or 0 if not supported. + */ +size_t +ds_digest_size_supported(int algo) +{ + switch(algo) { + case LDNS_SHA1: + return SHA1_DIGEST_SIZE; +#ifdef USE_SHA2 + case LDNS_SHA256: + return SHA256_DIGEST_SIZE; +#endif +#ifdef USE_ECDSA + case LDNS_SHA384: + return SHA384_DIGEST_SIZE; +#endif + /* GOST not supported */ + case LDNS_HASH_GOST: + default: + break; + } + return 0; +} + +int +secalgo_ds_digest(int algo, unsigned char* buf, size_t len, + unsigned char* res) +{ + switch(algo) { + case LDNS_SHA1: + return _digest_nettle(SHA1_DIGEST_SIZE, buf, len, res); +#if defined(USE_SHA2) + case LDNS_SHA256: + return _digest_nettle(SHA256_DIGEST_SIZE, buf, len, res); +#endif +#ifdef USE_ECDSA + case LDNS_SHA384: + return _digest_nettle(SHA384_DIGEST_SIZE, buf, len, res); + +#endif + case LDNS_HASH_GOST: + default: + verbose(VERB_QUERY, "unknown DS digest algorithm %d", + algo); + break; + } + return 0; +} + +int +dnskey_algo_id_is_supported(int id) +{ + /* uses libnettle */ + switch(id) { + case LDNS_DSA: + case LDNS_DSA_NSEC3: + case LDNS_RSASHA1: + case LDNS_RSASHA1_NSEC3: +#ifdef USE_SHA2 + case LDNS_RSASHA256: + case LDNS_RSASHA512: +#endif +#ifdef USE_ECDSA + case LDNS_ECDSAP256SHA256: + case LDNS_ECDSAP384SHA384: +#endif + return 1; + case LDNS_RSAMD5: /* RFC 6725 deprecates RSAMD5 */ + case LDNS_ECC_GOST: + default: + return 0; + } +} + +static char * +_verify_nettle_dsa(sldns_buffer* buf, unsigned char* sigblock, + unsigned int sigblock_len, unsigned char* key, unsigned int keylen) +{ + uint8_t digest[SHA1_DIGEST_SIZE]; + uint8_t key_t; + int res = 0; + size_t offset; + struct dsa_public_key pubkey; + struct dsa_signature signature; + unsigned int expected_len; + + /* Extract DSA signature from the record */ + nettle_dsa_signature_init(&signature); + /* Signature length: 41 bytes - RFC 2536 sec. 3 */ + if(sigblock_len == 41) { + if(key[0] != sigblock[0]) + return "invalid T value in DSA signature or pubkey"; + nettle_mpz_set_str_256_u(signature.r, 20, sigblock+1); + nettle_mpz_set_str_256_u(signature.s, 20, sigblock+1+20); + } else { + /* DER encoded, decode the ASN1 notated R and S bignums */ + /* SEQUENCE { r INTEGER, s INTEGER } */ + struct asn1_der_iterator i, seq; + if(asn1_der_iterator_first(&i, sigblock_len, + (uint8_t*)sigblock) != ASN1_ITERATOR_CONSTRUCTED + || i.type != ASN1_SEQUENCE) + return "malformed DER encoded DSA signature"; + /* decode this element of i using the seq iterator */ + if(asn1_der_decode_constructed(&i, &seq) != + ASN1_ITERATOR_PRIMITIVE || seq.type != ASN1_INTEGER) + return "malformed DER encoded DSA signature"; + if(!asn1_der_get_bignum(&seq, signature.r, 20*8)) + return "malformed DER encoded DSA signature"; + if(asn1_der_iterator_next(&seq) != ASN1_ITERATOR_PRIMITIVE + || seq.type != ASN1_INTEGER) + return "malformed DER encoded DSA signature"; + if(!asn1_der_get_bignum(&seq, signature.s, 20*8)) + return "malformed DER encoded DSA signature"; + if(asn1_der_iterator_next(&i) != ASN1_ITERATOR_END) + return "malformed DER encoded DSA signature"; + } + + /* Validate T values constraints - RFC 2536 sec. 2 & sec. 3 */ + key_t = key[0]; + if (key_t > 8) { + return "invalid T value in DSA pubkey"; + } + + /* Pubkey minimum length: 21 bytes - RFC 2536 sec. 2 */ + if (keylen < 21) { + return "DSA pubkey too short"; + } + + expected_len = 1 + /* T */ + 20 + /* Q */ + (64 + key_t*8) + /* P */ + (64 + key_t*8) + /* G */ + (64 + key_t*8); /* Y */ + if (keylen != expected_len ) { + return "invalid DSA pubkey length"; + } + + /* Extract DSA pubkey from the record */ + nettle_dsa_public_key_init(&pubkey); + offset = 1; + nettle_mpz_set_str_256_u(pubkey.q, 20, key+offset); + offset += 20; + nettle_mpz_set_str_256_u(pubkey.p, (64 + key_t*8), key+offset); + offset += (64 + key_t*8); + nettle_mpz_set_str_256_u(pubkey.g, (64 + key_t*8), key+offset); + offset += (64 + key_t*8); + nettle_mpz_set_str_256_u(pubkey.y, (64 + key_t*8), key+offset); + + /* Digest content of "buf" and verify its DSA signature in "sigblock"*/ + res = _digest_nettle(SHA1_DIGEST_SIZE, (unsigned char*)sldns_buffer_begin(buf), + (unsigned int)sldns_buffer_limit(buf), (unsigned char*)digest); + res &= dsa_sha1_verify_digest(&pubkey, digest, &signature); + + /* Clear and return */ + nettle_dsa_signature_clear(&signature); + nettle_dsa_public_key_clear(&pubkey); + if (!res) + return "DSA signature verification failed"; + else + return NULL; +} + +static char * +_verify_nettle_rsa(sldns_buffer* buf, unsigned int digest_size, char* sigblock, + unsigned int sigblock_len, uint8_t* key, unsigned int keylen) +{ + uint16_t exp_len = 0; + size_t exp_offset = 0, mod_offset = 0; + struct rsa_public_key pubkey; + mpz_t signature; + int res = 0; + + /* RSA pubkey parsing as per RFC 3110 sec. 2 */ + if( keylen <= 1) { + return "null RSA key"; + } + if (key[0] != 0) { + /* 1-byte length */ + exp_len = key[0]; + exp_offset = 1; + } else { + /* 1-byte NUL + 2-bytes exponent length */ + if (keylen < 3) { + return "incorrect RSA key length"; + } + exp_len = READ_UINT16(key+1); + if (exp_len == 0) + return "null RSA exponent length"; + exp_offset = 3; + } + /* Check that we are not over-running input length */ + if (keylen < exp_offset + exp_len + 1) { + return "RSA key content shorter than expected"; + } + mod_offset = exp_offset + exp_len; + nettle_rsa_public_key_init(&pubkey); + pubkey.size = keylen - mod_offset; + nettle_mpz_set_str_256_u(pubkey.e, exp_len, &key[exp_offset]); + nettle_mpz_set_str_256_u(pubkey.n, pubkey.size, &key[mod_offset]); + + /* Digest content of "buf" and verify its RSA signature in "sigblock"*/ + nettle_mpz_init_set_str_256_u(signature, sigblock_len, (uint8_t*)sigblock); + switch (digest_size) { + case SHA1_DIGEST_SIZE: + { + uint8_t digest[SHA1_DIGEST_SIZE]; + res = _digest_nettle(SHA1_DIGEST_SIZE, (unsigned char*)sldns_buffer_begin(buf), + (unsigned int)sldns_buffer_limit(buf), (unsigned char*)digest); + res &= rsa_sha1_verify_digest(&pubkey, digest, signature); + break; + } + case SHA256_DIGEST_SIZE: + { + uint8_t digest[SHA256_DIGEST_SIZE]; + res = _digest_nettle(SHA256_DIGEST_SIZE, (unsigned char*)sldns_buffer_begin(buf), + (unsigned int)sldns_buffer_limit(buf), (unsigned char*)digest); + res &= rsa_sha256_verify_digest(&pubkey, digest, signature); + break; + } + case SHA512_DIGEST_SIZE: + { + uint8_t digest[SHA512_DIGEST_SIZE]; + res = _digest_nettle(SHA512_DIGEST_SIZE, (unsigned char*)sldns_buffer_begin(buf), + (unsigned int)sldns_buffer_limit(buf), (unsigned char*)digest); + res &= rsa_sha512_verify_digest(&pubkey, digest, signature); + break; + } + default: + break; + } + + /* Clear and return */ + nettle_rsa_public_key_clear(&pubkey); + mpz_clear(signature); + if (!res) { + return "RSA signature verification failed"; + } else { + return NULL; + } +} + +#ifdef USE_ECDSA +static char * +_verify_nettle_ecdsa(sldns_buffer* buf, unsigned int digest_size, unsigned char* sigblock, + unsigned int sigblock_len, unsigned char* key, unsigned int keylen) +{ + int res = 0; + struct ecc_point pubkey; + struct dsa_signature signature; + + /* Always matched strength, as per RFC 6605 sec. 1 */ + if (sigblock_len != 2*digest_size || keylen != 2*digest_size) { + return "wrong ECDSA signature length"; + } + + /* Parse ECDSA signature as per RFC 6605 sec. 4 */ + nettle_dsa_signature_init(&signature); + switch (digest_size) { + case SHA256_DIGEST_SIZE: + { + uint8_t digest[SHA256_DIGEST_SIZE]; + mpz_t x, y; + nettle_ecc_point_init(&pubkey, &nettle_secp_256r1); + nettle_mpz_init_set_str_256_u(x, SHA256_DIGEST_SIZE, key); + nettle_mpz_init_set_str_256_u(y, SHA256_DIGEST_SIZE, key+SHA256_DIGEST_SIZE); + nettle_mpz_set_str_256_u(signature.r, SHA256_DIGEST_SIZE, sigblock); + nettle_mpz_set_str_256_u(signature.s, SHA256_DIGEST_SIZE, sigblock+SHA256_DIGEST_SIZE); + res = _digest_nettle(SHA256_DIGEST_SIZE, (unsigned char*)sldns_buffer_begin(buf), + (unsigned int)sldns_buffer_limit(buf), (unsigned char*)digest); + res &= nettle_ecc_point_set(&pubkey, x, y); + res &= nettle_ecdsa_verify (&pubkey, SHA256_DIGEST_SIZE, digest, &signature); + mpz_clear(x); + mpz_clear(y); + break; + } + case SHA384_DIGEST_SIZE: + { + uint8_t digest[SHA384_DIGEST_SIZE]; + mpz_t x, y; + nettle_ecc_point_init(&pubkey, &nettle_secp_384r1); + nettle_mpz_init_set_str_256_u(x, SHA384_DIGEST_SIZE, key); + nettle_mpz_init_set_str_256_u(y, SHA384_DIGEST_SIZE, key+SHA384_DIGEST_SIZE); + nettle_mpz_set_str_256_u(signature.r, SHA384_DIGEST_SIZE, sigblock); + nettle_mpz_set_str_256_u(signature.s, SHA384_DIGEST_SIZE, sigblock+SHA384_DIGEST_SIZE); + res = _digest_nettle(SHA384_DIGEST_SIZE, (unsigned char*)sldns_buffer_begin(buf), + (unsigned int)sldns_buffer_limit(buf), (unsigned char*)digest); + res &= nettle_ecc_point_set(&pubkey, x, y); + res &= nettle_ecdsa_verify (&pubkey, SHA384_DIGEST_SIZE, digest, &signature); + mpz_clear(x); + mpz_clear(y); + nettle_ecc_point_clear(&pubkey); + break; + } + default: + return "unknown ECDSA algorithm"; + } + + /* Clear and return */ + nettle_dsa_signature_clear(&signature); + if (!res) + return "ECDSA signature verification failed"; + else + return NULL; +} +#endif + +/** + * Check a canonical sig+rrset and signature against a dnskey + * @param buf: buffer with data to verify, the first rrsig part and the + * canonicalized rrset. + * @param algo: DNSKEY algorithm. + * @param sigblock: signature rdata field from RRSIG + * @param sigblock_len: length of sigblock data. + * @param key: public key data from DNSKEY RR. + * @param keylen: length of keydata. + * @param reason: bogus reason in more detail. + * @return secure if verification succeeded, bogus on crypto failure, + * unchecked on format errors and alloc failures. + */ +enum sec_status +verify_canonrrset(sldns_buffer* buf, int algo, unsigned char* sigblock, + unsigned int sigblock_len, unsigned char* key, unsigned int keylen, + char** reason) +{ + unsigned int digest_size = 0; + + if (sigblock_len == 0 || keylen == 0) { + *reason = "null signature"; + return sec_status_bogus; + } + + switch(algo) { + case LDNS_DSA: + case LDNS_DSA_NSEC3: + *reason = _verify_nettle_dsa(buf, sigblock, sigblock_len, key, keylen); + if (*reason != NULL) + return sec_status_bogus; + else + return sec_status_secure; + + case LDNS_RSASHA1: + case LDNS_RSASHA1_NSEC3: + digest_size = (digest_size ? digest_size : SHA1_DIGEST_SIZE); +#ifdef USE_SHA2 + case LDNS_RSASHA256: + digest_size = (digest_size ? digest_size : SHA256_DIGEST_SIZE); + case LDNS_RSASHA512: + digest_size = (digest_size ? digest_size : SHA512_DIGEST_SIZE); + +#endif + *reason = _verify_nettle_rsa(buf, digest_size, (char*)sigblock, + sigblock_len, key, keylen); + if (*reason != NULL) + return sec_status_bogus; + else + return sec_status_secure; + +#ifdef USE_ECDSA + case LDNS_ECDSAP256SHA256: + digest_size = (digest_size ? digest_size : SHA256_DIGEST_SIZE); + case LDNS_ECDSAP384SHA384: + digest_size = (digest_size ? digest_size : SHA384_DIGEST_SIZE); + *reason = _verify_nettle_ecdsa(buf, digest_size, sigblock, + sigblock_len, key, keylen); + if (*reason != NULL) + return sec_status_bogus; + else + return sec_status_secure; +#endif + case LDNS_RSAMD5: + case LDNS_ECC_GOST: + default: + *reason = "unable to verify signature, unknown algorithm"; + return sec_status_bogus; + } +} -#endif /* HAVE_SSL or HAVE_NSS */ +#endif /* HAVE_SSL or HAVE_NSS or HAVE_NETTLE */ diff --git a/external/unbound/validator/val_secalgo.h b/external/unbound/validator/val_secalgo.h index 085fbc5a4..589f1f11d 100644 --- a/external/unbound/validator/val_secalgo.h +++ b/external/unbound/validator/val_secalgo.h @@ -44,6 +44,21 @@ #define VALIDATOR_VAL_SECALGO_H struct sldns_buffer; +/** Return size of nsec3 hash algorithm, 0 if not supported */ +size_t nsec3_hash_algo_size_supported(int id); + +/** + * Hash a single hash call of an NSEC3 hash algorithm. + * Iterations and salt are done by the caller. + * @param algo: nsec3 hash algorithm. + * @param buf: the buffer to digest + * @param len: length of buffer to digest. + * @param res: result stored here (must have sufficient space). + * @return false on failure. +*/ +int secalgo_nsec3_hash(int algo, unsigned char* buf, size_t len, + unsigned char* res); + /** * Return size of DS digest according to its hash algorithm. * @param algo: DS digest algo. diff --git a/external/unbound/validator/val_sigcrypt.c b/external/unbound/validator/val_sigcrypt.c index 7c643cab1..1dd07b420 100644 --- a/external/unbound/validator/val_sigcrypt.c +++ b/external/unbound/validator/val_sigcrypt.c @@ -57,7 +57,7 @@ #include "sldns/wire2str.h" #include <ctype.h> -#if !defined(HAVE_SSL) && !defined(HAVE_NSS) +#if !defined(HAVE_SSL) && !defined(HAVE_NSS) && !defined(HAVE_NETTLE) #error "Need crypto library to do digital signature cryptography" #endif @@ -795,10 +795,6 @@ canonical_compare(struct ub_packed_rrset_key* rrset, size_t i, size_t j) if(i==j) return 0; - /* in case rdata-len is to be compared for canonical order - c = memcmp(d->rr_data[i], d->rr_data[j], 2); - if(c != 0) - return c; */ switch(type) { /* These RR types have only a name as RDATA. diff --git a/external/unbound/validator/val_utils.h b/external/unbound/validator/val_utils.h index cdb87697e..051824aba 100644 --- a/external/unbound/validator/val_utils.h +++ b/external/unbound/validator/val_utils.h @@ -391,7 +391,7 @@ int val_favorite_ds_algo(struct ub_packed_rrset_key* ds_rrset); * Find DS denial message in cache. Saves new qstate allocation and allows * the validator to use partial content which is not enough to construct a * message for network (or user) consumption. Without SOA for example, - * which is a common occurence in the unbound code since the referrals contain + * which is a common occurrence in the unbound code since the referrals contain * NSEC/NSEC3 rrs without the SOA element, thus do not allow synthesis of a * full negative reply, but do allow synthesis of sufficient proof. * @param env: query env with caches and time. diff --git a/external/unbound/validator/validator.c b/external/unbound/validator/validator.c index f8b429e52..db4383bed 100644 --- a/external/unbound/validator/validator.c +++ b/external/unbound/validator/validator.c @@ -749,7 +749,7 @@ validate_nodata_response(struct module_env* env, struct val_env* ve, /* Since we are here, there must be nothing in the ANSWER section to * validate. */ /* (Note: CNAME/DNAME responses will not directly get here -- - * instead, they are chased down into indiviual CNAME validations, + * instead, they are chased down into individual CNAME validations, * and at the end of the cname chain a POSITIVE, or CNAME_NOANSWER * validation.) */ @@ -1597,7 +1597,7 @@ processFindKey(struct module_qstate* qstate, struct val_qstate* vq, int id) target_key_name) != 0) { /* check if there is a cache entry : pick up an NSEC if * there is no DS, check if that NSEC has DS-bit unset, and - * thus can disprove the secure delagation we seek. + * thus can disprove the secure delegation we seek. * We can then use that NSEC even in the absence of a SOA * record that would be required by the iterator to supply * a completely protocol-correct response. @@ -1829,7 +1829,7 @@ processValidate(struct module_qstate* qstate, struct val_qstate* vq, * @return true if there is no DLV. * false: processing is finished for the validator operate(). * This function may exit in three ways: - * o no DLV (agressive cache), so insecure. (true) + * o no DLV (aggressive cache), so insecure. (true) * o error - stop processing (false) * o DLV lookup was started, stop processing (false) */ |