Commit 52ee7fdf27 for openssl.org
commit 52ee7fdf278c2316f1ddd94526f8730e014dd58f
Author: Alexandr Nedvedicky <sashan@openssl.org>
Date: Thu Jul 30 16:02:57 2026 +0200
SSL_dup() should copy additional members
currently those members are missing to be copied in SSL_dup(3ossl)
- server_cert_type
- client_cert_type
- ct_validation_callback
- retsc->ext.status_type (typically needed for OCSP)
All those missing members are usually set before handshake starts,
so SSL_dup() needs to copy them so behavior of duplicated SSL
object is consistent with its original.
Reviewed-by: Neil Horman <nhorman@openssl.org>
Reviewed-by: Andrew Dinh <andrewd@openssl.org>
Merge-date: Wed Aug 19 14:26:25 2026
Merged-from: https://github.com/openssl/openssl/pull/32122
diff --git a/doc/man3/SSL_new.pod b/doc/man3/SSL_new.pod
index 829229461d..64d726e10e 100644
--- a/doc/man3/SSL_new.pod
+++ b/doc/man3/SSL_new.pod
@@ -96,6 +96,14 @@ SSL_set0_client_CA_list() or similar functions
=item any Encrypted Client Hello (ECH) settings (see L<SSL_set1_echstore(3)>).
+=item type of server certificate set via L<SSL_set1_server_cert_type(3)>.
+
+=item type of client certificate set via L<SSL_set1_client_cert_type(3)>.
+
+=item certificate transparency validation callback set via L<SSL_set_ct_validation_callback(3)>,
+
+=item OCSP validation set via L<SSL_set_tlsext_status_type(3)>.
+
=back
SSL_dup() is not supported on QUIC SSL objects and returns NULL if called on
diff --git a/ssl/ssl_lib.c b/ssl/ssl_lib.c
index 362c720bcf..f48a5d9004 100644
--- a/ssl/ssl_lib.c
+++ b/ssl/ssl_lib.c
@@ -5494,6 +5494,31 @@ SSL *SSL_dup(SSL *s)
|| !dup_ca_names(&retsc->client_ca_names, sc->client_ca_names))
goto err;
+ if (sc->server_cert_type != NULL) {
+ OPENSSL_free(retsc->server_cert_type);
+ retsc->server_cert_type = OPENSSL_memdup(sc->server_cert_type,
+ sc->server_cert_type_len);
+ if (retsc->server_cert_type == NULL)
+ goto err;
+ retsc->server_cert_type_len = sc->server_cert_type_len;
+ }
+
+ if (sc->client_cert_type != NULL) {
+ OPENSSL_free(retsc->client_cert_type);
+ retsc->client_cert_type = OPENSSL_memdup(sc->client_cert_type,
+ sc->client_cert_type_len);
+ if (retsc->client_cert_type == NULL)
+ goto err;
+ retsc->client_cert_type_len = sc->client_cert_type_len;
+ }
+
+#ifndef OPENSSL_NO_CT
+ retsc->ct_validation_callback = sc->ct_validation_callback;
+ retsc->ct_validation_callback_arg = sc->ct_validation_callback_arg;
+#endif
+
+ retsc->ext.status_type = sc->ext.status_type;
+
return ret;
err:
diff --git a/test/sslapitest.c b/test/sslapitest.c
index b6081be702..c7c722c08a 100644
--- a/test/sslapitest.c
+++ b/test/sslapitest.c
@@ -11670,12 +11670,29 @@ end:
#endif
#ifndef OPENSSL_NO_TLS1_2
+
+#define CERT_TYPE_C "\x0" /* TLSEXT_cert_type_x509 */
+#define CERT_TYPE_S "\x2" /* TLSEXT_cert_type_rpk */
+
+#ifndef OPENSSL_NO_CT
+#define CB_ARG "callback arg"
+
+/* ARGSUSED */
+static int validation_cbk(const CT_POLICY_EVAL_CTX *ctx,
+ const STACK_OF(SCT) *scts, void *arg)
+{
+ return 1;
+}
+#endif
+
static int test_ssl_dup(void)
{
SSL_CTX *cctx = NULL, *sctx = NULL;
SSL *clientssl = NULL, *serverssl = NULL, *client2ssl = NULL;
int testresult = 0;
BIO *rbio = NULL, *wbio = NULL;
+ unsigned char *ctype;
+ size_t ctype_len;
if (!TEST_true(create_ssl_ctx_pair(libctx, TLS_server_method(),
TLS_client_method(),
@@ -11692,6 +11709,27 @@ static int test_ssl_dup(void)
|| !TEST_true(SSL_set_max_proto_version(clientssl, TLS1_2_VERSION)))
goto end;
+ if (!TEST_true(
+ SSL_set1_client_cert_type(clientssl,
+ (const unsigned char *)CERT_TYPE_C, sizeof(CERT_TYPE_C) - 1)))
+ goto end;
+
+ if (!TEST_true(
+ SSL_set1_server_cert_type(clientssl,
+ (const unsigned char *)CERT_TYPE_S, sizeof(CERT_TYPE_S) - 1)))
+ goto end;
+
+#ifndef OPENSSL_NO_CT
+ if (!TEST_true(SSL_set_ct_validation_callback(clientssl, validation_cbk, CB_ARG)))
+ goto end;
+#endif
+
+#ifndef OPENSSL_NO_OCSP
+ if (!TEST_true(
+ SSL_set_tlsext_status_type(clientssl, TLSEXT_STATUSTYPE_ocsp)))
+ goto end;
+#endif
+
client2ssl = SSL_dup(clientssl);
rbio = SSL_get_rbio(clientssl);
if (!TEST_ptr(rbio)
@@ -11719,6 +11757,28 @@ static int test_ssl_dup(void)
if (!TEST_true(create_ssl_connection(serverssl, client2ssl, SSL_ERROR_NONE)))
goto end;
+ if (!TEST_true(SSL_get0_client_cert_type(client2ssl, &ctype, &ctype_len)))
+ goto end;
+
+ if (!TEST_mem_eq(ctype, ctype_len, CERT_TYPE_C, sizeof(CERT_TYPE_C) - 1))
+ goto end;
+
+ if (!TEST_true(SSL_get0_server_cert_type(client2ssl, &ctype, &ctype_len)))
+ goto end;
+
+ if (!TEST_mem_eq(ctype, ctype_len, CERT_TYPE_S, sizeof(CERT_TYPE_S) - 1))
+ goto end;
+
+#ifndef OPENSSL_NO_CT
+ if (!TEST_true(SSL_ct_is_enabled(client2ssl)))
+ goto end;
+#endif
+
+#ifndef OPENSSL_NO_OCSP
+ if (!TEST_long_eq(SSL_get_tlsext_status_type(client2ssl), TLSEXT_STATUSTYPE_ocsp))
+ goto end;
+#endif
+
SSL_free(clientssl);
clientssl = SSL_dup(client2ssl);
if (!TEST_ptr(clientssl)