diff options
author | AnotherTest <ali.mpfard@gmail.com> | 2020-05-06 21:43:27 +0430 |
---|---|---|
committer | Andreas Kling <kling@serenityos.org> | 2020-05-07 10:23:58 +0200 |
commit | af1ce6c33d65c916894bb8f17544cb80cbe6f902 (patch) | |
tree | 658d9983e5bbc1a5b13a4344723e99bd1aeb1311 /Libraries/LibTLS | |
parent | d051fffe25ba76c8a62b00289cf0f86e37a83f58 (diff) | |
download | serenity-af1ce6c33d65c916894bb8f17544cb80cbe6f902.zip |
LibTLS: Verify server certificate expiry date
Diffstat (limited to 'Libraries/LibTLS')
-rw-r--r-- | Libraries/LibTLS/ClientHandshake.cpp | 15 | ||||
-rw-r--r-- | Libraries/LibTLS/TLSv12.cpp | 114 | ||||
-rw-r--r-- | Libraries/LibTLS/TLSv12.h | 24 |
3 files changed, 141 insertions, 12 deletions
diff --git a/Libraries/LibTLS/ClientHandshake.cpp b/Libraries/LibTLS/ClientHandshake.cpp index 5068977510..4938578b4e 100644 --- a/Libraries/LibTLS/ClientHandshake.cpp +++ b/Libraries/LibTLS/ClientHandshake.cpp @@ -363,6 +363,21 @@ ssize_t TLSv12::handle_payload(const ByteBuffer& vbuffer) ASSERT_NOT_REACHED(); } payload_res = handle_certificate(buffer.slice_view(1, payload_size)); + if (m_context.certificates.size()) { + auto it = m_context.certificates.find([&](auto& cert) { return cert.is_valid(); }); + + if (it.is_end()) { + // no valid certificates + dbg() << "No valid certificates found"; + payload_res = (i8)Error::BadCertificate; + m_context.critical_error = payload_res; + break; + } + + // swap the first certificate with the valid one + if (it.index() != 0) + swap(m_context.certificates[0], m_context.certificates[it.index()]); + } } else { payload_res = (i8)Error::UnexpectedMessage; } diff --git a/Libraries/LibTLS/TLSv12.cpp b/Libraries/LibTLS/TLSv12.cpp index ed2d8d6ee3..72a6186e93 100644 --- a/Libraries/LibTLS/TLSv12.cpp +++ b/Libraries/LibTLS/TLSv12.cpp @@ -24,6 +24,7 @@ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ +#include <LibCore/DateTime.h> #include <LibCore/Timer.h> #include <LibCrypto/ASN1/DER.h> #include <LibCrypto/PK/Code/EMSA_PSS.h> @@ -65,13 +66,58 @@ static bool _asn1_is_oid(const u8* oid, const u8* compare, size_t length = 3) return true; } -static void _set_algorithm(u32&, const u8* value, size_t length) +static bool _set_algorithm(CertificateKeyAlgorithm& algorithm, const u8* value, size_t length) { + if (length == 7) { + // Elliptic Curve pubkey + dbg() << "Cert.algorithm: EC, unsupported"; + return false; + } + + if (length == 8) { + // named EC key + dbg() << "Cert.algorithm: Named EC (" << *value << "), unsupported"; + return false; + } + + if (length == 5) { + // named EC SECP key + dbg() << "Cert.algorithm: Named EC secp (" << *value << "), unsupported"; + return false; + } + if (length != 9) { - dbg() << "unsupported algorithm " << value; + dbg() << "Invalid certificate algorithm"; + return false; + } + + if (_asn1_is_oid(value, Constants::RSA_SIGN_RSA_OID, 9)) { + algorithm = CertificateKeyAlgorithm::RSA_RSA; + return true; + } + + if (_asn1_is_oid(value, Constants::RSA_SIGN_SHA256_OID, 9)) { + algorithm = CertificateKeyAlgorithm::RSA_SHA256; + return true; } - dbg() << "FIXME: Set algorithm"; + if (_asn1_is_oid(value, Constants::RSA_SIGN_SHA512_OID, 9)) { + algorithm = CertificateKeyAlgorithm::RSA_SHA512; + return true; + } + + if (_asn1_is_oid(value, Constants::RSA_SIGN_SHA1_OID, 9)) { + algorithm = CertificateKeyAlgorithm::RSA_SHA1; + return true; + } + + if (_asn1_is_oid(value, Constants::RSA_SIGN_MD5_OID, 9)) { + algorithm = CertificateKeyAlgorithm::RSA_MD5; + return true; + } + + dbg() << "Unsupported RSA Signature mode " << value[8]; + return false; } static size_t _get_asn1_length(const u8* buffer, size_t length, size_t& octets) @@ -306,7 +352,35 @@ static ssize_t _parse_asn1(const Context& context, Certificate& cert, const u8* position += length; } if (level == 2 && cert.sign_key.size() && cert_length && cert_data) { - dbg() << "FIXME: Cert.fingerprint"; + cert.fingerprint.clear(); + Crypto::Hash::Manager hash; + switch (cert.key_algorithm) { + case CertificateKeyAlgorithm::RSA_MD5: + hash.initialize(Crypto::Hash::HashKind::MD5); + break; + case CertificateKeyAlgorithm::RSA_SHA1: + hash.initialize(Crypto::Hash::HashKind::SHA1); + break; + case CertificateKeyAlgorithm::RSA_SHA256: + hash.initialize(Crypto::Hash::HashKind::SHA256); + break; + case CertificateKeyAlgorithm::RSA_SHA512: + hash.initialize(Crypto::Hash::HashKind::SHA512); + break; + default: + dbg() << "Unsupported hash mode " << (u32)cert.key_algorithm; + // fallback to md5, it will fail later + hash.initialize(Crypto::Hash::HashKind::MD5); + break; + } + hash.update(cert_data, cert_length); + auto fingerprint = hash.digest(); + cert.fingerprint.grow(fingerprint.data_length()); + cert.fingerprint.overwrite(0, fingerprint.immutable_data(), fingerprint.data_length()); +#ifdef TLS_DEBUG + dbg() << "Certificate fingerprint:"; + print_buffer(cert.fingerprint); +#endif } return position; } @@ -377,11 +451,15 @@ ssize_t TLSv12::handle_certificate(const ByteBuffer& buffer) size_t certificates_in_chain = 0; do { - if (remaining <= 3) + if (remaining <= 3) { + dbg() << "Ran out of data"; break; + } ++certificates_in_chain; - if (buffer.size() < (size_t)res_cert + 3) + if (buffer.size() < (size_t)res_cert + 3) { + dbg() << "not enough data to read cert size (" << buffer.size() << " < " << res_cert + 3 << ")"; break; + } size_t certificate_size_specific = buffer[res_cert] * 0x10000 + buffer[res_cert + 1] * 0x100 + buffer[res_cert + 2]; res_cert += 3; remaining -= 3; @@ -397,7 +475,7 @@ ssize_t TLSv12::handle_certificate(const ByteBuffer& buffer) m_context.certificates.append(certificate.value()); valid_certificate = true; } - res_cert += certificate_size; + res_cert += certificate_size_specific; } while (remaining > 0); if (remaining) { dbg() << "extraneous " << remaining << " bytes left over after parsing certificates"; @@ -519,6 +597,27 @@ void TLSv12::ensure_hmac(size_t digest_size, bool local) m_hmac_remote = move(hmac); } +bool Certificate::is_valid() const +{ + auto now = Core::DateTime::now(); + + if (!not_before.is_empty()) { + if (now.is_before(not_before)) { + dbg() << "certificate expired (not yet valid, signed for " << not_before << ")"; + return false; + } + } + + if (!not_after.is_empty()) { + if (!now.is_before(not_after)) { + dbg() << "certificate expired (expiry date " << not_after << ")"; + return false; + } + } + + return true; +} + void TLSv12::try_disambiguate_error() const { dbg() << "Possible failure cause: "; @@ -542,5 +641,4 @@ void TLSv12::try_disambiguate_error() const break; } } - } diff --git a/Libraries/LibTLS/TLSv12.h b/Libraries/LibTLS/TLSv12.h index 6cd2613e12..ff4d844190 100644 --- a/Libraries/LibTLS/TLSv12.h +++ b/Libraries/LibTLS/TLSv12.h @@ -189,11 +189,20 @@ enum ClientVerificationStaus { VerificationNeeded, }; +enum class CertificateKeyAlgorithm { + Unsupported = 0x00, + RSA_RSA = 0x01, + RSA_MD5 = 0x04, + RSA_SHA1 = 0x05, + RSA_SHA256 = 0x0b, + RSA_SHA512 = 0x0d, +}; + struct Certificate { u16 version; - u32 algorithm; - u32 key_algorithm; - u32 ec_algorithm; + CertificateKeyAlgorithm algorithm; + CertificateKeyAlgorithm key_algorithm; + CertificateKeyAlgorithm ec_algorithm; ByteBuffer exponent; Crypto::PK::RSAPublicKey<Crypto::UnsignedBigInteger> public_key; String issuer_country; @@ -216,6 +225,8 @@ struct Certificate { ByteBuffer fingerprint; ByteBuffer der; ByteBuffer data; + + bool is_valid() const; }; struct Context { @@ -488,7 +499,12 @@ constexpr static const u8 subject_oid[] { 0x55, 0x04, 0x03, 0x00 }; constexpr static const u8 san_oid[] { 0x55, 0x1D, 0x11, 0x00 }; constexpr static const u8 ocsp_oid[] { 0x2B, 0x06, 0x01, 0x05, 0x05, 0x07, 0x30, 0x01, 0x00 }; -constexpr static const u8 TLS_RSA_SIGN_SHA256_OID[] { 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x0b, 0x00 }; +static constexpr const u8 RSA_SIGN_RSA_OID[] = { 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x01, 0x00 }; +static constexpr const u8 RSA_SIGN_MD5_OID[] = { 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x04, 0x00 }; +static constexpr const u8 RSA_SIGN_SHA1_OID[] = { 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x05, 0x00 }; +static constexpr const u8 RSA_SIGN_SHA256_OID[] = { 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x0b, 0x00 }; +static constexpr const u8 RSA_SIGN_SHA384_OID[] = { 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x0c, 0x00 }; +static constexpr const u8 RSA_SIGN_SHA512_OID[] = { 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x0d, 0x00 }; } |