From 39fb73bb26eb4e0feafdc526c7dad4d2984a055c Mon Sep 17 00:00:00 2001 From: James Yonan Date: Sat, 11 Jan 2025 14:34:35 -0700 Subject: [PATCH] Added client-side events for new TLS alerts generated on the server side Early rejection of CN: TLS_ALERT_BAD_CERTIFICATE Bad X509 key usage: TLS_ALERT_UNSUPPORTED_CERTIFICATE Bad peer-fingerprint: TLS_ALERT_UNKNOWN_CA Signed-off-by: James Yonan --- openvpn/client/cliconnect.hpp | 6 ++++++ openvpn/client/clievent.hpp | 20 ++++++++++++++++++++ openvpn/error/error.hpp | 4 ++++ openvpn/openssl/ssl/sslctx.hpp | 15 +++++++++------ openvpn/openssl/util/error.hpp | 6 ++++++ 5 files changed, 45 insertions(+), 6 deletions(-) diff --git a/openvpn/client/cliconnect.hpp b/openvpn/client/cliconnect.hpp index 5ca834963..f5d67bba7 100644 --- a/openvpn/client/cliconnect.hpp +++ b/openvpn/client/cliconnect.hpp @@ -597,6 +597,12 @@ class ClientConnect : ClientProto::NotifyCallback, case Error::TLS_ALERT_CERTIFICATE_REVOKED: add_error_and_stop(fatal_code); break; + case Error::TLS_ALERT_BAD_CERTIFICATE: + add_error_and_stop(fatal_code); + break; + case Error::TLS_ALERT_UNSUPPORTED_CERTIFICATE: + add_error_and_stop(fatal_code); + break; case Error::NEED_CREDS: { ClientEvent::Base::Ptr ev = new ClientEvent::NeedCreds(); diff --git a/openvpn/client/clievent.hpp b/openvpn/client/clievent.hpp index 010a6df8c..bb127d87c 100644 --- a/openvpn/client/clievent.hpp +++ b/openvpn/client/clievent.hpp @@ -71,6 +71,8 @@ enum Type TLS_ALERT_HANDSHAKE_FAILURE, TLS_ALERT_CERTIFICATE_EXPIRED, TLS_ALERT_CERTIFICATE_REVOKED, + TLS_ALERT_BAD_CERTIFICATE, + TLS_ALERT_UNSUPPORTED_CERTIFICATE, TLS_SIGALG_DISALLOWED_OR_UNSUPPORTED, CLIENT_HALT, CLIENT_SETUP, @@ -142,6 +144,8 @@ inline const char *event_name(const Type type) "TLS_ALERT_HANDSHAKE_FAILURE", "TLS_ALERT_CERTIFICATE_EXPIRED", "TLS_ALERT_CERTIFICATE_REVOKED", + "TLS_ALERT_BAD_CERTIFICATE", + "TLS_ALERT_UNSUPPORTED_CERTIFICATE", "TLS_SIGALG_DISALLOWED_OR_UNSUPPORTED", "CLIENT_HALT", "CLIENT_SETUP", @@ -374,6 +378,22 @@ struct TLSAlertCertificateRevoked : public Base } }; +struct TLSAlertBadCertificate : public Base +{ + TLSAlertBadCertificate() + : Base(TLS_ALERT_BAD_CERTIFICATE) + { + } +}; + +struct TLSAlertUnsupportedCertificate : public Base +{ + TLSAlertUnsupportedCertificate() + : Base(TLS_ALERT_UNSUPPORTED_CERTIFICATE) + { + } +}; + struct TLSSigAlgDisallowedOrUnsupported : public Base { TLSSigAlgDisallowedOrUnsupported() diff --git a/openvpn/error/error.hpp b/openvpn/error/error.hpp index 9a553c6d6..efb890cfc 100644 --- a/openvpn/error/error.hpp +++ b/openvpn/error/error.hpp @@ -71,6 +71,8 @@ enum Type TLS_ALERT_CERTIFICATE_REQUIRED, // TLS Alert: certificate is required TLS_ALERT_CERTIFICATE_EXPIRED, // TLS Alert: certificate has expired TLS_ALERT_CERTIFICATE_REVOKED, // TLS Alert: certificate is revoked + TLS_ALERT_BAD_CERTIFICATE, // TLS Alert: bad/rejected certificate + TLS_ALERT_UNSUPPORTED_CERTIFICATE, // TLS Alert: unsupported certificate (X509 key usage) TLS_ALERT_MISC, // Any TLS Alert that is in any of the previous TLS alerts TLS_AUTH_FAIL, // tls-auth HMAC verification failed TLS_CRYPT_META_FAIL, // tls-crypt-v2 metadata verification failed @@ -166,6 +168,8 @@ inline const char *name(const size_t type) "TLS_ALERT_CERTIFICATE_REQUIRED", "TLS_ALERT_CERTIFICATE_EXPIRED", "TLS_ALERT_CERTIFICATE_REVOKED", + "TLS_ALERT_BAD_CERTIFICATE", + "TLS_ALERT_UNSUPPORTED_CERTIFICATE", "TLS_ALERT_MISC", "TLS_AUTH_FAIL", "TLS_CRYPT_META_FAIL", diff --git a/openvpn/openssl/ssl/sslctx.hpp b/openvpn/openssl/ssl/sslctx.hpp index 098f28406..3e914b0e8 100644 --- a/openvpn/openssl/ssl/sslctx.hpp +++ b/openvpn/openssl/ssl/sslctx.hpp @@ -1954,6 +1954,9 @@ class OpenSSLContext : public SSLFactoryAPI cert_fail_code(err), X509_verify_cert_error_string(err)); + // Note on X509_STORE_CTX_set_error: see ssl/statem/statem_lib.c in + // OpenSSL source for mapping from X509_STORE_CTX_set_error() codes + // to TLS alert codes. if (depth == 1) // issuer cert { // save the issuer cert fingerprint @@ -1976,7 +1979,7 @@ class OpenSSLContext : public SSLFactoryAPI self_ssl->authcert->add_fail(depth, AuthCert::Fail::BAD_CERT_TYPE, "bad peer-fingerprint in leaf certificate"); - X509_STORE_CTX_set_error(ctx, X509_V_ERR_CERT_SIGNATURE_FAILURE); + X509_STORE_CTX_set_error(ctx, X509_V_ERR_UNABLE_TO_VERIFY_LEAF_SIGNATURE); // alert code: SSL_R_TLSV1_ALERT_UNKNOWN_CA preverify_ok = false; } @@ -1988,7 +1991,7 @@ class OpenSSLContext : public SSLFactoryAPI self_ssl->authcert->add_fail(depth, AuthCert::Fail::BAD_CERT_TYPE, "bad ns-cert-type in leaf certificate"); - X509_STORE_CTX_set_error(ctx, X509_V_ERR_INVALID_PURPOSE); + X509_STORE_CTX_set_error(ctx, X509_V_ERR_INVALID_PURPOSE); // alert code: SSL_R_SSLV3_ALERT_UNSUPPORTED_CERTIFICATE preverify_ok = false; } @@ -2000,7 +2003,7 @@ class OpenSSLContext : public SSLFactoryAPI self_ssl->authcert->add_fail(depth, AuthCert::Fail::BAD_CERT_TYPE, "bad X509 key usage in leaf certificate"); - X509_STORE_CTX_set_error(ctx, X509_V_ERR_INVALID_PURPOSE); + X509_STORE_CTX_set_error(ctx, X509_V_ERR_INVALID_PURPOSE); // alert code: SSL_R_SSLV3_ALERT_UNSUPPORTED_CERTIFICATE preverify_ok = false; } @@ -2012,7 +2015,7 @@ class OpenSSLContext : public SSLFactoryAPI self_ssl->authcert->add_fail(depth, AuthCert::Fail::BAD_CERT_TYPE, "bad X509 extended key usage in leaf certificate"); - X509_STORE_CTX_set_error(ctx, X509_V_ERR_INVALID_PURPOSE); + X509_STORE_CTX_set_error(ctx, X509_V_ERR_INVALID_PURPOSE); // alert code: SSL_R_SSLV3_ALERT_UNSUPPORTED_CERTIFICATE preverify_ok = false; } @@ -2027,14 +2030,14 @@ class OpenSSLContext : public SSLFactoryAPI if (self->config->cn_reject_handler->reject(cn)) { OVPN_LOG_INFO("VERIFY FAIL -- early rejection of leaf cert Common Name"); - X509_STORE_CTX_set_error(ctx, X509_V_ERR_CERT_REJECTED); + X509_STORE_CTX_set_error(ctx, X509_V_ERR_CERT_REJECTED); // alert code: SSL_R_SSLV3_ALERT_BAD_CERTIFICATE preverify_ok = false; } } catch (const std::exception &e) { OVPN_LOG_INFO("VERIFY FAIL -- early rejection of leaf cert Common Name due to handler exception: " << e.what()); - X509_STORE_CTX_set_error(ctx, X509_V_ERR_CERT_REJECTED); + X509_STORE_CTX_set_error(ctx, X509_V_ERR_CERT_REJECTED); // alert code: SSL_R_SSLV3_ALERT_BAD_CERTIFICATE preverify_ok = false; } } diff --git a/openvpn/openssl/util/error.hpp b/openvpn/openssl/util/error.hpp index a9a67136a..b6dcd587f 100644 --- a/openvpn/openssl/util/error.hpp +++ b/openvpn/openssl/util/error.hpp @@ -187,6 +187,12 @@ class OpenSSLException : public ExceptionCode case SSL_R_SSLV3_ALERT_CERTIFICATE_REVOKED: set_code(Error::TLS_ALERT_CERTIFICATE_REVOKED, true); break; + case SSL_R_SSLV3_ALERT_BAD_CERTIFICATE: + set_code(Error::TLS_ALERT_BAD_CERTIFICATE, true); + break; + case SSL_R_SSLV3_ALERT_UNSUPPORTED_CERTIFICATE: + set_code(Error::TLS_ALERT_UNSUPPORTED_CERTIFICATE, true); + break; default: if (reason > SSL_AD_REASON_OFFSET) {