]> git.ipfire.org Git - thirdparty/unbound.git/commitdiff
Make SHA-1 signed domains insecure if openssl refuses the digest
authorPetr Mensik <pemensik@redhat.com>
Fri, 8 Apr 2022 10:15:14 +0000 (12:15 +0200)
committerPetr Mensik <pemensik@redhat.com>
Fri, 8 Apr 2022 14:26:50 +0000 (16:26 +0200)
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.

validator/val_secalgo.c
validator/val_sigcrypt.c

index 7abf66f01d2a177e7ae3559286e5bd9d31239fb6..eaef8586e0e32a79c0fd68e825ca8519dc53b358 100644 (file)
@@ -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;
index b15fba3f499d44951b5cea0d65392cc42afe4940..240156d014ce1791d8a9aa9ed392ecde35d0de3a 100644 (file)
@@ -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;
 }