CVE-2024-12797
Description
Issue summary: Clients using RFC7250 Raw Public Keys (RPKs) to authenticate a server may fail to notice that the server was not authenticated, because handshakes don't abort as expected when the SSL_VERIFY_PEER verification mode is set.
Impact summary: TLS and DTLS connections using raw public keys may be vulnerable to man-in-middle attacks when server authentication failure is not detected by clients.
RPKs are disabled by default in both TLS clients and TLS servers. The issue only arises when TLS clients explicitly enable RPK use by the server, and the server, likewise, enables sending of an RPK instead of an X.509 certificate chain. The affected clients are those that then rely on the handshake to fail when the server's RPK fails to match one of the expected public keys, by setting the verification mode to SSL_VERIFY_PEER.
Clients that enable server-side raw public keys can still find out that raw public key verification failed by calling SSL_get_verify_result(), and those that do, and take appropriate action, are not affected. This issue was introduced in the initial implementation of RPK support in OpenSSL 3.2.
The FIPS modules in 3.4, 3.3, 3.2, 3.1 and 3.0 are not affected by this issue.
Affected packages
Versions sourced from the GitHub Security Advisory.
| Package | Affected versions | Patched versions |
|---|---|---|
cryptographyPyPI | >= 42.0.0, < 44.0.1 | 44.0.1 |
Patches
3798779d43494With SSL_VERIFY_PEER client RPK should abort on X509 error
2 files changed · +54 −9
ssl/statem/statem_clnt.c+13 −2 modified@@ -1909,6 +1909,7 @@ static WORK_STATE tls_post_process_server_rpk(SSL_CONNECTION *sc, { size_t certidx; const SSL_CERT_LOOKUP *clu; + int v_ok; if (sc->session->peer_rpk == NULL) { SSLfatal(sc, SSL_AD_ILLEGAL_PARAMETER, @@ -1918,9 +1919,19 @@ static WORK_STATE tls_post_process_server_rpk(SSL_CONNECTION *sc, if (sc->rwstate == SSL_RETRY_VERIFY) sc->rwstate = SSL_NOTHING; - if (ssl_verify_rpk(sc, sc->session->peer_rpk) > 0 - && sc->rwstate == SSL_RETRY_VERIFY) + + ERR_set_mark(); + v_ok = ssl_verify_rpk(sc, sc->session->peer_rpk); + if (v_ok <= 0 && sc->verify_mode != SSL_VERIFY_NONE) { + ERR_clear_last_mark(); + SSLfatal(sc, ssl_x509err2alert(sc->verify_result), + SSL_R_CERTIFICATE_VERIFY_FAILED); + return WORK_ERROR; + } + ERR_pop_to_mark(); /* but we keep s->verify_result */ + if (v_ok > 0 && sc->rwstate == SSL_RETRY_VERIFY) { return WORK_MORE_A; + } if ((clu = ssl_cert_lookup_by_pkey(sc->session->peer_rpk, &certidx, SSL_CONNECTION_GET_CTX(sc))) == NULL) {
test/rpktest.c+41 −7 modified@@ -89,12 +89,14 @@ static int rpk_verify_server_cb(int ok, X509_STORE_CTX *ctx) * idx = 13 - resumption with client authentication * idx = 14 - resumption with client authentication, no ticket * idx = 15 - like 0, but use non-default libctx + * idx = 16 - like 7, but with SSL_VERIFY_PEER connection should fail + * idx = 17 - like 8, but with SSL_VERIFY_PEER connection should fail * - * 16 * 2 * 4 * 2 * 2 * 2 * 2 = 2048 tests + * 18 * 2 * 4 * 2 * 2 * 2 * 2 = 2048 tests */ static int test_rpk(int idx) { -# define RPK_TESTS 16 +# define RPK_TESTS 18 # define RPK_DIMS (2 * 4 * 2 * 2 * 2 * 2) SSL_CTX *cctx = NULL, *sctx = NULL; SSL *clientssl = NULL, *serverssl = NULL; @@ -114,6 +116,7 @@ static int test_rpk(int idx) int idx_cert, idx_prot; int client_auth = 0; int resumption = 0; + int want_error = SSL_ERROR_NONE; long server_verify_result = 0; long client_verify_result = 0; OSSL_LIB_CTX *test_libctx = NULL; @@ -188,7 +191,7 @@ static int test_rpk(int idx) #ifdef OPENSSL_NO_ECDSA /* Can't get other_key if it's ECDSA */ if (other_pkey == NULL && idx_cert == 0 - && (idx == 4 || idx == 6 || idx == 7)) { + && (idx == 4 || idx == 6 || idx == 7 || idx == 16)) { testresult = TEST_skip("EDCSA disabled"); goto end; } @@ -266,8 +269,10 @@ static int test_rpk(int idx) goto end; /* Only a private key */ if (idx == 1) { - if (idx_server_server_rpk == 0 || idx_client_server_rpk == 0) + if (idx_server_server_rpk == 0 || idx_client_server_rpk == 0) { expected = 0; + want_error = SSL_ERROR_SSL; + } } else { /* Add certificate */ if (!TEST_int_eq(SSL_use_certificate_file(serverssl, cert_file, SSL_FILETYPE_PEM), 1)) @@ -333,12 +338,14 @@ static int test_rpk(int idx) client_expected = -1; if (!TEST_true(SSL_add_expected_rpk(clientssl, other_pkey))) goto end; + SSL_set_verify(clientssl, SSL_VERIFY_NONE, rpk_verify_client_cb); client_verify_result = X509_V_ERR_DANE_NO_MATCH; break; case 8: if (idx_server_server_rpk == 1 && idx_client_server_rpk == 1) client_expected = -1; /* no peer keys */ + SSL_set_verify(clientssl, SSL_VERIFY_NONE, rpk_verify_client_cb); client_verify_result = X509_V_ERR_RPK_UNTRUSTED; break; case 9: @@ -370,9 +377,13 @@ static int test_rpk(int idx) if (!TEST_int_eq(SSL_use_PrivateKey_file(clientssl, privkey_file, SSL_FILETYPE_PEM), 1)) goto end; /* Since there's no cert, this is expected to fail without RPK support */ - if (!idx_server_client_rpk || !idx_client_client_rpk) + if (!idx_server_client_rpk || !idx_client_client_rpk) { expected = 0; - SSL_set_verify(serverssl, SSL_VERIFY_PEER | SSL_VERIFY_FAIL_IF_NO_PEER_CERT, rpk_verify_server_cb); + want_error = SSL_ERROR_SSL; + SSL_set_verify(serverssl, SSL_VERIFY_PEER | SSL_VERIFY_FAIL_IF_NO_PEER_CERT, NULL); + } else { + SSL_set_verify(serverssl, SSL_VERIFY_PEER | SSL_VERIFY_FAIL_IF_NO_PEER_CERT, rpk_verify_server_cb); + } client_auth = 1; break; case 11: @@ -449,12 +460,35 @@ static int test_rpk(int idx) if (!TEST_true(SSL_add_expected_rpk(clientssl, pkey))) goto end; break; + case 16: + if (idx_server_server_rpk == 1 && idx_client_server_rpk == 1) { + /* wrong expected server key */ + expected = 0; + want_error = SSL_ERROR_SSL; + SSL_set_verify(serverssl, SSL_VERIFY_PEER, NULL); + } + if (!TEST_true(SSL_add_expected_rpk(clientssl, other_pkey))) + goto end; + break; + case 17: + if (idx_server_server_rpk == 1 && idx_client_server_rpk == 1) { + /* no expected server keys */ + expected = 0; + want_error = SSL_ERROR_SSL; + SSL_set_verify(serverssl, SSL_VERIFY_PEER, NULL); + } + break; } - ret = create_ssl_connection(serverssl, clientssl, SSL_ERROR_NONE); + ret = create_ssl_connection(serverssl, clientssl, want_error); if (!TEST_int_eq(expected, ret)) goto end; + if (expected <= 0) { + testresult = 1; + goto end; + } + /* Make sure client gets RPK or certificate as configured */ if (expected == 1) { if (idx_server_server_rpk && idx_client_server_rpk) {
738d4f9fdeaaWith SSL_VERIFY_PEER client RPK should abort on X509 error
2 files changed · +54 −9
ssl/statem/statem_clnt.c+13 −2 modified@@ -1910,6 +1910,7 @@ static WORK_STATE tls_post_process_server_rpk(SSL_CONNECTION *sc, { size_t certidx; const SSL_CERT_LOOKUP *clu; + int v_ok; if (sc->session->peer_rpk == NULL) { SSLfatal(sc, SSL_AD_ILLEGAL_PARAMETER, @@ -1919,9 +1920,19 @@ static WORK_STATE tls_post_process_server_rpk(SSL_CONNECTION *sc, if (sc->rwstate == SSL_RETRY_VERIFY) sc->rwstate = SSL_NOTHING; - if (ssl_verify_rpk(sc, sc->session->peer_rpk) > 0 - && sc->rwstate == SSL_RETRY_VERIFY) + + ERR_set_mark(); + v_ok = ssl_verify_rpk(sc, sc->session->peer_rpk); + if (v_ok <= 0 && sc->verify_mode != SSL_VERIFY_NONE) { + ERR_clear_last_mark(); + SSLfatal(sc, ssl_x509err2alert(sc->verify_result), + SSL_R_CERTIFICATE_VERIFY_FAILED); + return WORK_ERROR; + } + ERR_pop_to_mark(); /* but we keep s->verify_result */ + if (v_ok > 0 && sc->rwstate == SSL_RETRY_VERIFY) { return WORK_MORE_A; + } if ((clu = ssl_cert_lookup_by_pkey(sc->session->peer_rpk, &certidx, SSL_CONNECTION_GET_CTX(sc))) == NULL) {
test/rpktest.c+41 −7 modified@@ -89,12 +89,14 @@ static int rpk_verify_server_cb(int ok, X509_STORE_CTX *ctx) * idx = 13 - resumption with client authentication * idx = 14 - resumption with client authentication, no ticket * idx = 15 - like 0, but use non-default libctx + * idx = 16 - like 7, but with SSL_VERIFY_PEER connection should fail + * idx = 17 - like 8, but with SSL_VERIFY_PEER connection should fail * - * 16 * 2 * 4 * 2 * 2 * 2 * 2 = 2048 tests + * 18 * 2 * 4 * 2 * 2 * 2 * 2 = 2048 tests */ static int test_rpk(int idx) { -# define RPK_TESTS 16 +# define RPK_TESTS 18 # define RPK_DIMS (2 * 4 * 2 * 2 * 2 * 2) SSL_CTX *cctx = NULL, *sctx = NULL; SSL *clientssl = NULL, *serverssl = NULL; @@ -114,6 +116,7 @@ static int test_rpk(int idx) int idx_cert, idx_prot; int client_auth = 0; int resumption = 0; + int want_error = SSL_ERROR_NONE; long server_verify_result = 0; long client_verify_result = 0; OSSL_LIB_CTX *test_libctx = NULL; @@ -188,7 +191,7 @@ static int test_rpk(int idx) #ifdef OPENSSL_NO_ECDSA /* Can't get other_key if it's ECDSA */ if (other_pkey == NULL && idx_cert == 0 - && (idx == 4 || idx == 6 || idx == 7)) { + && (idx == 4 || idx == 6 || idx == 7 || idx == 16)) { testresult = TEST_skip("EDCSA disabled"); goto end; } @@ -266,8 +269,10 @@ static int test_rpk(int idx) goto end; /* Only a private key */ if (idx == 1) { - if (idx_server_server_rpk == 0 || idx_client_server_rpk == 0) + if (idx_server_server_rpk == 0 || idx_client_server_rpk == 0) { expected = 0; + want_error = SSL_ERROR_SSL; + } } else { /* Add certificate */ if (!TEST_int_eq(SSL_use_certificate_file(serverssl, cert_file, SSL_FILETYPE_PEM), 1)) @@ -333,12 +338,14 @@ static int test_rpk(int idx) client_expected = -1; if (!TEST_true(SSL_add_expected_rpk(clientssl, other_pkey))) goto end; + SSL_set_verify(clientssl, SSL_VERIFY_NONE, rpk_verify_client_cb); client_verify_result = X509_V_ERR_DANE_NO_MATCH; break; case 8: if (idx_server_server_rpk == 1 && idx_client_server_rpk == 1) client_expected = -1; /* no peer keys */ + SSL_set_verify(clientssl, SSL_VERIFY_NONE, rpk_verify_client_cb); client_verify_result = X509_V_ERR_RPK_UNTRUSTED; break; case 9: @@ -370,9 +377,13 @@ static int test_rpk(int idx) if (!TEST_int_eq(SSL_use_PrivateKey_file(clientssl, privkey_file, SSL_FILETYPE_PEM), 1)) goto end; /* Since there's no cert, this is expected to fail without RPK support */ - if (!idx_server_client_rpk || !idx_client_client_rpk) + if (!idx_server_client_rpk || !idx_client_client_rpk) { expected = 0; - SSL_set_verify(serverssl, SSL_VERIFY_PEER | SSL_VERIFY_FAIL_IF_NO_PEER_CERT, rpk_verify_server_cb); + want_error = SSL_ERROR_SSL; + SSL_set_verify(serverssl, SSL_VERIFY_PEER | SSL_VERIFY_FAIL_IF_NO_PEER_CERT, NULL); + } else { + SSL_set_verify(serverssl, SSL_VERIFY_PEER | SSL_VERIFY_FAIL_IF_NO_PEER_CERT, rpk_verify_server_cb); + } client_auth = 1; break; case 11: @@ -449,12 +460,35 @@ static int test_rpk(int idx) if (!TEST_true(SSL_add_expected_rpk(clientssl, pkey))) goto end; break; + case 16: + if (idx_server_server_rpk == 1 && idx_client_server_rpk == 1) { + /* wrong expected server key */ + expected = 0; + want_error = SSL_ERROR_SSL; + SSL_set_verify(serverssl, SSL_VERIFY_PEER, NULL); + } + if (!TEST_true(SSL_add_expected_rpk(clientssl, other_pkey))) + goto end; + break; + case 17: + if (idx_server_server_rpk == 1 && idx_client_server_rpk == 1) { + /* no expected server keys */ + expected = 0; + want_error = SSL_ERROR_SSL; + SSL_set_verify(serverssl, SSL_VERIFY_PEER, NULL); + } + break; } - ret = create_ssl_connection(serverssl, clientssl, SSL_ERROR_NONE); + ret = create_ssl_connection(serverssl, clientssl, want_error); if (!TEST_int_eq(expected, ret)) goto end; + if (expected <= 0) { + testresult = 1; + goto end; + } + /* Make sure client gets RPK or certificate as configured */ if (expected == 1) { if (idx_server_server_rpk && idx_client_server_rpk) {
87ebd203feffWith SSL_VERIFY_PEER client RPK should abort on X509 error
2 files changed · +54 −9
ssl/statem/statem_clnt.c+13 −2 modified@@ -1909,6 +1909,7 @@ static WORK_STATE tls_post_process_server_rpk(SSL_CONNECTION *sc, { size_t certidx; const SSL_CERT_LOOKUP *clu; + int v_ok; if (sc->session->peer_rpk == NULL) { SSLfatal(sc, SSL_AD_ILLEGAL_PARAMETER, @@ -1918,9 +1919,19 @@ static WORK_STATE tls_post_process_server_rpk(SSL_CONNECTION *sc, if (sc->rwstate == SSL_RETRY_VERIFY) sc->rwstate = SSL_NOTHING; - if (ssl_verify_rpk(sc, sc->session->peer_rpk) > 0 - && sc->rwstate == SSL_RETRY_VERIFY) + + ERR_set_mark(); + v_ok = ssl_verify_rpk(sc, sc->session->peer_rpk); + if (v_ok <= 0 && sc->verify_mode != SSL_VERIFY_NONE) { + ERR_clear_last_mark(); + SSLfatal(sc, ssl_x509err2alert(sc->verify_result), + SSL_R_CERTIFICATE_VERIFY_FAILED); + return WORK_ERROR; + } + ERR_pop_to_mark(); /* but we keep s->verify_result */ + if (v_ok > 0 && sc->rwstate == SSL_RETRY_VERIFY) { return WORK_MORE_A; + } if ((clu = ssl_cert_lookup_by_pkey(sc->session->peer_rpk, &certidx, SSL_CONNECTION_GET_CTX(sc))) == NULL) {
test/rpktest.c+41 −7 modified@@ -89,12 +89,14 @@ static int rpk_verify_server_cb(int ok, X509_STORE_CTX *ctx) * idx = 13 - resumption with client authentication * idx = 14 - resumption with client authentication, no ticket * idx = 15 - like 0, but use non-default libctx + * idx = 16 - like 7, but with SSL_VERIFY_PEER connection should fail + * idx = 17 - like 8, but with SSL_VERIFY_PEER connection should fail * - * 16 * 2 * 4 * 2 * 2 * 2 * 2 = 2048 tests + * 18 * 2 * 4 * 2 * 2 * 2 * 2 = 2048 tests */ static int test_rpk(int idx) { -# define RPK_TESTS 16 +# define RPK_TESTS 18 # define RPK_DIMS (2 * 4 * 2 * 2 * 2 * 2) SSL_CTX *cctx = NULL, *sctx = NULL; SSL *clientssl = NULL, *serverssl = NULL; @@ -114,6 +116,7 @@ static int test_rpk(int idx) int idx_cert, idx_prot; int client_auth = 0; int resumption = 0; + int want_error = SSL_ERROR_NONE; long server_verify_result = 0; long client_verify_result = 0; OSSL_LIB_CTX *test_libctx = NULL; @@ -188,7 +191,7 @@ static int test_rpk(int idx) #ifdef OPENSSL_NO_ECDSA /* Can't get other_key if it's ECDSA */ if (other_pkey == NULL && idx_cert == 0 - && (idx == 4 || idx == 6 || idx == 7)) { + && (idx == 4 || idx == 6 || idx == 7 || idx == 16)) { testresult = TEST_skip("EDCSA disabled"); goto end; } @@ -266,8 +269,10 @@ static int test_rpk(int idx) goto end; /* Only a private key */ if (idx == 1) { - if (idx_server_server_rpk == 0 || idx_client_server_rpk == 0) + if (idx_server_server_rpk == 0 || idx_client_server_rpk == 0) { expected = 0; + want_error = SSL_ERROR_SSL; + } } else { /* Add certificate */ if (!TEST_int_eq(SSL_use_certificate_file(serverssl, cert_file, SSL_FILETYPE_PEM), 1)) @@ -333,12 +338,14 @@ static int test_rpk(int idx) client_expected = -1; if (!TEST_true(SSL_add_expected_rpk(clientssl, other_pkey))) goto end; + SSL_set_verify(clientssl, SSL_VERIFY_NONE, rpk_verify_client_cb); client_verify_result = X509_V_ERR_DANE_NO_MATCH; break; case 8: if (idx_server_server_rpk == 1 && idx_client_server_rpk == 1) client_expected = -1; /* no peer keys */ + SSL_set_verify(clientssl, SSL_VERIFY_NONE, rpk_verify_client_cb); client_verify_result = X509_V_ERR_RPK_UNTRUSTED; break; case 9: @@ -370,9 +377,13 @@ static int test_rpk(int idx) if (!TEST_int_eq(SSL_use_PrivateKey_file(clientssl, privkey_file, SSL_FILETYPE_PEM), 1)) goto end; /* Since there's no cert, this is expected to fail without RPK support */ - if (!idx_server_client_rpk || !idx_client_client_rpk) + if (!idx_server_client_rpk || !idx_client_client_rpk) { expected = 0; - SSL_set_verify(serverssl, SSL_VERIFY_PEER | SSL_VERIFY_FAIL_IF_NO_PEER_CERT, rpk_verify_server_cb); + want_error = SSL_ERROR_SSL; + SSL_set_verify(serverssl, SSL_VERIFY_PEER | SSL_VERIFY_FAIL_IF_NO_PEER_CERT, NULL); + } else { + SSL_set_verify(serverssl, SSL_VERIFY_PEER | SSL_VERIFY_FAIL_IF_NO_PEER_CERT, rpk_verify_server_cb); + } client_auth = 1; break; case 11: @@ -449,12 +460,35 @@ static int test_rpk(int idx) if (!TEST_true(SSL_add_expected_rpk(clientssl, pkey))) goto end; break; + case 16: + if (idx_server_server_rpk == 1 && idx_client_server_rpk == 1) { + /* wrong expected server key */ + expected = 0; + want_error = SSL_ERROR_SSL; + SSL_set_verify(serverssl, SSL_VERIFY_PEER, NULL); + } + if (!TEST_true(SSL_add_expected_rpk(clientssl, other_pkey))) + goto end; + break; + case 17: + if (idx_server_server_rpk == 1 && idx_client_server_rpk == 1) { + /* no expected server keys */ + expected = 0; + want_error = SSL_ERROR_SSL; + SSL_set_verify(serverssl, SSL_VERIFY_PEER, NULL); + } + break; } - ret = create_ssl_connection(serverssl, clientssl, SSL_ERROR_NONE); + ret = create_ssl_connection(serverssl, clientssl, want_error); if (!TEST_int_eq(expected, ret)) goto end; + if (expected <= 0) { + testresult = 1; + goto end; + } + /* Make sure client gets RPK or certificate as configured */ if (expected == 1) { if (idx_server_server_rpk && idx_client_server_rpk) {
Vulnerability mechanics
Generated by null/stub on May 9, 2026. Inputs: CWE entries + fix-commit diffs from this CVE's patches. Citations validated against bundle.
References
10- github.com/advisories/GHSA-79v4-65xg-pq4gghsaADVISORY
- nvd.nist.gov/vuln/detail/CVE-2024-12797ghsaADVISORY
- www.openwall.com/lists/oss-security/2025/02/11/3nvdWEB
- www.openwall.com/lists/oss-security/2025/02/11/4nvdWEB
- github.com/openssl/openssl/commit/738d4f9fdeaad57660dcba50a619fafced3fd5e9nvdWEB
- github.com/openssl/openssl/commit/798779d43494549b611233f92652f0da5328fbe7nvdWEB
- github.com/openssl/openssl/commit/87ebd203feffcf92ad5889df92f90bb0ee10a699nvdWEB
- github.com/pyca/cryptography/security/advisories/GHSA-79v4-65xg-pq4gghsaWEB
- openssl-library.org/news/secadv/20250211.txtnvdWEB
- security.netapp.com/advisory/ntap-20250214-0001/nvd
News mentions
0No linked articles in our index yet.