summaryrefslogtreecommitdiffstats
path: root/security/nss/lib/ssl/tls13con.c
diff options
context:
space:
mode:
Diffstat (limited to 'security/nss/lib/ssl/tls13con.c')
-rw-r--r--security/nss/lib/ssl/tls13con.c773
1 files changed, 605 insertions, 168 deletions
diff --git a/security/nss/lib/ssl/tls13con.c b/security/nss/lib/ssl/tls13con.c
index 461cd2eb9..c3528a52f 100644
--- a/security/nss/lib/ssl/tls13con.c
+++ b/security/nss/lib/ssl/tls13con.c
@@ -24,22 +24,29 @@
#include "tls13esni.h"
#include "tls13exthandle.h"
#include "tls13hashstate.h"
+#include "tls13subcerts.h"
static SECStatus tls13_SetCipherSpec(sslSocket *ss, PRUint16 epoch,
- CipherSpecDirection install,
+ SSLSecretDirection install,
PRBool deleteSecret);
-static SECStatus tls13_AESGCM(
- ssl3KeyMaterial *keys,
- PRBool doDecrypt,
- unsigned char *out, int *outlen, int maxout,
- const unsigned char *in, int inlen,
- const unsigned char *additionalData, int additionalDataLen);
-static SECStatus tls13_ChaCha20Poly1305(
- ssl3KeyMaterial *keys,
- PRBool doDecrypt,
- unsigned char *out, int *outlen, int maxout,
- const unsigned char *in, int inlen,
- const unsigned char *additionalData, int additionalDataLen);
+static SECStatus tls13_AESGCM(const ssl3KeyMaterial *keys,
+ PRBool doDecrypt,
+ unsigned char *out,
+ unsigned int *outlen,
+ unsigned int maxout,
+ const unsigned char *in,
+ unsigned int inlen,
+ const unsigned char *additionalData,
+ unsigned int additionalDataLen);
+static SECStatus tls13_ChaCha20Poly1305(const ssl3KeyMaterial *keys,
+ PRBool doDecrypt,
+ unsigned char *out,
+ unsigned int *outlen,
+ unsigned int maxout,
+ const unsigned char *in,
+ unsigned int inlen,
+ const unsigned char *additionalData,
+ unsigned int additionalDataLen);
static SECStatus tls13_SendServerHelloSequence(sslSocket *ss);
static SECStatus tls13_SendEncryptedExtensions(sslSocket *ss);
static void tls13_SetKeyExchangeType(sslSocket *ss, const sslNamedGroupDef *group);
@@ -56,6 +63,7 @@ static SECStatus tls13_SendCertificate(sslSocket *ss);
static SECStatus tls13_HandleCertificate(
sslSocket *ss, PRUint8 *b, PRUint32 length);
static SECStatus tls13_ReinjectHandshakeTranscript(sslSocket *ss);
+static SECStatus tls13_SendCertificateRequest(sslSocket *ss);
static SECStatus tls13_HandleCertificateRequest(sslSocket *ss, PRUint8 *b,
PRUint32 length);
static SECStatus
@@ -104,6 +112,9 @@ static SECStatus tls13_ComputeFinished(
PRBool sending, PRUint8 *output, unsigned int *outputLen,
unsigned int maxOutputLen);
static SECStatus tls13_SendClientSecondRound(sslSocket *ss);
+static SECStatus tls13_SendClientSecondFlight(sslSocket *ss,
+ PRBool sendClientCert,
+ SSL3AlertDescription *sendAlert);
static SECStatus tls13_FinishHandshake(sslSocket *ss);
const char kHkdfLabelClient[] = "c";
@@ -249,6 +260,12 @@ tls13_CheckHsState(sslSocket *ss, int err, const char *error_name,
return SECFailure;
}
+PRBool
+tls13_IsPostHandshake(const sslSocket *ss)
+{
+ return ss->version >= SSL_LIBRARY_VERSION_TLS_1_3 && ss->firstHsDone;
+}
+
SSLHashType
tls13_GetHashForCipherSuite(ssl3CipherSuite suite)
{
@@ -289,7 +306,7 @@ tls13_GetHashSize(const sslSocket *ss)
return tls13_GetHashSizeForHash(tls13_GetHash(ss));
}
-static CK_MECHANISM_TYPE
+CK_MECHANISM_TYPE
tls13_GetHkdfMechanismForHash(SSLHashType hash)
{
switch (hash) {
@@ -406,7 +423,7 @@ SSL_SendAdditionalKeyShares(PRFileDesc *fd, unsigned int count)
* Called from ssl3_SendClientHello.
*/
SECStatus
-tls13_SetupClientHello(sslSocket *ss)
+tls13_SetupClientHello(sslSocket *ss, sslClientHelloType chType)
{
unsigned int i;
SSL3Statistics *ssl3stats = SSL_GetStatistics();
@@ -417,17 +434,24 @@ tls13_SetupClientHello(sslSocket *ss)
PORT_Assert(ss->opt.noLocks || ssl_HaveSSL3HandshakeLock(ss));
PORT_Assert(ss->opt.noLocks || ssl_HaveXmitBufLock(ss));
- PORT_Assert(PR_CLIST_IS_EMPTY(&ss->ephemeralKeyPairs));
- /* Do encrypted SNI. This may create a key share as a side effect. */
+ /* Do encrypted SNI.
+ * Note: this makes a new key even though we don't need one.
+ * Maybe remove this in future for efficiency. */
rv = tls13_ClientSetupESNI(ss);
if (rv != SECSuccess) {
return SECFailure;
}
+ /* Everything below here is only run on the first CH. */
+ if (chType != client_hello_initial) {
+ return SECSuccess;
+ }
+
/* Select the first enabled group.
* TODO(ekr@rtfm.com): be smarter about offering the group
* that the other side negotiated if we are resuming. */
+ PORT_Assert(PR_CLIST_IS_EMPTY(&ss->ephemeralKeyPairs));
for (i = 0; i < SSL_NAMED_GROUP_COUNT; ++i) {
if (!ss->namedGroupPreferences[i]) {
continue;
@@ -456,7 +480,7 @@ tls13_SetupClientHello(sslSocket *ss)
session_ticket = &sid->u.ssl3.locked.sessionTicket;
PORT_Assert(session_ticket && session_ticket->ticket.data);
- if (ssl_TicketTimeValid(session_ticket)) {
+ if (ssl_TicketTimeValid(ss, session_ticket)) {
ss->statelessResume = PR_TRUE;
}
@@ -588,13 +612,13 @@ loser:
}
static PRBool
-tls13_UseServerSecret(sslSocket *ss, CipherSpecDirection direction)
+tls13_UseServerSecret(sslSocket *ss, SSLSecretDirection direction)
{
- return ss->sec.isServer == (direction == CipherSpecWrite);
+ return ss->sec.isServer == (direction == ssl_secret_write);
}
static PK11SymKey **
-tls13_TrafficSecretRef(sslSocket *ss, CipherSpecDirection direction)
+tls13_TrafficSecretRef(sslSocket *ss, SSLSecretDirection direction)
{
if (tls13_UseServerSecret(ss, direction)) {
return &ss->ssl3.hs.serverTrafficSecret;
@@ -603,7 +627,7 @@ tls13_TrafficSecretRef(sslSocket *ss, CipherSpecDirection direction)
}
SECStatus
-tls13_UpdateTrafficKeys(sslSocket *ss, CipherSpecDirection direction)
+tls13_UpdateTrafficKeys(sslSocket *ss, SSLSecretDirection direction)
{
PK11SymKey **secret;
PK11SymKey *updatedSecret;
@@ -626,7 +650,7 @@ tls13_UpdateTrafficKeys(sslSocket *ss, CipherSpecDirection direction)
*secret = updatedSecret;
ssl_GetSpecReadLock(ss);
- if (direction == CipherSpecRead) {
+ if (direction == ssl_secret_read) {
epoch = ss->ssl3.crSpec->epoch;
} else {
epoch = ss->ssl3.cwSpec->epoch;
@@ -640,6 +664,11 @@ tls13_UpdateTrafficKeys(sslSocket *ss, CipherSpecDirection direction)
}
++epoch;
+ if (ss->secretCallback) {
+ ss->secretCallback(ss->fd, epoch, direction, updatedSecret,
+ ss->secretCallbackArg);
+ }
+
rv = tls13_SetCipherSpec(ss, epoch, direction, PR_FALSE);
if (rv != SECSuccess) {
FATAL_ERROR(ss, SEC_ERROR_LIBRARY_FAILURE, internal_error);
@@ -660,8 +689,9 @@ tls13_SendKeyUpdate(sslSocket *ss, tls13KeyUpdateRequest request, PRBool buffer)
: "not requested"));
PORT_Assert(ss->opt.noLocks || ssl_HaveSSL3HandshakeLock(ss));
+ PORT_Assert(!ss->sec.isServer || !ss->ssl3.clientCertRequested);
- if (!ss->firstHsDone) {
+ if (!tls13_IsPostHandshake(ss)) {
PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
return SECFailure;
}
@@ -698,7 +728,7 @@ tls13_SendKeyUpdate(sslSocket *ss, tls13KeyUpdateRequest request, PRBool buffer)
}
ssl_ReleaseXmitBufLock(ss);
- rv = tls13_UpdateTrafficKeys(ss, CipherSpecWrite);
+ rv = tls13_UpdateTrafficKeys(ss, ssl_secret_write);
if (rv != SECSuccess) {
goto loser; /* error code set by tls13_UpdateTrafficKeys */
}
@@ -719,11 +749,16 @@ SSLExp_KeyUpdate(PRFileDesc *fd, PRBool requestUpdate)
return SECFailure;
}
- if (!ss->firstHsDone) {
+ if (!tls13_IsPostHandshake(ss)) {
PORT_SetError(SEC_ERROR_INVALID_ARGS);
return SECFailure;
}
+ if (ss->ssl3.clientCertRequested) {
+ PORT_SetError(PR_WOULD_BLOCK_ERROR);
+ return SECFailure;
+ }
+
rv = TLS13_CHECK_HS_STATE(ss, SEC_ERROR_INVALID_ARGS,
idle_handshake);
if (rv != SECSuccess) {
@@ -763,8 +798,7 @@ tls13_HandleKeyUpdate(sslSocket *ss, PRUint8 *b, unsigned int length)
PORT_Assert(ss->opt.noLocks || ssl_HaveRecvBufLock(ss));
PORT_Assert(ss->opt.noLocks || ssl_HaveSSL3HandshakeLock(ss));
- PORT_Assert(ss->firstHsDone);
- if (!ss->firstHsDone) {
+ if (!tls13_IsPostHandshake(ss)) {
FATAL_ERROR(ss, SSL_ERROR_RX_UNEXPECTED_KEY_UPDATE, unexpected_message);
return SECFailure;
}
@@ -791,14 +825,19 @@ tls13_HandleKeyUpdate(sslSocket *ss, PRUint8 *b, unsigned int length)
return SECFailure;
}
- rv = tls13_UpdateTrafficKeys(ss, CipherSpecRead);
+ rv = tls13_UpdateTrafficKeys(ss, ssl_secret_read);
if (rv != SECSuccess) {
return SECFailure; /* Error code set by tls13_UpdateTrafficKeys. */
}
if (update == update_requested) {
PRBool sendUpdate;
- if (ss->ssl3.peerRequestedKeyUpdate) {
+ if (ss->ssl3.clientCertRequested) {
+ /* Post-handshake auth is in progress; defer sending a key update. */
+ ss->ssl3.keyUpdateDeferred = PR_TRUE;
+ ss->ssl3.deferredKeyUpdateRequest = update_not_requested;
+ sendUpdate = PR_FALSE;
+ } else if (ss->ssl3.peerRequestedKeyUpdate) {
/* Only send an update if we have sent with the current spec. This
* prevents us from being forced to crank forward pointlessly. */
ssl_GetSpecReadLock(ss);
@@ -821,10 +860,60 @@ tls13_HandleKeyUpdate(sslSocket *ss, PRUint8 *b, unsigned int length)
}
SECStatus
+SSLExp_SendCertificateRequest(PRFileDesc *fd)
+{
+ SECStatus rv;
+ sslSocket *ss = ssl_FindSocket(fd);
+ if (!ss) {
+ return SECFailure;
+ }
+
+ /* Not supported. */
+ if (IS_DTLS(ss)) {
+ PORT_SetError(SSL_ERROR_FEATURE_NOT_SUPPORTED_FOR_VERSION);
+ return SECFailure;
+ }
+
+ if (!tls13_IsPostHandshake(ss)) {
+ PORT_SetError(SEC_ERROR_INVALID_ARGS);
+ return SECFailure;
+ }
+
+ if (ss->ssl3.clientCertRequested) {
+ PORT_SetError(PR_WOULD_BLOCK_ERROR);
+ return SECFailure;
+ }
+
+ rv = TLS13_CHECK_HS_STATE(ss, SEC_ERROR_INVALID_ARGS,
+ idle_handshake);
+ if (rv != SECSuccess) {
+ return SECFailure;
+ }
+
+ if (!ssl3_ExtensionNegotiated(ss, ssl_tls13_post_handshake_auth_xtn)) {
+ PORT_SetError(SSL_ERROR_MISSING_POST_HANDSHAKE_AUTH_EXTENSION);
+ return SECFailure;
+ }
+
+ ssl_GetSSL3HandshakeLock(ss);
+
+ rv = tls13_SendCertificateRequest(ss);
+ if (rv == SECSuccess) {
+ ssl_GetXmitBufLock(ss);
+ rv = ssl3_FlushHandshake(ss, 0);
+ ssl_ReleaseXmitBufLock(ss);
+ ss->ssl3.clientCertRequested = PR_TRUE;
+ }
+
+ ssl_ReleaseSSL3HandshakeLock(ss);
+ return rv;
+}
+
+SECStatus
tls13_HandlePostHelloHandshakeMessage(sslSocket *ss, PRUint8 *b, PRUint32 length)
{
if (ss->sec.isServer && ss->ssl3.hs.zeroRttIgnore != ssl_0rtt_ignore_none) {
- SSL_TRC(3, ("%d: TLS13[%d]: %s successfully decrypted handshake after"
+ SSL_TRC(3, ("%d: TLS13[%d]: successfully decrypted handshake after "
"failed 0-RTT",
SSL_GETPID(), ss->fd));
ss->ssl3.hs.zeroRttIgnore = ssl_0rtt_ignore_none;
@@ -909,13 +998,13 @@ tls13_RecoverWrappedSharedSecret(sslSocket *ss, sslSessionID *sid)
wrappedMS.len = sid->u.ssl3.keys.wrapped_master_secret_len;
/* unwrap the "master secret" which is actually RMS. */
- ss->ssl3.hs.resumptionMasterSecret = PK11_UnwrapSymKeyWithFlags(
+ ss->ssl3.hs.resumptionMasterSecret = ssl_unwrapSymKey(
wrapKey, sid->u.ssl3.masterWrapMech,
NULL, &wrappedMS,
CKM_SSL3_MASTER_KEY_DERIVE,
CKA_DERIVE,
tls13_GetHashSizeForHash(hashType),
- CKF_SIGN | CKF_VERIFY);
+ CKF_SIGN | CKF_VERIFY, ss->pkcs11PinArg);
PK11_FreeSymKey(wrapKey);
if (!ss->ssl3.hs.resumptionMasterSecret) {
return SECFailure;
@@ -1030,6 +1119,13 @@ tls13_DeriveEarlySecrets(sslSocket *ss)
return SECFailure;
}
+ if (ss->secretCallback) {
+ ss->secretCallback(ss->fd, (PRUint16)TrafficKeyEarlyApplicationData,
+ ss->sec.isServer ? ssl_secret_read : ssl_secret_write,
+ ss->ssl3.hs.clientEarlyTrafficSecret,
+ ss->secretCallbackArg);
+ }
+
rv = tls13_DeriveSecretWrap(ss, ss->ssl3.hs.currentSecret,
NULL, kHkdfLabelEarlyExporterSecret,
keylogLabelEarlyExporterSecret,
@@ -1098,6 +1194,18 @@ tls13_ComputeHandshakeSecrets(sslSocket *ss)
return rv;
}
+ if (ss->secretCallback) {
+ SSLSecretDirection dir =
+ ss->sec.isServer ? ssl_secret_read : ssl_secret_write;
+ ss->secretCallback(ss->fd, (PRUint16)TrafficKeyHandshake, dir,
+ ss->ssl3.hs.clientHsTrafficSecret,
+ ss->secretCallbackArg);
+ dir = ss->sec.isServer ? ssl_secret_write : ssl_secret_read;
+ ss->secretCallback(ss->fd, (PRUint16)TrafficKeyHandshake, dir,
+ ss->ssl3.hs.serverHsTrafficSecret,
+ ss->secretCallbackArg);
+ }
+
SSL_TRC(5, ("%d: TLS13[%d]: compute master secret (%s)",
SSL_GETPID(), ss->fd, SSL_ROLE(ss)));
@@ -1148,6 +1256,18 @@ tls13_ComputeApplicationSecrets(sslSocket *ss)
return SECFailure;
}
+ if (ss->secretCallback) {
+ SSLSecretDirection dir =
+ ss->sec.isServer ? ssl_secret_read : ssl_secret_write;
+ ss->secretCallback(ss->fd, (PRUint16)TrafficKeyApplicationData,
+ dir, ss->ssl3.hs.clientTrafficSecret,
+ ss->secretCallbackArg);
+ dir = ss->sec.isServer ? ssl_secret_write : ssl_secret_read;
+ ss->secretCallback(ss->fd, (PRUint16)TrafficKeyApplicationData,
+ dir, ss->ssl3.hs.serverTrafficSecret,
+ ss->secretCallbackArg);
+ }
+
rv = tls13_DeriveSecretWrap(ss, ss->ssl3.hs.currentSecret,
NULL, kHkdfLabelExporterMasterSecret,
keylogLabelExporterSecret,
@@ -1271,29 +1391,34 @@ tls13_NegotiateZeroRtt(sslSocket *ss, const sslSessionID *sid)
return;
}
- /* If we rejected 0-RTT on the first ClientHello, then we can just say that
- * there is no 0-RTT for the second. We shouldn't get any more. Reset the
- * ignore state so that we treat decryption failure normally. */
- if (ss->ssl3.hs.zeroRttIgnore == ssl_0rtt_ignore_hrr) {
- PORT_Assert(ss->ssl3.hs.helloRetry);
- ss->ssl3.hs.zeroRttState = ssl_0rtt_none;
- ss->ssl3.hs.zeroRttIgnore = ssl_0rtt_ignore_none;
+ if (ss->ssl3.hs.zeroRttState == ssl_0rtt_ignored) {
+ /* HelloRetryRequest causes 0-RTT to be ignored. On the second
+ * ClientHello, reset the ignore state so that decryption failure is
+ * handled normally. */
+ if (ss->ssl3.hs.zeroRttIgnore == ssl_0rtt_ignore_hrr) {
+ PORT_Assert(ss->ssl3.hs.helloRetry);
+ ss->ssl3.hs.zeroRttState = ssl_0rtt_none;
+ ss->ssl3.hs.zeroRttIgnore = ssl_0rtt_ignore_none;
+ } else {
+ SSL_TRC(3, ("%d: TLS13[%d]: application ignored 0-RTT",
+ SSL_GETPID(), ss->fd));
+ }
return;
}
if (!tls13_CanNegotiateZeroRtt(ss, sid)) {
- SSL_TRC(3, ("%d: TLS13[%d]: ignore 0-RTT",
- SSL_GETPID(), ss->fd));
+ SSL_TRC(3, ("%d: TLS13[%d]: ignore 0-RTT", SSL_GETPID(), ss->fd));
ss->ssl3.hs.zeroRttState = ssl_0rtt_ignored;
ss->ssl3.hs.zeroRttIgnore = ssl_0rtt_ignore_trial;
return;
}
- SSL_TRC(3, ("%d: TLS13[%d]: enable 0-RTT",
- SSL_GETPID(), ss->fd));
+ SSL_TRC(3, ("%d: TLS13[%d]: enable 0-RTT", SSL_GETPID(), ss->fd));
PORT_Assert(ss->statelessResume);
ss->ssl3.hs.zeroRttState = ssl_0rtt_accepted;
ss->ssl3.hs.zeroRttIgnore = ssl_0rtt_ignore_none;
+ ss->ssl3.hs.zeroRttSuite = ss->ssl3.hs.cipher_suite;
+ ss->ssl3.hs.preliminaryInfo |= ssl_preinfo_0rtt_cipher_suite;
}
/* Check if the offered group is acceptable. */
@@ -1464,6 +1589,20 @@ tls13_SelectServerCert(sslSocket *ss)
if (rv == SECSuccess) {
/* Found one. */
ss->sec.serverCert = cert;
+
+ /* If we can use a delegated credential (DC) for authentication in
+ * the current handshake, then commit to using it now. We'll send a
+ * DC as an extension and use the DC private key to sign the
+ * handshake.
+ *
+ * This sets the signature scheme to be the signature scheme
+ * indicated by the DC.
+ */
+ rv = tls13_MaybeSetDelegatedCredential(ss);
+ if (rv != SECSuccess) {
+ return SECFailure; /* Failure indicates an internal error. */
+ }
+
ss->sec.authType = ss->ssl3.hs.kea_def_mutable.authKeyType =
ssl_SignatureSchemeToAuthType(ss->ssl3.hs.signatureScheme);
ss->sec.authKeyBits = cert->serverKeyBits;
@@ -1519,6 +1658,11 @@ tls13_MaybeSendHelloRetry(sslSocket *ss, const sslNamedGroupDef *requestedGroup,
return SECFailure;
}
+ if (action == ssl_hello_retry_reject_0rtt) {
+ ss->ssl3.hs.zeroRttState = ssl_0rtt_ignored;
+ ss->ssl3.hs.zeroRttIgnore = ssl_0rtt_ignore_trial;
+ }
+
if (!requestedGroup && action != ssl_hello_retry_request) {
return SECSuccess;
}
@@ -1573,24 +1717,23 @@ tls13_HandleClientHelloPart2(sslSocket *ss,
const sslNamedGroupDef *previousGroup = NULL;
PRBool hrr = PR_FALSE;
+ /* If the legacy_version field is set to 0x300 or smaller,
+ * reject the connection with protocol_version alert. */
+ if (ss->clientHelloVersion <= SSL_LIBRARY_VERSION_3_0) {
+ FATAL_ERROR(ss, SSL_ERROR_RX_MALFORMED_CLIENT_HELLO, protocol_version);
+ goto loser;
+ }
+
ss->ssl3.hs.endOfFlight = PR_TRUE;
if (ssl3_ExtensionNegotiated(ss, ssl_tls13_early_data_xtn)) {
ss->ssl3.hs.zeroRttState = ssl_0rtt_sent;
}
-#ifndef PARANOID
- /* Look for a matching cipher suite. */
- if (ssl3_config_match_init(ss) == 0) { /* no ciphers are working/supported by PK11 */
- FATAL_ERROR(ss, PORT_GetError(), internal_error);
- goto loser;
- }
-#endif
-
/* Negotiate cipher suite. */
rv = ssl3_NegotiateCipherSuite(ss, suites, PR_FALSE);
if (rv != SECSuccess) {
- FATAL_ERROR(ss, SSL_ERROR_NO_CYPHER_OVERLAP, handshake_failure);
+ FATAL_ERROR(ss, PORT_GetError(), handshake_failure);
goto loser;
}
@@ -2083,10 +2226,20 @@ tls13_SendCertificateRequest(sslSocket *ss)
{
SECStatus rv;
sslBuffer extensionBuf = SSL_BUFFER_EMPTY;
+ unsigned int offset = 0;
SSL_TRC(3, ("%d: TLS13[%d]: begin send certificate_request",
SSL_GETPID(), ss->fd));
+ if (ss->firstHsDone) {
+ PORT_Assert(ss->ssl3.hs.shaPostHandshake == NULL);
+ ss->ssl3.hs.shaPostHandshake = PK11_CloneContext(ss->ssl3.hs.sha);
+ if (ss->ssl3.hs.shaPostHandshake == NULL) {
+ ssl_MapLowLevelError(SSL_ERROR_SHA_DIGEST_FAILURE);
+ return SECFailure;
+ }
+ }
+
rv = ssl_ConstructExtensions(ss, &extensionBuf, ssl_hs_certificate_request);
if (rv != SECSuccess) {
return SECFailure; /* Code already set. */
@@ -2094,8 +2247,29 @@ tls13_SendCertificateRequest(sslSocket *ss)
/* We should always have at least one of these. */
PORT_Assert(SSL_BUFFER_LEN(&extensionBuf) > 0);
+ /* Create a new request context for post-handshake authentication */
+ if (ss->firstHsDone) {
+ PRUint8 context[16];
+ SECItem contextItem = { siBuffer, context, sizeof(context) };
+
+ rv = PK11_GenerateRandom(context, sizeof(context));
+ if (rv != SECSuccess) {
+ goto loser;
+ }
+
+ SECITEM_FreeItem(&ss->xtnData.certReqContext, PR_FALSE);
+ rv = SECITEM_CopyItem(NULL, &ss->xtnData.certReqContext, &contextItem);
+ if (rv != SECSuccess) {
+ FATAL_ERROR(ss, SEC_ERROR_NO_MEMORY, internal_error);
+ goto loser;
+ }
+
+ offset = SSL_BUFFER_LEN(&ss->sec.ci.sendBuf);
+ }
+
rv = ssl3_AppendHandshakeHeader(ss, ssl_hs_certificate_request,
- 1 + 0 + /* empty request context */
+ 1 + /* request context length */
+ ss->xtnData.certReqContext.len +
2 + /* extension length */
SSL_BUFFER_LEN(&extensionBuf));
if (rv != SECSuccess) {
@@ -2103,7 +2277,8 @@ tls13_SendCertificateRequest(sslSocket *ss)
}
/* Context. */
- rv = ssl3_AppendHandshakeNumber(ss, 0, 1);
+ rv = ssl3_AppendHandshakeVariable(ss, ss->xtnData.certReqContext.data,
+ ss->xtnData.certReqContext.len, 1);
if (rv != SECSuccess) {
goto loser; /* err set by AppendHandshake. */
}
@@ -2113,6 +2288,15 @@ tls13_SendCertificateRequest(sslSocket *ss)
goto loser; /* err set by AppendHandshake. */
}
+ if (ss->firstHsDone) {
+ rv = ssl3_UpdatePostHandshakeHashes(ss,
+ SSL_BUFFER_BASE(&ss->sec.ci.sendBuf) + offset,
+ SSL_BUFFER_LEN(&ss->sec.ci.sendBuf) - offset);
+ if (rv != SECSuccess) {
+ goto loser;
+ }
+ }
+
sslBuffer_Clear(&extensionBuf);
return SECSuccess;
@@ -2191,7 +2375,7 @@ tls13_HandleHelloRetryRequest(sslSocket *ss, const PRUint8 *savedMsg,
/* Restore the null cipher spec for writing. */
ssl_GetSpecWriteLock(ss);
ssl_CipherSpecRelease(ss->ssl3.cwSpec);
- ss->ssl3.cwSpec = ssl_FindCipherSpecByEpoch(ss, CipherSpecWrite,
+ ss->ssl3.cwSpec = ssl_FindCipherSpecByEpoch(ss, ssl_secret_write,
TrafficKeyClearText);
PORT_Assert(ss->ssl3.cwSpec);
ssl_ReleaseSpecWriteLock(ss);
@@ -2267,25 +2451,61 @@ tls13_HandleCertificateRequest(sslSocket *ss, PRUint8 *b, PRUint32 length)
PORT_Assert(ss->opt.noLocks || ssl_HaveSSL3HandshakeLock(ss));
/* Client */
- rv = TLS13_CHECK_HS_STATE(ss, SSL_ERROR_RX_UNEXPECTED_CERT_REQUEST,
- wait_cert_request);
+ if (ss->opt.enablePostHandshakeAuth) {
+ rv = TLS13_CHECK_HS_STATE(ss, SSL_ERROR_RX_UNEXPECTED_CERT_REQUEST,
+ wait_cert_request, idle_handshake);
+ } else {
+ rv = TLS13_CHECK_HS_STATE(ss, SSL_ERROR_RX_UNEXPECTED_CERT_REQUEST,
+ wait_cert_request);
+ }
if (rv != SECSuccess) {
return SECFailure;
}
- PORT_Assert(ss->ssl3.clientCertChain == NULL);
- PORT_Assert(ss->ssl3.clientCertificate == NULL);
- PORT_Assert(ss->ssl3.clientPrivateKey == NULL);
- PORT_Assert(!ss->ssl3.hs.clientCertRequested);
+ if (tls13_IsPostHandshake(ss)) {
+ PORT_Assert(ss->ssl3.hs.shaPostHandshake == NULL);
+ ss->ssl3.hs.shaPostHandshake = PK11_CloneContext(ss->ssl3.hs.sha);
+ if (ss->ssl3.hs.shaPostHandshake == NULL) {
+ ssl_MapLowLevelError(SSL_ERROR_SHA_DIGEST_FAILURE);
+ return SECFailure;
+ }
+ rv = ssl_HashPostHandshakeMessage(ss, ssl_hs_certificate_request, b, length);
+ if (rv != SECSuccess) {
+ FATAL_ERROR(ss, SEC_ERROR_LIBRARY_FAILURE, internal_error);
+ return SECFailure;
+ }
+
+ /* clean up anything left from previous handshake. */
+ if (ss->ssl3.clientCertChain != NULL) {
+ CERT_DestroyCertificateList(ss->ssl3.clientCertChain);
+ ss->ssl3.clientCertChain = NULL;
+ }
+ if (ss->ssl3.clientCertificate != NULL) {
+ CERT_DestroyCertificate(ss->ssl3.clientCertificate);
+ ss->ssl3.clientCertificate = NULL;
+ }
+ if (ss->ssl3.clientPrivateKey != NULL) {
+ SECKEY_DestroyPrivateKey(ss->ssl3.clientPrivateKey);
+ ss->ssl3.clientPrivateKey = NULL;
+ }
+ SECITEM_FreeItem(&ss->xtnData.certReqContext, PR_FALSE);
+ ss->xtnData.certReqContext.data = NULL;
+ } else {
+ PORT_Assert(ss->ssl3.clientCertChain == NULL);
+ PORT_Assert(ss->ssl3.clientCertificate == NULL);
+ PORT_Assert(ss->ssl3.clientPrivateKey == NULL);
+ PORT_Assert(!ss->ssl3.hs.clientCertRequested);
+ PORT_Assert(ss->xtnData.certReqContext.data == NULL);
+ }
rv = ssl3_ConsumeHandshakeVariable(ss, &context, 1, &b, &length);
if (rv != SECSuccess) {
return SECFailure;
}
- /* We don't support post-handshake client auth, the certificate request
- * context must always be empty. */
- if (context.len > 0) {
+ /* Unless it is a post-handshake client auth, the certificate
+ * request context must be empty. */
+ if (!tls13_IsPostHandshake(ss) && context.len > 0) {
FATAL_ERROR(ss, SSL_ERROR_RX_MALFORMED_CERT_REQUEST, illegal_parameter);
return SECFailure;
}
@@ -2319,7 +2539,38 @@ tls13_HandleCertificateRequest(sslSocket *ss, PRUint8 *b, PRUint32 length)
}
ss->ssl3.hs.clientCertRequested = PR_TRUE;
- TLS13_SET_HS_STATE(ss, wait_server_cert);
+
+ if (ss->firstHsDone) {
+ SSL3AlertDescription sendAlert = no_alert;
+
+ /* Request a client certificate. */
+ rv = ssl3_CompleteHandleCertificateRequest(
+ ss, ss->xtnData.sigSchemes, ss->xtnData.numSigSchemes,
+ &ss->xtnData.certReqAuthorities);
+ if (rv != SECSuccess) {
+ FATAL_ERROR(ss, SEC_ERROR_LIBRARY_FAILURE, internal_error);
+ return rv;
+ }
+
+ ssl_GetXmitBufLock(ss);
+ rv = tls13_SendClientSecondFlight(ss, !ss->ssl3.sendEmptyCert,
+ &sendAlert);
+ ssl_ReleaseXmitBufLock(ss);
+ if (rv != SECSuccess) {
+ if (sendAlert != no_alert) {
+ FATAL_ERROR(ss, PORT_GetError(), sendAlert);
+ } else {
+ LOG_ERROR(ss, PORT_GetError());
+ }
+ return SECFailure;
+ }
+ PORT_Assert(ss->ssl3.hs.ws == idle_handshake);
+ PORT_Assert(ss->ssl3.hs.shaPostHandshake != NULL);
+ PK11_DestroyContext(ss->ssl3.hs.shaPostHandshake, PR_TRUE);
+ ss->ssl3.hs.shaPostHandshake = NULL;
+ } else {
+ TLS13_SET_HS_STATE(ss, wait_server_cert);
+ }
return SECSuccess;
}
@@ -2341,7 +2592,7 @@ tls13_SendEncryptedServerSequence(sslSocket *ss)
}
rv = tls13_SetCipherSpec(ss, TrafficKeyHandshake,
- CipherSpecWrite, PR_FALSE);
+ ssl_secret_write, PR_FALSE);
if (rv != SECSuccess) {
LOG_ERROR(ss, SEC_ERROR_LIBRARY_FAILURE);
return SECFailure;
@@ -2375,7 +2626,14 @@ tls13_SendEncryptedServerSequence(sslSocket *ss)
return SECFailure; /* error code is set. */
}
- svrPrivKey = ss->sec.serverCert->serverKeyPair->privKey;
+ if (tls13_IsSigningWithDelegatedCredential(ss)) {
+ SSL_TRC(3, ("%d: TLS13[%d]: Signing with delegated credential",
+ SSL_GETPID(), ss->fd));
+ svrPrivKey = ss->sec.serverCert->delegCredKeyPair->privKey;
+ } else {
+ svrPrivKey = ss->sec.serverCert->serverKeyPair->privKey;
+ }
+
rv = tls13_SendCertificateVerify(ss, svrPrivKey);
if (rv != SECSuccess) {
return SECFailure; /* err code is set. */
@@ -2451,7 +2709,7 @@ tls13_SendServerHelloSequence(sslSocket *ss)
}
rv = tls13_SetCipherSpec(ss, TrafficKeyApplicationData,
- CipherSpecWrite, PR_FALSE);
+ ssl_secret_write, PR_FALSE);
if (rv != SECSuccess) {
LOG_ERROR(ss, SEC_ERROR_LIBRARY_FAILURE);
return SECFailure;
@@ -2463,7 +2721,7 @@ tls13_SendServerHelloSequence(sslSocket *ss)
}
if (ss->ssl3.hs.zeroRttState == ssl_0rtt_accepted) {
rv = tls13_SetCipherSpec(ss, TrafficKeyEarlyApplicationData,
- CipherSpecRead, PR_TRUE);
+ ssl_secret_read, PR_TRUE);
if (rv != SECSuccess) {
LOG_ERROR(ss, SEC_ERROR_LIBRARY_FAILURE);
return SECFailure;
@@ -2475,7 +2733,7 @@ tls13_SendServerHelloSequence(sslSocket *ss)
rv = tls13_SetCipherSpec(ss,
TrafficKeyHandshake,
- CipherSpecRead, PR_FALSE);
+ ssl_secret_read, PR_FALSE);
if (rv != SECSuccess) {
LOG_ERROR(ss, SEC_ERROR_LIBRARY_FAILURE);
return SECFailure;
@@ -2487,7 +2745,7 @@ tls13_SendServerHelloSequence(sslSocket *ss)
}
}
- ss->ssl3.hs.serverHelloTime = ssl_TimeUsec();
+ ss->ssl3.hs.serverHelloTime = ssl_Time(ss);
return SECSuccess;
}
@@ -2584,11 +2842,11 @@ tls13_HandleServerHelloPart2(sslSocket *ss)
/* When we send 0-RTT, we saved the null spec in case we needed it to
* send another ClientHello in response to a HelloRetryRequest. Now
* that we won't be receiving a HelloRetryRequest, release the spec. */
- ssl_CipherSpecReleaseByEpoch(ss, CipherSpecWrite, TrafficKeyClearText);
+ ssl_CipherSpecReleaseByEpoch(ss, ssl_secret_write, TrafficKeyClearText);
}
rv = tls13_SetCipherSpec(ss, TrafficKeyHandshake,
- CipherSpecRead, PR_FALSE);
+ ssl_secret_read, PR_FALSE);
if (rv != SECSuccess) {
FATAL_ERROR(ss, SSL_ERROR_INIT_CIPHER_SUITE_FAILURE, internal_error);
return SECFailure;
@@ -2855,8 +3113,13 @@ tls13_HandleCertificate(sslSocket *ss, PRUint8 *b, PRUint32 length)
PORT_Assert(ss->opt.noLocks || ssl_HaveSSL3HandshakeLock(ss));
if (ss->sec.isServer) {
- rv = TLS13_CHECK_HS_STATE(ss, SSL_ERROR_RX_UNEXPECTED_CERTIFICATE,
- wait_client_cert);
+ if (ss->ssl3.clientCertRequested) {
+ rv = TLS13_CHECK_HS_STATE(ss, SSL_ERROR_RX_UNEXPECTED_CERTIFICATE,
+ idle_handshake);
+ } else {
+ rv = TLS13_CHECK_HS_STATE(ss, SSL_ERROR_RX_UNEXPECTED_CERTIFICATE,
+ wait_client_cert);
+ }
} else {
rv = TLS13_CHECK_HS_STATE(ss, SSL_ERROR_RX_UNEXPECTED_CERTIFICATE,
wait_cert_request, wait_server_cert);
@@ -2866,18 +3129,29 @@ tls13_HandleCertificate(sslSocket *ss, PRUint8 *b, PRUint32 length)
/* We can ignore any other cleartext from the client. */
if (ss->sec.isServer && IS_DTLS(ss)) {
- ssl_CipherSpecReleaseByEpoch(ss, CipherSpecRead, TrafficKeyClearText);
+ ssl_CipherSpecReleaseByEpoch(ss, ssl_secret_read, TrafficKeyClearText);
dtls_ReceivedFirstMessageInFlight(ss);
}
+
+ if (ss->firstHsDone) {
+ rv = ssl_HashPostHandshakeMessage(ss, ssl_hs_certificate, b, length);
+ if (rv != SECSuccess) {
+ PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
+ return SECFailure;
+ }
+ }
+
/* Process the context string */
rv = ssl3_ConsumeHandshakeVariable(ss, &context, 1, &b, &length);
if (rv != SECSuccess)
return SECFailure;
- if (context.len) {
- /* The context string MUST be empty */
- FATAL_ERROR(ss, SSL_ERROR_RX_MALFORMED_CERTIFICATE, illegal_parameter);
- return SECFailure;
+ if (ss->ssl3.clientCertRequested) {
+ PORT_Assert(ss->sec.isServer);
+ if (SECITEM_CompareItem(&context, &ss->xtnData.certReqContext) != 0) {
+ FATAL_ERROR(ss, SSL_ERROR_RX_MALFORMED_CERTIFICATE, illegal_parameter);
+ return SECFailure;
+ }
}
rv = ssl3_ConsumeHandshakeVariable(ss, &certList, 3, &b, &length);
@@ -3118,6 +3392,25 @@ tls13_DeriveSecretWrap(sslSocket *ss, PK11SymKey *key,
return SECSuccess;
}
+SECStatus
+SSLExp_SecretCallback(PRFileDesc *fd, SSLSecretCallback cb, void *arg)
+{
+ sslSocket *ss = ssl_FindSocket(fd);
+ if (!ss) {
+ SSL_DBG(("%d: SSL[%d]: bad socket in SSL_SecretCallback",
+ SSL_GETPID(), fd));
+ return SECFailure;
+ }
+
+ ssl_Get1stHandshakeLock(ss);
+ ssl_GetSSL3HandshakeLock(ss);
+ ss->secretCallback = cb;
+ ss->secretCallbackArg = arg;
+ ssl_ReleaseSSL3HandshakeLock(ss);
+ ssl_Release1stHandshakeLock(ss);
+ return SECSuccess;
+}
+
/* Derive traffic keys for the next cipher spec in the queue. */
static SECStatus
tls13_DeriveTrafficKeys(sslSocket *ss, ssl3CipherSpec *spec,
@@ -3244,7 +3537,7 @@ tls13_SetupPendingCipherSpec(sslSocket *ss, ssl3CipherSpec *spec)
/* We want to keep read cipher specs around longer because
* there are cases where we might get either epoch N or
* epoch N+1. */
- if (IS_DTLS(ss) && spec->direction == CipherSpecRead) {
+ if (IS_DTLS(ss) && spec->direction == ssl_secret_read) {
ssl_CipherSpecAddRef(spec);
}
@@ -3267,7 +3560,7 @@ tls13_SetupPendingCipherSpec(sslSocket *ss, ssl3CipherSpec *spec)
/* The record size limit is reduced by one so that the remainder of the
* record handling code can use the same checks for all versions. */
if (ssl3_ExtensionNegotiated(ss, ssl_record_size_limit_xtn)) {
- spec->recordSizeLimit = ((spec->direction == CipherSpecRead)
+ spec->recordSizeLimit = ((spec->direction == ssl_secret_read)
? ss->opt.recordSizeLimit
: ss->xtnData.recordSizeLimit) -
1;
@@ -3303,7 +3596,7 @@ tls13_SetAlertCipherSpec(sslSocket *ss)
}
rv = tls13_SetCipherSpec(ss, TrafficKeyHandshake,
- CipherSpecWrite, PR_FALSE);
+ ssl_secret_write, PR_FALSE);
if (rv != SECSuccess) {
PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
return SECFailure;
@@ -3318,7 +3611,7 @@ tls13_SetAlertCipherSpec(sslSocket *ss)
*/
static SECStatus
tls13_SetCipherSpec(sslSocket *ss, PRUint16 epoch,
- CipherSpecDirection direction, PRBool deleteSecret)
+ SSLSecretDirection direction, PRBool deleteSecret)
{
TrafficKeyType type;
SECStatus rv;
@@ -3357,7 +3650,7 @@ tls13_SetCipherSpec(sslSocket *ss, PRUint16 epoch,
}
/* Now that we've set almost everything up, finally cut over. */
- specp = (direction == CipherSpecRead) ? &ss->ssl3.crSpec : &ss->ssl3.cwSpec;
+ specp = (direction == ssl_secret_read) ? &ss->ssl3.crSpec : &ss->ssl3.cwSpec;
ssl_GetSpecWriteLock(ss);
ssl_CipherSpecRelease(*specp); /* May delete old cipher. */
*specp = spec; /* Overwrite. */
@@ -3366,11 +3659,6 @@ tls13_SetCipherSpec(sslSocket *ss, PRUint16 epoch,
SSL_TRC(3, ("%d: TLS13[%d]: %s installed key for epoch=%d (%s) dir=%s",
SSL_GETPID(), ss->fd, SSL_ROLE(ss), spec->epoch,
spec->phase, SPEC_DIR(spec)));
-
- if (ss->ssl3.changedCipherSpecFunc) {
- ss->ssl3.changedCipherSpecFunc(ss->ssl3.changedCipherSpecArg,
- direction == CipherSpecWrite, spec);
- }
return SECSuccess;
loser:
@@ -3410,7 +3698,11 @@ tls13_ComputeHandshakeHashes(sslSocket *ss, SSL3Hashes *hashes)
goto loser;
}
} else {
- ctx = PK11_CloneContext(ss->ssl3.hs.sha);
+ if (ss->firstHsDone) {
+ ctx = PK11_CloneContext(ss->ssl3.hs.shaPostHandshake);
+ } else {
+ ctx = PK11_CloneContext(ss->ssl3.hs.sha);
+ }
if (!ctx) {
ssl_MapLowLevelError(SSL_ERROR_SHA_DIGEST_FAILURE);
return SECFailure;
@@ -3519,7 +3811,7 @@ tls13_DestroyEarlyData(PRCList *list)
* See RFC 5288 and https://tools.ietf.org/html/draft-ietf-tls-chacha20-poly1305-04#section-2
*/
static void
-tls13_WriteNonce(ssl3KeyMaterial *keys,
+tls13_WriteNonce(const ssl3KeyMaterial *keys,
const unsigned char *seqNumBuf, unsigned int seqNumLen,
unsigned char *nonce, unsigned int nonceLen)
{
@@ -3542,41 +3834,35 @@ tls13_WriteNonce(ssl3KeyMaterial *keys,
* a sequence number. In TLS 1.3 there is no additional data so this value is
* just the encoded sequence number.
*/
-static SECStatus
-tls13_AEAD(ssl3KeyMaterial *keys, PRBool doDecrypt,
- unsigned char *out, int *outlen, int maxout,
- const unsigned char *in, int inlen,
+SECStatus
+tls13_AEAD(const ssl3KeyMaterial *keys, PRBool doDecrypt,
+ unsigned char *out, unsigned int *outlen, unsigned int maxout,
+ const unsigned char *in, unsigned int inlen,
CK_MECHANISM_TYPE mechanism,
unsigned char *aeadParams, unsigned int aeadParamLength)
{
- SECStatus rv;
- unsigned int uOutLen = 0;
SECItem param = {
siBuffer, aeadParams, aeadParamLength
};
if (doDecrypt) {
- rv = PK11_Decrypt(keys->key, mechanism, &param,
- out, &uOutLen, maxout, in, inlen);
- } else {
- rv = PK11_Encrypt(keys->key, mechanism, &param,
- out, &uOutLen, maxout, in, inlen);
+ return PK11_Decrypt(keys->key, mechanism, &param,
+ out, outlen, maxout, in, inlen);
}
- *outlen = (int)uOutLen;
-
- return rv;
+ return PK11_Encrypt(keys->key, mechanism, &param,
+ out, outlen, maxout, in, inlen);
}
static SECStatus
-tls13_AESGCM(ssl3KeyMaterial *keys,
+tls13_AESGCM(const ssl3KeyMaterial *keys,
PRBool doDecrypt,
unsigned char *out,
- int *outlen,
- int maxout,
+ unsigned int *outlen,
+ unsigned int maxout,
const unsigned char *in,
- int inlen,
+ unsigned int inlen,
const unsigned char *additionalData,
- int additionalDataLen)
+ unsigned int additionalDataLen)
{
CK_GCM_PARAMS gcmParams;
unsigned char nonce[12];
@@ -3597,11 +3883,11 @@ tls13_AESGCM(ssl3KeyMaterial *keys,
}
static SECStatus
-tls13_ChaCha20Poly1305(ssl3KeyMaterial *keys, PRBool doDecrypt,
- unsigned char *out, int *outlen, int maxout,
- const unsigned char *in, int inlen,
+tls13_ChaCha20Poly1305(const ssl3KeyMaterial *keys, PRBool doDecrypt,
+ unsigned char *out, unsigned int *outlen, unsigned int maxout,
+ const unsigned char *in, unsigned int inlen,
const unsigned char *additionalData,
- int additionalDataLen)
+ unsigned int additionalDataLen)
{
CK_NSS_AEAD_PARAMS aeadParams;
unsigned char nonce[12];
@@ -3847,6 +4133,9 @@ done:
SECStatus
tls13_HandleCertificateVerify(sslSocket *ss, PRUint8 *b, PRUint32 length)
{
+ sslDelegatedCredential *dc = ss->xtnData.peerDelegCred;
+ CERTSubjectPublicKeyInfo *spki;
+ SECKEYPublicKey *pubKey = NULL;
SECItem signed_hash = { siBuffer, NULL, 0 };
SECStatus rv;
SSLSignatureScheme sigScheme;
@@ -3870,7 +4159,11 @@ tls13_HandleCertificateVerify(sslSocket *ss, PRUint8 *b, PRUint32 length)
return SECFailure;
}
- rv = ssl_HashHandshakeMessage(ss, ssl_hs_certificate_verify, b, length);
+ if (ss->firstHsDone) {
+ rv = ssl_HashPostHandshakeMessage(ss, ssl_hs_certificate_verify, b, length);
+ } else {
+ rv = ssl_HashHandshakeMessage(ss, ssl_hs_certificate_verify, b, length);
+ }
if (rv != SECSuccess) {
PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
return SECFailure;
@@ -3882,7 +4175,40 @@ tls13_HandleCertificateVerify(sslSocket *ss, PRUint8 *b, PRUint32 length)
return SECFailure;
}
- rv = ssl_CheckSignatureSchemeConsistency(ss, sigScheme, ss->sec.peerCert);
+ /* Set the |spki| used to verify the handshake. When verifying with a
+ * delegated credential (DC), this corresponds to the DC public key;
+ * otherwise it correspond to the public key of the peer's end-entity
+ * certificate.
+ */
+ if (tls13_IsVerifyingWithDelegatedCredential(ss)) {
+ /* DelegatedCredential.cred.expected_cert_verify_algorithm is expected
+ * to match CertificateVerify.scheme.
+ * DelegatedCredential.cred.expected_cert_verify_algorithm must also be
+ * the same as was reported in ssl3_AuthCertificate.
+ */
+ if (sigScheme != dc->expectedCertVerifyAlg || sigScheme != ss->sec.signatureScheme) {
+ FATAL_ERROR(ss, SSL_ERROR_DC_CERT_VERIFY_ALG_MISMATCH, illegal_parameter);
+ return SECFailure;
+ }
+
+ /* Verify the DC has three steps: (1) use the peer's end-entity
+ * certificate to verify DelegatedCredential.signature, (2) check that
+ * the certificate has the correct key usage, and (3) check that the DC
+ * hasn't expired.
+ */
+ rv = tls13_VerifyDelegatedCredential(ss, dc);
+ if (rv != SECSuccess) { /* Calls FATAL_ERROR() */
+ return SECFailure;
+ }
+
+ SSL_TRC(3, ("%d: TLS13[%d]: Verifying with delegated credential",
+ SSL_GETPID(), ss->fd));
+ spki = dc->spki;
+ } else {
+ spki = &ss->sec.peerCert->subjectPublicKeyInfo;
+ }
+
+ rv = ssl_CheckSignatureSchemeConsistency(ss, sigScheme, spki);
if (rv != SECSuccess) {
/* Error set already */
FATAL_ERROR(ss, PORT_GetError(), illegal_parameter);
@@ -3907,15 +4233,33 @@ tls13_HandleCertificateVerify(sslSocket *ss, PRUint8 *b, PRUint32 length)
return SECFailure;
}
- rv = ssl3_VerifySignedHashes(ss, sigScheme, &tbsHash, &signed_hash);
+ pubKey = SECKEY_ExtractPublicKey(spki);
+ if (pubKey == NULL) {
+ ssl_MapLowLevelError(SSL_ERROR_EXTRACT_PUBLIC_KEY_FAILURE);
+ return SECFailure;
+ }
+
+ rv = ssl_VerifySignedHashesWithPubKey(ss, pubKey, sigScheme,
+ &tbsHash, &signed_hash);
if (rv != SECSuccess) {
FATAL_ERROR(ss, PORT_GetError(), decrypt_error);
- return SECFailure;
+ goto loser;
}
- /* Set the auth type. */
+ /* Set the auth type and verify it is what we captured in ssl3_AuthCertificate */
if (!ss->sec.isServer) {
ss->sec.authType = ssl_SignatureSchemeToAuthType(sigScheme);
+
+ uint32_t prelimAuthKeyBits = ss->sec.authKeyBits;
+ rv = ssl_SetAuthKeyBits(ss, pubKey);
+ if (rv != SECSuccess) {
+ goto loser; /* Alert sent and code set. */
+ }
+
+ if (prelimAuthKeyBits != ss->sec.authKeyBits) {
+ FATAL_ERROR(ss, SSL_ERROR_DC_CERT_VERIFY_ALG_MISMATCH, illegal_parameter);
+ goto loser;
+ }
}
/* Request a client certificate now if one was requested. */
@@ -3926,13 +4270,17 @@ tls13_HandleCertificateVerify(sslSocket *ss, PRUint8 *b, PRUint32 length)
&ss->xtnData.certReqAuthorities);
if (rv != SECSuccess) {
FATAL_ERROR(ss, SEC_ERROR_LIBRARY_FAILURE, internal_error);
- return rv;
+ goto loser;
}
}
+ SECKEY_DestroyPublicKey(pubKey);
TLS13_SET_HS_STATE(ss, wait_finished);
-
return SECSuccess;
+
+loser:
+ SECKEY_DestroyPublicKey(pubKey);
+ return SECFailure;
}
static SECStatus
@@ -4190,7 +4538,11 @@ tls13_CommonHandleFinished(sslSocket *ss, PK11SymKey *key,
return SECFailure;
}
- rv = ssl_HashHandshakeMessage(ss, ssl_hs_finished, b, length);
+ if (ss->firstHsDone) {
+ rv = ssl_HashPostHandshakeMessage(ss, ssl_hs_finished, b, length);
+ } else {
+ rv = ssl_HashHandshakeMessage(ss, ssl_hs_finished, b, length);
+ }
if (rv != SECSuccess) {
PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
return SECFailure;
@@ -4231,26 +4583,48 @@ tls13_ServerHandleFinished(sslSocket *ss, PRUint8 *b, PRUint32 length)
SSL_TRC(3, ("%d: TLS13[%d]: server handle finished handshake",
SSL_GETPID(), ss->fd));
- rv = tls13_CommonHandleFinished(ss, ss->ssl3.hs.clientHsTrafficSecret,
+ rv = tls13_CommonHandleFinished(ss,
+ ss->firstHsDone ? ss->ssl3.hs.clientTrafficSecret : ss->ssl3.hs.clientHsTrafficSecret,
b, length);
if (rv != SECSuccess) {
return SECFailure;
}
+ if (ss->firstHsDone) {
+ TLS13_SET_HS_STATE(ss, idle_handshake);
+
+ PORT_Assert(ss->ssl3.hs.shaPostHandshake != NULL);
+ PK11_DestroyContext(ss->ssl3.hs.shaPostHandshake, PR_TRUE);
+ ss->ssl3.hs.shaPostHandshake = NULL;
+
+ ss->ssl3.clientCertRequested = PR_FALSE;
+
+ if (ss->ssl3.keyUpdateDeferred) {
+ rv = tls13_SendKeyUpdate(ss, ss->ssl3.deferredKeyUpdateRequest,
+ PR_FALSE);
+ if (rv != SECSuccess) {
+ return SECFailure; /* error is set. */
+ }
+ ss->ssl3.keyUpdateDeferred = PR_FALSE;
+ }
+
+ return SECSuccess;
+ }
+
if (!tls13_ShouldRequestClientAuth(ss) &&
(ss->ssl3.hs.zeroRttState != ssl_0rtt_done)) {
dtls_ReceivedFirstMessageInFlight(ss);
}
rv = tls13_SetCipherSpec(ss, TrafficKeyApplicationData,
- CipherSpecRead, PR_FALSE);
+ ssl_secret_read, PR_FALSE);
if (rv != SECSuccess) {
FATAL_ERROR(ss, SEC_ERROR_LIBRARY_FAILURE, internal_error);
return SECFailure;
}
if (IS_DTLS(ss)) {
- ssl_CipherSpecReleaseByEpoch(ss, CipherSpecRead, TrafficKeyClearText);
+ ssl_CipherSpecReleaseByEpoch(ss, ssl_secret_read, TrafficKeyClearText);
/* We need to keep the handshake cipher spec so we can
* read re-transmitted client Finished. */
rv = dtls_StartTimer(ss, ss->ssl3.hs.hdTimer,
@@ -4266,6 +4640,11 @@ tls13_ServerHandleFinished(sslSocket *ss, PRUint8 *b, PRUint32 length)
return SECFailure;
}
+ rv = tls13_FinishHandshake(ss);
+ if (rv != SECSuccess) {
+ return SECFailure;
+ }
+
ssl_GetXmitBufLock(ss);
if (ss->opt.enableSessionTickets) {
rv = tls13_SendNewSessionTicket(ss, NULL, 0);
@@ -4278,8 +4657,7 @@ tls13_ServerHandleFinished(sslSocket *ss, PRUint8 *b, PRUint32 length)
}
}
ssl_ReleaseXmitBufLock(ss);
-
- return tls13_FinishHandshake(ss);
+ return SECSuccess;
loser:
ssl_ReleaseXmitBufLock(ss);
@@ -4316,11 +4694,16 @@ tls13_SendClientSecondFlight(sslSocket *ss, PRBool sendClientCert,
SSL3AlertDescription *sendAlert)
{
SECStatus rv;
+ unsigned int offset = 0;
PORT_Assert(ss->opt.noLocks || ssl_HaveXmitBufLock(ss));
*sendAlert = internal_error;
+ if (ss->firstHsDone) {
+ offset = SSL_BUFFER_LEN(&ss->sec.ci.sendBuf);
+ }
+
if (ss->ssl3.sendEmptyCert) {
ss->ssl3.sendEmptyCert = PR_FALSE;
rv = ssl3_SendEmptyCertificate(ss);
@@ -4334,6 +4717,16 @@ tls13_SendClientSecondFlight(sslSocket *ss, PRBool sendClientCert,
return SECFailure; /* error code is set. */
}
}
+
+ if (ss->firstHsDone) {
+ rv = ssl3_UpdatePostHandshakeHashes(ss,
+ SSL_BUFFER_BASE(&ss->sec.ci.sendBuf) + offset,
+ SSL_BUFFER_LEN(&ss->sec.ci.sendBuf) - offset);
+ if (rv != SECSuccess) {
+ return SECFailure; /* error code is set. */
+ }
+ }
+
if (ss->ssl3.hs.clientCertRequested) {
SECITEM_FreeItem(&ss->xtnData.certReqContext, PR_FALSE);
if (ss->xtnData.certReqAuthorities.arena) {
@@ -4346,15 +4739,28 @@ tls13_SendClientSecondFlight(sslSocket *ss, PRBool sendClientCert,
}
if (sendClientCert) {
+ if (ss->firstHsDone) {
+ offset = SSL_BUFFER_LEN(&ss->sec.ci.sendBuf);
+ }
+
rv = tls13_SendCertificateVerify(ss, ss->ssl3.clientPrivateKey);
SECKEY_DestroyPrivateKey(ss->ssl3.clientPrivateKey);
ss->ssl3.clientPrivateKey = NULL;
if (rv != SECSuccess) {
return SECFailure; /* err is set. */
}
+
+ if (ss->firstHsDone) {
+ rv = ssl3_UpdatePostHandshakeHashes(ss,
+ SSL_BUFFER_BASE(&ss->sec.ci.sendBuf) + offset,
+ SSL_BUFFER_LEN(&ss->sec.ci.sendBuf) - offset);
+ if (rv != SECSuccess) {
+ return SECFailure; /* error is set. */
+ }
+ }
}
- rv = tls13_SendFinished(ss, ss->ssl3.hs.clientHsTrafficSecret);
+ rv = tls13_SendFinished(ss, ss->firstHsDone ? ss->ssl3.hs.clientTrafficSecret : ss->ssl3.hs.clientHsTrafficSecret);
if (rv != SECSuccess) {
return SECFailure; /* err code was set. */
}
@@ -4397,7 +4803,8 @@ tls13_SendClientSecondRound(sslSocket *ss)
" certificate authentication is still pending.",
SSL_GETPID(), ss->fd));
ss->ssl3.hs.restartTarget = tls13_SendClientSecondRound;
- return SECWouldBlock;
+ PORT_SetError(PR_WOULD_BLOCK_ERROR);
+ return SECFailure;
}
rv = tls13_ComputeApplicationSecrets(ss);
@@ -4425,14 +4832,14 @@ tls13_SendClientSecondRound(sslSocket *ss)
}
rv = tls13_SetCipherSpec(ss, TrafficKeyHandshake,
- CipherSpecWrite, PR_FALSE);
+ ssl_secret_write, PR_FALSE);
if (rv != SECSuccess) {
FATAL_ERROR(ss, SSL_ERROR_INIT_CIPHER_SUITE_FAILURE, internal_error);
return SECFailure;
}
rv = tls13_SetCipherSpec(ss, TrafficKeyApplicationData,
- CipherSpecRead, PR_FALSE);
+ ssl_secret_read, PR_FALSE);
if (rv != SECSuccess) {
FATAL_ERROR(ss, SEC_ERROR_LIBRARY_FAILURE, internal_error);
return SECFailure;
@@ -4450,7 +4857,7 @@ tls13_SendClientSecondRound(sslSocket *ss)
return SECFailure;
}
rv = tls13_SetCipherSpec(ss, TrafficKeyApplicationData,
- CipherSpecWrite, PR_FALSE);
+ ssl_secret_write, PR_FALSE);
if (rv != SECSuccess) {
PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
return SECFailure;
@@ -4615,8 +5022,7 @@ SSLExp_SendSessionTicket(PRFileDesc *fd, const PRUint8 *token,
return SECFailure;
}
- if (!ss->sec.isServer || !ss->firstHsDone ||
- ss->version < SSL_LIBRARY_VERSION_TLS_1_3 ||
+ if (!ss->sec.isServer || !tls13_IsPostHandshake(ss) ||
tokenLen > 0xffff) {
PORT_SetError(SEC_ERROR_INVALID_ARGS);
return SECFailure;
@@ -4652,13 +5058,13 @@ tls13_HandleNewSessionTicket(sslSocket *ss, PRUint8 *b, PRUint32 length)
if (rv != SECSuccess) {
return SECFailure;
}
- if (!ss->firstHsDone || ss->sec.isServer) {
+ if (!tls13_IsPostHandshake(ss) || ss->sec.isServer) {
FATAL_ERROR(ss, SSL_ERROR_RX_UNEXPECTED_NEW_SESSION_TICKET,
unexpected_message);
return SECFailure;
}
- ticket.received_timestamp = ssl_TimeUsec();
+ ticket.received_timestamp = ssl_Time(ss);
rv = ssl3_ConsumeHandshakeNumber(ss, &ticket.ticket_lifetime_hint, 4, &b,
&length);
if (rv != SECSuccess) {
@@ -4803,12 +5209,14 @@ static const struct {
certificate) },
{ ssl_cert_status_xtn, _M3(client_hello, certificate_request,
certificate) },
+ { ssl_delegated_credentials_xtn, _M2(client_hello, certificate) },
{ ssl_tls13_cookie_xtn, _M2(client_hello, hello_retry_request) },
{ ssl_tls13_certificate_authorities_xtn, _M1(certificate_request) },
{ ssl_tls13_supported_versions_xtn, _M3(client_hello, server_hello,
hello_retry_request) },
{ ssl_record_size_limit_xtn, _M2(client_hello, encrypted_extensions) },
- { ssl_tls13_encrypted_sni_xtn, _M2(client_hello, encrypted_extensions) }
+ { ssl_tls13_encrypted_sni_xtn, _M2(client_hello, encrypted_extensions) },
+ { ssl_tls13_post_handshake_auth_xtn, _M1(client_hello) }
};
tls13ExtensionStatus
@@ -4917,7 +5325,7 @@ tls13_ProtectRecord(sslSocket *ss,
const int tagLen = cipher_def->tag_size;
SECStatus rv;
- PORT_Assert(cwSpec->direction == CipherSpecWrite);
+ PORT_Assert(cwSpec->direction == ssl_secret_write);
SSL_TRC(3, ("%d: TLS13[%d]: spec=%d epoch=%d (%s) protect 0x%0llx len=%u",
SSL_GETPID(), ss->fd, cwSpec, cwSpec->epoch, cwSpec->phase,
cwSpec->nextSeqNum, contentLen));
@@ -4941,7 +5349,7 @@ tls13_ProtectRecord(sslSocket *ss,
PRBool needsLength;
PRUint8 aad[21];
unsigned int aadLen;
- int len;
+ unsigned int len;
PORT_Assert(cipher_def->type == type_aead);
@@ -5011,7 +5419,7 @@ tls13_UnprotectRecord(sslSocket *ss,
*alert = bad_record_mac; /* Default alert for most issues. */
- PORT_Assert(spec->direction == CipherSpecRead);
+ PORT_Assert(spec->direction == ssl_secret_read);
SSL_TRC(3, ("%d: TLS13[%d]: spec=%d epoch=%d (%s) unprotect 0x%0llx len=%u",
SSL_GETPID(), ss->fd, spec, spec->epoch, spec->phase,
cText->seqNum, cText->buf->len));
@@ -5062,12 +5470,12 @@ tls13_UnprotectRecord(sslSocket *ss,
return SECFailure;
}
rv = spec->aead(&spec->keyMaterial,
- PR_TRUE, /* do decrypt */
- plaintext->buf, /* out */
- (int *)&plaintext->len, /* outlen */
- plaintext->space, /* maxout */
- cText->buf->buf, /* in */
- cText->buf->len, /* inlen */
+ PR_TRUE, /* do decrypt */
+ plaintext->buf, /* out */
+ &plaintext->len, /* outlen */
+ plaintext->space, /* maxout */
+ cText->buf->buf, /* in */
+ cText->buf->len, /* inlen */
aad, aadLen);
if (rv != SECSuccess) {
SSL_TRC(3,
@@ -5168,6 +5576,9 @@ tls13_MaybeDo0RTTHandshake(sslSocket *ss)
ss->ssl3.hs.zeroRttState = ssl_0rtt_sent;
ss->ssl3.hs.zeroRttSuite = ss->ssl3.hs.cipher_suite;
+ /* Note: Reset the preliminary info here rather than just add 0-RTT. We are
+ * only guessing what might happen at this point.*/
+ ss->ssl3.hs.preliminaryInfo = ssl_preinfo_0rtt_cipher_suite;
SSL_TRC(3, ("%d: TLS13[%d]: in 0-RTT mode", SSL_GETPID(), ss->fd));
@@ -5196,9 +5607,6 @@ tls13_MaybeDo0RTTHandshake(sslSocket *ss)
}
}
- /* Cipher suite already set in tls13_SetupClientHello. */
- ss->ssl3.hs.preliminaryInfo = 0;
-
rv = tls13_DeriveEarlySecrets(ss);
if (rv != SECSuccess) {
return SECFailure;
@@ -5209,7 +5617,7 @@ tls13_MaybeDo0RTTHandshake(sslSocket *ss)
ssl_CipherSpecAddRef(ss->ssl3.cwSpec);
rv = tls13_SetCipherSpec(ss, TrafficKeyEarlyApplicationData,
- CipherSpecWrite, PR_TRUE);
+ ssl_secret_write, PR_TRUE);
if (rv != SECSuccess) {
return SECFailure;
}
@@ -5218,25 +5626,45 @@ tls13_MaybeDo0RTTHandshake(sslSocket *ss)
}
PRInt32
-tls13_Read0RttData(sslSocket *ss, void *buf, PRInt32 len)
+tls13_Read0RttData(sslSocket *ss, PRUint8 *buf, PRInt32 len)
{
- TLS13EarlyData *msg;
-
PORT_Assert(!PR_CLIST_IS_EMPTY(&ss->ssl3.hs.bufferedEarlyData));
- msg = (TLS13EarlyData *)PR_NEXT_LINK(&ss->ssl3.hs.bufferedEarlyData);
+ PRInt32 offset = 0;
+ while (!PR_CLIST_IS_EMPTY(&ss->ssl3.hs.bufferedEarlyData)) {
+ TLS13EarlyData *msg =
+ (TLS13EarlyData *)PR_NEXT_LINK(&ss->ssl3.hs.bufferedEarlyData);
+ unsigned int tocpy = msg->data.len - msg->consumed;
+
+ if (tocpy > (len - offset)) {
+ if (IS_DTLS(ss)) {
+ /* In DTLS, we only return entire records.
+ * So offset and consumed are always zero. */
+ PORT_Assert(offset == 0);
+ PORT_Assert(msg->consumed == 0);
+ PORT_SetError(SSL_ERROR_RX_SHORT_DTLS_READ);
+ return -1;
+ }
- PR_REMOVE_LINK(&msg->link);
- if (msg->data.len > len) {
- PORT_SetError(SSL_ERROR_ILLEGAL_PARAMETER_ALERT);
- return SECFailure;
- }
- len = msg->data.len;
+ tocpy = len - offset;
+ }
+
+ PORT_Memcpy(buf + offset, msg->data.data + msg->consumed, tocpy);
+ offset += tocpy;
+ msg->consumed += tocpy;
- PORT_Memcpy(buf, msg->data.data, msg->data.len);
- SECITEM_ZfreeItem(&msg->data, PR_FALSE);
- PORT_ZFree(msg, sizeof(*msg));
+ if (msg->consumed == msg->data.len) {
+ PR_REMOVE_LINK(&msg->link);
+ SECITEM_ZfreeItem(&msg->data, PR_FALSE);
+ PORT_ZFree(msg, sizeof(*msg));
+ }
+
+ /* We are done after one record for DTLS; otherwise, when the buffer fills up. */
+ if (IS_DTLS(ss) || offset == len) {
+ break;
+ }
+ }
- return len;
+ return offset;
}
static SECStatus
@@ -5272,7 +5700,7 @@ tls13_HandleEndOfEarlyData(sslSocket *ss, PRUint8 *b, PRUint32 length)
/* We shouldn't be getting any more early data, and if we do,
* it is because of reordering and we drop it. */
if (IS_DTLS(ss)) {
- ssl_CipherSpecReleaseByEpoch(ss, CipherSpecRead,
+ ssl_CipherSpecReleaseByEpoch(ss, ssl_secret_read,
TrafficKeyEarlyApplicationData);
dtls_ReceivedFirstMessageInFlight(ss);
}
@@ -5285,7 +5713,7 @@ tls13_HandleEndOfEarlyData(sslSocket *ss, PRUint8 *b, PRUint32 length)
}
rv = tls13_SetCipherSpec(ss, TrafficKeyHandshake,
- CipherSpecRead, PR_FALSE);
+ ssl_secret_read, PR_FALSE);
if (rv != SECSuccess) {
PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
return SECFailure;
@@ -5403,6 +5831,15 @@ tls13_NegotiateVersion(sslSocket *ss, const TLSExtension *supportedVersions)
return SECFailure;
}
for (version = ss->vrange.max; version >= ss->vrange.min; --version) {
+ if (ss->ssl3.hs.helloRetry && version < SSL_LIBRARY_VERSION_TLS_1_3) {
+ /* Prevent negotiating to a lower version in response to a TLS 1.3 HRR.
+ * Since we check in descending (local) order, this will only fail if
+ * our vrange has changed or the client didn't offer 1.3 in response. */
+ PORT_SetError(SSL_ERROR_UNSUPPORTED_VERSION);
+ FATAL_ERROR(ss, SSL_ERROR_UNSUPPORTED_VERSION, protocol_version);
+ return SECFailure;
+ }
+
PRUint16 wire = tls13_EncodeDraftVersion(version, ss->protocolVariant);
unsigned long offset;