Skip to content
Merged
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
2 changes: 1 addition & 1 deletion src/internal.c
Original file line number Diff line number Diff line change
Expand Up @@ -26449,7 +26449,7 @@ int SendCertificateStatus(WOLFSSL* ssl)
WC_FREE_VAR_EX(cert, ssl->heap, DYNAMIC_TYPE_DCERT);
}
else {
while (ret == 0 &&
while (ret == 0 && i < MAX_CHAIN_DEPTH &&
NULL != (request = ssl->ctx->chainOcspRequest[i])) {
if ((i + 1) >= MAX_CERT_EXTENSIONS) {
ret = MAX_CERT_EXTENSIONS_ERR;
Expand Down
10 changes: 5 additions & 5 deletions src/ssl_api_cert.c
Original file line number Diff line number Diff line change
Expand Up @@ -1991,15 +1991,15 @@ int wolfSSL_get_chain_count(WOLFSSL_X509_CHAIN* chain)
* @param [in] chain Certificate chain object.
* @param [in] idx Index of the certificate in the chain.
* @return Length of the DER certificate in bytes on success.
* @return 0 when chain is NULL.
* @return 0 when chain is NULL or idx is out of range.
*/
int wolfSSL_get_chain_length(WOLFSSL_X509_CHAIN* chain, int idx)
{
int length = 0;

WOLFSSL_ENTER("wolfSSL_get_chain_length");

if (chain != NULL) {
if ((chain != NULL) && (idx >= 0) && (idx < chain->count)) {
/* DER length of the certificate stored at the given index. */
length = chain->certs[idx].length;
}
Expand All @@ -2013,15 +2013,15 @@ int wolfSSL_get_chain_length(WOLFSSL_X509_CHAIN* chain, int idx)
* @param [in] chain Certificate chain object.
* @param [in] idx Index of the certificate in the chain.
* @return Buffer holding the DER certificate on success.
* @return 0 when chain is NULL.
* @return 0 when chain is NULL or idx is out of range.
*/
byte* wolfSSL_get_chain_cert(WOLFSSL_X509_CHAIN* chain, int idx)
{
byte* cert = NULL;

WOLFSSL_ENTER("wolfSSL_get_chain_cert");

if (chain != NULL) {
if ((chain != NULL) && (idx >= 0) && (idx < chain->count)) {
/* DER buffer of the certificate stored at the given index. */
cert = chain->certs[idx].buffer;
}
Expand Down Expand Up @@ -2049,7 +2049,7 @@ WOLFSSL_X509* wolfSSL_get_chain_X509(WOLFSSL_X509_CHAIN* chain, int idx)

WOLFSSL_ENTER("wolfSSL_get_chain_X509");

if ((chain != NULL) && (idx < MAX_CHAIN_DEPTH)) {
if ((chain != NULL) && (idx >= 0) && (idx < chain->count)) {
x509 = (WOLFSSL_X509*)XMALLOC(sizeof(WOLFSSL_X509), NULL,
DYNAMIC_TYPE_X509);
if (x509 == NULL) {
Expand Down
7 changes: 7 additions & 0 deletions src/ssl_load.c
Original file line number Diff line number Diff line change
Expand Up @@ -329,6 +329,13 @@ static int ProcessUserChain(WOLFSSL_CTX* ctx, WOLFSSL* ssl,
ret = DataToDerBuffer(buff + consumed, (word32)(sz - consumed),
format, type, info, heap, &part, NULL);
if (ret == 0) {
/* Enforce maximum chain depth once a real cert is parsed. */
if (cnt >= MAX_CHAIN_DEPTH) {
WOLFSSL_MSG("Chain depth limit reached");
FreeDer(&part);
ret = MAX_CHAIN_ERROR;
break;
}
/* Process the user certificate. */
ret = ProcessUserCert(ctx->cm, &part, type, verify,
chain.buffer, &idx, (word32)maxSz);
Expand Down
8 changes: 7 additions & 1 deletion src/tls.c
Original file line number Diff line number Diff line change
Expand Up @@ -2849,6 +2849,9 @@ int TLSX_SNI_GetFromBuffer(const byte* clientHello, word32 helloSz,
ato16(clientHello + offset, &listLen);
offset += OPAQUE16_LEN;

if (listLen != extLen - OPAQUE16_LEN)
return BUFFER_ERROR;

if (helloSz < offset + listLen)
return BUFFER_ERROR;

Expand All @@ -2859,6 +2862,9 @@ int TLSX_SNI_GetFromBuffer(const byte* clientHello, word32 helloSz,
ato16(clientHello + offset, &sniLen);
offset += OPAQUE16_LEN;

if (sniLen > listLen - (ENUM_LEN + OPAQUE16_LEN))
return BUFFER_ERROR;

if (helloSz < offset + sniLen)
return BUFFER_ERROR;

Expand Down Expand Up @@ -3434,7 +3440,7 @@ static void TLSX_CSR_Free(CertificateStatusRequest* csr, void* heap)

switch (csr->status_type) {
case WOLFSSL_CSR_OCSP:
for (i = 0; i <= csr->requests; i++) {
for (i = 0; i < csr->requests; i++) {
FreeOcspRequest(&csr->request.ocsp[i]);
}
break;
Expand Down
4 changes: 4 additions & 0 deletions src/tls13.c
Original file line number Diff line number Diff line change
Expand Up @@ -9616,6 +9616,10 @@ static int SendTls13Certificate(WOLFSSL* ssl)
}
/* Certificate Data */
certSz = ssl->buffers.certificate->length;
if (ssl->buffers.certChainCnt > MAX_CHAIN_DEPTH) {
Comment thread
dgarske marked this conversation as resolved.
WOLFSSL_MSG("Certificate chain count exceeds maximum depth");
return MAX_CHAIN_ERROR;
}
/* Cert Req Ctx Len | Cert Req Ctx | Cert List Len | Cert Data Len */
headerSz = OPAQUE8_LEN + certReqCtxLen + CERT_HEADER_SZ +
CERT_HEADER_SZ;
Expand Down
104 changes: 104 additions & 0 deletions tests/api.c
Original file line number Diff line number Diff line change
Expand Up @@ -3856,6 +3856,108 @@ static int test_wolfSSL_CTX_use_certificate_chain_buffer_format(void)
return EXPECT_RESULT();
}

/* wolfSSL_get_chain_{length,cert,X509} must reject out-of-range idx. */
static int test_wolfSSL_get_chain_idx_bounds(void)
{
EXPECT_DECLS;
#if defined(SESSION_CERTS) && \
defined(HAVE_MANUAL_MEMIO_TESTS_DEPENDENCIES)
struct test_memio_ctx test_ctx;
WOLFSSL_CTX* ctx_c = NULL;
Comment thread
douzzer marked this conversation as resolved.
WOLFSSL_CTX* ctx_s = NULL;
WOLFSSL* ssl_c = NULL;
WOLFSSL* ssl_s = NULL;
WOLFSSL_X509_CHAIN* chain = NULL;
int count = 0;

XMEMSET(&test_ctx, 0, sizeof(test_ctx));
ExpectIntEQ(test_memio_setup(&test_ctx, &ctx_c, &ctx_s, &ssl_c, &ssl_s,
wolfTLS_client_method, wolfTLS_server_method), 0);
ExpectIntEQ(test_memio_do_handshake(ssl_c, ssl_s, 10, NULL), 0);

ExpectNotNull(chain = wolfSSL_get_peer_chain(ssl_c));
ExpectIntGT(count = wolfSSL_get_chain_count(chain), 0);

ExpectIntEQ(wolfSSL_get_chain_length(chain, -1), 0);
ExpectIntEQ(wolfSSL_get_chain_length(chain, count), 0);
ExpectIntEQ(wolfSSL_get_chain_length(chain, MAX_CHAIN_DEPTH), 0);
ExpectNull(wolfSSL_get_chain_cert(chain, -1));
ExpectNull(wolfSSL_get_chain_cert(chain, count));
ExpectNull(wolfSSL_get_chain_cert(chain, MAX_CHAIN_DEPTH));
#ifdef OPENSSL_EXTRA
{
WOLFSSL_X509* x = NULL;
ExpectNull(x = wolfSSL_get_chain_X509(chain, -1));
if (x != NULL) { wolfSSL_X509_free(x); x = NULL; }
ExpectNull(x = wolfSSL_get_chain_X509(chain, count));
if (x != NULL) { wolfSSL_X509_free(x); x = NULL; }
ExpectNull(x = wolfSSL_get_chain_X509(chain, MAX_CHAIN_DEPTH));
if (x != NULL) { wolfSSL_X509_free(x); x = NULL; }
}
#endif

wolfSSL_free(ssl_c);
wolfSSL_free(ssl_s);
wolfSSL_CTX_free(ctx_c);
wolfSSL_CTX_free(ctx_s);
#endif
return EXPECT_RESULT();
}

/* Chain-depth boundary: exactly MAX_CHAIN_DEPTH chain certs (plus trailing data
* that forces one more parse pass) must load; one more cert must be rejected.
* cliCertFile is single-cert, so copy 0 is the leaf and N copies => N-1 chain. */
static int test_wolfSSL_CTX_use_certificate_chain_buffer_max_depth(void)
{
EXPECT_DECLS;
#if !defined(NO_FILESYSTEM) && !defined(NO_CERTS) && !defined(NO_TLS) && \
!defined(NO_WOLFSSL_CLIENT) && !defined(NO_RSA) && \
defined(WOLFSSL_PEM_TO_DER)
WOLFSSL_CTX* ctx = NULL;
unsigned char* one = NULL;
unsigned char* buf = NULL;
size_t oneLen = 0;
const char* tail = "# trailing comment\n";
size_t tailLen = XSTRLEN(tail);
/* +1 copy for the leaf yields exactly MAX_CHAIN_DEPTH chain certs. */
const int atMax = MAX_CHAIN_DEPTH + 1;
int i;

ExpectIntEQ(load_file(cliCertFile, &one, &oneLen), 0);

/* Exactly MAX_CHAIN_DEPTH chain certs + trailing data: loads. */
ExpectNotNull(buf = (unsigned char*)XMALLOC(
oneLen * (size_t)atMax + tailLen, NULL, DYNAMIC_TYPE_TMP_BUFFER));
for (i = 0; EXPECT_SUCCESS() && i < atMax; i++)
XMEMCPY(buf + (size_t)i * oneLen, one, oneLen);
if (buf != NULL)
XMEMCPY(buf + (size_t)atMax * oneLen, tail, tailLen);
ExpectNotNull(ctx = wolfSSL_CTX_new(wolfSSLv23_client_method()));
ExpectIntEQ(wolfSSL_CTX_use_certificate_chain_buffer(ctx, buf,
(long)(oneLen * (size_t)atMax + tailLen)), WOLFSSL_SUCCESS);
wolfSSL_CTX_free(ctx);
ctx = NULL;
if (buf != NULL)
XFREE(buf, NULL, DYNAMIC_TYPE_TMP_BUFFER);
buf = NULL;

/* One more chain cert: rejected. */
ExpectNotNull(buf = (unsigned char*)XMALLOC(oneLen * (size_t)(atMax + 1),
NULL, DYNAMIC_TYPE_TMP_BUFFER));
for (i = 0; EXPECT_SUCCESS() && i < atMax + 1; i++)
XMEMCPY(buf + (size_t)i * oneLen, one, oneLen);
ExpectNotNull(ctx = wolfSSL_CTX_new(wolfSSLv23_client_method()));
ExpectIntEQ(wolfSSL_CTX_use_certificate_chain_buffer(ctx, buf,
(long)(oneLen * (size_t)(atMax + 1))), WC_NO_ERR_TRACE(MAX_CHAIN_ERROR));
wolfSSL_CTX_free(ctx);
if (buf != NULL)
XFREE(buf, NULL, DYNAMIC_TYPE_TMP_BUFFER);
if (one != NULL)
XFREE(one, NULL, DYNAMIC_TYPE_TMP_BUFFER);
#endif
return EXPECT_RESULT();
}

static int test_wolfSSL_CTX_use_certificate_chain_file_format(void)
{
EXPECT_DECLS;
Expand Down Expand Up @@ -35060,6 +35162,8 @@ TEST_CASE testCases[] = {
TEST_DECL(test_wolfSSL_CTX_add1_chain_cert),
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_buffer_max_depth),
TEST_DECL(test_wolfSSL_get_chain_idx_bounds),
TEST_DECL(test_wolfSSL_CTX_use_certificate_chain_file_format),
TEST_DECL(test_wolfSSL_use_certificate_chain_file),
TEST_DECL(test_wolfSSL_CTX_trust_peer_cert),
Expand Down
1 change: 0 additions & 1 deletion tests/api/test_dtls.h
Original file line number Diff line number Diff line change
Expand Up @@ -160,7 +160,6 @@ int test_WOLFSSL_dtls_version_alert(void);
TEST_DECL_GROUP("dtls", test_dtls12_export_import_etm), \
TEST_DECL_GROUP("dtls", test_dtls13_min_rtx_interval), \
TEST_DECL_GROUP("dtls", test_dtls13_no_session_id_echo), \
TEST_DECL_GROUP("dtls", test_dtls13_oversized_cert_chain), \
TEST_DECL_GROUP("dtls", test_dtls_set_session_min_downgrade), \
TEST_DECL_GROUP("dtls", test_wolfSSL_dtls_create_free_peer), \
TEST_DECL_GROUP("dtls", test_wolfSSL_dtls_get0_peer), \
Expand Down
94 changes: 0 additions & 94 deletions tests/api/test_dtls13.c
Original file line number Diff line number Diff line change
Expand Up @@ -1779,97 +1779,3 @@ int test_dtls13_5_9_0_compat(void)
#endif
return EXPECT_RESULT();
}

/*-- oversized_cert_chain (test_dtls.c lines 3174,3265) ---*/
int test_dtls13_oversized_cert_chain(void)
{
EXPECT_DECLS;
#if defined(HAVE_MANUAL_MEMIO_TESTS_DEPENDENCIES) && defined(WOLFSSL_DTLS13) \
&& !defined(NO_FILESYSTEM) && !defined(NO_RSA)
WOLFSSL_CTX *ctx_c = NULL, *ctx_s = NULL;
WOLFSSL *ssl_c = NULL, *ssl_s = NULL;
struct test_memio_ctx test_ctx;
XFILE f = XBADFILE;
long sz = 0;
byte *cert = NULL;
byte *chain = NULL;
int copies, off, i;

XMEMSET(&test_ctx, 0, sizeof(test_ctx));

/* Read server cert */
f = XFOPEN(svrCertFile, "rb");
ExpectTrue(f != XBADFILE);
if (EXPECT_SUCCESS()) {
(void)XFSEEK(f, 0, XSEEK_END);
sz = XFTELL(f);
(void)XFSEEK(f, 0, XSEEK_SET);
}
ExpectTrue(sz > 0);
cert = (byte*)XMALLOC((size_t)(sz + 1), NULL, DYNAMIC_TYPE_TMP_BUFFER);
ExpectNotNull(cert);
if (EXPECT_SUCCESS())
ExpectIntEQ((int)XFREAD(cert, 1, (size_t)sz, f), (int)sz);
if (f != XBADFILE)
XFCLOSE(f);

/* Build an oversized chain by duplicating the cert */
copies = EXPECT_SUCCESS() ? (int)(70000 / sz) + 2 : 0;
chain = (byte*)XMALLOC((size_t)(sz * copies + 1), NULL,
DYNAMIC_TYPE_TMP_BUFFER);
ExpectNotNull(chain);
off = 0;
if (EXPECT_SUCCESS()) {
for (i = 0; i < copies; i++) {
XMEMCPY(chain + off, cert, (size_t)sz);
off += (int)sz;
}
}

/* Server context: load the oversized chain */
ExpectNotNull(ctx_s = wolfSSL_CTX_new(wolfDTLSv1_3_server_method()));
ExpectIntEQ(wolfSSL_CTX_use_certificate_chain_buffer(ctx_s,
chain, (long)off), WOLFSSL_SUCCESS);
ExpectIntEQ(wolfSSL_CTX_use_PrivateKey_file(ctx_s, svrKeyFile,
WOLFSSL_FILETYPE_PEM), WOLFSSL_SUCCESS);
if (EXPECT_SUCCESS()) {
wolfSSL_SetIORecv(ctx_s, test_memio_read_cb);
wolfSSL_SetIOSend(ctx_s, test_memio_write_cb);
}

/* Client context: no verification (chain certs are duplicates) */
ExpectNotNull(ctx_c = wolfSSL_CTX_new(wolfDTLSv1_3_client_method()));
if (EXPECT_SUCCESS()) {
wolfSSL_CTX_set_verify(ctx_c, WOLFSSL_VERIFY_NONE, NULL);
wolfSSL_SetIORecv(ctx_c, test_memio_read_cb);
wolfSSL_SetIOSend(ctx_c, test_memio_write_cb);
}

ExpectNotNull(ssl_s = wolfSSL_new(ctx_s));
if (EXPECT_SUCCESS()) {
wolfSSL_SetIOWriteCtx(ssl_s, &test_ctx);
wolfSSL_SetIOReadCtx(ssl_s, &test_ctx);
}

ExpectNotNull(ssl_c = wolfSSL_new(ctx_c));
if (EXPECT_SUCCESS()) {
wolfSSL_SetIOWriteCtx(ssl_c, &test_ctx);
wolfSSL_SetIOReadCtx(ssl_c, &test_ctx);
}

/* Handshake must not crash. If SendTls13Certificate mishandles the
* oversized chain this will trigger a wild pointer dereference or stack
* overflow resulting with the test failing.
* The correct behaviour either returns BUFFER_E or succeeds
* if the build config truncated the chain during loading. */
(void)test_memio_do_handshake(ssl_c, ssl_s, 10, NULL);

wolfSSL_free(ssl_c);
wolfSSL_free(ssl_s);
wolfSSL_CTX_free(ctx_c);
wolfSSL_CTX_free(ctx_s);
XFREE(cert, NULL, DYNAMIC_TYPE_TMP_BUFFER);
XFREE(chain, NULL, DYNAMIC_TYPE_TMP_BUFFER);
#endif
return EXPECT_RESULT();
}
4 changes: 1 addition & 3 deletions tests/api/test_dtls13.h
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,6 @@ int test_dtls_srtp(void);
int test_dtls13_min_rtx_interval(void);
int test_dtls13_no_session_id_echo(void);
int test_dtls13_5_9_0_compat(void);
int test_dtls13_oversized_cert_chain(void);

#define TEST_DTLS13_DECLS \
TEST_DECL_GROUP("dtls13", test_dtls13_bad_epoch_ch), \
Expand All @@ -75,7 +74,6 @@ int test_dtls13_oversized_cert_chain(void);
TEST_DECL_GROUP("dtls13", test_dtls_srtp), \
TEST_DECL_GROUP("dtls13", test_dtls13_min_rtx_interval), \
TEST_DECL_GROUP("dtls13", test_dtls13_no_session_id_echo), \
TEST_DECL_GROUP("dtls13", test_dtls13_5_9_0_compat), \
TEST_DECL_GROUP("dtls13", test_dtls13_oversized_cert_chain)
TEST_DECL_GROUP("dtls13", test_dtls13_5_9_0_compat)

#endif /* TESTS_API_DTLS13_H */
Loading
Loading