Repository: randombit/botan
Pull request #3325 (2023-02-25 18:11:41)

Add PK_Verifier::hash_function, remove X509_Object::hash_used_for_signature
Further push on #3227



Patch:
diff --git a/src/lib/prov/pkcs11/p11_ecdsa.cpp b/src/lib/prov/pkcs11/p11_ecdsa.cpp
index f6661e40d..ae5d9d32e 100644
--- a/src/lib/prov/pkcs11/p11_ecdsa.cpp
+++ b/src/lib/prov/pkcs11/p11_ecdsa.cpp
@@ -131,8 +131,10 @@ AlgorithmIdentifier PKCS11_ECDSA_Signature_Operation::algorithm_identifier() con
 class PKCS11_ECDSA_Verification_Operation final : public PK_Ops::Verification
    {
    public:
-      PKCS11_ECDSA_Verification_Operation(const PKCS11_EC_PublicKey& key, const std::string& emsa)
-         : PK_Ops::Verification(), m_key(key), m_order(key.domain().get_order()), m_mechanism(MechanismWrapper::create_ecdsa_mechanism(emsa))
+      PKCS11_ECDSA_Verification_Operation(const PKCS11_EC_PublicKey& key, const std::string& hash)
+         : PK_Ops::Verification(), m_key(key), m_order(key.domain().get_order()),
+           m_mechanism(MechanismWrapper::create_ecdsa_mechanism(hash)),
+           m_hash(hash)
          {}
 
       void update(const uint8_t msg[], size_t msg_len) override
@@ -183,10 +185,13 @@ class PKCS11_ECDSA_Verification_Operation final : public PK_Ops::Verification
          return return_value == ReturnValue::OK;
          }
 
+      std::string hash_function() const override { return m_hash; }
+
    private:
       const PKCS11_EC_PublicKey& m_key;
       const BigInt& m_order;
       MechanismWrapper m_mechanism;
+      const std::string m_hash;
       secure_vector<uint8_t> m_first_message;
       bool m_initialized = false;
    };
diff --git a/src/lib/prov/pkcs11/p11_rsa.cpp b/src/lib/prov/pkcs11/p11_rsa.cpp
index 49bf3ba9f..d4d3919c2 100644
--- a/src/lib/prov/pkcs11/p11_rsa.cpp
+++ b/src/lib/prov/pkcs11/p11_rsa.cpp
@@ -294,9 +294,11 @@ class PKCS11_RSA_Signature_Operation final : public PK_Ops::Signature
       MechanismWrapper m_mechanism;
    };
 
-std::string PKCS11_RSA_Signature_Operation::hash_function() const
+namespace {
+
+std::string hash_function_name_from_pkcs11_rsa_mechanism_type(MechanismType type)
    {
-   switch(m_mechanism.mechanism_type())
+   switch(type)
       {
       case MechanismType::Sha1RsaPkcs:
       case MechanismType::Sha1RsaPkcsPss:
@@ -330,6 +332,13 @@ std::string PKCS11_RSA_Signature_Operation::hash_function() const
       }
    }
 
+}
+
+std::string PKCS11_RSA_Signature_Operation::hash_function() const
+   {
+   return hash_function_name_from_pkcs11_rsa_mechanism_type(m_mechanism.mechanism_type());
+   }
+
 AlgorithmIdentifier PKCS11_RSA_Signature_Operation::algorithm_identifier() const
    {
    const std::string hash = this->hash_function();
@@ -411,6 +420,8 @@ class PKCS11_RSA_Verification_Operation final : public PK_Ops::Verification
          return return_value == ReturnValue::OK;
          }
 
+      std::string hash_function() const override;
+
    private:
       const PKCS11_RSA_PublicKey& m_key;
       bool m_initialized = false;
@@ -418,6 +429,11 @@ class PKCS11_RSA_Verification_Operation final : public PK_Ops::Verification
       MechanismWrapper m_mechanism;
    };
 
+std::string PKCS11_RSA_Verification_Operation::hash_function() const
+   {
+   return hash_function_name_from_pkcs11_rsa_mechanism_type(m_mechanism.mechanism_type());
+   }
+
 }
 
 std::unique_ptr<PK_Ops::Encryption>
diff --git a/src/lib/pubkey/dilithium/dilithium_common/dilithium.cpp b/src/lib/pubkey/dilithium/dilithium_common/dilithium.cpp
index 463b8f17a..8ebdaa317 100644
--- a/src/lib/pubkey/dilithium/dilithium_common/dilithium.cpp
+++ b/src/lib/pubkey/dilithium/dilithium_common/dilithium.cpp
@@ -588,6 +588,8 @@ class Dilithium_Verification_Operation final : public PK_Ops::Verification
          return std::equal(c.begin(), c.end(), c2.begin());
          }
 
+      std::string hash_function() const override { return "SHAKE-256(512)"; }
+
    private:
       const Dilithium_PublicKey& m_pub_key;
       SHAKE_256 m_shake;
diff --git a/src/lib/pubkey/eckcdsa/eckcdsa.cpp b/src/lib/pubkey/eckcdsa/eckcdsa.cpp
index 7dc86077f..96404b1e7 100644
--- a/src/lib/pubkey/eckcdsa/eckcdsa.cpp
+++ b/src/lib/pubkey/eckcdsa/eckcdsa.cpp
@@ -205,6 +205,9 @@ class ECKCDSA_Verification_Operation final : public PK_Ops::Verification
       void update(const uint8_t msg[], size_t msg_len) override;
 
       bool is_valid_signature(const uint8_t sig[], size_t sig_len) override;
+
+      std::string hash_function() const override { return m_hash->name(); }
+
    private:
       bool verify(const uint8_t msg[], size_t msg_len,
                   const uint8_t sig[], size_t sig_len);
diff --git a/src/lib/pubkey/ed25519/ed25519_key.cpp b/src/lib/pubkey/ed25519/ed25519_key.cpp
index de440a1f4..be5a4e3be 100644
--- a/src/lib/pubkey/ed25519/ed25519_key.cpp
+++ b/src/lib/pubkey/ed25519/ed25519_key.cpp
@@ -166,6 +166,8 @@ class Ed25519_Pure_Verify_Operation final : public PK_Ops::Verification
          return ok;
          }
 
+      std::string hash_function() const override { return "SHA-512"; }
+
    private:
       std::vector<uint8_t> m_msg;
       const Ed25519_PublicKey& m_key;
@@ -208,6 +210,8 @@ class Ed25519_Hashed_Verify_Operation final : public PK_Ops::Verification
          return ed25519_verify(msg_hash.data(), msg_hash.size(), sig, pub_key.data(), m_domain_sep.data(), m_domain_sep.size());
          }
 
+      std::string hash_function() const override { return m_hash->name(); }
+
    private:
       std::unique_ptr<HashFunction> m_hash;
       const Ed25519_PublicKey& m_key;
diff --git a/src/lib/pubkey/pk_keys.h b/src/lib/pubkey/pk_keys.h
index 7f14d2d81..f5ca35325 100644
--- a/src/lib/pubkey/pk_keys.h
+++ b/src/lib/pubkey/pk_keys.h
@@ -198,7 +198,7 @@ class BOTAN_PUBLIC_API(2,0) Public_Key : public virtual Asymmetric_Key
 
       /**
       * This is an internal library function exposed on key types.
-      * In almost all cases applications should use wrappers in pubkey.h
+      * In all cases applications should use wrappers in pubkey.h
       *
       * Return a verification operation for this key/params or throw
       * @param params additional parameters
@@ -255,7 +255,7 @@ class BOTAN_PUBLIC_API(2,0) Private_Key : public virtual Public_Key
 
       /**
       * This is an internal library function exposed on key types.
-      * In almost all cases applications should use wrappers in pubkey.h
+      * In all cases applications should use wrappers in pubkey.h
       *
       * Return an decryption operation for this key/params or throw
       *
@@ -273,7 +273,7 @@ class BOTAN_PUBLIC_API(2,0) Private_Key : public virtual Public_Key
 
       /**
       * This is an internal library function exposed on key types.
-      * In almost all cases applications should use wrappers in pubkey.h
+      * In all cases applications should use wrappers in pubkey.h
       *
       * Return a KEM decryption operation for this key/params or throw
       *
@@ -290,7 +290,7 @@ class BOTAN_PUBLIC_API(2,0) Private_Key : public virtual Public_Key
 
       /**
       * This is an internal library function exposed on key types.
-      * In almost all cases applications should use wrappers in pubkey.h
+      * In all cases applications should use wrappers in pubkey.h
       *
       * Return a signature operation for this key/params or throw
       *
@@ -307,7 +307,7 @@ class BOTAN_PUBLIC_API(2,0) Private_Key : public virtual Public_Key
 
       /**
       * This is an internal library function exposed on key types.
-      * In almost all cases applications should use wrappers in pubkey.h
+      * In all cases applications should use wrappers in pubkey.h
       *
       * Return a key agreement operation for this key/params or throw
       *
diff --git a/src/lib/pubkey/pk_ops.h b/src/lib/pubkey/pk_ops.h
index eda5f9194..3640603b7 100644
--- a/src/lib/pubkey/pk_ops.h
+++ b/src/lib/pubkey/pk_ops.h
@@ -80,6 +80,11 @@ class Verification
       */
       virtual bool is_valid_signature(const uint8_t sig[], size_t sig_len) = 0;
 
+      /**
+      * Return the hash function being used by this signer
+      */
+      virtual std::string hash_function() const = 0;
+
       virtual ~Verification() = default;
    };
 
diff --git a/src/lib/pubkey/pk_ops_impl.h b/src/lib/pubkey/pk_ops_impl.h
index bf2127e57..c4e652062 100644
--- a/src/lib/pubkey/pk_ops_impl.h
+++ b/src/lib/pubkey/pk_ops_impl.h
@@ -58,6 +58,8 @@ class Verification_with_Hash : public Verification
       void update(const uint8_t msg[], size_t msg_len) override;
       bool is_valid_signature(const uint8_t sig[], size_t sig_len) override;
 
+      std::string hash_function() const override final { return m_hash->name(); }
+
    protected:
       explicit Verification_with_Hash(const std::string& hash);
 
diff --git a/src/lib/pubkey/pubkey.cpp b/src/lib/pubkey/pubkey.cpp
index 02a6814bc..07a619bc7 100644
--- a/src/lib/pubkey/pubkey.cpp
+++ b/src/lib/pubkey/pubkey.cpp
@@ -321,6 +321,11 @@ PK_Verifier::PK_Verifier(const Public_Key& key,
 
 PK_Verifier::~PK_Verifier() = default;
 
+std::string PK_Verifier::hash_function() const
+   {
+   return m_op->hash_function();
+   }
+
 void PK_Verifier::set_input_format(Signature_Format format)
    {
    check_der_format_supported(format, m_parts);
diff --git a/src/lib/pubkey/pubkey.h b/src/lib/pubkey/pubkey.h
index 5731c90e8..d2d4e9591 100644
--- a/src/lib/pubkey/pubkey.h
+++ b/src/lib/pubkey/pubkey.h
@@ -171,14 +171,13 @@ class BOTAN_PUBLIC_API(2,0) PK_Signer final
       * Construct a PK Signer.
       * @param key the key to use inside this signer
       * @param rng the random generator to use
-      * @param emsa the EMSA to use
-      * An example would be "EMSA1(SHA-224)".
+      * @param padding the padding/hash to use, eg "EMSA_PKCS1(SHA-256)"
       * @param format the signature format to use
       * @param provider the provider to use
       */
       PK_Signer(const Private_Key& key,
                 RandomNumberGenerator& rng,
-                const std::string& emsa,
+                const std::string& padding,
                 Signature_Format format = Signature_Format::Standard,
                 const std::string& provider = "");
 
@@ -301,12 +300,12 @@ class BOTAN_PUBLIC_API(2,0) PK_Verifier final
       /**
       * Construct a PK Verifier.
       * @param pub_key the public key to verify against
-      * @param emsa the EMSA to use (eg "EMSA3(SHA-1)")
+      * @param padding the padding/hash to use (eg "EMSA_PKCS1(SHA-256)")
       * @param format the signature format to use
       * @param provider the provider to use
       */
       PK_Verifier(const Public_Key& pub_key,
-                  const std::string& emsa,
+                  const std::string& padding,
                   Signature_Format format = Signature_Format::Standard,
                   const std::string& provider = "");
 
@@ -403,6 +402,14 @@ class BOTAN_PUBLIC_API(2,0) PK_Verifier final
       */
       void set_input_format(Signature_Format format);
 
+      /**
+      * Return the hash function which is being used to verify signatures.
+      * This should never return an empty string however it may return a string
+      * which does not map directly to a hash function, in particular if "Raw"
+      * (unhashed) encoding is being used.
+      */
+      std::string hash_function() const;
+
    private:
       std::unique_ptr<PK_Ops::Verification> m_op;
       Signature_Format m_sig_format;
diff --git a/src/lib/pubkey/rsa/rsa.cpp b/src/lib/pubkey/rsa/rsa.cpp
index e3e5fed83..1305fd282 100644
--- a/src/lib/pubkey/rsa/rsa.cpp
+++ b/src/lib/pubkey/rsa/rsa.cpp
@@ -677,6 +677,8 @@ class RSA_Verify_Operation final : public PK_Ops::Verification,
          {
          }
 
+      std::string hash_function() const override { return m_emsa->hash_function(); }
+
    private:
       secure_vector<uint8_t> recover_message_repr(const uint8_t input[], size_t input_len)
          {
diff --git a/src/lib/pubkey/sm2/sm2.cpp b/src/lib/pubkey/sm2/sm2.cpp
index 5b97a401a..0e585fa41 100644
--- a/src/lib/pubkey/sm2/sm2.cpp
+++ b/src/lib/pubkey/sm2/sm2.cpp
@@ -203,6 +203,8 @@ class SM2_Verification_Operation final : public PK_Ops::Verification
          }
 
       bool is_valid_signature(const uint8_t sig[], size_t sig_len) override;
+
+      std::string hash_function() const override { return m_hash->name(); }
    private:
       const EC_Group m_group;
       const EC_Point_Multi_Point_Precompute m_gy_mul;
diff --git a/src/lib/pubkey/xmss/xmss_verification_operation.h b/src/lib/pubkey/xmss/xmss_verification_operation.h
index 7ef6d83b2..9cc2c4d35 100644
--- a/src/lib/pubkey/xmss/xmss_verification_operation.h
+++ b/src/lib/pubkey/xmss/xmss_verification_operation.h
@@ -28,6 +28,7 @@ namespace Botan {
 
       void update(const uint8_t msg[], size_t msg_len) override;
 
+      std::string hash_function() const override { return m_hash.hash_function(); }
    private:
       /**
        * Algorithm 13: "XMSS_rootFromSig"
diff --git a/src/lib/x509/x509_obj.cpp b/src/lib/x509/x509_obj.cpp
index cc96ee029..ee1cef6e4 100644
--- a/src/lib/x509/x509_obj.cpp
+++ b/src/lib/x509/x509_obj.cpp
@@ -104,59 +104,23 @@ std::vector<uint8_t> X509_Object::tbs_data() const
    return ASN1::put_in_sequence(m_tbs_bits);
    }
 
-/*
-* Return the hash used in generating the signature
-*/
-std::string X509_Object::hash_used_for_signature() const
-   {
-   const OID& oid = m_sig_algo.oid();
-   const std::vector<std::string> sig_info = split_on(oid.to_formatted_string(), '/');
-
-   if(sig_info.size() == 1)
-      {
-      if(sig_info[0] == "Ed25519")
-         return "SHA-512";
-      else if(sig_info[0].starts_with("Dilithium-"))
-         return "SHAKE-256(512)";
-      }
-   else if(sig_info.size() != 2)
-      throw Internal_Error("Invalid name format found for " + oid.to_string());
-
-   if(sig_info[1] == "EMSA4")
-      {
-      PSS_Params pss_params(signature_algorithm().parameters());
-      return pss_params.hash_function();
-      }
-   else
-      {
-      const std::vector<std::string> pad_and_hash =
-         parse_algorithm_name(sig_info[1]);
-
-      if(pad_and_hash.size() != 2)
-         {
-         throw Internal_Error("Invalid name format " + sig_info[1]);
-         }
-
-      return pad_and_hash[1];
-      }
-   }
-
 /*
 * Check the signature on an object
 */
 bool X509_Object::check_signature(const Public_Key& pub_key) const
    {
-   const Certificate_Status_Code code = verify_signature(pub_key);
-   return (code == Certificate_Status_Code::VERIFIED);
+   const auto result = this->verify_signature(pub_key);
+   return (result.first == Certificate_Status_Code::VERIFIED);
    }
 
-Certificate_Status_Code X509_Object::verify_signature(const Public_Key& pub_key) const
+std::pair<Certificate_Status_Code, std::string>
+X509_Object::verify_signature(const Public_Key& pub_key) const
    {
    const std::vector<std::string> sig_info =
       split_on(m_sig_algo.oid().to_formatted_string(), '/');
 
    if(sig_info.empty() || sig_info.size() > 2 || sig_info[0] != pub_key.algo_name())
-      return Certificate_Status_Code::SIGNATURE_ALGO_BAD_PARAMS;
+      return std::make_pair(Certificate_Status_Code::SIGNATURE_ALGO_BAD_PARAMS, "");
 
    const auto& pub_key_algo = sig_info[0];
    std::string padding;
@@ -165,7 +129,7 @@ Certificate_Status_Code X509_Object::verify_signature(const Public_Key& pub_key)
    else if(pub_key_algo == "Ed25519" || pub_key_algo == "XMSS" || pub_key_algo.starts_with("Dilithium-"))
       padding = "Pure";
    else
-      return Certificate_Status_Code::SIGNATURE_ALGO_BAD_PARAMS;
+      return std::make_pair(Certificate_Status_Code::SIGNATURE_ALGO_BAD_PARAMS, "");
 
    const Signature_Format format = pub_key.default_x509_signature_format();
 
@@ -174,7 +138,7 @@ Certificate_Status_Code X509_Object::verify_signature(const Public_Key& pub_key)
       // "MUST contain RSASSA-PSS-params"
       if(signature_algorithm().parameters().empty())
          {
-         return Certificate_Status_Code::SIGNATURE_ALGO_BAD_PARAMS;
+         return std::make_pair(Certificate_Status_Code::SIGNATURE_ALGO_BAD_PARAMS, "");
          }
 
       PSS_Params pss_params(signature_algorithm().parameters());
@@ -187,12 +151,12 @@ Certificate_Status_Code X509_Object::verify_signature(const Public_Key& pub_key)
          hash_algo != "SHA-384" &&
          hash_algo != "SHA-512")
          {
-         return Certificate_Status_Code::UNTRUSTED_HASH;
+         return std::make_pair(Certificate_Status_Code::UNTRUSTED_HASH, "");
          }
 
       if(pss_params.mgf_function() != "MGF1")
          {
-         return Certificate_Status_Code::SIGNATURE_ALGO_BAD_PARAMS;
+         return std::make_pair(Certificate_Status_Code::SIGNATURE_ALGO_BAD_PARAMS, "");
          }
 
       // For MGF1, it is strongly RECOMMENDED that the underlying hash
@@ -201,12 +165,12 @@ Certificate_Status_Code X509_Object::verify_signature(const Public_Key& pub_key)
       // Must be SHA1, SHA2-224, SHA2-256, SHA2-384 or SHA2-512
       if(pss_params.hash_algid() != pss_params.mgf_hash_algid())
          {
-         return Certificate_Status_Code::SIGNATURE_ALGO_BAD_PARAMS;
+         return std::make_pair(Certificate_Status_Code::SIGNATURE_ALGO_BAD_PARAMS, "");
          }
 
       if(pss_params.trailer_field() != 1)
          {
-         return Certificate_Status_Code::SIGNATURE_ALGO_BAD_PARAMS;
+         return std::make_pair(Certificate_Status_Code::SIGNATURE_ALGO_BAD_PARAMS, "");
          }
 
       padding += "(" + hash_algo + ",MGF1," +
@@ -235,14 +199,14 @@ Certificate_Status_Code X509_Object::verify_signature(const Public_Key& pub_key)
          {
          if(!signature_algorithm().parameters_are_empty())
             {
-            return Certificate_Status_Code::SIGNATURE_ALGO_BAD_PARAMS;
+            return std::make_pair(Certificate_Status_Code::SIGNATURE_ALGO_BAD_PARAMS, "");
             }
          }
       else
          {
          if(!signature_algorithm().parameters_are_null_or_empty())
             {
-            return Certificate_Status_Code::SIGNATURE_ALGO_BAD_PARAMS;
+            return std::make_pair(Certificate_Status_Code::SIGNATURE_ALGO_BAD_PARAMS, "");
             }
          }
       }
@@ -253,18 +217,18 @@ Certificate_Status_Code X509_Object::verify_signature(const Public_Key& pub_key)
       const bool valid = verifier.verify_message(tbs_data(), signature());
 
       if(valid)
-         return Certificate_Status_Code::VERIFIED;
+         return std::make_pair(Certificate_Status_Code::VERIFIED, verifier.hash_function());
       else
-         return Certificate_Status_Code::SIGNATURE_ERROR;
+         return std::make_pair(Certificate_Status_Code::SIGNATURE_ERROR, "");
       }
    catch(Algorithm_Not_Found&)
       {
-      return Certificate_Status_Code::SIGNATURE_ALGO_UNKNOWN;
+      return std::make_pair(Certificate_Status_Code::SIGNATURE_ALGO_UNKNOWN, "");
       }
    catch(...)
       {
       // This shouldn't happen, fallback to generic signature error
-      return Certificate_Status_Code::SIGNATURE_ERROR;
+      return std::make_pair(Certificate_Status_Code::SIGNATURE_ERROR, "");
       }
    }
 
diff --git a/src/lib/x509/x509_obj.h b/src/lib/x509/x509_obj.h
index 6d9fa7cb6..39e658d5f 100644
--- a/src/lib/x509/x509_obj.h
+++ b/src/lib/x509/x509_obj.h
@@ -47,11 +47,6 @@ class BOTAN_PUBLIC_API(2,0) X509_Object : public ASN1_Object
       */
       const AlgorithmIdentifier& signature_algorithm() const { return m_sig_algo; }
 
-      /**
-      * @return hash algorithm that was used to generate signature
-      */
-      std::string hash_used_for_signature() const;
-
       /**
       * Create a signed X509 object.
       * @param signer the signer used to sign the object
@@ -69,9 +64,11 @@ class BOTAN_PUBLIC_API(2,0) X509_Object : public ASN1_Object
       * Check the signature on this data
       * @param key the public key purportedly used to sign this data
       * @return status of the signature - OK if verified or otherwise an indicator of
-      *         the problem preventing verification.
+      *         the problem preventing verification, along with the hash function that
+      *         was used, for further policy checks. The second parameter is empty
+      *         unless the validation was sucessful.
       */
-      Certificate_Status_Code verify_signature(const Public_Key& key) const;
+      std::pair<Certificate_Status_Code, std::string> verify_signature(const Public_Key& key) const;
 
       /**
       * Check the signature on this data
diff --git a/src/lib/x509/x509cert.cpp b/src/lib/x509/x509cert.cpp
index 20988232b..8526bece1 100644
--- a/src/lib/x509/x509cert.cpp
+++ b/src/lib/x509/x509cert.cpp
@@ -308,10 +308,10 @@ std::unique_ptr<X509_Certificate_Data> parse_x509_cert_body(const X509_Object& o
             {
             std::unique_ptr<Public_Key> pub_key(X509::load_key(data->m_subject_public_key_bits_seq));
 
-            Certificate_Status_Code sig_status = obj.verify_signature(*pub_key);
+            const auto sig_status = obj.verify_signature(*pub_key);
 
-            if(sig_status == Certificate_Status_Code::OK ||
-               sig_status == Certificate_Status_Code::SIGNATURE_ALGO_UNKNOWN)
+            if(sig_status.first == Certificate_Status_Code::OK ||
+               sig_status.first == Certificate_Status_Code::SIGNATURE_ALGO_UNKNOWN)
                {
                data->m_self_signed = true;
                }
diff --git a/src/lib/x509/x509path.cpp b/src/lib/x509/x509path.cpp
index 8c08a0031..d66b28ebd 100644
--- a/src/lib/x509/x509path.cpp
+++ b/src/lib/x509/x509path.cpp
@@ -133,22 +133,29 @@ PKIX::check_chain(const std::vector<X509_Certificate>& cert_path,
             }
          else
             {
-            const Certificate_Status_Code sig_status = subject.verify_signature(*issuer_key);
+            const auto sig_status = subject.verify_signature(*issuer_key);
 
-            if(sig_status != Certificate_Status_Code::VERIFIED)
-               status.insert(sig_status);
+            if(sig_status.first == Certificate_Status_Code::VERIFIED)
+               {
+               const std::string hash_used_for_signature = sig_status.second;
+               BOTAN_ASSERT_NOMSG(!hash_used_for_signature.empty());
+               const auto& trusted_hashes = restrictions.trusted_hashes();
+
+               // Ignore untrusted hashes on self-signed roots
+               if(!trusted_hashes.empty() && !at_self_signed_root)
+                  {
+                  if(!trusted_hashes.contains(hash_used_for_signature))
+                     status.insert(Certificate_Status_Code::UNTRUSTED_HASH);
+                  }
+               }
+            else
+               {
+               status.insert(sig_status.first);
+               }
 
             if(issuer_key->estimated_strength() < restrictions.minimum_key_strength())
                status.insert(Certificate_Status_Code::SIGNATURE_METHOD_TOO_WEAK);
             }
-
-         // Ignore untrusted hashes on self-signed roots
-         const auto& trusted_hashes = restrictions.trusted_hashes();
-         if(!trusted_hashes.empty() && !at_self_signed_root)
-            {
-            if(!trusted_hashes.contains(subject.hash_used_for_signature()))
-               status.insert(Certificate_Status_Code::UNTRUSTED_HASH);
-            }
          }
 
       // Check cert extensions
@@ -1105,14 +1112,6 @@ const X509_Certificate& Path_Validation_Result::trust_root() const
    return m_cert_path[m_cert_path.size()-1];
    }
 
-std::set<std::string> Path_Validation_Result::trusted_hashes() const
-   {
-   std::set<std::string> hashes;
-   for(const auto& cert : m_cert_path)
-      hashes.insert(cert.hash_used_for_signature());
-   return hashes;
-   }
-
 bool Path_Validation_Result::successful_validation() const
    {
    return (result() == Certificate_Status_Code::VERIFIED ||
diff --git a/src/lib/x509/x509path.h b/src/lib/x509/x509path.h
index b125126c6..c21bdb834 100644
--- a/src/lib/x509/x509path.h
+++ b/src/lib/x509/x509path.h
@@ -143,12 +143,6 @@ class BOTAN_PUBLIC_API(2,0) Path_Validation_Result final
    public:
       typedef Certificate_Status_Code Code;
 
-      /**
-      * @return the set of hash functions you are implicitly
-      * trusting by trusting this result.
-      */
-      std::set<std::string> trusted_hashes() const;
-
       /**
       * @return the trust root of the validation if successful
       * throws an exception if the validation failed


Test patch:
diff --git a/src/tests/unit_x509.cpp b/src/tests/unit_x509.cpp
index 7d1119b40..e1b2f80e1 100644
--- a/src/tests/unit_x509.cpp
+++ b/src/tests/unit_x509.cpp
@@ -934,15 +934,6 @@ Test::Result test_x509_cert(const Botan::Private_Key& ca_key,
       {
       result.test_note("user 1 validation result was " + result_u1.result_string());
       }
-   else
-      {
-      const std::set<std::string> u1_hashes = result_u1.trusted_hashes();
-
-      if(result.test_eq("Single trusted hash", u1_hashes.size(), 1))
-         {
-         result.test_eq("Hash matches test", *u1_hashes.begin(), hash_fn);
-         }
-      }
 
    Botan::Path_Validation_Result result_u2 = Botan::x509_path_validate(user2_cert, restrictions, store);
    if(!result.confirm("user 2 validates", result_u2.successful_validation()))