@@ -38542,6 +38542,11 @@ static int AddPSKtoPreMasterSecret(WOLFSSL* ssl)
3854238542 if((ret=ALPN_Select(ssl)))
3854338543 goto out;
3854438544 #endif
38545+ #if defined(HAVE_SESSION_TICKET) && \
38546+ (defined(HAVE_SNI) || defined(HAVE_ALPN))
38547+ if((ret=VerifyTicketBinding(ssl)))
38548+ goto out;
38549+ #endif
3854538550
3854638551 i += totalExtSz;
3854738552#else
@@ -39323,6 +39328,77 @@ static int AddPSKtoPreMasterSecret(WOLFSSL* ssl)
3932339328 return ret;
3932439329 }
3932539330
39331+ #ifdef HAVE_SNI
39332+ /* Hash server-selected SNI; zeros dst when none. */
39333+ static int TicketSniHash(WOLFSSL* ssl, byte* dst)
39334+ {
39335+ char* name = NULL;
39336+ word16 nameLen;
39337+
39338+ nameLen = TLSX_SNI_GetRequest(ssl->extensions,
39339+ WOLFSSL_SNI_HOST_NAME,
39340+ (void**)&name, 0);
39341+ if (name != NULL && nameLen > 0) {
39342+ return wc_Hash(TICKET_BINDING_HASH_TYPE, (const byte*)name,
39343+ nameLen, dst, TICKET_BINDING_HASH_SZ);
39344+ }
39345+
39346+ XMEMSET(dst, 0, TICKET_BINDING_HASH_SZ);
39347+ return 0;
39348+ }
39349+ #endif
39350+
39351+ #ifdef HAVE_ALPN
39352+ /* Hash negotiated ALPN; zeros dst when none. */
39353+ static int TicketAlpnHash(WOLFSSL* ssl, byte* dst)
39354+ {
39355+ char* proto = NULL;
39356+ word16 protoLen = 0;
39357+
39358+ if (TLSX_ALPN_GetRequest(ssl->extensions, (void**)&proto,
39359+ &protoLen) == WOLFSSL_SUCCESS &&
39360+ proto != NULL && protoLen > 0) {
39361+ return wc_Hash(TICKET_BINDING_HASH_TYPE, (const byte*)proto,
39362+ protoLen, dst, TICKET_BINDING_HASH_SZ);
39363+ }
39364+
39365+ XMEMSET(dst, 0, TICKET_BINDING_HASH_SZ);
39366+ return 0;
39367+ }
39368+ #endif
39369+
39370+ #if defined(HAVE_SNI) || defined(HAVE_ALPN)
39371+ /* Server-side: verify the SNI/ALPN bindings carried on a resumed
39372+ * session match what was negotiated for the current connection.
39373+ * Must be called after extension parsing and ALPN_Select.
39374+ * Returns 0 on match, WOLFSSL_FATAL_ERROR on mismatch. */
39375+ int VerifyTicketBinding(WOLFSSL* ssl)
39376+ {
39377+ byte curHash[TICKET_BINDING_HASH_SZ];
39378+
39379+ if (!ssl->options.resuming || !ssl->options.useTicket)
39380+ return 0;
39381+
39382+ #ifdef HAVE_SNI
39383+ if (TicketSniHash(ssl, curHash) != 0 ||
39384+ XMEMCMP(curHash, ssl->session->sniHash,
39385+ TICKET_BINDING_HASH_SZ) != 0) {
39386+ WOLFSSL_MSG("Ticket SNI mismatch");
39387+ return WOLFSSL_FATAL_ERROR;
39388+ }
39389+ #endif
39390+ #ifdef HAVE_ALPN
39391+ if (TicketAlpnHash(ssl, curHash) != 0 ||
39392+ XMEMCMP(curHash, ssl->session->alpnHash,
39393+ TICKET_BINDING_HASH_SZ) != 0) {
39394+ WOLFSSL_MSG("Ticket ALPN mismatch");
39395+ return WOLFSSL_FATAL_ERROR;
39396+ }
39397+ #endif
39398+ return 0;
39399+ }
39400+ #endif
39401+
3932639402 /* create a new session ticket, 0 on success
3932739403 * Do any kind of setup in SetupTicket */
3932839404 int CreateTicket(WOLFSSL* ssl)
@@ -39421,6 +39497,18 @@ static int AddPSKtoPreMasterSecret(WOLFSSL* ssl)
3942139497 it->sessionCtxSz = ssl->sessionCtxSz;
3942239498 XMEMCPY(it->sessionCtx, ssl->sessionCtx, ID_LEN);
3942339499#endif
39500+ #ifdef HAVE_SNI
39501+ ret = TicketSniHash(ssl, it->sniHash);
39502+ if (ret != 0)
39503+ goto error;
39504+ XMEMCPY(ssl->session->sniHash, it->sniHash, TICKET_BINDING_HASH_SZ);
39505+ #endif
39506+ #ifdef HAVE_ALPN
39507+ ret = TicketAlpnHash(ssl, it->alpnHash);
39508+ if (ret != 0)
39509+ goto error;
39510+ XMEMCPY(ssl->session->alpnHash, it->alpnHash, TICKET_BINDING_HASH_SZ);
39511+ #endif
3942439512
3942539513#if defined(OPENSSL_ALL) && defined(KEEP_PEER_CERT) && \
3942639514 !defined(NO_CERT_IN_TICKET)
@@ -39776,6 +39864,8 @@ static int AddPSKtoPreMasterSecret(WOLFSSL* ssl)
3977639864 ssl->sessionCtxSz) != 0))
3977739865 return WOLFSSL_FATAL_ERROR;
3977839866#endif
39867+ /* SNI/ALPN binding is verified after ALPN_Select via
39868+ * VerifyTicketBinding(). */
3977939869 return 0;
3978039870 }
3978139871#endif /* WOLFSSL_SLT13 */
@@ -39787,36 +39877,54 @@ static int AddPSKtoPreMasterSecret(WOLFSSL* ssl)
3978739877 word16 peerCertLen = 0;
3978839878 ato16(it->peerCertLen, &peerCertLen);
3978939879
39790- if (peerCertLen > 0 && peerCertLen <= MAX_TICKET_PEER_CERT_SZ) {
39880+ /* Clear any peer cert state that may have been copied from the session
39881+ * cache by wolfSSL_DupSession before we got here. */
39882+ FreeX509(&ssl->peerCert);
39883+ InitX509(&ssl->peerCert, 0, ssl->heap);
3979139884#ifdef SESSION_CERTS
39792- /* Clear existing chain and add the peer certificate */
39793- ssl->session->chain.count = 0;
39794- AddSessionCertToChain(&ssl->session->chain,
39795- it->peerCert, peerCertLen);
39885+ ssl->session->chain.count = 0;
3979639886#endif
39797- /* Also decode into ssl->peerCert for direct access */
39798- {
39799- int ret;
39800- DecodedCert* dCert;
39801-
39802- dCert = (DecodedCert*)XMALLOC(sizeof(DecodedCert), ssl->heap,
39803- DYNAMIC_TYPE_DCERT);
39804- if (dCert != NULL) {
39805- InitDecodedCert(dCert, it->peerCert, peerCertLen, ssl->heap);
39806- ret = ParseCertRelative(dCert, CERT_TYPE, 0, NULL, NULL);
39807- if (ret == 0) {
39887+
39888+ if (peerCertLen > 0 && peerCertLen <= MAX_TICKET_PEER_CERT_SZ) {
39889+ int ret;
39890+ DecodedCert* dCert;
39891+
39892+ dCert = (DecodedCert*)XMALLOC(sizeof(DecodedCert), ssl->heap,
39893+ DYNAMIC_TYPE_DCERT);
39894+ if (dCert != NULL) {
39895+ int verify = ssl->options.verifyPeer ? VERIFY : NO_VERIFY;
39896+ InitDecodedCert(dCert, it->peerCert, peerCertLen, ssl->heap);
39897+ /* Re-verify against the current trust store so that CA
39898+ * removal since ticket issue is enforced. */
39899+ ret = ParseCertRelative(dCert, CERT_TYPE, verify,
39900+ SSL_CM(ssl), NULL);
39901+ #ifdef HAVE_OCSP
39902+ /* ParseCertRelative does not check revocation status.
39903+ * Run OCSP if the CertManager has it enabled. */
39904+ if (ret == 0 && SSL_CM(ssl)->ocspEnabled) {
39905+ ret = CheckCertOCSP_ex(SSL_CM(ssl)->ocsp, dCert, ssl);
39906+ }
39907+ #endif
39908+ #ifdef HAVE_CRL
39909+ if (ret == 0 && SSL_CM(ssl)->crlEnabled) {
39910+ ret = CheckCertCRL(SSL_CM(ssl)->crl, dCert);
39911+ }
39912+ #endif
39913+ if (ret == 0) {
39914+ #ifdef SESSION_CERTS
39915+ AddSessionCertToChain(&ssl->session->chain,
39916+ it->peerCert, peerCertLen);
39917+ #endif
39918+ FreeX509(&ssl->peerCert);
39919+ InitX509(&ssl->peerCert, 0, ssl->heap);
39920+ ret = CopyDecodedToX509(&ssl->peerCert, dCert);
39921+ if (ret != 0) {
3980839922 FreeX509(&ssl->peerCert);
3980939923 InitX509(&ssl->peerCert, 0, ssl->heap);
39810- ret = CopyDecodedToX509(&ssl->peerCert, dCert);
39811- if (ret != 0) {
39812- /* Failed to copy - clear peerCert */
39813- FreeX509(&ssl->peerCert);
39814- InitX509(&ssl->peerCert, 0, ssl->heap);
39815- }
3981639924 }
39817- FreeDecodedCert(dCert);
39818- XFREE(dCert, ssl->heap, DYNAMIC_TYPE_DCERT);
3981939925 }
39926+ FreeDecodedCert(dCert);
39927+ XFREE(dCert, ssl->heap, DYNAMIC_TYPE_DCERT);
3982039928 }
3982139929 }
3982239930 }
@@ -39853,6 +39961,14 @@ static int AddPSKtoPreMasterSecret(WOLFSSL* ssl)
3985339961 }
3985439962 }
3985539963#endif
39964+ /* Carry the ticket bindings on the session for the deferred
39965+ * VerifyTicketBinding() check. */
39966+ #ifdef HAVE_SNI
39967+ XMEMCPY(ssl->session->sniHash, it->sniHash, TICKET_BINDING_HASH_SZ);
39968+ #endif
39969+ #ifdef HAVE_ALPN
39970+ XMEMCPY(ssl->session->alpnHash, it->alpnHash, TICKET_BINDING_HASH_SZ);
39971+ #endif
3985639972
3985739973 if (!IsAtLeastTLSv1_3(ssl->version)) {
3985839974 if (ssl->arrays == NULL)
@@ -39962,6 +40078,12 @@ static int AddPSKtoPreMasterSecret(WOLFSSL* ssl)
3996240078 it->sessionCtxSz = sess->sessionCtxSz;
3996340079 XMEMCPY(it->sessionCtx, sess->sessionCtx, sess->sessionCtxSz);
3996440080#endif
40081+ #ifdef HAVE_SNI
40082+ XMEMCPY(it->sniHash, sess->sniHash, TICKET_BINDING_HASH_SZ);
40083+ #endif
40084+ #ifdef HAVE_ALPN
40085+ XMEMCPY(it->alpnHash, sess->alpnHash, TICKET_BINDING_HASH_SZ);
40086+ #endif
3996540087#if defined(OPENSSL_ALL) && defined(KEEP_PEER_CERT) && \
3996640088 defined(SESSION_CERTS) && !defined(NO_CERT_IN_TICKET)
3996740089 /* Store peer certificate from session chain */
@@ -40206,6 +40328,8 @@ static int AddPSKtoPreMasterSecret(WOLFSSL* ssl)
4020640328 goto cleanup;
4020740329 }
4020840330
40331+ /* SNI/ALPN binding is verified after ALPN_Select via
40332+ * VerifyTicketBinding(). */
4020940333 DoClientTicketFinalize(ssl, it, NULL);
4021040334
4021140335cleanup:
0 commit comments