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
91 changes: 72 additions & 19 deletions src/internal.c
Original file line number Diff line number Diff line change
Expand Up @@ -19116,10 +19116,10 @@ int ProcessPeerCerts(WOLFSSL* ssl, byte* input, word32* inOutIdx,
#endif /* HAVE_RPK && WOLFSSL_TLS13 */

if (args->count == 0) {
/* Empty certificate message. */
if ((ssl->options.side == WOLFSSL_SERVER_END) &&
(ssl->options.mutualAuth || (ssl->options.failNoCert &&
IsAtLeastTLSv1_2(ssl)))) {
/* Empty certificate message. Only mutualAuth fails here
* before TLS 1.2; the later check catches the rest. */
if (ClientAuthRequired(ssl, ssl->options.usingPSK_cipher) &&
(ssl->options.mutualAuth || IsAtLeastTLSv1_2(ssl))) {
WOLFSSL_MSG("No peer cert from Client");
Comment thread
kareem-wolfssl marked this conversation as resolved.
Resolved
ret = NO_PEER_CERT;
WOLFSSL_ERROR_VERBOSE(ret);
Expand Down Expand Up @@ -40363,6 +40363,26 @@ const byte* MaskCurve25519PeerKey(const byte* pub, word32 pubSz,
return MATCH_SUITE_ERROR;
}

/* Does a full handshake on this connection require a client certificate?
* usingPsk is whether the suite in question authenticates with a PSK, which
* only the caller knows. verifyPostHandshake is deliberately absent: it defers
* the demand, not the policy, so the callers that care apply it. */
int ClientAuthRequired(const WOLFSSL* ssl, int usingPsk)
{
#if !defined(NO_CERTS) && !defined(NO_WOLFSSL_SERVER) && !defined(NO_TLS)
if (ssl->options.side != WOLFSSL_SERVER_END)
return 0;
if (ssl->options.verifyNone)
return 0;
return ssl->options.mutualAuth || ssl->options.failNoCert ||
(ssl->options.failNoCertxPSK && !usingPsk);
#else
/* Only a TLS server asks for a certificate, so only it can require one. */
(void)ssl;
(void)usingPsk;
return 0;
#endif
}

#if !defined(NO_WOLFSSL_SERVER) && !defined(NO_TLS)

Expand Down Expand Up @@ -42658,7 +42678,15 @@ static int AddPSKtoPreMasterSecret(WOLFSSL* ssl)
if (!session) {
WOLFSSL_MSG("Session lookup for resume failed");
ssl->options.resuming = 0;
} else {
}
else if (ClientAuthRequired(ssl, CipherRequires(
session->cipherSuite0, session->cipherSuite,
REQUIRES_PSK)) && !session->peerAuthOk) {
WOLFSSL_MSG("Session lacks client auth, do full handshake");
ssl->options.resuming = 0;
ssl->options.peerAuthGood = 0;
}
else {
if (MatchSuite(ssl, &clSuites) < 0) {
WOLFSSL_MSG("Unsupported cipher suite, OldClientHello");
return UNSUPPORTED_SUITE;
Expand Down Expand Up @@ -42742,6 +42770,16 @@ static int AddPSKtoPreMasterSecret(WOLFSSL* ssl)
#endif
) {
int secretSz = SECRET_LEN;
/* The secret comes from the callback, and nothing records an auth
* outcome for it. The suite is not chosen yet, so no PSK exception
* applies. */
if (ClientAuthRequired(ssl, 0)) {
WOLFSSL_MSG("Session secret callback cannot assert client auth,"
" do full handshake");
ssl->options.resuming = 0;
ssl->options.peerAuthGood = 0;
return ret;
}
WOLFSSL_MSG("Calling session secret callback");
ret = wc_RNG_GenerateBlock(ssl->rng, ssl->arrays->serverRandom,
RAN_LEN);
Expand Down Expand Up @@ -42789,6 +42827,14 @@ static int AddPSKtoPreMasterSecret(WOLFSSL* ssl)
ssl->options.resuming = 0;
return ret;
}
if (ClientAuthRequired(ssl, CipherRequires(session->cipherSuite0,
session->cipherSuite, REQUIRES_PSK)) &&
!session->peerAuthOk) {
Comment thread
philljj marked this conversation as resolved.
Resolved
WOLFSSL_MSG("Session lacks client auth, do full handshake");
ssl->options.resuming = 0;
ssl->options.peerAuthGood = 0;
return ret;
}
#if defined(HAVE_SESSION_TICKET) && \
(defined(HAVE_SNI) || defined(HAVE_ALPN))
/* Do not resume session if sniHash/alpnHash do not match. */
Expand Down Expand Up @@ -42991,6 +43037,15 @@ static int AddPSKtoPreMasterSecret(WOLFSSL* ssl)
/* Reset to sane value for SCR */
ssl->options.resuming = 0;
ssl->arrays->sessionIDSz = 0;
#ifdef HAVE_SESSION_TICKET
/* Only this ClientHello may set them, in TLSX_SessionTicket_Parse(),
* which ignores the extension during SCR - so an SCR hello inherits
* the connection's. */
if (!IsSCR(ssl)) {
ssl->options.useTicket = 0;
ssl->options.createTicket = 0;
}
#endif

/* protocol version, random and session id length check */
if (OPAQUE16_LEN + RAN_LEN + OPAQUE8_LEN > helloSz)
Expand Down Expand Up @@ -44477,6 +44532,9 @@ static int AddPSKtoPreMasterSecret(WOLFSSL* ssl)
it->suite[0] = ssl->options.cipherSuite0;
it->suite[1] = ssl->options.cipherSuite;

it->peerAuthOk = (byte)SSL_PEER_CERT_VERIFIED(ssl);
it->isPSK = (byte)ssl->options.usingPSK_cipher;

#ifdef WOLFSSL_EARLY_DATA
c32toa(ssl->options.maxEarlyDataSz, it->maxEarlyDataSz);
#endif
Expand Down Expand Up @@ -45050,6 +45108,9 @@ static int AddPSKtoPreMasterSecret(WOLFSSL* ssl)
#ifdef HAVE_ALPN
XMEMCPY(ssl->session->alpnHash, it->alpnHash, TICKET_BINDING_HASH_SZ);
#endif
/* After the DupSession above, which would otherwise overwrite it. */
ssl->session->peerAuthOk = it->peerAuthOk;
ssl->session->isPSK = it->isPSK;

if (!IsAtLeastTLSv1_3(ssl->version)) {
if (ssl->arrays == NULL)
Expand Down Expand Up @@ -45139,6 +45200,8 @@ static int AddPSKtoPreMasterSecret(WOLFSSL* ssl)
c32toa((word32)milliBornOn , it->timestamp + OPAQUE32_LEN);
#endif
it->haveEMS = (byte)sess->haveEMS;
it->peerAuthOk = sess->peerAuthOk;
it->isPSK = sess->isPSK;
c32toa(sess->ticketAdd, it->ageAdd);
c16toa(sess->namedGroup, it->namedGroup);
if (sess->ticketNonce.len <= MAX_TICKET_NONCE_STATIC_SZ) {
Expand Down Expand Up @@ -46652,20 +46715,10 @@ static int DefTicketEncCb(WOLFSSL* ssl, byte key_name[WOLFSSL_TICKET_NAME_SZ],
}

#if !defined(NO_CERTS) && !defined(WOLFSSL_NO_CLIENT_AUTH)
if (ssl->options.verifyPeer &&
(ssl->options.mutualAuth || ssl->options.failNoCert)) {
if (!ssl->options.havePeerCert) {
WOLFSSL_MSG("client didn't present peer cert");
ERROR_OUT(NO_PEER_CERT, exit_dcke);
}
}

if (ssl->options.verifyPeer && ssl->options.failNoCertxPSK) {
if (!ssl->options.havePeerCert &&
!ssl->options.usingPSK_cipher) {
WOLFSSL_MSG("client didn't present peer cert");
ERROR_OUT(NO_PEER_CERT, exit_dcke);
}
if (ClientAuthRequired(ssl, ssl->options.usingPSK_cipher) &&
!ssl->options.havePeerCert) {
WOLFSSL_MSG("client didn't present peer cert");
ERROR_OUT(NO_PEER_CERT, exit_dcke);
}
#endif /* !NO_CERTS && !WOLFSSL_NO_CLIENT_AUTH */

Expand Down
10 changes: 7 additions & 3 deletions src/keys.c
Original file line number Diff line number Diff line change
Expand Up @@ -46,9 +46,13 @@

int SetCipherSpecs(WOLFSSL* ssl)
{
int ret = GetCipherSpec(ssl->options.side, ssl->options.cipherSuite0,
ssl->options.cipherSuite, &ssl->specs,
&ssl->options);
int ret;

/* GetCipherSpec only sets these, for the suite being set. */
ssl->options.usingPSK_cipher = 0;
ssl->options.usingAnon_cipher = 0;
ret = GetCipherSpec(ssl->options.side, ssl->options.cipherSuite0,
ssl->options.cipherSuite, &ssl->specs, &ssl->options);
if (ret == 0) {
#ifdef WOLFSSL_TLS13
/* The client only checks that the ServerHello suite was offered, and
Expand Down
37 changes: 30 additions & 7 deletions src/ssl.c
Original file line number Diff line number Diff line change
Expand Up @@ -5793,14 +5793,30 @@ size_t wolfSSL_get_client_random(const WOLFSSL* ssl, unsigned char* out,
return WOLFSSL_FAILURE;
}

if (!ssl->options.handShakeDone) {
/* Only reset the session if we didn't complete a handshake */
/* A client keeps the session it may resume. A server's is per
* connection: take a new one when the application holds a reference,
* else reset ours, as wolfSSL_get_session() hands out a pointer
* without taking one. */
if (!ssl->options.handShakeDone ||
((ssl->options.side == WOLFSSL_SERVER_END) &&
(wolfSSL_RefCur(ssl->session->ref) > 1))) {
wolfSSL_FreeSession(ssl->ctx, ssl->session);
Comment thread
kareem-wolfssl marked this conversation as resolved.
Resolved
ssl->session = wolfSSL_NewSession(ssl->heap);
if (ssl->session == NULL) {
return WOLFSSL_FAILURE;
}
}
else if (ssl->options.side == WOLFSSL_SERVER_END) {
ssl->session->haveAltSessionID = 0;
ForceZero(ssl->session->altSessionID, ID_LEN);
#ifndef NO_WOLFSSL_SERVER
ssl->session->peerAuthOk = 0;
ssl->session->isPSK = 0;
#endif
#if defined(HAVE_SESSION_TICKET) && defined(WOLFSSL_TLS13)
ssl->session->ticketNonce.len = 0;
#endif
}

/* reset error */
ssl->error = 0;
Expand All @@ -5811,6 +5827,9 @@ size_t wolfSSL_get_client_random(const WOLFSSL* ssl, unsigned char* out,
ssl->options.connReset = 0;
ssl->options.sentNotify = 0;
ssl->options.closeNotify = 0;
/* Per-connection budgets, not cumulative across a reused object. */
ssl->options.alertCount = 0;
ssl->options.emptyRecordCount = 0;
ssl->options.sendVerify = 0;
ssl->options.serverState = NULL_STATE;
ssl->options.clientState = NULL_STATE;
Expand All @@ -5834,12 +5853,18 @@ size_t wolfSSL_get_client_random(const WOLFSSL* ssl, unsigned char* out,
DYNAMIC_TYPE_TMP_BUFFER);
ssl->buffers.certVerifyMsg.buffer = NULL;
ssl->buffers.certVerifyMsg.length = 0;
ssl->fragOffset = 0;
#endif
ssl->fragOffset = 0;
ssl->options.buildingMsg = 0;
ssl->options.processReply = 0; /* doProcessInit */
ssl->options.havePeerVerify = 0;
ssl->options.havePeerCert = 0;
ssl->options.peerAuthGood = 0;
ssl->options.usingPSK_cipher = 0;
ssl->options.usingAnon_cipher = 0;
#if defined(WOLFSSL_TLS13) && (defined(HAVE_SESSION_TICKET) || !defined(NO_PSK))
ssl->options.pskNegotiated = 0;
#endif
ssl->options.tls1_3 = 0;
ssl->options.haveSessionId = 0;
ssl->options.tls = 0;
Expand Down Expand Up @@ -5939,10 +5964,6 @@ size_t wolfSSL_get_client_random(const WOLFSSL* ssl, unsigned char* out,
#ifdef HAVE_SESSION_TICKET
#ifdef WOLFSSL_TLS13
ssl->options.ticketsSent = 0;
#ifndef NO_WOLFSSL_SERVER
if (ssl->options.side == WOLFSSL_SERVER_END)
ssl->session->ticketNonce.len = 0;
#endif
#if !defined(NO_WOLFSSL_SERVER) && \
defined(WOLFSSL_TLS13_TICKET_CHECK_PSK_MODES)
/* Recorded from the ClientHello, so it must not carry into the next
Expand All @@ -5955,6 +5976,8 @@ size_t wolfSSL_get_client_random(const WOLFSSL* ssl, unsigned char* out,
#endif
#endif
ssl->options.rejectTicket = 0;
ssl->options.useTicket = 0;
ssl->options.createTicket = 0;
#endif
#ifdef WOLFSSL_EARLY_DATA
ssl->earlyData = no_early_data;
Expand Down
15 changes: 15 additions & 0 deletions src/ssl_api_cert.c
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,11 @@ int wolfSSL_CTX_mutual_auth(WOLFSSL_CTX* ctx, int req)
return SIDE_ERROR;

ctx->mutualAuth = (byte)req;
/* A certificate has to be asked for to be required. */
if (req) {
ctx->verifyNone = 0;
ctx->verifyPeer = 1;
}

return 0;
}
Expand All @@ -69,6 +74,11 @@ int wolfSSL_mutual_auth(WOLFSSL* ssl, int req)
return SIDE_ERROR;

ssl->options.mutualAuth = (word16)req;
/* A certificate has to be asked for to be required. */
if (req) {
ssl->options.verifyNone = 0;
ssl->options.verifyPeer = 1;
}

return 0;
}
Expand Down Expand Up @@ -587,6 +597,11 @@ static SetVerifyOptions ModeToVerifyOptions(int mode)
(mode & WOLFSSL_VERIFY_FAIL_EXCEPT_PSK) != 0;
opts.failNoCert =
(mode & WOLFSSL_VERIFY_FAIL_IF_NO_PEER_CERT) != 0;
/* Both only fail a certificate that was asked for, so they imply
* asking. */
if (opts.failNoCert || opts.failNoCertxPSK) {
opts.verifyPeer = 1;
}
#if defined(WOLFSSL_TLS13) && defined(WOLFSSL_POST_HANDSHAKE_AUTH)
opts.verifyPostHandshake =
(mode & WOLFSSL_VERIFY_POST_HANDSHAKE) != 0;
Expand Down
4 changes: 2 additions & 2 deletions src/ssl_api_hs.c
Original file line number Diff line number Diff line change
Expand Up @@ -1102,11 +1102,11 @@ int wolfSSL_accept(WOLFSSL* ssl)
case ACCEPT_SECOND_REPLY_DONE :
#ifndef NO_CERTS
/* SERVER: When not resuming and verifying peer but no certificate
* received and not failing when not received then peer auth good.
* received and none was required then peer auth good.
*/
if ((!ssl->options.resuming) && (ssl->options.verifyPeer) &&
(!ssl->options.havePeerCert) &&
(!ssl->options.failNoCert)) {
(!ClientAuthRequired(ssl, ssl->options.usingPSK_cipher))) {
ssl->options.peerAuthGood = 1;
}
#endif /* !NO_CERTS */
Expand Down
40 changes: 39 additions & 1 deletion src/ssl_sess.c
Original file line number Diff line number Diff line change
Expand Up @@ -2952,6 +2952,10 @@ int wolfSSL_i2d_SSL_SESSION(WOLFSSL_SESSION* sess, unsigned char** p)
size += TICKET_BINDING_HASH_SZ;
#endif
#endif /* !NO_WOLFSSL_SERVER && !NO_TLS */
#endif
#ifndef NO_WOLFSSL_SERVER
/* peerAuthOk and isPSK */
size += OPAQUE8_LEN;
#endif

if (p != NULL) {
Expand Down Expand Up @@ -3047,6 +3051,9 @@ int wolfSSL_i2d_SSL_SESSION(WOLFSSL_SESSION* sess, unsigned char** p)
idx += TICKET_BINDING_HASH_SZ;
#endif
#endif /* !NO_WOLFSSL_SERVER && !NO_TLS */
#endif
#ifndef NO_WOLFSSL_SERVER
data[idx++] = (byte)(sess->peerAuthOk | (sess->isPSK << 1));
#endif
}
#endif
Expand All @@ -3068,6 +3075,11 @@ int wolfSSL_i2d_SSL_SESSION(WOLFSSL_SESSION* sess, unsigned char** p)
* enabled with the wolfSSL library exporting a session then it is
* expected to be turned on with the wolfSSL library importing the
* session.
*
* i is how many bytes are readable at *p, not necessarily the size of the
* session: trailing bytes are ignored, and *p is advanced to the end of the
* session decoded, so sessions stored back to back decode with repeated
* calls. Passing in too few bytes will cause an error.
*/
WOLFSSL_SESSION* wolfSSL_d2i_SSL_SESSION(WOLFSSL_SESSION** sess,
const unsigned char** p, long i)
Expand Down Expand Up @@ -3354,7 +3366,15 @@ WOLFSSL_SESSION* wolfSSL_d2i_SSL_SESSION(WOLFSSL_SESSION** sess,
#endif
#endif /* !NO_WOLFSSL_SERVER && !NO_TLS */
#endif
(void)idx;
#ifndef NO_WOLFSSL_SERVER
if (i - idx < OPAQUE8_LEN) {
ret = BUFFER_ERROR;
goto end;
}
s->peerAuthOk = (data[idx] & 0x01) != 0;
s->isPSK = (data[idx] & 0x02) != 0;
idx++;
#endif

if (sess != NULL) {
wolfSSL_FreeSession(NULL, *sess);
Expand Down Expand Up @@ -3928,6 +3948,24 @@ void SetupSession(WOLFSSL* ssl)
session->haveEMS = 1;
else
session->haveEMS = ssl->options.haveEMS;
/* Server only: on a client these flags describe the server certificate,
* a different statement that nothing reads. A full handshake records its
* own outcome; a resumed one keeps what it inherited unless post-handshake
* auth added a certificate. */
#ifndef NO_WOLFSSL_SERVER
if (ssl->options.side == WOLFSSL_SERVER_END) {
if (!ssl->options.resuming) {
session->peerAuthOk = 0;
session->isPSK = (byte)ssl->options.usingPSK_cipher;
}
if (SSL_PEER_CERT_VERIFIED(ssl))
session->peerAuthOk = 1;
}
Comment thread
kareem-wolfssl marked this conversation as resolved.
Resolved
else {
session->peerAuthOk = 0;
session->isPSK = 0;
}
#endif
#ifdef WOLFSSL_SESSION_ID_CTX
/* If using compatibility layer then check for and copy over session context
* id. */
Expand Down
Loading
Loading