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
52 changes: 43 additions & 9 deletions src/internal.c
Original file line number Diff line number Diff line change
Expand Up @@ -16508,6 +16508,29 @@ int LoadCertByIssuer(WOLFSSL_X509_STORE* store, X509_NAME* issuer, int type)
#endif


#if defined(HAVE_RPK)
/* Certificate type negotiated for the peer's certificate: the server cert type
* received (client side) or the client cert type selected (server side). When
* no type was negotiated the default is X.509 (RFC 7250 Section 4.1).
*
* @param [in] ssl SSL/TLS object.
* @return the negotiated WOLFSSL_CERT_TYPE_* value.
*/
static int GetPeerCertType(const WOLFSSL* ssl)
{
if (ssl->options.side == WOLFSSL_CLIENT_END) {
if (ssl->options.rpkState.received_ServerCertTypeCnt == 1)
return ssl->options.rpkState.received_ServerCertTypes[0];
}
else if (ssl->options.side == WOLFSSL_SERVER_END) {
if (ssl->options.rpkState.sending_ClientCertTypeCnt == 1)
return ssl->options.rpkState.sending_ClientCertTypes[0];
}

return WOLFSSL_CERT_TYPE_X509;
}
#endif /* HAVE_RPK */

static int ProcessPeerCertParse(WOLFSSL* ssl, ProcPeerCertArgs* args,
int certType, int verify, byte** pSubjectHash, int* pAlreadySigner)
{
Expand Down Expand Up @@ -16634,15 +16657,7 @@ PRAGMA_GCC_DIAG_POP
* un-negotiated bare key is rejected. The negotiated type is the received
* server cert type (client) or the selected client cert type (server). */
if (ret == 0) {
cType = WOLFSSL_CERT_TYPE_X509;
if (ssl->options.side == WOLFSSL_CLIENT_END) {
if (ssl->options.rpkState.received_ServerCertTypeCnt == 1)
cType = ssl->options.rpkState.received_ServerCertTypes[0];
}
else if (ssl->options.side == WOLFSSL_SERVER_END) {
if (ssl->options.rpkState.sending_ClientCertTypeCnt == 1)
cType = ssl->options.rpkState.sending_ClientCertTypes[0];
}
cType = GetPeerCertType(ssl);

if ((cType == WOLFSSL_CERT_TYPE_RPK && !args->dCert->isRPK) ||
(cType != WOLFSSL_CERT_TYPE_RPK && args->dCert->isRPK)) {
Expand Down Expand Up @@ -17997,6 +18012,22 @@ int ProcessPeerCerts(WOLFSSL* ssl, byte* input, word32* inOutIdx,
args->count = args->totalCerts;
args->certIdx = 0; /* select peer cert (first one) */

#if defined(HAVE_RPK) && defined(WOLFSSL_TLS13)
/* RFC 8446 Section 4.4.2: "If the RawPublicKey certificate type was
* negotiated, then the certificate_list MUST contain no more than
* one CertificateEntry". Only TLS 1.3 needs the check: a TLS 1.2
* Certificate carries the bare SubjectPublicKeyInfo, which the
* length handling above already limits to a single entry. */
if (ssl->options.tls1_3 && args->count > 1 &&
GetPeerCertType(ssl) == WOLFSSL_CERT_TYPE_RPK) {
WOLFSSL_MSG("Multiple certs with raw public key negotiated");
ret = UNSUPPORTED_CERTIFICATE;
WOLFSSL_ERROR_VERBOSE(ret);
DoCertFatalAlert(ssl, ret);
goto exit_ppc;
}
#endif /* HAVE_RPK && WOLFSSL_TLS13 */

if (args->count == 0) {
/* Empty certificate message. */
if ((ssl->options.side == WOLFSSL_SERVER_END) &&
Expand Down Expand Up @@ -29228,6 +29259,9 @@ static int SendAlert_ex(WOLFSSL* ssl, int severity, int type)

#ifdef WOLFSSL_QUIC
if (WOLFSSL_IS_QUIC(ssl)) {
/* Record for the duplicate-alert guards, as the TLS path below does. */
ssl->alert_history.last_tx.code = type;
ssl->alert_history.last_tx.level = severity;
ret = !ssl->quic.method->send_alert(ssl, ssl->quic.enc_level_write, (uint8_t)type);
if (ret) {
WOLFSSL_MSG("QUIC send_alert callback error");
Expand Down
27 changes: 26 additions & 1 deletion src/tls.c
Original file line number Diff line number Diff line change
Expand Up @@ -13176,6 +13176,20 @@ static int TLSX_EarlyData_Parse(WOLFSSL* ssl, const byte* input, word16 length,
return BUFFER_E;
ato32(input, &maxSz);

#ifdef WOLFSSL_QUIC
/* RFC 9001 Section 4.6.1: "Servers MUST NOT send the early_data
* extension with a max_early_data_size field set to any value other
* than 0xffffffff. A client MUST treat receipt of a NewSessionTicket
* that contains an early_data extension with any other value as a
* connection error of type PROTOCOL_VIOLATION." */
if (WOLFSSL_IS_QUIC(ssl) && maxSz != WOLFSSL_MAX_32BIT) {
WOLFSSL_MSG("QUIC ticket early data size not 0xffffffff");
SendAlert(ssl, alert_fatal, WOLFSSL_QUIC_ERR_PROTOCOL_VIOLATION);
WOLFSSL_ERROR_VERBOSE(INVALID_PARAMETER);
return INVALID_PARAMETER;
Comment thread
kareem-wolfssl marked this conversation as resolved.
}
#endif /* WOLFSSL_QUIC */

ssl->session->maxEarlyDataSz = maxSz;
return 0;
}
Expand Down Expand Up @@ -18888,7 +18902,6 @@ WOLFSSL_TEST_VIS int TLSX_Parse(WOLFSSL* ssl, const byte* input, word16 length,

#ifdef WOLFSSL_TLS13
case TLSX_SUPPORTED_VERSIONS:
WOLFSSL_MSG("Skipping Supported Versions - already processed");
#ifdef WOLFSSL_DEBUG_TLS
WOLFSSL_BUFFER(input + offset, size);
#endif
Expand All @@ -18897,6 +18910,18 @@ WOLFSSL_TEST_VIS int TLSX_Parse(WOLFSSL* ssl, const byte* input, word16 length,
msgType != hello_retry_request)
return EXT_NOT_ALLOWED;

/* RFC 8446 Section 4.2.1: "A server which negotiates a version
* of TLS prior to TLS 1.3 MUST set ServerHello.version and MUST
* NOT send the "supported_versions" extension." If TLS version
* is <1.3, supported_versions is invalid. */
if (msgType == server_hello &&
!IsAtLeastTLSv1_3(ssl->version)) {
WOLFSSL_MSG("Supported Versions in older ServerHello");
WOLFSSL_ERROR_VERBOSE(VERSION_ERROR);
return VERSION_ERROR;
}

WOLFSSL_MSG("Skipping Supported Versions - already processed");
break;

case TLSX_COOKIE:
Expand Down
149 changes: 149 additions & 0 deletions tests/api/test_tls13.c
Original file line number Diff line number Diff line change
Expand Up @@ -4351,6 +4351,79 @@ int test_tls13_rpk_unoffered_cert_type(void)
return EXPECT_RESULT();
}

/* RFC 8446 Section 4.4.2: "If the RawPublicKey certificate type was negotiated,
* then the certificate_list MUST contain no more than one CertificateEntry,
* which contains an ASN1_subjectPublicKeyInfo value as defined in [RFC7250],
* Section 3." Make the server send a second raw public key and check that the
* client rejects the Certificate message. */
int test_tls13_rpk_multiple_certs(void)
{
EXPECT_DECLS;
#if defined(HAVE_RPK) && defined(WOLFSSL_TLS13) && !defined(NO_TLS) && \
defined(HAVE_MANUAL_MEMIO_TESTS_DEPENDENCIES) && \
!defined(NO_FILESYSTEM) && !defined(NO_SHA256) && \
!defined(NO_WOLFSSL_CLIENT) && !defined(NO_WOLFSSL_SERVER)
WOLFSSL_CTX *ctx_c = NULL;
WOLFSSL_CTX *ctx_s = NULL;
WOLFSSL *ssl_c = NULL;
WOLFSSL *ssl_s = NULL;
struct test_memio_ctx test_ctx;
WOLFSSL_ALERT_HISTORY h;
byte* spki = NULL;
size_t spkiSz = 0;
DerBuffer* chain = NULL;
char certType[] = { WOLFSSL_CERT_TYPE_RPK, WOLFSSL_CERT_TYPE_X509 };

XMEMSET(&test_ctx, 0, sizeof(test_ctx));
XMEMSET(&h, 0, sizeof(h));
ExpectIntEQ(
test_rpk_memio_setup(
&test_ctx, &ctx_c, &ctx_s, &ssl_c, &ssl_s,
wolfTLSv1_3_client_method, wolfTLSv1_3_server_method,
clntRpkCertFile, WOLFSSL_FILETYPE_ASN1,
svrRpkCertFile, WOLFSSL_FILETYPE_ASN1,
cliKeyFile, CERT_FILETYPE,
svrKeyFile, CERT_FILETYPE)
, 0);

ExpectIntEQ(wolfSSL_set_server_cert_type(ssl_c, certType,
(int)sizeof(certType)), WOLFSSL_SUCCESS);
ExpectIntEQ(wolfSSL_set_server_cert_type(ssl_s, certType,
(int)sizeof(certType)), WOLFSSL_SUCCESS);

/* Append a second entry to the server's certificate_list: the same raw
* public key again, in the length-prefixed form the chain is sent in. */
ExpectIntEQ(load_file(svrRpkCertFile, &spki, &spkiSz), 0);
ExpectIntEQ(AllocDer(&chain, (word32)spkiSz + CERT_HEADER_SZ,
CERT_TYPE, NULL), 0);
if (EXPECT_SUCCESS()) {
chain->buffer[0] = (byte)(spkiSz >> 16);
chain->buffer[1] = (byte)(spkiSz >> 8);
chain->buffer[2] = (byte)spkiSz;
XMEMCPY(chain->buffer + CERT_HEADER_SZ, spki, spkiSz);
ssl_s->buffers.certChain = chain;
ssl_s->buffers.certChainCnt = 1;
ssl_s->buffers.weOwnCertChain = 1;
chain = NULL; /* owned by ssl_s now */
}

ExpectIntNE(test_memio_do_handshake(ssl_c, ssl_s, 10, NULL), 0);
ExpectIntEQ(wolfSSL_get_error(ssl_c, WOLFSSL_FATAL_ERROR),
WC_NO_ERR_TRACE(UNSUPPORTED_CERTIFICATE));
ExpectIntEQ(wolfSSL_get_alert_history(ssl_c, &h), WOLFSSL_SUCCESS);
ExpectIntEQ(h.last_tx.code, unsupported_certificate);
ExpectIntEQ(h.last_tx.level, alert_fatal);

FreeDer(&chain);
XFREE(spki, NULL, DYNAMIC_TYPE_TMP_BUFFER);
wolfSSL_free(ssl_c);
wolfSSL_CTX_free(ctx_c);
wolfSSL_free(ssl_s);
wolfSSL_CTX_free(ctx_s);
#endif /* HAVE_RPK && WOLFSSL_TLS13 && memio && !NO_SHA256 && client+server */
return EXPECT_RESULT();
}


#if defined(HAVE_IO_TESTS_DEPENDENCIES) && defined(WOLFSSL_TLS13) && \
defined(WOLFSSL_HAVE_MLKEM) && !defined(WOLFSSL_MLKEM_NO_ENCAPSULATE) && \
Expand Down Expand Up @@ -8252,6 +8325,82 @@ int test_tls13_downgrade_sentinel(void)
return EXPECT_RESULT();
}

/* Test that a client does not treat a ServerHello carrying supported_versions
* as an older-version ServerHello because of its legacy_version. RFC 8446
* Section 4.2.1: "A server which negotiates a version of TLS prior to TLS 1.3
* MUST set ServerHello.version and MUST NOT send the "supported_versions"
* extension", and a client "MUST ignore the ServerHello.legacy_version value
* and MUST use only the "supported_versions" extension to determine the
* selected version". A server selecting TLS 1.3 must set legacy_version to
* 0x0303 (Section 4.1.3). */
int test_tls13_serverhello_legacy_version(void)
{
EXPECT_DECLS;
#if defined(WOLFSSL_TLS13) && !defined(WOLFSSL_NO_TLS12) && \
defined(HAVE_MANUAL_MEMIO_TESTS_DEPENDENCIES) && \
!defined(NO_WOLFSSL_CLIENT) && !defined(NO_WOLFSSL_SERVER)
WOLFSSL_CTX *ctx_c = NULL;
WOLFSSL_CTX *ctx_s = NULL;
WOLFSSL *ssl_c = NULL;
WOLFSSL *ssl_s = NULL;
struct test_memio_ctx test_ctx;
WOLFSSL_ALERT_HISTORY h;
/* legacy_version follows the record (5) and handshake (4) headers. */
int verOff = 9;

XMEMSET(&test_ctx, 0, sizeof(test_ctx));
XMEMSET(&h, 0, sizeof(h));
/* Client allows downgrading, so the legacy dispatch is reachable. */
ExpectIntEQ(test_memio_setup(&test_ctx, &ctx_c, &ctx_s, &ssl_c, &ssl_s,
wolfTLS_client_method, wolfTLSv1_3_server_method), 0);

ExpectIntNE(wolfSSL_connect(ssl_c), WOLFSSL_SUCCESS);
ExpectIntEQ(wolfSSL_get_error(ssl_c, WOLFSSL_FATAL_ERROR),
WOLFSSL_ERROR_WANT_READ);
ExpectIntNE(wolfSSL_accept(ssl_s), WOLFSSL_SUCCESS);
ExpectIntEQ(wolfSSL_get_error(ssl_s, WOLFSSL_FATAL_ERROR),
WOLFSSL_ERROR_WANT_READ);

/* Claim TLS 1.0 in legacy_version. supported_versions still selects
* TLS 1.3. */
if (EXPECT_SUCCESS()) {
ExpectIntGT(test_ctx.c_len, verOff + 1);
test_ctx.c_buff[verOff + 0] = SSLv3_MAJOR;
test_ctx.c_buff[verOff + 1] = TLSv1_MINOR;
}

ExpectIntNE(wolfSSL_connect(ssl_c), WOLFSSL_SUCCESS);
ExpectIntEQ(wolfSSL_get_error(ssl_c, WOLFSSL_FATAL_ERROR),
WC_NO_ERR_TRACE(VERSION_ERROR));
ExpectIntEQ(wolfSSL_get_alert_history(ssl_c, &h), WOLFSSL_SUCCESS);
ExpectIntEQ(h.last_tx.code, wolfssl_alert_protocol_version);
ExpectIntEQ(h.last_tx.level, alert_fatal);

wolfSSL_free(ssl_c);
wolfSSL_CTX_free(ctx_c);
wolfSSL_free(ssl_s);
wolfSSL_CTX_free(ctx_s);

/* A ServerHello that really is older still downgrades: no
* supported_versions extension to contradict its legacy_version. */
XMEMSET(&test_ctx, 0, sizeof(test_ctx));
ctx_c = NULL;
ctx_s = NULL;
ssl_c = NULL;
ssl_s = NULL;
ExpectIntEQ(test_memio_setup(&test_ctx, &ctx_c, &ctx_s, &ssl_c, &ssl_s,
wolfTLS_client_method, wolfTLSv1_2_server_method), 0);
ExpectIntEQ(test_memio_do_handshake(ssl_c, ssl_s, 10, NULL), 0);
ExpectIntEQ(wolfSSL_version(ssl_c), TLS1_2_VERSION);

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

/* Test that a TLS 1.3 client rejects ServerHello cipher suites that are not
* TLS 1.3 suites or were not offered by the client. */
int test_tls13_serverhello_bad_cipher_suites(void)
Expand Down
4 changes: 4 additions & 0 deletions tests/api/test_tls13.h
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ int test_tls13_pha(void);
int test_tls13_rpk_untrusted(void);
int test_tls13_rpk_trust(void);
int test_tls13_rpk_unoffered_cert_type(void);
int test_tls13_rpk_multiple_certs(void);
int test_tls13_pq_groups(void);
int test_tls13_multi_pqc_key_share(void);
int test_tls13_early_data(void);
Expand Down Expand Up @@ -71,6 +72,7 @@ int test_tls13_zero_inner_content_type(void);
int test_tls13_post_handshake_auth_no_ext(void);
int test_tls13_post_handshake_auth_late_allow(void);
int test_tls13_downgrade_sentinel(void);
int test_tls13_serverhello_legacy_version(void);
int test_tls13_serverhello_bad_cipher_suites(void);
int test_tls13_psk_no_cert_bad_binder(void);
int test_tls13_psk_age_no_identity_oracle(void);
Expand Down Expand Up @@ -119,6 +121,7 @@ int test_tls13_pha_status_request(void);
TEST_DECL_GROUP("tls13", test_tls13_rpk_untrusted), \
TEST_DECL_GROUP("tls13", test_tls13_rpk_trust), \
TEST_DECL_GROUP("tls13", test_tls13_rpk_unoffered_cert_type), \
TEST_DECL_GROUP("tls13", test_tls13_rpk_multiple_certs), \
TEST_DECL_GROUP("tls13", test_tls13_pq_groups), \
TEST_DECL_GROUP("tls13", test_tls13_multi_pqc_key_share), \
TEST_DECL_GROUP("tls13", test_tls13_early_data), \
Expand Down Expand Up @@ -157,6 +160,7 @@ int test_tls13_pha_status_request(void);
TEST_DECL_GROUP("tls13", test_tls13_post_handshake_auth_no_ext), \
TEST_DECL_GROUP("tls13", test_tls13_post_handshake_auth_late_allow), \
TEST_DECL_GROUP("tls13", test_tls13_downgrade_sentinel), \
TEST_DECL_GROUP("tls13", test_tls13_serverhello_legacy_version), \
TEST_DECL_GROUP("tls13", test_tls13_serverhello_bad_cipher_suites), \
TEST_DECL_GROUP("tls13", test_tls13_psk_no_cert_bad_binder), \
TEST_DECL_GROUP("tls13", test_tls13_psk_age_no_identity_oracle), \
Expand Down
Loading
Loading