Skip to content
7 changes: 7 additions & 0 deletions src/dtls13.c
Original file line number Diff line number Diff line change
Expand Up @@ -1823,6 +1823,13 @@ int Dtls13CheckEpoch(WOLFSSL* ssl, enum HandShakeType type)
}
break;
case end_of_early_data:
/* RFC 9147 5.6.1: EndOfEarlyData is not used in DTLS 1.3. Its
* receipt must terminate the connection with an
* unexpected_message alert. */
WOLFSSL_MSG("EndOfEarlyData not valid in DTLS 1.3");
SendAlert(ssl, alert_fatal, unexpected_message);
WOLFSSL_ERROR_VERBOSE(SANITY_MSG_E);
return SANITY_MSG_E;
case message_hash:
case no_shake:
default:
Expand Down
30 changes: 28 additions & 2 deletions src/internal.c
Original file line number Diff line number Diff line change
Expand Up @@ -3519,6 +3519,16 @@ void InitSuitesHashSigAlgo(byte* hashSigAlgo, int haveSig, int tls1_2,
int tls1_3, int keySz, word16* len)
{
word16 idx = 0;
#if !defined(NO_SHA) && (!defined(NO_OLD_TLS) || defined(WOLFSSL_ALLOW_TLS_SHA1))
/* RFC 9155 deprecates SHA-1 signatures for TLS 1.2. Offer them only for a
* TLS 1.0/1.1 handshake unless the operator opts in with
* WOLFSSL_ALLOW_TLS_SHA1. */
#ifdef WOLFSSL_ALLOW_TLS_SHA1
int offerSha1Sig = 1;
#else
int offerSha1Sig = !tls1_2;
#endif
#endif

(void)tls1_2;
(void)tls1_3;
Expand Down Expand Up @@ -3559,7 +3569,10 @@ void InitSuitesHashSigAlgo(byte* hashSigAlgo, int haveSig, int tls1_2,
#endif
#if !defined(NO_SHA) && (!defined(NO_OLD_TLS) || \
defined(WOLFSSL_ALLOW_TLS_SHA1))
AddSuiteHashSigAlgo(hashSigAlgo, sha_mac, ecc_dsa_sa_algo, keySz, &idx);
if (offerSha1Sig) {
AddSuiteHashSigAlgo(hashSigAlgo, sha_mac, ecc_dsa_sa_algo, keySz,
&idx);
}
#endif
#endif
#ifdef HAVE_ED25519
Expand Down Expand Up @@ -3625,7 +3638,9 @@ void InitSuitesHashSigAlgo(byte* hashSigAlgo, int haveSig, int tls1_2,
#endif
#if !defined(NO_SHA) && (!defined(NO_OLD_TLS) || \
defined(WOLFSSL_ALLOW_TLS_SHA1))
AddSuiteHashSigAlgo(hashSigAlgo, sha_mac, rsa_sa_algo, keySz, &idx);
if (offerSha1Sig) {
AddSuiteHashSigAlgo(hashSigAlgo, sha_mac, rsa_sa_algo, keySz, &idx);
}
#endif
}

Expand Down Expand Up @@ -18037,6 +18052,11 @@ int ProcessPeerCerts(WOLFSSL* ssl, byte* input, word32* inOutIdx,
}
#endif /* KEEP_PEER_CERT */

/* Enforced by default (RFC 5280 4.2.1.3 / RFC 8446 4.4.2.4:
* keyEncipherment/digitalSignature and serverAuth/clientAuth EKU
* on TLS certs). IGNORE_KEY_EXTENSIONS is a deliberate,
* RFC-non-conformant opt-out; see the macro list at the top of
* wolfcrypt/src/asn.c. */
#ifndef IGNORE_KEY_EXTENSIONS
#if defined(OPENSSL_EXTRA)
/* when compatibility layer is turned on and no verify is
Expand Down Expand Up @@ -24712,6 +24732,12 @@ static int DoProcessReplyEx(WOLFSSL* ssl, int allowSocketErr)
* DTLS handshake message */
ssl->dtls_timeout = ssl->dtls_timeout_init;
}
else {
if (SendFatalAlertOnly(ssl, ret)
== WC_NO_ERR_TRACE(SOCKET_ERROR_E)) {
ret = SOCKET_ERROR_E;
}
}
}
#endif /* WOLFSSL_DTLS13 */
}
Expand Down
4 changes: 4 additions & 0 deletions src/pk_ec.c
Original file line number Diff line number Diff line change
Expand Up @@ -5349,6 +5349,10 @@ int wolfSSL_ECDSA_do_verify(const unsigned char *dgst, int dLen,
ret = 0;
}
}
else {
WOLFSSL_MSG("i2d_ECDSA_SIG failed");
ret = WOLFSSL_FATAL_ERROR;
}
#endif /* WOLF_CRYPTO_CB_ONLY_ECC */
}

Expand Down
34 changes: 23 additions & 11 deletions src/sniffer.c
Original file line number Diff line number Diff line change
Expand Up @@ -564,15 +564,27 @@ typedef struct SnifferSession {
} SnifferSession;


/* The session, server, and keylog secret tables below are qualified
* THREAD_LS_T. When thread-local storage is genuinely available each thread
* owns a private copy of these tables, so their lookups and list mutations
* need no mutex. THREAD_LS_T is only a real thread-local qualifier when
* HAVE_THREAD_LS is defined and NO_THREAD_LS is not; otherwise the tables are
* process-shared globals that must be locked. HAVE_C___ATOMIC by itself does
* not make the tables thread-local, so the lock elision is gated on both. */
#if defined(HAVE_C___ATOMIC) && defined(HAVE_THREAD_LS) && \
!defined(NO_THREAD_LS)
#define SNIFFER_LOCKLESS_TABLES
#endif

/* Sniffer Server List and mutex */
static THREAD_LS_T SnifferServer* ServerList = NULL;
#ifndef HAVE_C___ATOMIC
#ifndef SNIFFER_LOCKLESS_TABLES
static WC_THREADSHARED wolfSSL_Mutex ServerListMutex WOLFSSL_MUTEX_INITIALIZER_CLAUSE(ServerListMutex);
#endif

/* Session Hash Table, mutex, and count */
static THREAD_LS_T SnifferSession* SessionTable[HASH_SIZE];
#ifndef HAVE_C___ATOMIC
#ifndef SNIFFER_LOCKLESS_TABLES
static WC_THREADSHARED wolfSSL_Mutex SessionMutex WOLFSSL_MUTEX_INITIALIZER_CLAUSE(SessionMutex);
#endif
static THREAD_LS_T int SessionCount = 0;
Expand Down Expand Up @@ -641,7 +653,7 @@ static void UpdateMissedDataSessions(void)
NOLOCK_INC_STAT(x); UNLOCK_STAT(); } while (0)
#endif /* WOLFSSL_SNIFFER_STATS */

#ifdef HAVE_C___ATOMIC
#ifdef SNIFFER_LOCKLESS_TABLES
#define LOCK_SESSION() WC_DO_NOTHING
#define UNLOCK_SESSION() WC_DO_NOTHING
#define LOCK_SERVER_LIST() WC_DO_NOTHING
Expand Down Expand Up @@ -682,7 +694,7 @@ void ssl_InitSniffer_ex(int devId)
{
wolfSSL_Init();
#ifndef WOLFSSL_MUTEX_INITIALIZER
#ifndef HAVE_C___ATOMIC
#ifndef SNIFFER_LOCKLESS_TABLES
wc_InitMutex(&ServerListMutex);
wc_InitMutex(&SessionMutex);
#endif
Expand Down Expand Up @@ -908,7 +920,7 @@ void ssl_FreeSniffer(void)
#ifndef WOLFSSL_SNIFFER_NO_RECOVERY
wc_FreeMutex(&RecoveryMutex);
#endif
#ifndef HAVE_C___ATOMIC
#ifndef SNIFFER_LOCKLESS_TABLES
wc_FreeMutex(&SessionMutex);
wc_FreeMutex(&ServerListMutex);
#endif
Expand Down Expand Up @@ -5222,22 +5234,22 @@ static void RemoveSession(SnifferSession* session, IpInfo* ipInfo,
SnifferSession* previous = 0;
SnifferSession* current;
word32 row = rowHint;
#ifndef HAVE_C___ATOMIC
#ifndef SNIFFER_LOCKLESS_TABLES
int haveLock = 0;
#endif
Trace(REMOVE_SESSION_STR);

if (ipInfo && tcpInfo)
row = SessionHash(ipInfo, tcpInfo);
#ifndef HAVE_C___ATOMIC
#ifndef SNIFFER_LOCKLESS_TABLES
else
haveLock = 1;
#endif

if (row >= HASH_SIZE)
return;

#ifndef HAVE_C___ATOMIC
#ifndef SNIFFER_LOCKLESS_TABLES
if (!haveLock) {
LOCK_SESSION();
}
Expand All @@ -5259,7 +5271,7 @@ static void RemoveSession(SnifferSession* session, IpInfo* ipInfo,
current = current->next;
}

#ifndef HAVE_C___ATOMIC
#ifndef SNIFFER_LOCKLESS_TABLES
if (!haveLock) {
UNLOCK_SESSION();
}
Expand Down Expand Up @@ -7439,13 +7451,13 @@ typedef struct SecretNode {
static THREAD_LS_T
SecretNode*
secretHashTable[WOLFSSL_SNIFFER_KEYLOGFILE_HASH_TABLE_SIZE] = {NULL};
#ifndef HAVE_C___ATOMIC
#ifndef SNIFFER_LOCKLESS_TABLES
static WC_THREADSHARED wolfSSL_Mutex secretListMutex WOLFSSL_MUTEX_INITIALIZER_CLAUSE(secretListMutex);
#endif

static unsigned int secretHashFunction(unsigned char* clientRandom);

#ifdef HAVE_C___ATOMIC
#ifdef SNIFFER_LOCKLESS_TABLES
#define LOCK_SECRET_LIST() WC_DO_NOTHING
#define UNLOCK_SECRET_LIST() WC_DO_NOTHING
#else
Expand Down
10 changes: 9 additions & 1 deletion src/ssl_api_ext.c
Original file line number Diff line number Diff line change
Expand Up @@ -554,7 +554,15 @@ int wolfSSL_set1_groups(WOLFSSL* ssl, int* groups, int count)
* @param [in] ssl SSL/TLS object.
* @param [in] protocol_name_list Comma-separated list of protocol names.
* @param [in] protocol_name_listSz Length of the list in bytes.
* @param [in] options Bitmask of ALPN options.
* @param [in] options Bitmask of ALPN options. A mismatch
* behavior must be set or BAD_FUNC_ARG is returned.
* WOLFSSL_ALPN_FAILED_ON_MISMATCH sends the fatal
* no_application_protocol alert and fails the handshake when no
* protocol matches, per RFC 7301 section 3.2.
* WOLFSSL_ALPN_CONTINUE_ON_MISMATCH instead continues without an
* agreed protocol like OpenSSL. That does not send the alert and is
* therefore not RFC 7301 compliant, so use it only for OpenSSL
* interop.
* @return WOLFSSL_SUCCESS on success.
* @return BAD_FUNC_ARG when an argument is NULL, the list is too long or
* options are unsupported.
Expand Down
4 changes: 4 additions & 0 deletions src/ssl_certman.c
Original file line number Diff line number Diff line change
Expand Up @@ -3213,6 +3213,10 @@ int AddCA(WOLFSSL_CERT_MANAGER* cm, DerBuffer** pDer, int type, int verify)
WOLFSSL_MSG("\tCan't add as CA if not actually one");
ret = NOT_CA_ERROR;
}
/* Enforced by default. ALLOW_INVALID_CERTSIGN is a deliberate,
* RFC-non-conformant opt-out for interop with deployed certs that carry
* malformed keyUsage; see the macro list at the top of
* wolfcrypt/src/asn.c. */
#ifndef ALLOW_INVALID_CERTSIGN
else if (ret == 0 && cert->isCA == 1 && type != WOLFSSL_USER_CA &&
!cert->selfSigned && cert->extKeyUsageSet &&
Expand Down
22 changes: 18 additions & 4 deletions src/tls.c
Original file line number Diff line number Diff line change
Expand Up @@ -1957,8 +1957,10 @@ static int ALPN_find_match(WOLFSSL *ssl, TLSX **pextension,
if (sel == NULL) {
WOLFSSL_MSG("No ALPN protocol match");

/* do nothing if no protocol match between client and server and option
is set to continue (like OpenSSL) */
/* The caller explicitly opted out of failing on mismatch by passing
* WOLFSSL_ALPN_CONTINUE_ON_MISMATCH, so continue without an agreed
* protocol like OpenSSL. This deliberately skips the RFC 7301 section
* 3.2 fatal no_application_protocol alert. */
if (list->options & WOLFSSL_ALPN_CONTINUE_ON_MISMATCH) {
WOLFSSL_MSG("Continue on mismatch");
}
Expand Down Expand Up @@ -6401,6 +6403,18 @@ static int TLSX_SecureRenegotiation_Parse(WOLFSSL* ssl, const byte* input,
return ret;
}

/* tmp_keys holds a copy of the session cipher and MAC keys, so wipe the
* struct before freeing it, matching the ForceZero of ssl->keys on connection
* teardown. */
static void TLSX_SecureRenegotiation_Free(SecureRenegotiation* data, void* heap)
{
if (data != NULL) {
ForceZero(data, sizeof(SecureRenegotiation));
}
XFREE(data, heap, DYNAMIC_TYPE_TLSX);
(void)heap;
}

int TLSX_UseSecureRenegotiation(TLSX** extensions, void* heap)
{
int ret = 0;
Expand Down Expand Up @@ -6446,7 +6460,7 @@ int TLSX_AddEmptyRenegotiationInfo(TLSX** extensions, void* heap)
#endif /* HAVE_SERVER_RENEGOTIATION_INFO */


#define SCR_FREE_ALL(data, heap) XFREE(data, (heap), DYNAMIC_TYPE_TLSX)
#define SCR_FREE_ALL TLSX_SecureRenegotiation_Free
#define SCR_GET_SIZE TLSX_SecureRenegotiation_GetSize
#define SCR_WRITE TLSX_SecureRenegotiation_Write
#define SCR_PARSE TLSX_SecureRenegotiation_Parse
Expand Down Expand Up @@ -15192,7 +15206,7 @@ void TLSX_FreeAll(TLSX* list, void* heap)

case TLSX_RENEGOTIATION_INFO:
WOLFSSL_MSG("Secure Renegotiation extension free");
SCR_FREE_ALL(extension->data, heap);
SCR_FREE_ALL((SecureRenegotiation*)extension->data, heap);
break;

case TLSX_SESSION_TICKET:
Expand Down
37 changes: 37 additions & 0 deletions tests/api.c
Original file line number Diff line number Diff line change
Expand Up @@ -19470,6 +19470,12 @@ static int test_wolfSSL_sigalg_info(void)
word16 len = 0;
word16 idx = 0;
int allSigAlgs = SIG_ECDSA | SIG_RSA | SIG_SM2 | SIG_FALCON | SIG_MLDSA;
#if !defined(NO_SHA) && (!defined(NO_OLD_TLS) || defined(WOLFSSL_ALLOW_TLS_SHA1))
int sawSha1 = 0;
#endif
#ifndef WOLFSSL_ALLOW_TLS_SHA1
int tls13 = 0;
#endif

InitSuitesHashSigAlgo(hashSigAlgo, allSigAlgs, 1, 1, 0xFFFFFFFF, &len);
for (idx = 0; idx < len; idx += 2) {
Expand All @@ -19495,6 +19501,37 @@ static int test_wolfSSL_sigalg_info(void)
ExpectIntNE(hashAlgo, 0);
}

/* RFC 9155 deprecates SHA-1 signatures for TLS 1.2, and RFC 8446 forbids
* them for TLS 1.3. When the negotiated version is TLS 1.2 or higher
* (tls1_2 argument set, whether or not tls1_3 is also set) the SHA-1
* schemes must not be offered unless the operator opts in with
* WOLFSSL_ALLOW_TLS_SHA1. */
#ifndef WOLFSSL_ALLOW_TLS_SHA1
for (tls13 = 0; tls13 <= 1; tls13++) {
InitSuitesHashSigAlgo(hashSigAlgo, allSigAlgs, 1, tls13, 0xFFFFFFFF,
&len);
for (idx = 0; idx < len; idx += 2) {
ExpectFalse((hashSigAlgo[idx] == sha_mac) &&
((hashSigAlgo[idx + 1] == rsa_sa_algo) ||
(hashSigAlgo[idx + 1] == ecc_dsa_sa_algo)));
}
}
#endif

/* For a TLS 1.0/1.1 handshake the SHA-1 schemes remain available when
* they are compiled in. */
#if !defined(NO_SHA) && (!defined(NO_OLD_TLS) || defined(WOLFSSL_ALLOW_TLS_SHA1))
InitSuitesHashSigAlgo(hashSigAlgo, allSigAlgs, 0, 0, 0xFFFFFFFF, &len);
for (idx = 0; idx < len; idx += 2) {
if ((hashSigAlgo[idx] == sha_mac) &&
((hashSigAlgo[idx + 1] == rsa_sa_algo) ||
(hashSigAlgo[idx + 1] == ecc_dsa_sa_algo))) {
sawSha1 = 1;
}
}
ExpectIntEQ(sawSha1, 1);
#endif

#endif
return EXPECT_RESULT();
}
Expand Down
6 changes: 6 additions & 0 deletions tests/api/test_dtls13.c
Original file line number Diff line number Diff line change
Expand Up @@ -1073,6 +1073,7 @@ int test_dtls13_epochs(void) {
WOLFSSL* ssl = NULL;
byte input[20];
word32 inOutIdx = 0;
WOLFSSL_ALERT_HISTORY alertHistory;

XMEMSET(input, 0, sizeof(input));

Expand Down Expand Up @@ -1107,6 +1108,11 @@ int test_dtls13_epochs(void) {
ExpectIntEQ(Dtls13CheckEpoch(ssl, key_update), SANITY_MSG_E);
ExpectIntEQ(Dtls13CheckEpoch(ssl, session_ticket), SANITY_MSG_E);
ExpectIntEQ(Dtls13CheckEpoch(ssl, end_of_early_data), SANITY_MSG_E);
/* RFC 9147 5.6.1: EndOfEarlyData is not used in DTLS 1.3 and its receipt
* must terminate the connection with an unexpected_message alert. */
ExpectIntEQ(wolfSSL_get_alert_history(ssl, &alertHistory), WOLFSSL_SUCCESS);
ExpectIntEQ(alertHistory.last_tx.level, alert_fatal);
ExpectIntEQ(alertHistory.last_tx.code, unexpected_message);
ExpectIntEQ(Dtls13CheckEpoch(ssl, message_hash), SANITY_MSG_E);
ExpectIntEQ(Dtls13CheckEpoch(ssl, no_shake), SANITY_MSG_E);

Expand Down
27 changes: 27 additions & 0 deletions tests/api/test_ossl_x509_acert.c
Original file line number Diff line number Diff line change
Expand Up @@ -104,6 +104,22 @@ static int do_acert_verify_test(const char * acert_file,

return 0;
}

#if !defined(NO_ASN_TIME) && !defined(NO_ASN_TIME_CHECK)
/* Return a fixed time after the notAfter date of certs/acert/acert.pem
* (2028-01-01), used to exercise attribute certificate validity period
* enforcement without depending on the real system clock. */
static time_t acert_expired_time_cb(time_t* t)
{
time_t expired = (time_t)1893456000; /* 2030-01-01 00:00:00 UTC */

if (t != NULL) {
*t = expired;
}

return expired;
}
#endif /* !NO_ASN_TIME && !NO_ASN_TIME_CHECK */
#endif

int test_wolfSSL_X509_ACERT_verify(void)
Expand Down Expand Up @@ -140,6 +156,17 @@ int test_wolfSSL_X509_ACERT_verify(void)
}

ExpectIntEQ(rc, 0);

#if !defined(NO_ASN_TIME) && !defined(NO_ASN_TIME_CHECK)
/* Override the current time to be past the acert's notAfter date. A
* cert with a valid signature must now fail verification because its
* validity period no longer includes the current time (RFC 5755). */
ExpectIntEQ(wc_SetTimeCb(acert_expired_time_cb), 0);
ExpectIntEQ(do_acert_verify_test(acerts[0], pkeys[0], 0), 0);
/* Always restore the real time source, even if the check above failed,
* so subsequent tests are unaffected. */
wc_SetTimeCb(NULL);
#endif /* !NO_ASN_TIME && !NO_ASN_TIME_CHECK */
#endif
return EXPECT_RESULT();
}
Expand Down
Loading
Loading