From: Petr Mensik Date: Fri, 8 Apr 2022 10:15:14 +0000 (+0200) Subject: Make SHA-1 signed domains insecure if openssl refuses the digest X-Git-Tag: release-1.16.1rc1~8^2~2 X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=6cfcf214516b93622602684be5c3036bc1e3df1e;p=thirdparty%2Funbound.git Make SHA-1 signed domains insecure if openssl refuses the digest RHEL9/CentOS 9 would fail in default crypto policy. If call to openssl returns invalid digest then report the name insecure. If all tested signatures return the same issue, then make the reply insecure. --- diff --git a/validator/val_secalgo.c b/validator/val_secalgo.c index 7abf66f01..eaef8586e 100644 --- a/validator/val_secalgo.c +++ b/validator/val_secalgo.c @@ -652,6 +652,33 @@ setup_key_digest(int algo, EVP_PKEY** evp_key, const EVP_MD** digest_type, return 1; } +static void +digest_ctx_free(EVP_MD_CTX* ctx, EVP_PKEY *evp_key, + unsigned char* sigblock, int dofree, int docrypto_free) +{ +#ifdef HAVE_EVP_MD_CTX_NEW + EVP_MD_CTX_destroy(ctx); +#else + EVP_MD_CTX_cleanup(ctx); + free(ctx); +#endif + EVP_PKEY_free(evp_key); + if(dofree) free(sigblock); + else if(docrypto_free) OPENSSL_free(sigblock); +} + +static enum sec_status +digest_error_status(void) +{ +#ifdef EVP_R_INVALID_DIGEST + unsigned long e = ERR_get_error(); + if (ERR_GET_LIB(e) == ERR_LIB_EVP && + ERR_GET_REASON(e) == EVP_R_INVALID_DIGEST) + return sec_status_indeterminate; +#endif + return sec_status_unchecked; +} + /** * Check a canonical sig+rrset and signature against a dnskey * @param buf: buffer with data to verify, the first rrsig part and the @@ -735,62 +762,35 @@ verify_canonrrset(sldns_buffer* buf, int algo, unsigned char* sigblock, } #ifndef HAVE_EVP_DIGESTVERIFY if(EVP_DigestInit(ctx, digest_type) == 0) { + enum sec_status sec = digest_error_status(); verbose(VERB_QUERY, "verify: EVP_DigestInit failed"); -#ifdef HAVE_EVP_MD_CTX_NEW - EVP_MD_CTX_destroy(ctx); -#else - EVP_MD_CTX_cleanup(ctx); - free(ctx); -#endif - EVP_PKEY_free(evp_key); - if(dofree) free(sigblock); - else if(docrypto_free) OPENSSL_free(sigblock); - return sec_status_unchecked; + digest_ctx_free(ctx, evp_key, sigblock, + dofree, docrypto_free); + return sec; } if(EVP_DigestUpdate(ctx, (unsigned char*)sldns_buffer_begin(buf), (unsigned int)sldns_buffer_limit(buf)) == 0) { verbose(VERB_QUERY, "verify: EVP_DigestUpdate failed"); -#ifdef HAVE_EVP_MD_CTX_NEW - EVP_MD_CTX_destroy(ctx); -#else - EVP_MD_CTX_cleanup(ctx); - free(ctx); -#endif - EVP_PKEY_free(evp_key); - if(dofree) free(sigblock); - else if(docrypto_free) OPENSSL_free(sigblock); + digest_ctx_free(ctx, evp_key, sigblock, + dofree, docrypto_free); return sec_status_unchecked; } res = EVP_VerifyFinal(ctx, sigblock, sigblock_len, evp_key); #else /* HAVE_EVP_DIGESTVERIFY */ if(EVP_DigestVerifyInit(ctx, NULL, digest_type, NULL, evp_key) == 0) { + enum sec_status sec = digest_error_status(); verbose(VERB_QUERY, "verify: EVP_DigestVerifyInit failed"); -#ifdef HAVE_EVP_MD_CTX_NEW - EVP_MD_CTX_destroy(ctx); -#else - EVP_MD_CTX_cleanup(ctx); - free(ctx); -#endif - EVP_PKEY_free(evp_key); - if(dofree) free(sigblock); - else if(docrypto_free) OPENSSL_free(sigblock); - return sec_status_unchecked; + digest_ctx_free(ctx, evp_key, sigblock, + dofree, docrypto_free); + return sec; } res = EVP_DigestVerify(ctx, sigblock, sigblock_len, (unsigned char*)sldns_buffer_begin(buf), sldns_buffer_limit(buf)); #endif -#ifdef HAVE_EVP_MD_CTX_NEW - EVP_MD_CTX_destroy(ctx); -#else - EVP_MD_CTX_cleanup(ctx); - free(ctx); -#endif - EVP_PKEY_free(evp_key); - - if(dofree) free(sigblock); - else if(docrypto_free) OPENSSL_free(sigblock); + digest_ctx_free(ctx, evp_key, sigblock, + dofree, docrypto_free); if(res == 1) { return sec_status_secure; diff --git a/validator/val_sigcrypt.c b/validator/val_sigcrypt.c index b15fba3f4..240156d01 100644 --- a/validator/val_sigcrypt.c +++ b/validator/val_sigcrypt.c @@ -646,6 +646,7 @@ dnskeyset_verify_rrset_sig(struct module_env* env, struct val_env* ve, int algo = rrset_get_sig_algo(rrset, sig_idx); size_t i, num = rrset_get_count(dnskey); size_t numchecked = 0; + size_t numindeterminate = 0; int buf_canon = 0; verbose(VERB_ALGO, "verify sig %d %d", (int)tag, algo); if(!dnskey_algo_id_is_supported(algo)) { @@ -666,12 +667,16 @@ dnskeyset_verify_rrset_sig(struct module_env* env, struct val_env* ve, sig_idx, sortree, &buf_canon, reason, section, qstate); if(sec == sec_status_secure) return sec; + else if(sec == sec_status_indeterminate) + numindeterminate ++; } if(numchecked == 0) { *reason = "signatures from unknown keys"; verbose(VERB_QUERY, "verify: could not find appropriate key"); return sec_status_bogus; } + if (numindeterminate == numchecked) + return sec_status_indeterminate; return sec_status_bogus; }