Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
43 changes: 43 additions & 0 deletions src/ssl.c
Original file line number Diff line number Diff line change
Expand Up @@ -10992,6 +10992,49 @@ const WOLFSSL_CIPHER* wolfSSL_get_cipher_by_value(word16 value)
return cipher;
}

#if defined(OPENSSL_ALL) || defined(WOLFSSL_NGINX) || \
defined(WOLFSSL_HAPROXY) || defined(OPENSSL_EXTRA) || defined(HAVE_LIGHTY)
/* Locate a cipher in the SSL's cipher list by 2-byte wire-format suite id.
*
* Mirrors OpenSSL's SSL_CIPHER_find(ssl, ptr). The two bytes pointed to by
* ptr are the on-the-wire cipher suite identifier (ptr[0] is the high byte,
* ptr[1] is the low byte). Lookup is restricted to ciphers in ssl's cipher
* list, matching OpenSSL semantics.
*
* Returned pointer references storage owned by the SSL object's internal
* cipher list; callers must not free it. It remains valid until SSL_free.
*
* @param [in] ssl SSL/TLS object whose cipher list is searched.
* @param [in] ptr Pointer to a 2-byte cipher suite identifier.
* @return Matching cipher on success.
* @return NULL if ssl or ptr is NULL, or no cipher matches.
*/
const WOLFSSL_CIPHER* wolfSSL_SSL_CIPHER_find(WOLFSSL* ssl,
const unsigned char* ptr)
{
WOLF_STACK_OF(WOLFSSL_CIPHER)* sk;
WOLFSSL_STACK* node;

WOLFSSL_ENTER("wolfSSL_SSL_CIPHER_find");

if (ssl == NULL || ptr == NULL)
return NULL;

sk = wolfSSL_get_ciphers_compat(ssl);
if (sk == NULL)
return NULL;

for (node = sk; node != NULL; node = node->next) {
if (node->data.cipher.cipherSuite0 == ptr[0] &&
node->data.cipher.cipherSuite == ptr[1]) {
return &node->data.cipher;
}
}

return NULL;
}
#endif


#if defined(HAVE_ECC) || defined(HAVE_CURVE25519) || defined(HAVE_CURVE448) || \
!defined(NO_DH) || (defined(WOLFSSL_TLS13) && defined(WOLFSSL_HAVE_MLKEM))
Expand Down
35 changes: 35 additions & 0 deletions src/ssl_load.c
Original file line number Diff line number Diff line change
Expand Up @@ -5270,6 +5270,41 @@ int wolfSSL_add1_chain_cert(WOLFSSL* ssl, WOLFSSL_X509* x509)

return ret;
}

/* Clear all extra chain certificates set on the SSL object.
*
* Mirrors OpenSSL's SSL_clear_chain_certs(): frees any chain certificates
* previously added via SSL_add0_chain_cert / SSL_add1_chain_cert (or set via
* SSL_set0_chain / SSL_set1_chain) on this SSL. Does not affect the leaf
* certificate, the private key, or chain certificates inherited from the
* WOLFSSL_CTX.
*
* @param [in, out] ssl SSL object.
* @return 1 on success.
* @return 0 when ssl is NULL.
*/
int wolfSSL_clear_chain_certs(WOLFSSL* ssl)
{
WOLFSSL_ENTER("wolfSSL_clear_chain_certs");

if (ssl == NULL)
return 0;

/* Free the DER-encoded chain buffer if this SSL owns it. */
if (ssl->buffers.weOwnCertChain) {
FreeDer(&ssl->buffers.certChain);
ssl->buffers.weOwnCertChain = 0;
}
ssl->buffers.certChain = NULL;

/* Free the X509 stack used to track ownership of added chain certs. */
if (ssl->ourCertChain != NULL) {
wolfSSL_sk_X509_pop_free(ssl->ourCertChain, NULL);
ssl->ourCertChain = NULL;
}

return 1;
}
#endif /* KEEP_OUR_CERT */
#endif /* OPENSSL_EXTRA, HAVE_LIGHTY, WOLFSSL_MYSQL_COMPATIBLE, HAVE_STUNNEL,
WOLFSSL_NGINX, HAVE_POCO_LIB, WOLFSSL_HAPROXY */
Expand Down
48 changes: 48 additions & 0 deletions src/ssl_sk.c
Original file line number Diff line number Diff line change
Expand Up @@ -1205,6 +1205,54 @@ void wolfSSL_sk_SSL_CIPHER_free(WOLF_STACK_OF(WOLFSSL_CIPHER)* sk)
WOLFSSL_ENTER("wolfSSL_sk_SSL_CIPHER_free");
wolfSSL_sk_free(sk);
}

/* Remove the cipher at the given index from the stack.
*
* @param [in,out] sk Stack of ciphers.
* @param [in] idx Index of cipher to remove.
* @return Heap copy of removed cipher on success.
* @return NULL on failure.
*/
WOLFSSL_CIPHER* wolfSSL_sk_SSL_CIPHER_delete(
WOLF_STACK_OF(WOLFSSL_CIPHER)* sk, int idx)
{
WOLFSSL_CIPHER* ret = NULL;
WOLFSSL_STACK* node;
int num;

WOLFSSL_ENTER("wolfSSL_sk_SSL_CIPHER_delete");

if (sk == NULL || idx < 0)
return NULL;

num = wolfSSL_sk_SSL_CIPHER_num(sk);
if (idx >= num)
return NULL;

/* Walk to the node so we can capture its inline cipher value before the
* pop_node call frees the underlying memory. */
node = sk;
{
int i;
for (i = 0; i < idx && node != NULL; i++)
node = node->next;
}
if (node == NULL)
return NULL;

ret = (WOLFSSL_CIPHER*)XMALLOC(sizeof(WOLFSSL_CIPHER), NULL,
DYNAMIC_TYPE_OPENSSL);
if (ret == NULL)
return NULL;

*ret = node->data.cipher;

/* pop_node returns NULL for STACK_TYPE_CIPHER (data is static/inline),
* but it still performs the unlink and node free that we need. */
(void)wolfSSL_sk_pop_node(sk, idx);

return ret;
}
#endif /* OPENSSL_ALL || OPENSSL_EXTRA */

/*******************************************************************************
Expand Down
161 changes: 161 additions & 0 deletions tests/api.c
Original file line number Diff line number Diff line change
Expand Up @@ -3693,6 +3693,89 @@ static int test_wolfSSL_CTX_add1_chain_cert(void)
return EXPECT_RESULT();
}

/* Test SSL_clear_chain_certs: must drop chain certs added via add0/add1,
* leave leaf certificate intact, and tolerate repeated calls / NULL input. */
static int test_wolfSSL_clear_chain_certs(void)
{
EXPECT_DECLS;
#if !defined(NO_FILESYSTEM) && !defined(NO_CERTS) && defined(OPENSSL_EXTRA) && \
defined(KEEP_OUR_CERT) && !defined(NO_RSA) && !defined(NO_TLS) && \
!defined(NO_WOLFSSL_CLIENT)
WOLFSSL_CTX* ctx = NULL;
WOLFSSL* ssl = NULL;
WOLFSSL_X509* x509 = NULL;
WOLF_STACK_OF(X509)* chain = NULL;
const char* chainCerts[] = {
"./certs/intermediate/ca-int2-cert.pem",
"./certs/intermediate/ca-int-cert.pem",
NULL
};
const char** cert;

/* NULL arg. */
ExpectIntEQ(SSL_clear_chain_certs(NULL), 0);

ExpectNotNull(ctx = wolfSSL_CTX_new(wolfSSLv23_client_method()));
ExpectNotNull(ssl = wolfSSL_new(ctx));

/* Clear on an SSL with no chain is a no-op success. */
ExpectIntEQ(SSL_clear_chain_certs(ssl), 1);

/* Set leaf so subsequent adds go to the chain. */
ExpectNotNull(x509 = wolfSSL_X509_load_certificate_file(
"./certs/intermediate/client-int-cert.pem", WOLFSSL_FILETYPE_PEM));
ExpectIntEQ(SSL_add1_chain_cert(ssl, x509), 1);
wolfSSL_X509_free(x509);
x509 = NULL;

for (cert = chainCerts; EXPECT_SUCCESS() && *cert != NULL; cert++) {
ExpectNotNull(x509 = wolfSSL_X509_load_certificate_file(*cert,
WOLFSSL_FILETYPE_PEM));
ExpectIntEQ(SSL_add1_chain_cert(ssl, x509), 1);
wolfSSL_X509_free(x509);
x509 = NULL;
}

/* Chain populated with the 2 intermediates. */
ExpectIntEQ(SSL_get0_chain_certs(ssl, &chain), 1);
ExpectIntEQ(sk_X509_num(chain), 2);
if (ssl != NULL) {
ExpectIntEQ(ssl->buffers.certChainCnt, 2);
ExpectNotNull(ssl->buffers.certChain);
ExpectNotNull(ssl->ourCertChain);
}

/* Clear. */
ExpectIntEQ(SSL_clear_chain_certs(ssl), 1);
if (ssl != NULL) {
ExpectNull(ssl->buffers.certChain);
ExpectNull(ssl->ourCertChain);
ExpectIntEQ(ssl->buffers.weOwnCertChain, 0);
/* Leaf untouched. */
ExpectNotNull(ssl->ourCert);
}
chain = NULL;
ExpectIntEQ(SSL_get0_chain_certs(ssl, &chain), 1);
ExpectIntEQ(sk_X509_num(chain), 0);

/* Idempotent: clearing again still succeeds. */
ExpectIntEQ(SSL_clear_chain_certs(ssl), 1);

/* Re-adding after clear works. */
ExpectNotNull(x509 = wolfSSL_X509_load_certificate_file(
"./certs/intermediate/ca-int2-cert.pem", WOLFSSL_FILETYPE_PEM));
ExpectIntEQ(SSL_add1_chain_cert(ssl, x509), 1);
wolfSSL_X509_free(x509);
chain = NULL;
ExpectIntEQ(SSL_get0_chain_certs(ssl, &chain), 1);
ExpectIntEQ(sk_X509_num(chain), 1);

SSL_free(ssl);
SSL_CTX_free(ctx);
#endif
return EXPECT_RESULT();
}

/* Test that wolfssl_add_to_chain rejects sizes that would overflow word32.
* ZD #21241 */
static int test_wolfSSL_add_to_chain_overflow(void)
Expand Down Expand Up @@ -17028,6 +17111,26 @@ static int test_wolfSSL_sk_SSL_CIPHER(void)

/* error case because connection has not been established yet */
ExpectIntEQ(sk_SSL_CIPHER_find(sk, SSL_get_current_cipher(ssl)), -1);

/* Exercise sk_SSL_CIPHER_delete on the duplicated stack so we don't
* disturb the SSL object's internal cipher list. */
{
int dupNum = sk_SSL_CIPHER_num(dupSk);
if (dupNum > 0) {
SSL_CIPHER* removed = NULL;

/* Out-of-range and negative idx should return NULL. */
ExpectNull(sk_SSL_CIPHER_delete(dupSk, -1));
ExpectNull(sk_SSL_CIPHER_delete(dupSk, dupNum));
ExpectNull(sk_SSL_CIPHER_delete(NULL, 0));

/* Delete the head element and verify count decreased. */
ExpectNotNull(removed = sk_SSL_CIPHER_delete(dupSk, 0));
ExpectIntEQ(sk_SSL_CIPHER_num(dupSk), dupNum - 1);
XFREE(removed, NULL, DYNAMIC_TYPE_OPENSSL);
}
}

sk_SSL_CIPHER_free(dupSk);

/* sk is pointer to internal struct that should be free'd in SSL_free */
Expand All @@ -17039,6 +17142,62 @@ static int test_wolfSSL_sk_SSL_CIPHER(void)
return EXPECT_RESULT();
}

static int test_wolfSSL_SSL_CIPHER_find(void)
{
EXPECT_DECLS;
#if (defined(OPENSSL_ALL) || defined(OPENSSL_EXTRA) || \
defined(WOLFSSL_NGINX) || defined(WOLFSSL_HAPROXY) || \
defined(HAVE_LIGHTY)) && \
!defined(NO_CERTS) && !defined(NO_TLS) && !defined(NO_FILESYSTEM) && \
!defined(NO_RSA) && \
(!defined(NO_WOLFSSL_CLIENT) || !defined(NO_WOLFSSL_SERVER))
SSL* ssl = NULL;
SSL_CTX* ctx = NULL;
STACK_OF(SSL_CIPHER)* sk = NULL;
const SSL_CIPHER* found = NULL;
unsigned char id[2];
const unsigned char bogus[2] = { 0xFF, 0xFF };

#ifndef NO_WOLFSSL_SERVER
ExpectNotNull(ctx = SSL_CTX_new(wolfSSLv23_server_method()));
#else
ExpectNotNull(ctx = SSL_CTX_new(wolfSSLv23_client_method()));
#endif
ExpectTrue(SSL_CTX_use_certificate_file(ctx, svrCertFile, SSL_FILETYPE_PEM));
ExpectTrue(SSL_CTX_use_PrivateKey_file(ctx, svrKeyFile, SSL_FILETYPE_PEM));
ExpectNotNull(ssl = SSL_new(ctx));
ExpectNotNull(sk = SSL_get_ciphers(ssl));
ExpectIntGT(sk_SSL_CIPHER_num(sk), 0);

/* Pick the first cipher in ssl's list and round-trip via SSL_CIPHER_find. */
if (sk != NULL && sk_SSL_CIPHER_num(sk) > 0) {
const WOLFSSL_CIPHER* first = sk_SSL_CIPHER_value(sk, 0);
ExpectNotNull(first);
if (first != NULL) {
id[0] = first->cipherSuite0;
id[1] = first->cipherSuite;

ExpectNotNull(found = SSL_CIPHER_find(ssl, id));
if (found != NULL) {
ExpectIntEQ(found->cipherSuite0, id[0]);
ExpectIntEQ(found->cipherSuite, id[1]);
}
}
}

/* NULL arg handling. */
ExpectNull(SSL_CIPHER_find(NULL, id));
ExpectNull(SSL_CIPHER_find(ssl, NULL));

/* Suite not in ssl's cipher list. */
ExpectNull(SSL_CIPHER_find(ssl, bogus));

SSL_free(ssl);
SSL_CTX_free(ctx);
#endif
return EXPECT_RESULT();
}

static int test_wolfSSL_set1_curves_list(void)
{
EXPECT_DECLS;
Expand Down Expand Up @@ -40180,6 +40339,7 @@ TEST_CASE testCases[] = {
#endif
TEST_DECL(test_wolfSSL_configure_args),
TEST_DECL(test_wolfSSL_sk_SSL_CIPHER),
TEST_DECL(test_wolfSSL_SSL_CIPHER_find),
TEST_DECL(test_wolfSSL_set1_curves_list),
TEST_DECL(test_wolfSSL_curves_mismatch),
TEST_DECL(test_wolfSSL_set1_sigalgs_list),
Expand Down Expand Up @@ -40483,6 +40643,7 @@ TEST_CASE testCases[] = {
TEST_DECL(test_wolfSSL_CTX_load_verify_buffer_ex),
TEST_DECL(test_wolfSSL_CTX_load_verify_chain_buffer_format),
TEST_DECL(test_wolfSSL_CTX_add1_chain_cert),
TEST_DECL(test_wolfSSL_clear_chain_certs),
TEST_DECL(test_wolfSSL_add_to_chain_overflow),
TEST_DECL(test_wolfSSL_CTX_use_certificate_chain_buffer_format),
TEST_DECL(test_wolfSSL_CTX_use_certificate_chain_file_format),
Expand Down
3 changes: 3 additions & 0 deletions wolfssl/openssl/ssl.h
Original file line number Diff line number Diff line change
Expand Up @@ -1367,6 +1367,8 @@ typedef WOLFSSL_SRTP_PROTECTION_PROFILE SRTP_PROTECTION_PROFILE;
#define sk_SSL_CIPHER_dup wolfSSL_shallow_sk_dup
#define sk_SSL_CIPHER_free wolfSSL_sk_SSL_CIPHER_free
#define sk_SSL_CIPHER_find wolfSSL_sk_SSL_CIPHER_find
#define sk_SSL_CIPHER_delete wolfSSL_sk_SSL_CIPHER_delete
#define SSL_CIPHER_find wolfSSL_SSL_CIPHER_find

#if defined(SESSION_CERTS) && defined(OPENSSL_EXTRA)
#define SSL_get0_peername wolfSSL_get0_peername
Expand All @@ -1383,6 +1385,7 @@ typedef WOLFSSL_SRTP_PROTECTION_PROFILE SRTP_PROTECTION_PROFILE;
#define SSL_CTRL_CLEAR_EXTRA_CHAIN_CERTS 83

#define SSL_CTX_clear_chain_certs(ctx) SSL_CTX_set0_chain(ctx,NULL)
#define SSL_clear_chain_certs wolfSSL_clear_chain_certs
#define d2i_RSAPrivateKey_bio wolfSSL_d2i_RSAPrivateKey_bio
#define SSL_CTX_use_RSAPrivateKey wolfSSL_CTX_use_RSAPrivateKey
#define d2i_PrivateKey_bio wolfSSL_d2i_PrivateKey_bio
Expand Down
8 changes: 8 additions & 0 deletions wolfssl/ssl.h
Original file line number Diff line number Diff line change
Expand Up @@ -2985,6 +2985,11 @@ WOLFSSL_API int wolfSSL_CIPHER_get_digest_nid(const WOLFSSL_CIPHER* cipher);
WOLFSSL_API int wolfSSL_CIPHER_get_kx_nid(const WOLFSSL_CIPHER* cipher);
WOLFSSL_API int wolfSSL_CIPHER_is_aead(const WOLFSSL_CIPHER* cipher);
WOLFSSL_API const WOLFSSL_CIPHER* wolfSSL_get_cipher_by_value(word16 value);
#if defined(OPENSSL_ALL) || defined(WOLFSSL_NGINX) || \
defined(WOLFSSL_HAPROXY) || defined(OPENSSL_EXTRA) || defined(HAVE_LIGHTY)
WOLFSSL_API const WOLFSSL_CIPHER* wolfSSL_SSL_CIPHER_find(WOLFSSL* ssl,
const unsigned char* ptr);
#endif
WOLFSSL_API const char* wolfSSL_SESSION_CIPHER_get_name(const WOLFSSL_SESSION* session);
WOLFSSL_API const char* wolfSSL_get_cipher(WOLFSSL* ssl);
WOLFSSL_API void wolfSSL_sk_CIPHER_free(WOLF_STACK_OF(WOLFSSL_CIPHER)* sk);
Expand Down Expand Up @@ -5403,6 +5408,7 @@ WOLFSSL_API int wolfSSL_CTX_add0_chain_cert(WOLFSSL_CTX* ctx, WOLFSSL_X509* x509
WOLFSSL_API int wolfSSL_CTX_add1_chain_cert(WOLFSSL_CTX* ctx, WOLFSSL_X509* x509);
WOLFSSL_API int wolfSSL_add0_chain_cert(WOLFSSL* ssl, WOLFSSL_X509* x509);
WOLFSSL_API int wolfSSL_add1_chain_cert(WOLFSSL* ssl, WOLFSSL_X509* x509);
WOLFSSL_API int wolfSSL_clear_chain_certs(WOLFSSL* ssl);
WOLFSSL_API int wolfSSL_BIO_read_filename(WOLFSSL_BIO *b, const char *name);
/* These are to be merged shortly */
WOLFSSL_API void wolfSSL_set_verify_depth(WOLFSSL *ssl,int depth);
Expand Down Expand Up @@ -6054,6 +6060,8 @@ WOLFSSL_API int wolfSSL_sk_SSL_CIPHER_num(const WOLF_STACK_OF(WOLFSSL_CIPHER)* p
WOLFSSL_API int wolfSSL_sk_SSL_CIPHER_find(
WOLF_STACK_OF(WOLFSSL_CIPHER)* sk, const WOLFSSL_CIPHER* toFind);
WOLFSSL_API void wolfSSL_sk_SSL_CIPHER_free(WOLF_STACK_OF(WOLFSSL_CIPHER)* sk);
WOLFSSL_API WOLFSSL_CIPHER* wolfSSL_sk_SSL_CIPHER_delete(
WOLF_STACK_OF(WOLFSSL_CIPHER)* sk, int idx);
WOLFSSL_API int wolfSSL_sk_SSL_COMP_zero(WOLFSSL_STACK* st);
WOLFSSL_API int wolfSSL_sk_SSL_COMP_num(WOLF_STACK_OF(WOLFSSL_COMP)* sk);
WOLFSSL_API WOLFSSL_CIPHER* wolfSSL_sk_SSL_CIPHER_value(WOLFSSL_STACK* sk, int i);
Expand Down
Loading