From 2ed9cf0f79f416f20f5347b26474911ecbff25a8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ren=C3=A9=20Meusel?= Date: Mon, 18 Apr 2022 15:04:22 +0530 Subject: [PATCH] Signature_Scheme::is_suitable_for and ::is_compatible_with --- src/lib/tls/msg_cert_verify.cpp | 13 +----- src/lib/tls/tls12/tls_handshake_state.cpp | 7 +--- src/lib/tls/tls_signature_scheme.cpp | 51 +++++++++++++++++++---- src/lib/tls/tls_signature_scheme.h | 6 ++- 4 files changed, 51 insertions(+), 26 deletions(-) diff --git a/src/lib/tls/msg_cert_verify.cpp b/src/lib/tls/msg_cert_verify.cpp index 1a1af9a72aa..17404e90e23 100644 --- a/src/lib/tls/msg_cert_verify.cpp +++ b/src/lib/tls/msg_cert_verify.cpp @@ -114,17 +114,8 @@ Certificate_Verify_13::Certificate_Verify_13(const std::vector& buf, if(!m_scheme.is_available()) { throw TLS_Exception(Alert::HANDSHAKE_FAILURE, "Peer sent unknown signature scheme"); } - // RFC 8446 4.4.3: - // The SHA-1 algorithm MUST NOT be used in any signatures of - // CertificateVerify messages. - if(m_scheme.is_sha1()) - { throw TLS_Exception(Alert::ILLEGAL_PARAMETER, "SHA-1 algorithm must not be used"); } - - // RFC 8446 4.4.3: - // RSA signatures MUST use an RSASSA-PSS algorithm, regardless of whether - // RSASSA-PKCS1-v1_5 algorithms appear in "signature_algorithms". - if(m_scheme.is_rsa_pkcs1()) - { throw TLS_Exception(Alert::ILLEGAL_PARAMETER, "RSA signatures must use an RSASSA-PSS algorithm"); } + if(!m_scheme.is_compatible_with(Protocol_Version::TLS_V13)) + { throw TLS_Exception(Alert::ILLEGAL_PARAMETER, "Peer sent signature algorithm that is not suitable for TLS 1.3"); } } /* diff --git a/src/lib/tls/tls12/tls_handshake_state.cpp b/src/lib/tls/tls12/tls_handshake_state.cpp index 2ce835318e0..54a27c63d14 100644 --- a/src/lib/tls/tls12/tls_handshake_state.cpp +++ b/src/lib/tls/tls12/tls_handshake_state.cpp @@ -380,11 +380,8 @@ Handshake_State::parse_sig_format(const Public_Key& key, const std::string hash_algo = scheme.hash_function_name(); - // RFC 8446 4.4.3: - // The SHA-1 algorithm MUST NOT be used in any signatures of - // CertificateVerify messages. - if(scheme.is_sha1()) - { throw TLS_Exception(Alert::ILLEGAL_PARAMETER, "SHA-1 algorithm must not be used"); } + if(!scheme.is_compatible_with(Protocol_Version::TLS_V12)) + { throw TLS_Exception(Alert::ILLEGAL_PARAMETER, "Peer sent unexceptable signature scheme"); } if(!supported_algos_include(supported_algos, key_type, hash_algo)) { diff --git a/src/lib/tls/tls_signature_scheme.cpp b/src/lib/tls/tls_signature_scheme.cpp index a1cccb95496..4d0109804c9 100644 --- a/src/lib/tls/tls_signature_scheme.cpp +++ b/src/lib/tls/tls_signature_scheme.cpp @@ -8,6 +8,8 @@ #include #include +#include +#include #include namespace Botan::TLS { @@ -284,18 +286,51 @@ std::optional Signature_Scheme::format() const noexcept } } -bool Signature_Scheme::is_sha1() const noexcept +bool Signature_Scheme::is_compatible_with(const Protocol_Version& protocol_version) const noexcept { - return hash_function_name() == "SHA-1"; + // RFC 8446 4.4.3: + // The SHA-1 algorithm MUST NOT be used in any signatures of + // CertificateVerify messages. + // + // Note that Botan enforces that for TLS 1.2 as well. + if(hash_function_name() == "SHA-1") + return false; + + // RFC 8446 4.4.3: + // RSA signatures MUST use an RSASSA-PSS algorithm, regardless of whether + // RSASSA-PKCS1-v1_5 algorithms appear in "signature_algorithms". + // + // Note that this is enforced for TLS 1.3 and above only. + if(!protocol_version.is_pre_tls_13() && + (m_code == RSA_PKCS1_SHA1 || + m_code == RSA_PKCS1_SHA256 || + m_code == RSA_PKCS1_SHA384 || + m_code == RSA_PKCS1_SHA512)) + return false; + + return true; } -bool Signature_Scheme::is_rsa_pkcs1() const noexcept +bool Signature_Scheme::is_suitable_for(const Private_Key &private_key) const noexcept { - return - m_code == RSA_PKCS1_SHA1 || - m_code == RSA_PKCS1_SHA256 || - m_code == RSA_PKCS1_SHA384 || - m_code == RSA_PKCS1_SHA512; + if(algorithm_name() != private_key.algo_name()) + return false; + + // The ECDSA private key length must match the utilized hash output length. + const auto keylen = private_key.key_length(); + if(keylen <= 250) + return false; + + if(m_code == ECDSA_SHA256 && !(keylen >= 250 && keylen <= 350)) + return false; + + if(m_code == ECDSA_SHA384 && !(keylen >= 350 && keylen <= 450)) + return false; + + if(m_code == ECDSA_SHA512 && !(keylen >= 450 && keylen <= 550)) + return false; + + return true; } } // Botan::TLS diff --git a/src/lib/tls/tls_signature_scheme.h b/src/lib/tls/tls_signature_scheme.h index 78931188100..179ff602a7b 100644 --- a/src/lib/tls/tls_signature_scheme.h +++ b/src/lib/tls/tls_signature_scheme.h @@ -18,6 +18,8 @@ namespace Botan::TLS { +class Protocol_Version; + class BOTAN_PUBLIC_API(3,0) Signature_Scheme { public: @@ -89,8 +91,8 @@ enum Code : uint16_t { AlgorithmIdentifier algorithm_identifier() const noexcept; std::optional format() const noexcept; - bool is_sha1() const noexcept; - bool is_rsa_pkcs1() const noexcept; + bool is_compatible_with(const Protocol_Version& protocol_version) const noexcept; + bool is_suitable_for(const Private_Key& private_key) const noexcept; bool operator==(const Signature_Scheme& rhs) const { return m_code == rhs.m_code; } bool operator!=(const Signature_Scheme& rhs) const { return !(*this == rhs); }