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
20 changes: 9 additions & 11 deletions src/ssl_load.c
Original file line number Diff line number Diff line change
Expand Up @@ -1672,7 +1672,7 @@ static int ProcessBufferCertPublicKey(WOLFSSL_CTX* ctx, WOLFSSL* ssl,
ECC_KEY_SIZE_E);
}
break;
#endif /* HAVE_ED25519 */
#endif /* WOLFSSL_SM2 && WOLFSSL_SM3 */
#ifdef HAVE_ED25519
case ED25519k:
keyType = ed25519_sa_algo;
Expand Down Expand Up @@ -1882,7 +1882,7 @@ static int ProcessBufferCertAltPublicKey(WOLFSSL_CTX* ctx, WOLFSSL* ssl,
ECC_KEY_SIZE_E);
}
break;
#endif /* HAVE_ED25519 */
#endif /* WOLFSSL_SM2 && WOLFSSL_SM3 */
#ifdef HAVE_ED25519
case ED25519k:
keyType = ed25519_sa_algo;
Expand Down Expand Up @@ -4684,7 +4684,7 @@ int wolfSSL_use_AltPrivateKey_Id(WOLFSSL* ssl, const unsigned char* id, long sz,
#endif
}
if (AllocDer(&ssl->buffers.altKey, (word32)sz, ALT_PRIVATEKEY_TYPE,
ssl->heap) == 0) {
ssl->heap) != 0) {
ret = 0;
}
}
Expand Down Expand Up @@ -4732,7 +4732,7 @@ int wolfSSL_use_AltPrivateKey_Label(WOLFSSL* ssl, const char* label, int devId)
#endif
}
if (AllocDer(&ssl->buffers.altKey, (word32)sz, ALT_PRIVATEKEY_TYPE,
ssl->heap) == 0) {
ssl->heap) != 0) {
ret = 0;
}
}
Expand Down Expand Up @@ -5202,7 +5202,7 @@ int wolfSSL_add1_chain_cert(WOLFSSL* ssl, WOLFSSL_X509* x509)
}

/* Increase reference count on X509 object before adding. */
if ((ret == 1) && ((ret == wolfSSL_X509_up_ref(x509)) == 1)) {
if ((ret == 1) && ((ret = wolfSSL_X509_up_ref(x509)) == 1)) {
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟡 [Medium] No regression test for wolfSSL_add1_chain_cert comparison-to-assignment fix
💡 SUGGEST test

The fix changes ret == wolfSSL_X509_up_ref(x509) to ret = wolfSSL_X509_up_ref(x509). While there is an existing test_wolfSSL_CTX_add1_chain_cert that exercises wolfSSL_add1_chain_cert, no new test was added specifically to catch this regression. The old bug was masked because wolfSSL_X509_up_ref normally returns 1 and ret was already 1, making the comparison accidentally true. A test that forces wolfSSL_X509_up_ref to fail (e.g., by corrupting the ref count mutex or testing error propagation) would guard against future regressions of this type. The PR description acknowledges the bug but no dedicated test was added, unlike the AltPrivateKey fixes which got regression tests.

Recommendation: Consider adding a targeted regression test or at minimum a comment in the existing test noting which code path validates this fix.

— Skoll automated review via openclaw

/* Add this to the chain. */
if ((ret = wolfSSL_add0_chain_cert(ssl, x509)) != 1) {
/* Decrease reference count on error as not stored. */
Expand Down Expand Up @@ -5864,7 +5864,7 @@ long wolfSSL_CTX_set_tmp_dh(WOLFSSL_CTX* ctx, WOLFSSL_DH* dh)
pSz = wolfSSL_BN_bn2bin(dh->p, p);
gSz = wolfSSL_BN_bn2bin(dh->g, g);
/* Check encoding worked. */
if ((pSz < 0) && (gSz < 0)) {
if ((pSz <= 0) || (gSz <= 0)) {
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟡 [Medium] No regression test for wolfSSL_CTX_set_tmp_dh operator fix
💡 SUGGEST test

The fix changes (pSz < 0) && (gSz < 0) to (pSz <= 0) || (gSz <= 0). The old code only detected failure when both p and g encoding failed, and missed zero-length returns. No new test was added to exercise the case where exactly one of p or g fails, or where a zero-length return occurs. The existing test_wolfSSL_tmp_dh covers valid DH operations but does not specifically test the error path that was broken. Unlike the AltPrivateKey fixes, there is no regression test for this.

Recommendation: Consider adding a test that triggers the single-operand failure or zero-length case to guard against regression of the && vs || and < 0 vs <= 0 fix.

— Skoll automated review via openclaw

ret = WOLFSSL_FATAL_ERROR;
}
}
Expand Down Expand Up @@ -5930,12 +5930,10 @@ static int ws_ctx_ssl_set_tmp_dh(WOLFSSL_CTX* ctx, WOLFSSL* ssl,

/* PemToDer allocates its own DER buffer. */
if ((res == 1) && (format != WOLFSSL_FILETYPE_PEM)) {
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟡 [Medium] ws_ctx_ssl_set_tmp_dh fix could benefit from a targeted test for the ASN1 path
💡 SUGGEST test

The fix replaces a dangerous cast-away-const + zero-size AllocDer pattern with a proper sized allocation + XMEMCPY. This is a correct and important fix — the old code pointed der->buffer directly at the caller's const buf, meaning FreeDer at line 5990 would try to free memory it didn't own (undefined behavior). The new code properly allocates (word32)sz bytes and copies data in. However, the ws_ctx_ssl_set_tmp_dh function is called by wolfSSL_SetTmpDH_buffer and wolfSSL_CTX_SetTmpDH_buffer, and there is no specific test exercising the WOLFSSL_FILETYPE_ASN1 format path through these callers. A test passing raw DER-encoded DH parameters would exercise the fixed code path.

Recommendation: Consider adding a test that calls wolfSSL_SetTmpDH_buffer or wolfSSL_CTX_SetTmpDH_buffer with WOLFSSL_FILETYPE_ASN1 to exercise the fixed DER allocation path.

— Skoll automated review via openclaw

/* Create an empty DER buffer. */
ret = AllocDer(&der, 0, DH_PARAM_TYPE, heap);
/* Create a DER buffer and copy in the encoded DH parameters. */
ret = AllocDer(&der, (word32)sz, DH_PARAM_TYPE, heap);
if (ret == 0) {
/* Assign encoded DH parameters to DER buffer. */
der->buffer = (byte*)buf;
der->length = (word32)sz;
XMEMCPY(der->buffer, buf, (word32)sz);
}
else {
res = ret;
Expand Down
133 changes: 133 additions & 0 deletions tests/api.c
Original file line number Diff line number Diff line change
Expand Up @@ -1683,6 +1683,68 @@ static int test_dual_alg_ecdsa_mldsa(void)
return EXPECT_RESULT();
}

/* Test wolfSSL_use_AltPrivateKey_Id.
* Verify that a valid key ID can be set successfully. Guards against an
* inverted AllocDer return check (== 0 vs != 0) that would treat successful
* allocation as failure. */
static int test_wolfSSL_use_AltPrivateKey_Id(void)
{
EXPECT_DECLS;
#if defined(WOLFSSL_DUAL_ALG_CERTS) && !defined(NO_TLS) && \
!defined(NO_WOLFSSL_CLIENT)
WOLFSSL_CTX* ctx = NULL;
WOLFSSL* ssl = NULL;
const unsigned char id[] = { 0x01, 0x02, 0x03, 0x04 };

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

/* Negative tests. */
ExpectIntEQ(wolfSSL_use_AltPrivateKey_Id(NULL, id, sizeof(id),
INVALID_DEVID), 0);
ExpectIntEQ(wolfSSL_use_AltPrivateKey_Id(ssl, NULL, sizeof(id),
INVALID_DEVID), 0);

/* Positive test - valid ID should succeed. */
ExpectIntEQ(wolfSSL_use_AltPrivateKey_Id(ssl, id, sizeof(id),
INVALID_DEVID), 1);

wolfSSL_free(ssl);
wolfSSL_CTX_free(ctx);
#endif /* WOLFSSL_DUAL_ALG_CERTS && !NO_TLS && !NO_WOLFSSL_CLIENT */
return EXPECT_RESULT();
}

/* Test wolfSSL_use_AltPrivateKey_Label.
* Verify that a valid key label can be set successfully. Guards against an
* inverted AllocDer return check (== 0 vs != 0) that would treat successful
* allocation as failure. */
static int test_wolfSSL_use_AltPrivateKey_Label(void)
{
EXPECT_DECLS;
#if defined(WOLFSSL_DUAL_ALG_CERTS) && !defined(NO_TLS) && \
!defined(NO_WOLFSSL_CLIENT)
WOLFSSL_CTX* ctx = NULL;
WOLFSSL* ssl = NULL;

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

/* Negative tests. */
ExpectIntEQ(wolfSSL_use_AltPrivateKey_Label(NULL, "label", INVALID_DEVID),
0);
ExpectIntEQ(wolfSSL_use_AltPrivateKey_Label(ssl, NULL, INVALID_DEVID), 0);

/* Positive test - valid label should succeed. */
ExpectIntEQ(wolfSSL_use_AltPrivateKey_Label(ssl, "test_label",
INVALID_DEVID), 1);

wolfSSL_free(ssl);
wolfSSL_CTX_free(ctx);
#endif /* WOLFSSL_DUAL_ALG_CERTS && !NO_TLS && !NO_WOLFSSL_CLIENT */
return EXPECT_RESULT();
}


/*----------------------------------------------------------------------------*
| Context
Expand Down Expand Up @@ -3492,6 +3554,11 @@ static int test_wolfSSL_CTX_add1_chain_cert(void)
}

ExpectIntEQ(SSL_CTX_add1_chain_cert(ctx, x509), 1);
/* add1 must increment ref count (was 1, now 2). Verifies the
* up_ref return value is assigned, not just compared. */
if (EXPECT_SUCCESS() && x509 != NULL) {
ExpectIntEQ(wolfSSL_RefCur(x509->ref), 2);
}
X509_free(x509);
x509 = NULL;
}
Expand All @@ -3511,6 +3578,10 @@ static int test_wolfSSL_CTX_add1_chain_cert(void)
}

ExpectIntEQ(SSL_add1_chain_cert(ssl, x509), 1);
/* add1 must increment ref count (was 1, now 2) */
if (EXPECT_SUCCESS() && x509 != NULL) {
ExpectIntEQ(wolfSSL_RefCur(x509->ref), 2);
}
X509_free(x509);
x509 = NULL;
}
Expand Down Expand Up @@ -13235,6 +13306,64 @@ static int test_wolfSSL_tmp_dh(void)
return EXPECT_RESULT();
}

/* Tests SSL_CTX_set_tmp_dh with single-operand failure (p set, g missing)
* and wolfSSL_CTX_SetTmpDH_buffer with WOLFSSL_FILETYPE_ASN1 DER input. */
static int test_wolfSSL_tmp_dh_regression(void)
{
EXPECT_DECLS;
#if defined(OPENSSL_EXTRA) && !defined(NO_DH) && !defined(NO_CERTS) && \
!defined(NO_FILESYSTEM) && !defined(NO_RSA) && !defined(NO_TLS) && \
!defined(NO_WOLFSSL_SERVER)
SSL_CTX* ctx = NULL;

ExpectNotNull(ctx = SSL_CTX_new(wolfSSLv23_server_method()));
ExpectTrue(SSL_CTX_use_certificate_file(ctx, svrCertFile,
WOLFSSL_FILETYPE_PEM));
ExpectTrue(SSL_CTX_use_PrivateKey_file(ctx, svrKeyFile,
WOLFSSL_FILETYPE_PEM));

#if defined(OPENSSL_ALL) || \
(defined(OPENSSL_VERSION_NUMBER) && OPENSSL_VERSION_NUMBER >= 0x10100000L)
{
/* Test single-operand failure: DH with p but no g. */
DH* dh = NULL;
WOLFSSL_BIGNUM* p_bn = NULL;

ExpectNotNull(dh = wolfSSL_DH_new());
ExpectNotNull(p_bn = wolfSSL_BN_new());
ExpectIntEQ(wolfSSL_BN_set_word(p_bn, 0xFFFF), 1);
if (dh != NULL && p_bn != NULL) {
if (wolfSSL_DH_set0_pqg(dh, p_bn, NULL, NULL) == 1) {
p_bn = NULL; /* ownership transferred on success */
}
}
ExpectIntEQ((int)SSL_CTX_set_tmp_dh(ctx, dh), WOLFSSL_FATAL_ERROR);
DH_free(dh);
wolfSSL_BN_free(p_bn);
}
#endif

/* Test ASN1/DER path through wolfSSL_CTX_SetTmpDH_buffer. */
{
byte derBuf[4096];
XFILE f = XBADFILE;
int derSz = 0;

ExpectTrue((f = XFOPEN("./certs/dh2048.der", "rb")) != XBADFILE);
if (f != XBADFILE) {
derSz = (int)XFREAD(derBuf, 1, sizeof(derBuf), f);
XFCLOSE(f);
}
ExpectIntGT(derSz, 0);
ExpectIntEQ(wolfSSL_CTX_SetTmpDH_buffer(ctx, derBuf, (long)derSz,
WOLFSSL_FILETYPE_ASN1), WOLFSSL_SUCCESS);
}

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

static int test_wolfSSL_ctrl(void)
{
EXPECT_DECLS;
Expand Down Expand Up @@ -35125,6 +35254,9 @@ TEST_CASE testCases[] = {

TEST_DECL(test_dual_alg_ecdsa_mldsa),

TEST_DECL(test_wolfSSL_use_AltPrivateKey_Id),
TEST_DECL(test_wolfSSL_use_AltPrivateKey_Label),

/*********************************
* OpenSSL compatibility API tests
*********************************/
Expand Down Expand Up @@ -35396,6 +35528,7 @@ TEST_CASE testCases[] = {
TEST_TLS13_DECLS,

TEST_DECL(test_wolfSSL_tmp_dh),
TEST_DECL(test_wolfSSL_tmp_dh_regression),
TEST_DECL(test_wolfSSL_ctrl),

TEST_DECL(test_wolfSSL_get0_param),
Expand Down
Loading