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.c2419
1 files changed, 1598 insertions, 821 deletions
diff --git a/security/nss/lib/ssl/tls13con.c b/security/nss/lib/ssl/tls13con.c
index 560493848..1fecaf3f8 100644
--- a/security/nss/lib/ssl/tls13con.c
+++ b/security/nss/lib/ssl/tls13con.c
@@ -17,23 +17,14 @@
#include "sslimpl.h"
#include "sslproto.h"
#include "sslerr.h"
+#include "ssl3exthandle.h"
#include "tls13hkdf.h"
#include "tls13con.h"
+#include "tls13err.h"
#include "tls13exthandle.h"
+#include "tls13hashstate.h"
-typedef enum {
- TrafficKeyClearText = 0,
- TrafficKeyEarlyApplicationData = 1,
- TrafficKeyHandshake = 2,
- TrafficKeyApplicationData = 3
-} TrafficKeyType;
-
-typedef enum {
- CipherSpecRead,
- CipherSpecWrite,
-} CipherSpecDirection;
-
-static SECStatus tls13_SetCipherSpec(sslSocket *ss, TrafficKeyType type,
+static SECStatus tls13_SetCipherSpec(sslSocket *ss, PRUint16 epoch,
CipherSpecDirection install,
PRBool deleteSecret);
static SECStatus tls13_AESGCM(
@@ -53,8 +44,9 @@ static SECStatus tls13_SendEncryptedExtensions(sslSocket *ss);
static void tls13_SetKeyExchangeType(sslSocket *ss, const sslNamedGroupDef *group);
static SECStatus tls13_HandleClientKeyShare(sslSocket *ss,
TLS13KeyShareEntry *peerShare);
-static SECStatus tls13_SendHelloRetryRequest(sslSocket *ss,
- const sslNamedGroupDef *selectedGroup);
+static SECStatus tls13_SendHelloRetryRequest(
+ sslSocket *ss, const sslNamedGroupDef *selectedGroup,
+ const PRUint8 *token, unsigned int tokenLen);
static SECStatus tls13_HandleServerKeyShare(sslSocket *ss);
static SECStatus tls13_HandleEncryptedExtensions(sslSocket *ss, PRUint8 *b,
@@ -62,40 +54,46 @@ static SECStatus tls13_HandleEncryptedExtensions(sslSocket *ss, PRUint8 *b,
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_HandleCertificateRequest(sslSocket *ss, PRUint8 *b,
PRUint32 length);
static SECStatus
tls13_SendCertificateVerify(sslSocket *ss, SECKEYPrivateKey *privKey);
static SECStatus tls13_HandleCertificateVerify(
- sslSocket *ss, PRUint8 *b, PRUint32 length,
- SSL3Hashes *hashes);
+ sslSocket *ss, PRUint8 *b, PRUint32 length);
static SECStatus tls13_RecoverWrappedSharedSecret(sslSocket *ss,
sslSessionID *sid);
static SECStatus
+tls13_DeriveSecretWrap(sslSocket *ss, PK11SymKey *key,
+ const char *prefix,
+ const char *suffix,
+ const char *keylogLabel,
+ PK11SymKey **dest);
+static SECStatus
tls13_DeriveSecret(sslSocket *ss, PK11SymKey *key,
- const char *prefix,
- const char *suffix,
+ const char *label,
+ unsigned int labelLen,
const SSL3Hashes *hashes,
PK11SymKey **dest);
static SECStatus tls13_SendEndOfEarlyData(sslSocket *ss);
+static SECStatus tls13_HandleEndOfEarlyData(sslSocket *ss, PRUint8 *b,
+ PRUint32 length);
static SECStatus tls13_SendFinished(sslSocket *ss, PK11SymKey *baseKey);
-static SECStatus tls13_ComputePskBinderHash(sslSocket *ss,
- unsigned long prefixLength,
+static SECStatus tls13_ComputePskBinderHash(sslSocket *ss, unsigned int prefix,
SSL3Hashes *hashes);
-static SECStatus tls13_VerifyFinished(sslSocket *ss, SSL3HandshakeType message,
+static SECStatus tls13_VerifyFinished(sslSocket *ss, SSLHandshakeType message,
PK11SymKey *secret,
PRUint8 *b, PRUint32 length,
const SSL3Hashes *hashes);
static SECStatus tls13_ClientHandleFinished(sslSocket *ss,
- PRUint8 *b, PRUint32 length,
- const SSL3Hashes *hashes);
+ PRUint8 *b, PRUint32 length);
static SECStatus tls13_ServerHandleFinished(sslSocket *ss,
- PRUint8 *b, PRUint32 length,
- const SSL3Hashes *hashes);
+ PRUint8 *b, PRUint32 length);
+static SECStatus tls13_SendNewSessionTicket(sslSocket *ss,
+ const PRUint8 *appToken,
+ unsigned int appTokenLen);
static SECStatus tls13_HandleNewSessionTicket(sslSocket *ss, PRUint8 *b,
PRUint32 length);
-static SECStatus tls13_ComputeHandshakeHashes(sslSocket *ss,
- SSL3Hashes *hashes);
static SECStatus tls13_ComputeEarlySecrets(sslSocket *ss);
static SECStatus tls13_ComputeHandshakeSecrets(sslSocket *ss);
static SECStatus tls13_ComputeApplicationSecrets(sslSocket *ss);
@@ -107,26 +105,28 @@ static SECStatus tls13_ComputeFinished(
static SECStatus tls13_SendClientSecondRound(sslSocket *ss);
static SECStatus tls13_FinishHandshake(sslSocket *ss);
-const char kHkdfLabelClient[] = "client";
-const char kHkdfLabelServer[] = "server";
-const char kHkdfLabelPskBinderKey[] = "resumption psk binder key";
-const char kHkdfLabelEarlyTrafficSecret[] = "early traffic secret";
-const char kHkdfLabelEarlyExporterSecret[] = "early exporter master secret";
-const char kHkdfLabelHandshakeTrafficSecret[] = "handshake traffic secret";
-const char kHkdfLabelApplicationTrafficSecret[] = "application traffic secret";
+const char kHkdfLabelClient[] = "c";
+const char kHkdfLabelServer[] = "s";
+const char kHkdfLabelDerivedSecret[] = "derived";
+const char kHkdfLabelPskBinderKey[] = "res binder";
+const char kHkdfLabelEarlyTrafficSecret[] = "e traffic";
+const char kHkdfLabelEarlyExporterSecret[] = "e exp master";
+const char kHkdfLabelHandshakeTrafficSecret[] = "hs traffic";
+const char kHkdfLabelApplicationTrafficSecret[] = "ap traffic";
const char kHkdfLabelFinishedSecret[] = "finished";
-const char kHkdfLabelResumptionMasterSecret[] = "resumption master secret";
-const char kHkdfLabelExporterMasterSecret[] = "exporter master secret";
+const char kHkdfLabelResumptionMasterSecret[] = "res master";
+const char kHkdfLabelExporterMasterSecret[] = "exp master";
+const char kHkdfLabelResumption[] = "resumption";
const char kHkdfPurposeKey[] = "key";
const char kHkdfPurposeIv[] = "iv";
-#define TRAFFIC_SECRET(ss, dir, name) ((ss->sec.isServer ^ \
- (dir == CipherSpecWrite)) \
- ? ss->ssl3.hs.client##name \
- : ss->ssl3.hs.server##name)
-
-const SSL3ProtocolVersion kTlsRecordVersion = SSL_LIBRARY_VERSION_TLS_1_0;
-const SSL3ProtocolVersion kDtlsRecordVersion = SSL_LIBRARY_VERSION_TLS_1_1;
+const char keylogLabelClientEarlyTrafficSecret[] = "CLIENT_EARLY_TRAFFIC_SECRET";
+const char keylogLabelClientHsTrafficSecret[] = "CLIENT_HANDSHAKE_TRAFFIC_SECRET";
+const char keylogLabelServerHsTrafficSecret[] = "SERVER_HANDSHAKE_TRAFFIC_SECRET";
+const char keylogLabelClientTrafficSecret[] = "CLIENT_TRAFFIC_SECRET_0";
+const char keylogLabelServerTrafficSecret[] = "SERVER_TRAFFIC_SECRET_0";
+const char keylogLabelEarlyExporterSecret[] = "EARLY_EXPORTER_SECRET";
+const char keylogLabelExporterSecret[] = "EXPORTER_SECRET";
/* Belt and suspenders in case we ever add a TLS 1.4. */
PR_STATIC_ASSERT(SSL_LIBRARY_VERSION_MAX_SUPPORTED <=
@@ -165,6 +165,7 @@ tls13_HandshakeState(SSL3WaitState st)
switch (st) {
STATE_CASE(idle_handshake);
STATE_CASE(wait_client_hello);
+ STATE_CASE(wait_end_of_early_data);
STATE_CASE(wait_client_cert);
STATE_CASE(wait_client_key);
STATE_CASE(wait_cert_verify);
@@ -336,6 +337,23 @@ tls13_GetHmacMechanism(sslSocket *ss)
}
SECStatus
+tls13_ComputeHash(sslSocket *ss, SSL3Hashes *hashes,
+ const PRUint8 *buf, unsigned int len)
+{
+ SECStatus rv;
+
+ rv = PK11_HashBuf(ssl3_HashTypeToOID(tls13_GetHash(ss)),
+ hashes->u.raw, buf, len);
+ if (rv != SECSuccess) {
+ FATAL_ERROR(ss, SEC_ERROR_LIBRARY_FAILURE, internal_error);
+ return SECFailure;
+ }
+ hashes->len = tls13_GetHashSize(ss);
+
+ return SECSuccess;
+}
+
+SECStatus
tls13_CreateKeyShare(sslSocket *ss, const sslNamedGroupDef *groupDef)
{
SECStatus rv;
@@ -450,7 +468,8 @@ tls13_SetupClientHello(sslSocket *ss)
return SECFailure;
}
- rv = ssl3_SetCipherSuite(ss, ss->sec.ci.sid->u.ssl3.cipherSuite, PR_FALSE);
+ ss->ssl3.hs.cipher_suite = ss->sec.ci.sid->u.ssl3.cipherSuite;
+ rv = ssl3_SetupCipherSuite(ss, PR_FALSE);
if (rv != SECSuccess) {
FATAL_ERROR(ss, PORT_GetError(), internal_error);
return SECFailure;
@@ -558,9 +577,241 @@ loser:
return SECFailure;
}
+static PRBool
+tls13_UseServerSecret(sslSocket *ss, CipherSpecDirection direction)
+{
+ return ss->sec.isServer == (direction == CipherSpecWrite);
+}
+
+static PK11SymKey **
+tls13_TrafficSecretRef(sslSocket *ss, CipherSpecDirection direction)
+{
+ if (tls13_UseServerSecret(ss, direction)) {
+ return &ss->ssl3.hs.serverTrafficSecret;
+ }
+ return &ss->ssl3.hs.clientTrafficSecret;
+}
+
+SECStatus
+tls13_UpdateTrafficKeys(sslSocket *ss, CipherSpecDirection direction)
+{
+ PK11SymKey **secret;
+ PK11SymKey *updatedSecret;
+ PRUint16 epoch;
+ SECStatus rv;
+
+ secret = tls13_TrafficSecretRef(ss, direction);
+ rv = tls13_HkdfExpandLabel(*secret, tls13_GetHash(ss),
+ NULL, 0,
+ kHkdfLabelApplicationTrafficSecret,
+ strlen(kHkdfLabelApplicationTrafficSecret),
+ tls13_GetHmacMechanism(ss),
+ tls13_GetHashSize(ss),
+ &updatedSecret);
+ if (rv != SECSuccess) {
+ return SECFailure;
+ }
+
+ PK11_FreeSymKey(*secret);
+ *secret = updatedSecret;
+
+ ssl_GetSpecReadLock(ss);
+ if (direction == CipherSpecRead) {
+ epoch = ss->ssl3.crSpec->epoch;
+ } else {
+ epoch = ss->ssl3.cwSpec->epoch;
+ }
+ ssl_ReleaseSpecReadLock(ss);
+
+ if (epoch == PR_UINT16_MAX) {
+ /* Good chance that this is an overflow from too many updates. */
+ FATAL_ERROR(ss, SSL_ERROR_TOO_MANY_KEY_UPDATES, internal_error);
+ return SECFailure;
+ }
+ ++epoch;
+
+ rv = tls13_SetCipherSpec(ss, epoch, direction, PR_FALSE);
+ if (rv != SECSuccess) {
+ FATAL_ERROR(ss, SEC_ERROR_LIBRARY_FAILURE, internal_error);
+ return SECFailure;
+ }
+
+ return SECSuccess;
+}
+
+SECStatus
+tls13_SendKeyUpdate(sslSocket *ss, tls13KeyUpdateRequest request, PRBool buffer)
+{
+ SECStatus rv;
+
+ SSL_TRC(3, ("%d: TLS13[%d]: %s send key update, response %s",
+ SSL_GETPID(), ss->fd, SSL_ROLE(ss),
+ (request == update_requested) ? "requested"
+ : "not requested"));
+
+ PORT_Assert(ss->opt.noLocks || ssl_HaveSSL3HandshakeLock(ss));
+
+ if (!ss->firstHsDone) {
+ PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
+ return SECFailure;
+ }
+
+ rv = TLS13_CHECK_HS_STATE(ss, SEC_ERROR_LIBRARY_FAILURE,
+ idle_handshake);
+ if (rv != SECSuccess) {
+ return SECFailure;
+ }
+
+ /* Not supported. */
+ if (IS_DTLS(ss)) {
+ PORT_SetError(SEC_ERROR_INVALID_ARGS);
+ return SECFailure;
+ }
+
+ ssl_GetXmitBufLock(ss);
+ rv = ssl3_AppendHandshakeHeader(ss, ssl_hs_key_update, 1);
+ if (rv != SECSuccess) {
+ FATAL_ERROR(ss, SEC_ERROR_LIBRARY_FAILURE, internal_error);
+ goto loser;
+ }
+ rv = ssl3_AppendHandshakeNumber(ss, request, 1);
+ if (rv != SECSuccess) {
+ FATAL_ERROR(ss, SEC_ERROR_LIBRARY_FAILURE, internal_error);
+ goto loser;
+ }
+
+ /* If we have been asked to buffer, then do so. This allows us to coalesce
+ * a KeyUpdate with a pending write. */
+ rv = ssl3_FlushHandshake(ss, buffer ? ssl_SEND_FLAG_FORCE_INTO_BUFFER : 0);
+ if (rv != SECSuccess) {
+ goto loser; /* error code set by ssl3_FlushHandshake */
+ }
+ ssl_ReleaseXmitBufLock(ss);
+
+ rv = tls13_UpdateTrafficKeys(ss, CipherSpecWrite);
+ if (rv != SECSuccess) {
+ goto loser; /* error code set by tls13_UpdateTrafficKeys */
+ }
+
+ return SECSuccess;
+
+loser:
+ ssl_ReleaseXmitBufLock(ss);
+ return SECFailure;
+}
+
+SECStatus
+SSLExp_KeyUpdate(PRFileDesc *fd, PRBool requestUpdate)
+{
+ SECStatus rv;
+ sslSocket *ss = ssl_FindSocket(fd);
+ if (!ss) {
+ return SECFailure;
+ }
+
+ if (!ss->firstHsDone) {
+ PORT_SetError(SEC_ERROR_INVALID_ARGS);
+ return SECFailure;
+ }
+
+ rv = TLS13_CHECK_HS_STATE(ss, SEC_ERROR_INVALID_ARGS,
+ idle_handshake);
+ if (rv != SECSuccess) {
+ return SECFailure;
+ }
+
+ ssl_GetSSL3HandshakeLock(ss);
+ rv = tls13_SendKeyUpdate(ss, requestUpdate ? update_requested : update_not_requested,
+ PR_FALSE /* don't buffer */);
+
+ /* Remember that we are the ones that initiated this KeyUpdate. */
+ if (rv == SECSuccess) {
+ ss->ssl3.peerRequestedKeyUpdate = PR_FALSE;
+ }
+ ssl_ReleaseSSL3HandshakeLock(ss);
+ return rv;
+}
+
+/*
+ * enum {
+ * update_not_requested(0), update_requested(1), (255)
+ * } KeyUpdateRequest;
+ *
+ * struct {
+ * KeyUpdateRequest request_update;
+ * } KeyUpdate;
+ */
+static SECStatus
+tls13_HandleKeyUpdate(sslSocket *ss, PRUint8 *b, unsigned int length)
+{
+ SECStatus rv;
+ PRUint32 update;
+
+ SSL_TRC(3, ("%d: TLS13[%d]: %s handle key update",
+ SSL_GETPID(), ss->fd, SSL_ROLE(ss)));
+
+ PORT_Assert(ss->opt.noLocks || ssl_HaveRecvBufLock(ss));
+ PORT_Assert(ss->opt.noLocks || ssl_HaveSSL3HandshakeLock(ss));
+
+ PORT_Assert(ss->firstHsDone);
+ if (!ss->firstHsDone) {
+ FATAL_ERROR(ss, SSL_ERROR_RX_UNEXPECTED_KEY_UPDATE, unexpected_message);
+ return SECFailure;
+ }
+
+ rv = TLS13_CHECK_HS_STATE(ss, SSL_ERROR_RX_UNEXPECTED_KEY_UPDATE,
+ idle_handshake);
+ if (rv != SECSuccess) {
+ /* We should never be idle_handshake prior to firstHsDone. */
+ FATAL_ERROR(ss, SEC_ERROR_LIBRARY_FAILURE, internal_error);
+ return SECFailure;
+ }
+
+ rv = ssl3_ConsumeHandshakeNumber(ss, &update, 1, &b, &length);
+ if (rv != SECSuccess) {
+ return SECFailure; /* Error code set already. */
+ }
+ if (length != 0) {
+ FATAL_ERROR(ss, SSL_ERROR_RX_MALFORMED_KEY_UPDATE, decode_error);
+ return SECFailure;
+ }
+ if (!(update == update_requested ||
+ update == update_not_requested)) {
+ FATAL_ERROR(ss, SSL_ERROR_RX_MALFORMED_KEY_UPDATE, decode_error);
+ return SECFailure;
+ }
+
+ rv = tls13_UpdateTrafficKeys(ss, CipherSpecRead);
+ if (rv != SECSuccess) {
+ return SECFailure; /* Error code set by tls13_UpdateTrafficKeys. */
+ }
+
+ if (update == update_requested) {
+ PRBool sendUpdate;
+ 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);
+ sendUpdate = ss->ssl3.cwSpec->seqNum > 0;
+ ssl_ReleaseSpecReadLock(ss);
+ } else {
+ sendUpdate = PR_TRUE;
+ }
+ if (sendUpdate) {
+ /* Respond immediately (don't buffer). */
+ rv = tls13_SendKeyUpdate(ss, update_not_requested, PR_FALSE);
+ if (rv != SECSuccess) {
+ return SECFailure; /* Error already set. */
+ }
+ }
+ ss->ssl3.peerRequestedKeyUpdate = PR_TRUE;
+ }
+
+ return SECSuccess;
+}
+
SECStatus
-tls13_HandlePostHelloHandshakeMessage(sslSocket *ss, PRUint8 *b,
- PRUint32 length, SSL3Hashes *hashesPtr)
+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"
@@ -571,36 +822,34 @@ tls13_HandlePostHelloHandshakeMessage(sslSocket *ss, PRUint8 *b,
/* TODO(ekr@rtfm.com): Would it be better to check all the states here? */
switch (ss->ssl3.hs.msg_type) {
- case certificate:
+ case ssl_hs_certificate:
return tls13_HandleCertificate(ss, b, length);
- case certificate_request:
+ case ssl_hs_certificate_request:
return tls13_HandleCertificateRequest(ss, b, length);
- case certificate_verify:
- if (!hashesPtr) {
- FATAL_ERROR(ss, SSL_ERROR_RX_UNEXPECTED_CERT_VERIFY, unexpected_message);
- return SECFailure;
- }
- return tls13_HandleCertificateVerify(ss, b, length, hashesPtr);
+ case ssl_hs_certificate_verify:
+ return tls13_HandleCertificateVerify(ss, b, length);
- case encrypted_extensions:
+ case ssl_hs_encrypted_extensions:
return tls13_HandleEncryptedExtensions(ss, b, length);
- case new_session_ticket:
+ case ssl_hs_new_session_ticket:
return tls13_HandleNewSessionTicket(ss, b, length);
- case finished:
- if (!hashesPtr) {
- FATAL_ERROR(ss, SSL_ERROR_RX_UNEXPECTED_FINISHED, unexpected_message);
- return SECFailure;
- }
+ case ssl_hs_finished:
if (ss->sec.isServer) {
- return tls13_ServerHandleFinished(ss, b, length, hashesPtr);
+ return tls13_ServerHandleFinished(ss, b, length);
} else {
- return tls13_ClientHandleFinished(ss, b, length, hashesPtr);
+ return tls13_ClientHandleFinished(ss, b, length);
}
+ case ssl_hs_end_of_early_data:
+ return tls13_HandleEndOfEarlyData(ss, b, length);
+
+ case ssl_hs_key_update:
+ return tls13_HandleKeyUpdate(ss, b, length);
+
default:
FATAL_ERROR(ss, SSL_ERROR_RX_UNKNOWN_HANDSHAKE, unexpected_message);
return SECFailure;
@@ -619,10 +868,6 @@ tls13_RecoverWrappedSharedSecret(sslSocket *ss, sslSessionID *sid)
SSL_TRC(3, ("%d: TLS13[%d]: recovering static secret (%s)",
SSL_GETPID(), ss->fd, SSL_ROLE(ss)));
- if (!sid->u.ssl3.keys.msIsWrapped) {
- PORT_Assert(0); /* I think this can't happen. */
- return SECFailure;
- }
/* Now find the hash used as the PRF for the previous handshake. */
hashType = tls13_GetHashForCipherSuite(sid->u.ssl3.cipherSuite);
@@ -673,53 +918,55 @@ tls13_RecoverWrappedSharedSecret(sslSocket *ss, sslSessionID *sid)
/* Key Derivation Functions.
*
- * Below is the key schedule from [draft-ietf-tls-tls13].
- *
- * * The relevant functions from this file are indicated by tls13_Foo().
* 0
* |
* v
- * PSK -> HKDF-Extract
+ * PSK -> HKDF-Extract = Early Secret
* |
- * v
- * Early Secret ---> Derive-Secret(., "client early traffic secret",
- * | ClientHello)
- * | = client_early_traffic_secret
- * v
- * (EC)DHE -> HKDF-Extract
+ * +-----> Derive-Secret(., "ext binder" | "res binder", "")
+ * | = binder_key
+ * |
+ * +-----> Derive-Secret(., "c e traffic",
+ * | ClientHello)
+ * | = client_early_traffic_secret
* |
+ * +-----> Derive-Secret(., "e exp master",
+ * | ClientHello)
+ * | = early_exporter_secret
* v
- * Handshake Secret
+ * Derive-Secret(., "derived", "")
* |
- * +---------> Derive-Secret(., "client handshake traffic secret",
- * | ClientHello...ServerHello)
- * | = client_handshake_traffic_secret
+ * v
+ *(EC)DHE -> HKDF-Extract = Handshake Secret
* |
- * +---------> Derive-Secret(., "server handshake traffic secret",
- * | ClientHello...ServerHello)
- * | = server_handshake_traffic_secret
+ * +-----> Derive-Secret(., "c hs traffic",
+ * | ClientHello...ServerHello)
+ * | = client_handshake_traffic_secret
* |
+ * +-----> Derive-Secret(., "s hs traffic",
+ * | ClientHello...ServerHello)
+ * | = server_handshake_traffic_secret
* v
- * 0 -> HKDF-Extract
+ * Derive-Secret(., "derived", "")
* |
* v
- * Master Secret
+ * 0 -> HKDF-Extract = Master Secret
* |
- * +---------> Derive-Secret(., "client application traffic secret",
- * | ClientHello...Server Finished)
- * | = client_traffic_secret_0
+ * +-----> Derive-Secret(., "c ap traffic",
+ * | ClientHello...Server Finished)
+ * | = client_traffic_secret_0
* |
- * +---------> Derive-Secret(., "server application traffic secret",
- * | ClientHello...Server Finished)
- * | = server_traffic_secret_0
+ * +-----> Derive-Secret(., "s ap traffic",
+ * | ClientHello...Server Finished)
+ * | = server_traffic_secret_0
* |
- * +---------> Derive-Secret(., "exporter master secret",
- * | ClientHello...Client Finished)
- * | = exporter_secret
+ * +-----> Derive-Secret(., "exp master",
+ * | ClientHello...Server Finished)
+ * | = exporter_secret
* |
- * +---------> Derive-Secret(., "resumption master secret",
- * ClientHello...Client Finished)
- * = resumption_secret
+ * +-----> Derive-Secret(., "res master",
+ * ClientHello...Client Finished)
+ * = resumption_master_secret
*
*/
@@ -742,35 +989,43 @@ tls13_ComputeEarlySecrets(sslSocket *ss)
PORT_Assert(ss->statelessResume == (ss->ssl3.hs.resumptionMasterSecret != NULL));
if (ss->statelessResume) {
- PRUint8 buf[1] = { 0 };
- SSL3Hashes hashes;
-
PK11_FreeSymKey(ss->ssl3.hs.resumptionMasterSecret);
ss->ssl3.hs.resumptionMasterSecret = NULL;
- rv = PK11_HashBuf(ssl3_HashTypeToOID(tls13_GetHash(ss)),
- hashes.u.raw, buf, 0);
+ rv = tls13_DeriveSecretNullHash(ss, ss->ssl3.hs.currentSecret,
+ kHkdfLabelPskBinderKey,
+ strlen(kHkdfLabelPskBinderKey),
+ &ss->ssl3.hs.pskBinderKey);
if (rv != SECSuccess) {
- FATAL_ERROR(ss, SEC_ERROR_LIBRARY_FAILURE, internal_error);
return SECFailure;
}
- hashes.len = tls13_GetHashSize(ss);
+ }
+ PORT_Assert(!ss->ssl3.hs.resumptionMasterSecret);
- rv = tls13_DeriveSecret(ss, ss->ssl3.hs.currentSecret,
- NULL, kHkdfLabelPskBinderKey, &hashes,
- &ss->ssl3.hs.pskBinderKey);
- if (rv != SECSuccess) {
- return SECFailure;
- }
+ return SECSuccess;
+}
+
+/* This derives the early traffic and early exporter secrets. */
+static SECStatus
+tls13_DeriveEarlySecrets(sslSocket *ss)
+{
+ SECStatus rv;
+
+ rv = tls13_DeriveSecretWrap(ss, ss->ssl3.hs.currentSecret,
+ kHkdfLabelClient,
+ kHkdfLabelEarlyTrafficSecret,
+ keylogLabelClientEarlyTrafficSecret,
+ &ss->ssl3.hs.clientEarlyTrafficSecret);
+ if (rv != SECSuccess) {
+ return SECFailure;
+ }
- rv = tls13_DeriveSecret(ss, ss->ssl3.hs.currentSecret,
+ rv = tls13_DeriveSecretWrap(ss, ss->ssl3.hs.currentSecret,
NULL, kHkdfLabelEarlyExporterSecret,
- &hashes, &ss->ssl3.hs.earlyExporterSecret);
- if (rv != SECSuccess) {
- return SECFailure;
- }
- } else {
- PORT_Assert(!ss->ssl3.hs.resumptionMasterSecret);
+ keylogLabelEarlyExporterSecret,
+ &ss->ssl3.hs.earlyExporterSecret);
+ if (rv != SECSuccess) {
+ return SECFailure;
}
return SECSuccess;
@@ -780,6 +1035,7 @@ static SECStatus
tls13_ComputeHandshakeSecrets(sslSocket *ss)
{
SECStatus rv;
+ PK11SymKey *derivedSecret = NULL;
PK11SymKey *newSecret = NULL;
SSL_TRC(5, ("%d: TLS13[%d]: compute handshake secrets (%s)",
@@ -788,8 +1044,21 @@ tls13_ComputeHandshakeSecrets(sslSocket *ss)
/* First update |currentSecret| to add |dheSecret|, if any. */
PORT_Assert(ss->ssl3.hs.currentSecret);
PORT_Assert(ss->ssl3.hs.dheSecret);
- rv = tls13_HkdfExtract(ss->ssl3.hs.currentSecret, ss->ssl3.hs.dheSecret,
+
+ /* Expand before we extract. */
+ rv = tls13_DeriveSecretNullHash(ss, ss->ssl3.hs.currentSecret,
+ kHkdfLabelDerivedSecret,
+ strlen(kHkdfLabelDerivedSecret),
+ &derivedSecret);
+ if (rv != SECSuccess) {
+ LOG_ERROR(ss, SEC_ERROR_LIBRARY_FAILURE);
+ return rv;
+ }
+
+ rv = tls13_HkdfExtract(derivedSecret, ss->ssl3.hs.dheSecret,
tls13_GetHash(ss), &newSecret);
+ PK11_FreeSymKey(derivedSecret);
+
if (rv != SECSuccess) {
LOG_ERROR(ss, SEC_ERROR_LIBRARY_FAILURE);
return rv;
@@ -800,18 +1069,20 @@ tls13_ComputeHandshakeSecrets(sslSocket *ss)
ss->ssl3.hs.currentSecret = newSecret;
/* Now compute |*HsTrafficSecret| */
- rv = tls13_DeriveSecret(ss, ss->ssl3.hs.currentSecret,
- kHkdfLabelClient,
- kHkdfLabelHandshakeTrafficSecret, NULL,
- &ss->ssl3.hs.clientHsTrafficSecret);
+ rv = tls13_DeriveSecretWrap(ss, ss->ssl3.hs.currentSecret,
+ kHkdfLabelClient,
+ kHkdfLabelHandshakeTrafficSecret,
+ keylogLabelClientHsTrafficSecret,
+ &ss->ssl3.hs.clientHsTrafficSecret);
if (rv != SECSuccess) {
LOG_ERROR(ss, SEC_ERROR_LIBRARY_FAILURE);
return rv;
}
- rv = tls13_DeriveSecret(ss, ss->ssl3.hs.currentSecret,
- kHkdfLabelServer,
- kHkdfLabelHandshakeTrafficSecret, NULL,
- &ss->ssl3.hs.serverHsTrafficSecret);
+ rv = tls13_DeriveSecretWrap(ss, ss->ssl3.hs.currentSecret,
+ kHkdfLabelServer,
+ kHkdfLabelHandshakeTrafficSecret,
+ keylogLabelServerHsTrafficSecret,
+ &ss->ssl3.hs.serverHsTrafficSecret);
if (rv != SECSuccess) {
LOG_ERROR(ss, SEC_ERROR_LIBRARY_FAILURE);
return rv;
@@ -822,11 +1093,19 @@ tls13_ComputeHandshakeSecrets(sslSocket *ss)
/* Crank HKDF forward to make master secret, which we
* stuff in current secret. */
- rv = tls13_HkdfExtract(ss->ssl3.hs.currentSecret,
+ rv = tls13_DeriveSecretNullHash(ss, ss->ssl3.hs.currentSecret,
+ kHkdfLabelDerivedSecret,
+ strlen(kHkdfLabelDerivedSecret),
+ &derivedSecret);
+ if (rv != SECSuccess) {
+ LOG_ERROR(ss, SEC_ERROR_LIBRARY_FAILURE);
+ return rv;
+ }
+ rv = tls13_HkdfExtract(derivedSecret,
NULL,
tls13_GetHash(ss),
&newSecret);
-
+ PK11_FreeSymKey(derivedSecret);
if (rv != SECSuccess) {
LOG_ERROR(ss, SEC_ERROR_LIBRARY_FAILURE);
return SECFailure;
@@ -842,26 +1121,27 @@ tls13_ComputeApplicationSecrets(sslSocket *ss)
{
SECStatus rv;
- rv = tls13_DeriveSecret(ss, ss->ssl3.hs.currentSecret,
- kHkdfLabelClient,
- kHkdfLabelApplicationTrafficSecret,
- NULL,
- &ss->ssl3.hs.clientTrafficSecret);
+ rv = tls13_DeriveSecretWrap(ss, ss->ssl3.hs.currentSecret,
+ kHkdfLabelClient,
+ kHkdfLabelApplicationTrafficSecret,
+ keylogLabelClientTrafficSecret,
+ &ss->ssl3.hs.clientTrafficSecret);
if (rv != SECSuccess) {
return SECFailure;
}
- rv = tls13_DeriveSecret(ss, ss->ssl3.hs.currentSecret,
- kHkdfLabelServer,
- kHkdfLabelApplicationTrafficSecret,
- NULL,
- &ss->ssl3.hs.serverTrafficSecret);
+ rv = tls13_DeriveSecretWrap(ss, ss->ssl3.hs.currentSecret,
+ kHkdfLabelServer,
+ kHkdfLabelApplicationTrafficSecret,
+ keylogLabelServerTrafficSecret,
+ &ss->ssl3.hs.serverTrafficSecret);
if (rv != SECSuccess) {
return SECFailure;
}
- rv = tls13_DeriveSecret(ss, ss->ssl3.hs.currentSecret,
- NULL, kHkdfLabelExporterMasterSecret,
- NULL, &ss->ssl3.hs.exporterSecret);
+ rv = tls13_DeriveSecretWrap(ss, ss->ssl3.hs.currentSecret,
+ NULL, kHkdfLabelExporterMasterSecret,
+ keylogLabelExporterSecret,
+ &ss->ssl3.hs.exporterSecret);
if (rv != SECSuccess) {
return SECFailure;
}
@@ -873,30 +1153,20 @@ static SECStatus
tls13_ComputeFinalSecrets(sslSocket *ss)
{
SECStatus rv;
- PK11SymKey *resumptionMasterSecret = NULL;
- PORT_Assert(!ss->ssl3.crSpec->master_secret);
- PORT_Assert(!ss->ssl3.cwSpec->master_secret);
+ PORT_Assert(!ss->ssl3.crSpec->masterSecret);
+ PORT_Assert(!ss->ssl3.cwSpec->masterSecret);
- rv = tls13_DeriveSecret(ss, ss->ssl3.hs.currentSecret,
- NULL, kHkdfLabelResumptionMasterSecret,
- NULL, &resumptionMasterSecret);
+ rv = tls13_DeriveSecretWrap(ss, ss->ssl3.hs.currentSecret,
+ NULL, kHkdfLabelResumptionMasterSecret,
+ NULL,
+ &ss->ssl3.hs.resumptionMasterSecret);
PK11_FreeSymKey(ss->ssl3.hs.currentSecret);
ss->ssl3.hs.currentSecret = NULL;
if (rv != SECSuccess) {
return SECFailure;
}
- /* This is pretty gross. TLS 1.3 uses a number of master secrets:
- * The master secret to generate the keys and then the resumption
- * master secret for future connections. To make this work without
- * refactoring too much of the SSLv3 code, we store the RMS in
- * |crSpec->master_secret| and |cwSpec->master_secret|.
- */
- ss->ssl3.crSpec->master_secret = resumptionMasterSecret;
- ss->ssl3.cwSpec->master_secret =
- PK11_ReferenceSymKey(ss->ssl3.crSpec->master_secret);
-
return SECSuccess;
}
@@ -909,6 +1179,8 @@ tls13_RestoreCipherInfo(sslSocket *ss, sslSessionID *sid)
*/
ss->sec.authType = sid->authType;
ss->sec.authKeyBits = sid->authKeyBits;
+ ss->sec.originalKeaGroup = ssl_LookupNamedGroup(sid->keaGroup);
+ ss->sec.signatureScheme = sid->sigScheme;
}
/* Check whether resumption-PSK is allowed. */
@@ -961,6 +1233,10 @@ tls13_CanNegotiateZeroRtt(sslSocket *ss, const sslSessionID *sid)
&sid->u.ssl3.alpnSelection) != 0)
return PR_FALSE;
+ if (tls13_IsReplay(ss, sid)) {
+ return PR_FALSE;
+ }
+
return PR_TRUE;
}
@@ -1046,7 +1322,9 @@ tls13_FindKeyShareEntry(sslSocket *ss, const sslNamedGroupDef *group)
}
static SECStatus
-tls13_NegotiateKeyExchange(sslSocket *ss, TLS13KeyShareEntry **clientShare)
+tls13_NegotiateKeyExchange(sslSocket *ss,
+ const sslNamedGroupDef **requestedGroup,
+ TLS13KeyShareEntry **clientShare)
{
unsigned int index;
TLS13KeyShareEntry *entry = NULL;
@@ -1126,13 +1404,16 @@ tls13_NegotiateKeyExchange(sslSocket *ss, TLS13KeyShareEntry **clientShare)
SSL_TRC(3, ("%d: TLS13[%d]: group = %d", SSL_GETPID(), ss->fd,
preferredGroup->name));
- if (!entry) {
- return tls13_SendHelloRetryRequest(ss, preferredGroup);
+ /* Either provide a share, or provide a group that should be requested in a
+ * HelloRetryRequest, but not both. */
+ if (entry) {
+ PORT_Assert(preferredGroup == entry->group);
+ *clientShare = entry;
+ *requestedGroup = NULL;
+ } else {
+ *clientShare = NULL;
+ *requestedGroup = preferredGroup;
}
-
- PORT_Assert(preferredGroup == entry->group);
- *clientShare = entry;
-
return SECSuccess;
}
@@ -1190,8 +1471,8 @@ tls13_SelectServerCert(sslSocket *ss)
rv = ssl_PickSignatureScheme(ss,
cert->serverKeyPair->pubKey,
cert->serverKeyPair->privKey,
- ss->xtnData.clientSigSchemes,
- ss->xtnData.numClientSigScheme,
+ ss->xtnData.sigSchemes,
+ ss->xtnData.numSigSchemes,
PR_FALSE);
if (rv == SECSuccess) {
/* Found one. */
@@ -1208,6 +1489,62 @@ tls13_SelectServerCert(sslSocket *ss)
return SECFailure;
}
+/* Note: |requestedGroup| is non-NULL when we send a key_share extension. */
+static SECStatus
+tls13_MaybeSendHelloRetry(sslSocket *ss, const sslNamedGroupDef *requestedGroup,
+ PRBool *hrrSent)
+{
+ SSLHelloRetryRequestAction action = ssl_hello_retry_accept;
+ PRUint8 token[256] = { 0 };
+ unsigned int tokenLen = 0;
+ SECStatus rv;
+
+ if (ss->hrrCallback) {
+ action = ss->hrrCallback(!ss->ssl3.hs.helloRetry,
+ ss->xtnData.applicationToken.data,
+ ss->xtnData.applicationToken.len,
+ token, &tokenLen, sizeof(token),
+ ss->hrrCallbackArg);
+ }
+
+ /* These use SSL3_SendAlert directly to avoid an assertion in
+ * tls13_FatalError(), which is ordinarily OK. */
+ if (action == ssl_hello_retry_request && ss->ssl3.hs.helloRetry) {
+ (void)SSL3_SendAlert(ss, alert_fatal, internal_error);
+ PORT_SetError(SSL_ERROR_APP_CALLBACK_ERROR);
+ return SECFailure;
+ }
+
+ if (action != ssl_hello_retry_request && tokenLen) {
+ (void)SSL3_SendAlert(ss, alert_fatal, internal_error);
+ PORT_SetError(SSL_ERROR_APP_CALLBACK_ERROR);
+ return SECFailure;
+ }
+
+ if (tokenLen > sizeof(token)) {
+ (void)SSL3_SendAlert(ss, alert_fatal, internal_error);
+ PORT_SetError(SSL_ERROR_APP_CALLBACK_ERROR);
+ return SECFailure;
+ }
+
+ if (action == ssl_hello_retry_fail) {
+ FATAL_ERROR(ss, SSL_ERROR_APPLICATION_ABORT, handshake_failure);
+ return SECFailure;
+ }
+
+ if (!requestedGroup && action != ssl_hello_retry_request) {
+ return SECSuccess;
+ }
+
+ rv = tls13_SendHelloRetryRequest(ss, requestedGroup, token, tokenLen);
+ if (rv != SECSuccess) {
+ return SECFailure; /* Code already set. */
+ }
+
+ *hrrSent = PR_TRUE;
+ return SECSuccess;
+}
+
static SECStatus
tls13_NegotiateAuthentication(sslSocket *ss)
{
@@ -1237,13 +1574,19 @@ tls13_NegotiateAuthentication(sslSocket *ss)
SECStatus
tls13_HandleClientHelloPart2(sslSocket *ss,
const SECItem *suites,
- sslSessionID *sid)
+ sslSessionID *sid,
+ const PRUint8 *msg,
+ unsigned int len)
{
SECStatus rv;
SSL3Statistics *ssl3stats = SSL_GetStatistics();
+ const sslNamedGroupDef *requestedGroup = NULL;
TLS13KeyShareEntry *clientShare = NULL;
- int j;
- ssl3CipherSuite previousCipherSuite;
+ ssl3CipherSuite previousCipherSuite = 0;
+ const sslNamedGroupDef *previousGroup = NULL;
+ PRBool hrr = PR_FALSE;
+
+ ss->ssl3.hs.endOfFlight = PR_TRUE;
if (ssl3_ExtensionNegotiated(ss, ssl_tls13_early_data_xtn)) {
ss->ssl3.hs.zeroRttState = ssl_0rtt_sent;
@@ -1251,24 +1594,59 @@ tls13_HandleClientHelloPart2(sslSocket *ss,
#ifndef PARANOID
/* Look for a matching cipher suite. */
- j = ssl3_config_match_init(ss);
- if (j <= 0) { /* no ciphers are working/supported by PK11 */
+ if (ssl3_config_match_init(ss) == 0) { /* no ciphers are working/supported by PK11 */
FATAL_ERROR(ss, PORT_GetError(), internal_error);
goto loser;
}
#endif
- previousCipherSuite = ss->ssl3.hs.cipher_suite;
+ /* Negotiate cipher suite. */
rv = ssl3_NegotiateCipherSuite(ss, suites, PR_FALSE);
if (rv != SECSuccess) {
FATAL_ERROR(ss, SSL_ERROR_NO_CYPHER_OVERLAP, handshake_failure);
goto loser;
}
+
/* If we are going around again, then we should make sure that the cipher
* suite selection doesn't change. That's a sign of client shennanigans. */
- if (ss->ssl3.hs.helloRetry &&
- ss->ssl3.hs.cipher_suite != previousCipherSuite) {
- FATAL_ERROR(ss, SSL_ERROR_RX_MALFORMED_CLIENT_HELLO, handshake_failure);
+ if (ss->ssl3.hs.helloRetry) {
+
+ /* Update sequence numbers before checking the cookie so that any alerts
+ * we generate are sent with the right sequence numbers. */
+ if (IS_DTLS(ss)) {
+ /* Count the first ClientHello and the HelloRetryRequest. */
+ ss->ssl3.hs.sendMessageSeq = 1;
+ ss->ssl3.hs.recvMessageSeq = 1;
+ ssl_GetSpecWriteLock(ss);
+ /* Increase the write sequence number. The read sequence number
+ * will be reset after this to early data or handshake. */
+ ss->ssl3.cwSpec->seqNum = 1;
+ ssl_ReleaseSpecWriteLock(ss);
+ }
+
+ if (!ssl3_ExtensionNegotiated(ss, ssl_tls13_cookie_xtn) ||
+ !ss->xtnData.cookie.len) {
+ FATAL_ERROR(ss, SSL_ERROR_MISSING_COOKIE_EXTENSION,
+ missing_extension);
+ goto loser;
+ }
+ PRINT_BUF(50, (ss, "Client sent cookie",
+ ss->xtnData.cookie.data, ss->xtnData.cookie.len));
+
+ rv = tls13_RecoverHashState(ss, ss->xtnData.cookie.data,
+ ss->xtnData.cookie.len,
+ &previousCipherSuite,
+ &previousGroup);
+ if (rv != SECSuccess) {
+ FATAL_ERROR(ss, SSL_ERROR_BAD_2ND_CLIENT_HELLO, illegal_parameter);
+ goto loser;
+ }
+ }
+
+ /* Now merge the ClientHello into the hash state. */
+ rv = ssl_HashHandshakeMessage(ss, ssl_hs_client_hello, msg, len);
+ if (rv != SECSuccess) {
+ FATAL_ERROR(ss, SEC_ERROR_LIBRARY_FAILURE, internal_error);
goto loser;
}
@@ -1296,13 +1674,50 @@ tls13_HandleClientHelloPart2(sslSocket *ss,
}
/* Select key exchange. */
- rv = tls13_NegotiateKeyExchange(ss, &clientShare);
+ rv = tls13_NegotiateKeyExchange(ss, &requestedGroup, &clientShare);
if (rv != SECSuccess) {
goto loser;
}
+ /* We should get either one of these, but not both. */
+ PORT_Assert((requestedGroup && !clientShare) ||
+ (!requestedGroup && clientShare));
- /* If we didn't find a client key share, we have to retry. */
- if (!clientShare) {
+ /* After HelloRetryRequest, check consistency of cipher and group. */
+ if (ss->ssl3.hs.helloRetry) {
+ PORT_Assert(previousCipherSuite);
+ if (ss->ssl3.hs.cipher_suite != previousCipherSuite) {
+ FATAL_ERROR(ss, SSL_ERROR_BAD_2ND_CLIENT_HELLO,
+ illegal_parameter);
+ goto loser;
+ }
+ if (!clientShare) {
+ FATAL_ERROR(ss, SSL_ERROR_BAD_2ND_CLIENT_HELLO,
+ illegal_parameter);
+ goto loser;
+ }
+
+ /* If we requested a new key share, check that the client provided just
+ * one of the right type. */
+ if (previousGroup) {
+ if (PR_PREV_LINK(&ss->xtnData.remoteKeyShares) !=
+ PR_NEXT_LINK(&ss->xtnData.remoteKeyShares)) {
+ FATAL_ERROR(ss, SSL_ERROR_BAD_2ND_CLIENT_HELLO,
+ illegal_parameter);
+ goto loser;
+ }
+ if (clientShare->group != previousGroup) {
+ FATAL_ERROR(ss, SSL_ERROR_BAD_2ND_CLIENT_HELLO,
+ illegal_parameter);
+ goto loser;
+ }
+ }
+ }
+
+ rv = tls13_MaybeSendHelloRetry(ss, requestedGroup, &hrr);
+ if (rv != SECSuccess) {
+ goto loser;
+ }
+ if (hrr) {
if (sid) { /* Free the sid. */
ss->sec.uncache(sid);
ssl_FreeSID(sid);
@@ -1373,14 +1788,17 @@ tls13_HandleClientHelloPart2(sslSocket *ss,
if (ss->statelessResume) {
SSL3Hashes hashes;
- rv = tls13_ComputePskBinderHash(ss, ss->xtnData.pskBinderPrefixLen,
- &hashes);
+ PORT_Assert(ss->ssl3.hs.messages.len > ss->xtnData.pskBindersLen);
+ rv = tls13_ComputePskBinderHash(
+ ss,
+ ss->ssl3.hs.messages.len - ss->xtnData.pskBindersLen,
+ &hashes);
if (rv != SECSuccess) {
FATAL_ERROR(ss, SEC_ERROR_LIBRARY_FAILURE, internal_error);
goto loser;
}
- rv = tls13_VerifyFinished(ss, client_hello,
+ rv = tls13_VerifyFinished(ss, ssl_hs_client_hello,
ss->ssl3.hs.pskBinderKey,
ss->xtnData.pskBinder.data,
ss->xtnData.pskBinder.len,
@@ -1429,11 +1847,7 @@ tls13_HandleClientHelloPart2(sslSocket *ss,
sid = NULL;
if (ss->ssl3.hs.zeroRttState == ssl_0rtt_accepted) {
- rv = tls13_DeriveSecret(ss, ss->ssl3.hs.currentSecret,
- kHkdfLabelClient,
- kHkdfLabelEarlyTrafficSecret,
- NULL, /* Current running hash. */
- &ss->ssl3.hs.clientEarlyTrafficSecret);
+ rv = tls13_DeriveEarlySecrets(ss);
if (rv != SECSuccess) {
FATAL_ERROR(ss, SEC_ERROR_LIBRARY_FAILURE, internal_error);
return SECFailure;
@@ -1458,70 +1872,143 @@ loser:
return SECFailure;
}
-static SECStatus
-tls13_SendHelloRetryRequest(sslSocket *ss, const sslNamedGroupDef *selectedGroup)
+SECStatus
+SSLExp_HelloRetryRequestCallback(PRFileDesc *fd,
+ SSLHelloRetryRequestCallback cb, void *arg)
{
- SECStatus rv;
-
- SSL_TRC(3, ("%d: TLS13[%d]: send hello retry request handshake",
- SSL_GETPID(), ss->fd));
-
- PORT_Assert(ss->opt.noLocks || ssl_HaveSSL3HandshakeLock(ss));
-
- /* We asked already, but made no progress. */
- if (ss->ssl3.hs.helloRetry) {
- FATAL_ERROR(ss, SSL_ERROR_BAD_2ND_CLIENT_HELLO, illegal_parameter);
- return SECFailure;
+ sslSocket *ss = ssl_FindSocket(fd);
+ if (!ss) {
+ return SECFailure; /* Code already set. */
}
- ssl_GetXmitBufLock(ss);
- rv = ssl3_AppendHandshakeHeader(ss, hello_retry_request,
- 2 + /* version */
- 2 + /* extension length */
- 2 + /* group extension id */
- 2 + /* group extension length */
- 2 /* group */);
+ ss->hrrCallback = cb;
+ ss->hrrCallbackArg = arg;
+ return SECSuccess;
+}
+
+/*
+ * struct {
+ * ProtocolVersion server_version;
+ * CipherSuite cipher_suite;
+ * Extension extensions<2..2^16-1>;
+ * } HelloRetryRequest;
+ *
+ * Note: this function takes an empty buffer and returns
+ * a non-empty one on success, in which case the caller must
+ * eventually clean up.
+ */
+SECStatus
+tls13_ConstructHelloRetryRequest(sslSocket *ss,
+ ssl3CipherSuite cipherSuite,
+ const sslNamedGroupDef *selectedGroup,
+ PRUint8 *cookie, unsigned int cookieLen,
+ sslBuffer *buffer)
+{
+ SECStatus rv;
+ sslBuffer extensionsBuf = SSL_BUFFER_EMPTY;
+ PORT_Assert(buffer->len == 0);
+
+ /* Note: cookie is pointing to a stack variable, so is only valid
+ * now. */
+ ss->xtnData.selectedGroup = selectedGroup;
+ ss->xtnData.cookie.data = cookie;
+ ss->xtnData.cookie.len = cookieLen;
+ rv = ssl_ConstructExtensions(ss, &extensionsBuf,
+ ssl_hs_hello_retry_request);
if (rv != SECSuccess) {
- FATAL_ERROR(ss, SEC_ERROR_LIBRARY_FAILURE, internal_error);
goto loser;
}
+ /* These extensions can't be empty. */
+ PORT_Assert(SSL_BUFFER_LEN(&extensionsBuf) > 0);
- rv = ssl3_AppendHandshakeNumber(
- ss, tls13_EncodeDraftVersion(ss->version), 2);
+ /* Clean up cookie so we're not pointing at random memory. */
+ ss->xtnData.cookie.data = NULL;
+ ss->xtnData.cookie.len = 0;
+
+ rv = ssl_ConstructServerHello(ss, PR_TRUE, &extensionsBuf, buffer);
if (rv != SECSuccess) {
- FATAL_ERROR(ss, SEC_ERROR_LIBRARY_FAILURE, internal_error);
goto loser;
}
+ sslBuffer_Clear(&extensionsBuf);
+ return SECSuccess;
+
+loser:
+ sslBuffer_Clear(&extensionsBuf);
+ sslBuffer_Clear(buffer);
+ return SECFailure;
+}
+
+static SECStatus
+tls13_SendHelloRetryRequest(sslSocket *ss,
+ const sslNamedGroupDef *requestedGroup,
+ const PRUint8 *appToken, unsigned int appTokenLen)
+{
+ SECStatus rv;
+ unsigned int cookieLen;
+ PRUint8 cookie[1024];
+ sslBuffer messageBuf = SSL_BUFFER_EMPTY;
- /* Length of extensions. */
- rv = ssl3_AppendHandshakeNumber(ss, 2 + 2 + 2, 2);
+ SSL_TRC(3, ("%d: TLS13[%d]: send hello retry request handshake",
+ SSL_GETPID(), ss->fd));
+
+ PORT_Assert(ss->opt.noLocks || ssl_HaveSSL3HandshakeLock(ss));
+
+ /* Compute the cookie we are going to need. */
+ rv = tls13_MakeHrrCookie(ss, requestedGroup,
+ appToken, appTokenLen,
+ cookie, &cookieLen, sizeof(cookie));
if (rv != SECSuccess) {
FATAL_ERROR(ss, SEC_ERROR_LIBRARY_FAILURE, internal_error);
- goto loser;
+ return SECFailure;
}
- /* Key share extension - currently the only reason we send this. */
- rv = ssl3_AppendHandshakeNumber(ss, ssl_tls13_key_share_xtn, 2);
+ /* Now build the body of the message. */
+ rv = tls13_ConstructHelloRetryRequest(ss, ss->ssl3.hs.cipher_suite,
+ requestedGroup,
+ cookie, cookieLen, &messageBuf);
if (rv != SECSuccess) {
FATAL_ERROR(ss, SEC_ERROR_LIBRARY_FAILURE, internal_error);
- goto loser;
+ return SECFailure;
}
- /* Key share extension length. */
- rv = ssl3_AppendHandshakeNumber(ss, 2, 2);
+
+ /* And send it. */
+ ssl_GetXmitBufLock(ss);
+ rv = ssl3_AppendHandshakeHeader(ss, ssl_hs_server_hello,
+ SSL_BUFFER_LEN(&messageBuf));
if (rv != SECSuccess) {
- FATAL_ERROR(ss, SEC_ERROR_LIBRARY_FAILURE, internal_error);
goto loser;
}
- rv = ssl3_AppendHandshakeNumber(ss, selectedGroup->name, 2);
+ rv = ssl3_AppendBufferToHandshake(ss, &messageBuf);
if (rv != SECSuccess) {
- FATAL_ERROR(ss, SEC_ERROR_LIBRARY_FAILURE, internal_error);
goto loser;
}
+ sslBuffer_Clear(&messageBuf); /* Done with messageBuf */
- rv = ssl3_FlushHandshake(ss, 0);
- if (rv != SECSuccess) {
- goto loser; /* error code set by ssl3_FlushHandshake */
+ if (ss->ssl3.hs.fakeSid.len) {
+ PRInt32 sent;
+
+ PORT_Assert(!IS_DTLS(ss));
+ rv = ssl3_SendChangeCipherSpecsInt(ss);
+ if (rv != SECSuccess) {
+ goto loser;
+ }
+ /* ssl3_SendChangeCipherSpecsInt() only flushes to the output buffer, so we
+ * have to force a send. */
+ sent = ssl_SendSavedWriteData(ss);
+ if (sent < 0 && PORT_GetError() != PR_WOULD_BLOCK_ERROR) {
+ PORT_SetError(SSL_ERROR_SOCKET_WRITE_FAILURE);
+ goto loser;
+ }
+ } else {
+ rv = ssl3_FlushHandshake(ss, 0);
+ if (rv != SECSuccess) {
+ goto loser; /* error code set by ssl3_FlushHandshake */
+ }
}
+
+ /* We depend on this being exactly one record and one message. */
+ PORT_Assert(!IS_DTLS(ss) || (ss->ssl3.hs.sendMessageSeq == 1 &&
+ ss->ssl3.cwSpec->seqNum == 1));
ssl_ReleaseXmitBufLock(ss);
ss->ssl3.hs.helloRetry = PR_TRUE;
@@ -1535,6 +2022,7 @@ tls13_SendHelloRetryRequest(sslSocket *ss, const sslNamedGroupDef *selectedGroup
return SECSuccess;
loser:
+ sslBuffer_Clear(&messageBuf);
ssl_ReleaseXmitBufLock(ss);
return SECFailure;
}
@@ -1606,67 +2094,96 @@ static SECStatus
tls13_SendCertificateRequest(sslSocket *ss)
{
SECStatus rv;
- unsigned int calen;
- SECItem *names;
- unsigned int nnames;
- SECItem *name;
- int i;
- PRUint8 sigSchemes[MAX_SIGNATURE_SCHEMES * 2];
- unsigned int sigSchemesLength = 0;
- int length;
+ sslBuffer extensionBuf = SSL_BUFFER_EMPTY;
SSL_TRC(3, ("%d: TLS13[%d]: begin send certificate_request",
SSL_GETPID(), ss->fd));
- rv = ssl3_EncodeSigAlgs(ss, sigSchemes, sizeof(sigSchemes),
- &sigSchemesLength);
+ rv = ssl_ConstructExtensions(ss, &extensionBuf, ssl_hs_certificate_request);
if (rv != SECSuccess) {
- return rv;
+ return SECFailure; /* Code already set. */
}
+ /* We should always have at least one of these. */
+ PORT_Assert(SSL_BUFFER_LEN(&extensionBuf) > 0);
- rv = ssl_GetCertificateRequestCAs(ss, &calen, &names, &nnames);
+ rv = ssl3_AppendHandshakeHeader(ss, ssl_hs_certificate_request,
+ 1 + 0 + /* empty request context */
+ 2 + /* extension length */
+ SSL_BUFFER_LEN(&extensionBuf));
if (rv != SECSuccess) {
- return rv;
+ goto loser; /* err set by AppendHandshake. */
}
- length = 1 + 0 /* length byte for empty request context */ +
- 2 + sigSchemesLength + 2 + calen + 2;
- rv = ssl3_AppendHandshakeHeader(ss, certificate_request, length);
- if (rv != SECSuccess) {
- return rv; /* err set by AppendHandshake. */
- }
+ /* Context. */
rv = ssl3_AppendHandshakeNumber(ss, 0, 1);
if (rv != SECSuccess) {
- return rv; /* err set by AppendHandshake. */
+ goto loser; /* err set by AppendHandshake. */
}
- rv = ssl3_AppendHandshakeVariable(ss, sigSchemes, sigSchemesLength, 2);
+ /* Extensions. */
+ rv = ssl3_AppendBufferToHandshakeVariable(ss, &extensionBuf, 2);
if (rv != SECSuccess) {
- return rv; /* err set by AppendHandshake. */
+ goto loser; /* err set by AppendHandshake. */
}
- rv = ssl3_AppendHandshakeNumber(ss, calen, 2);
+
+ sslBuffer_Clear(&extensionBuf);
+ return SECSuccess;
+
+loser:
+ sslBuffer_Clear(&extensionBuf);
+ return SECFailure;
+}
+
+/* [draft-ietf-tls-tls13; S 4.4.1] says:
+ *
+ * Transcript-Hash(ClientHello1, HelloRetryRequest, ... MN) =
+ * Hash(message_hash || // Handshake type
+ * 00 00 Hash.length || // Handshake message length
+ * Hash(ClientHello1) || // Hash of ClientHello1
+ * HelloRetryRequest ... MN)
+ */
+static SECStatus
+tls13_ReinjectHandshakeTranscript(sslSocket *ss)
+{
+ SSL3Hashes hashes;
+ SECStatus rv;
+
+ // First compute the hash.
+ rv = tls13_ComputeHash(ss, &hashes,
+ ss->ssl3.hs.messages.buf,
+ ss->ssl3.hs.messages.len);
if (rv != SECSuccess) {
- return rv; /* err set by AppendHandshake. */
- }
- for (i = 0, name = names; i < nnames; i++, name++) {
- rv = ssl3_AppendHandshakeVariable(ss, name->data, name->len, 2);
- if (rv != SECSuccess) {
- return rv; /* err set by AppendHandshake. */
- }
+ return SECFailure;
}
- rv = ssl3_AppendHandshakeNumber(ss, 0, 2);
+
+ // Now re-init the handshake.
+ ssl3_RestartHandshakeHashes(ss);
+
+ // And reinject the message.
+ rv = ssl_HashHandshakeMessage(ss, ssl_hs_message_hash,
+ hashes.u.raw, hashes.len);
if (rv != SECSuccess) {
- return rv; /* err set by AppendHandshake. */
+ return SECFailure;
}
return SECSuccess;
}
+static unsigned int
+ssl_ListCount(PRCList *list)
+{
+ unsigned int c = 0;
+ PRCList *cur;
+ for (cur = PR_NEXT_LINK(list); cur != list; cur = PR_NEXT_LINK(cur)) {
+ ++c;
+ }
+ return c;
+}
+
SECStatus
-tls13_HandleHelloRetryRequest(sslSocket *ss, PRUint8 *b, PRUint32 length)
+tls13_HandleHelloRetryRequest(sslSocket *ss, const PRUint8 *savedMsg,
+ PRUint32 savedLength)
{
SECStatus rv;
- PRUint32 tmp;
- SSL3ProtocolVersion version;
SSL_TRC(3, ("%d: TLS13[%d]: handle hello retry request",
SSL_GETPID(), ss->fd));
@@ -1679,84 +2196,77 @@ tls13_HandleHelloRetryRequest(sslSocket *ss, PRUint8 *b, PRUint32 length)
unexpected_message);
return SECFailure;
}
-
- /* Client only. */
- rv = TLS13_CHECK_HS_STATE(ss, SSL_ERROR_RX_UNEXPECTED_HELLO_RETRY_REQUEST,
- wait_server_hello);
- if (rv != SECSuccess) {
- return SECFailure;
- }
-
- /* Fool me once, shame on you; fool me twice... */
- if (ss->ssl3.hs.helloRetry) {
- FATAL_ERROR(ss, SSL_ERROR_RX_UNEXPECTED_HELLO_RETRY_REQUEST,
- unexpected_message);
- return SECFailure;
- }
+ PORT_Assert(ss->ssl3.hs.ws == wait_server_hello);
if (ss->ssl3.hs.zeroRttState == ssl_0rtt_sent) {
ss->ssl3.hs.zeroRttState = ssl_0rtt_ignored;
/* Restore the null cipher spec for writing. */
ssl_GetSpecWriteLock(ss);
- tls13_CipherSpecRelease(ss->ssl3.cwSpec);
- ss->ssl3.cwSpec = ss->ssl3.crSpec;
- PORT_Assert(ss->ssl3.cwSpec->cipher_def->cipher == cipher_null);
+ ssl_CipherSpecRelease(ss->ssl3.cwSpec);
+ ss->ssl3.cwSpec = ssl_FindCipherSpecByEpoch(ss, CipherSpecWrite,
+ TrafficKeyClearText);
+ PORT_Assert(ss->ssl3.cwSpec);
ssl_ReleaseSpecWriteLock(ss);
} else {
PORT_Assert(ss->ssl3.hs.zeroRttState == ssl_0rtt_none);
}
- /* Version. */
- rv = ssl_ClientReadVersion(ss, &b, &length, &version);
- if (rv != SECSuccess) {
- return SECFailure; /* alert already sent */
- }
- if (version > ss->vrange.max || version < SSL_LIBRARY_VERSION_TLS_1_3) {
- FATAL_ERROR(ss, SSL_ERROR_RX_MALFORMED_HELLO_RETRY_REQUEST,
- protocol_version);
- return SECFailure;
- }
-
- /* Extensions. */
- rv = ssl3_ConsumeHandshakeNumber(ss, &tmp, 2, &b, &length);
- if (rv != SECSuccess) {
- return SECFailure; /* error code already set */
- }
- /* Extensions must be non-empty and use the remainder of the message.
- * This means that a HelloRetryRequest cannot be a no-op: we must have an
- * extension, it must be one that we understand and recognize as being valid
- * for HelloRetryRequest, and all the extensions we permit cause us to
- * modify our ClientHello in some way. */
- if (!tmp || tmp != length) {
+ /* Extensions must contain more than just supported_versions. This will
+ * ensure that a HelloRetryRequest isn't a no-op: we must have at least two
+ * extensions, supported_versions plus one other. That other must be one
+ * that we understand and recognize as being valid for HelloRetryRequest,
+ * and all the extensions we permit cause us to modify our second
+ * ClientHello in some meaningful way. */
+ if (ssl_ListCount(&ss->ssl3.hs.remoteExtensions) <= 1) {
FATAL_ERROR(ss, SSL_ERROR_RX_MALFORMED_HELLO_RETRY_REQUEST,
decode_error);
return SECFailure;
}
- rv = ssl3_HandleExtensions(ss, &b, &length, hello_retry_request);
+ rv = ssl3_HandleParsedExtensions(ss, ssl_hs_hello_retry_request);
+ ssl3_DestroyRemoteExtensions(&ss->ssl3.hs.remoteExtensions);
if (rv != SECSuccess) {
return SECFailure; /* Error code set below */
}
ss->ssl3.hs.helloRetry = PR_TRUE;
+ rv = tls13_ReinjectHandshakeTranscript(ss);
+ if (rv != SECSuccess) {
+ return rv;
+ }
+
+ rv = ssl_HashHandshakeMessage(ss, ssl_hs_server_hello,
+ savedMsg, savedLength);
+ if (rv != SECSuccess) {
+ return SECFailure;
+ }
ssl_GetXmitBufLock(ss);
+ if (ss->opt.enableTls13CompatMode && !IS_DTLS(ss) &&
+ ss->ssl3.hs.zeroRttState == ssl_0rtt_none) {
+ rv = ssl3_SendChangeCipherSpecsInt(ss);
+ if (rv != SECSuccess) {
+ goto loser;
+ }
+ }
rv = ssl3_SendClientHello(ss, client_hello_retry);
- ssl_ReleaseXmitBufLock(ss);
if (rv != SECSuccess) {
- return SECFailure;
+ goto loser;
}
+ ssl_ReleaseXmitBufLock(ss);
return SECSuccess;
+
+loser:
+ ssl_ReleaseXmitBufLock(ss);
+ return SECFailure;
}
static SECStatus
tls13_HandleCertificateRequest(sslSocket *ss, PRUint8 *b, PRUint32 length)
{
SECStatus rv;
- TLS13CertificateRequest *certRequest = NULL;
SECItem context = { siBuffer, NULL, 0 };
- PLArenaPool *arena;
SECItem extensionsData = { siBuffer, NULL, 0 };
SSL_TRC(3, ("%d: TLS13[%d]: handle certificate_request sequence",
@@ -1775,71 +2285,51 @@ tls13_HandleCertificateRequest(sslSocket *ss, PRUint8 *b, PRUint32 length)
PORT_Assert(ss->ssl3.clientCertChain == NULL);
PORT_Assert(ss->ssl3.clientCertificate == NULL);
PORT_Assert(ss->ssl3.clientPrivateKey == NULL);
- PORT_Assert(ss->ssl3.hs.certificateRequest == NULL);
+ PORT_Assert(!ss->ssl3.hs.clientCertRequested);
- arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
- if (!arena) {
- FATAL_ERROR(ss, SEC_ERROR_LIBRARY_FAILURE, internal_error);
+ rv = ssl3_ConsumeHandshakeVariable(ss, &context, 1, &b, &length);
+ if (rv != SECSuccess) {
return SECFailure;
}
- rv = ssl3_ConsumeHandshakeVariable(ss, &context, 1, &b, &length);
- if (rv != SECSuccess)
- goto loser;
-
/* We don't support post-handshake client auth, the certificate request
- * context must always be null. */
+ * context must always be empty. */
if (context.len > 0) {
FATAL_ERROR(ss, SSL_ERROR_RX_MALFORMED_CERT_REQUEST, illegal_parameter);
- goto loser;
- }
-
- certRequest = PORT_ArenaZNew(arena, TLS13CertificateRequest);
- if (!certRequest)
- goto loser;
- certRequest->arena = arena;
- certRequest->ca_list.arena = arena;
-
- rv = ssl_ParseSignatureSchemes(ss, arena,
- &certRequest->signatureSchemes,
- &certRequest->signatureSchemeCount,
- &b, &length);
- if (rv != SECSuccess || certRequest->signatureSchemeCount == 0) {
- FATAL_ERROR(ss, SSL_ERROR_RX_MALFORMED_CERT_REQUEST,
- decode_error);
- goto loser;
+ return SECFailure;
}
- rv = ssl3_ParseCertificateRequestCAs(ss, &b, &length, arena,
- &certRequest->ca_list);
- if (rv != SECSuccess)
- goto loser; /* alert already sent */
-
- /* Verify that the extensions are sane. */
rv = ssl3_ConsumeHandshakeVariable(ss, &extensionsData, 2, &b, &length);
if (rv != SECSuccess) {
- goto loser;
+ return SECFailure;
+ }
+
+ if (length) {
+ FATAL_ERROR(ss, SSL_ERROR_RX_MALFORMED_CERT_REQUEST, decode_error);
+ return SECFailure;
}
- /* Process all the extensions (note: currently a no-op). */
+ /* Process all the extensions. */
rv = ssl3_HandleExtensions(ss, &extensionsData.data, &extensionsData.len,
- certificate_request);
+ ssl_hs_certificate_request);
if (rv != SECSuccess) {
- goto loser;
+ return SECFailure;
}
- rv = SECITEM_CopyItem(arena, &certRequest->context, &context);
- if (rv != SECSuccess)
- goto loser;
+ if (!ss->xtnData.numSigSchemes) {
+ FATAL_ERROR(ss, SSL_ERROR_MISSING_SIGNATURE_ALGORITHMS_EXTENSION,
+ missing_extension);
+ return SECFailure;
+ }
- TLS13_SET_HS_STATE(ss, wait_server_cert);
- ss->ssl3.hs.certificateRequest = certRequest;
+ rv = SECITEM_CopyItem(NULL, &ss->xtnData.certReqContext, &context);
+ if (rv != SECSuccess) {
+ return SECFailure;
+ }
+ ss->ssl3.hs.clientCertRequested = PR_TRUE;
+ TLS13_SET_HS_STATE(ss, wait_server_cert);
return SECSuccess;
-
-loser:
- PORT_FreeArena(arena, PR_FALSE);
- return SECFailure;
}
static SECStatus
@@ -1859,12 +2349,10 @@ tls13_SendEncryptedServerSequence(sslSocket *ss)
return SECFailure;
}
- ss->ssl3.hs.shortHeaders = ssl3_ExtensionNegotiated(
- ss, ssl_tls13_short_header_xtn);
-
if (ss->ssl3.hs.zeroRttState == ssl_0rtt_accepted) {
- rv = ssl3_RegisterExtensionSender(ss, &ss->xtnData, ssl_tls13_early_data_xtn,
- tls13_ServerSendEarlyDataXtn);
+ rv = ssl3_RegisterExtensionSender(ss, &ss->xtnData,
+ ssl_tls13_early_data_xtn,
+ ssl_SendEmptyExtension);
if (rv != SECSuccess) {
return SECFailure; /* Error code set already. */
}
@@ -1917,11 +2405,29 @@ tls13_SendServerHelloSequence(sslSocket *ss)
PORT_Assert(ss->opt.noLocks || ssl_HaveSSL3HandshakeLock(ss));
PORT_Assert(ss->opt.noLocks || ssl_HaveXmitBufLock(ss));
+ rv = ssl3_RegisterExtensionSender(ss, &ss->xtnData,
+ ssl_tls13_supported_versions_xtn,
+ tls13_ServerSendSupportedVersionsXtn);
+ if (rv != SECSuccess) {
+ return SECFailure;
+ }
+
rv = ssl3_SendServerHello(ss);
if (rv != SECSuccess) {
return rv; /* err code is set. */
}
+ if (ss->ssl3.hs.fakeSid.len) {
+ PORT_Assert(!IS_DTLS(ss));
+ SECITEM_FreeItem(&ss->ssl3.hs.fakeSid, PR_FALSE);
+ if (!ss->ssl3.hs.helloRetry) {
+ rv = ssl3_SendChangeCipherSpecsInt(ss);
+ if (rv != SECSuccess) {
+ return rv;
+ }
+ }
+ }
+
rv = tls13_SendEncryptedServerSequence(ss);
if (rv != SECSuccess) {
err = PORT_GetError();
@@ -1953,14 +2459,18 @@ tls13_SendServerHelloSequence(sslSocket *ss)
return SECFailure;
}
+ if (IS_DTLS(ss)) {
+ /* We need this for reading ACKs. */
+ ssl_CipherSpecAddRef(ss->ssl3.crSpec);
+ }
if (ss->ssl3.hs.zeroRttState == ssl_0rtt_accepted) {
- rv = tls13_SetCipherSpec(ss,
- TrafficKeyEarlyApplicationData,
+ rv = tls13_SetCipherSpec(ss, TrafficKeyEarlyApplicationData,
CipherSpecRead, PR_TRUE);
if (rv != SECSuccess) {
LOG_ERROR(ss, SEC_ERROR_LIBRARY_FAILURE);
return SECFailure;
}
+ TLS13_SET_HS_STATE(ss, wait_end_of_early_data);
} else {
PORT_Assert(ss->ssl3.hs.zeroRttState == ssl_0rtt_none ||
ss->ssl3.hs.zeroRttState == ssl_0rtt_ignored);
@@ -1972,11 +2482,12 @@ tls13_SendServerHelloSequence(sslSocket *ss)
LOG_ERROR(ss, SEC_ERROR_LIBRARY_FAILURE);
return SECFailure;
}
+ TLS13_SET_HS_STATE(ss,
+ ss->opt.requestCertificate ? wait_client_cert
+ : wait_finished);
}
- TLS13_SET_HS_STATE(ss,
- ss->opt.requestCertificate ? wait_client_cert
- : wait_finished);
+ ss->ssl3.hs.serverHelloTime = ssl_TimeUsec();
return SECSuccess;
}
@@ -2023,7 +2534,7 @@ tls13_HandleServerHelloPart2(sslSocket *ss)
SSL_AtomicIncrementLong(&ssl3stats->hsh_sid_stateless_resumes);
} else {
/* !PSK */
- if (ssl3_ClientExtensionAdvertised(ss, ssl_tls13_pre_shared_key_xtn)) {
+ if (ssl3_ExtensionAdvertised(ss, ssl_tls13_pre_shared_key_xtn)) {
SSL_AtomicIncrementLong(&ssl3stats->hsh_sid_cache_misses);
}
if (sid->cached == in_client_cache) {
@@ -2068,8 +2579,12 @@ tls13_HandleServerHelloPart2(sslSocket *ss)
return SECFailure; /* error code is set. */
}
- ss->ssl3.hs.shortHeaders = ssl3_ExtensionNegotiated(
- ss, ssl_tls13_short_header_xtn);
+ if (ss->ssl3.hs.zeroRttState == ssl_0rtt_sent) {
+ /* 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);
+ }
rv = tls13_SetCipherSpec(ss, TrafficKeyHandshake,
CipherSpecRead, PR_FALSE);
@@ -2171,8 +2686,7 @@ tls13_SendCertificate(sslSocket *ss)
int certChainLen = 0;
int i;
SECItem context = { siBuffer, NULL, 0 };
- PRInt32 extensionsLen = 0;
- PRUint32 maxBytes = 65535;
+ sslBuffer extensionBuf = SSL_BUFFER_EMPTY;
SSL_TRC(3, ("%d: TLS1.3[%d]: send certificate handshake",
SSL_GETPID(), ss->fd));
@@ -2195,26 +2709,28 @@ tls13_SendCertificate(sslSocket *ss)
ss->sec.localCert = CERT_DupCertificate(ss->ssl3.clientCertificate);
}
- /* Get the extensions length. This only applies to the leaf cert,
- * because we don't yet send extensions for non-leaf certs. */
- extensionsLen = ssl3_CallHelloExtensionSenders(
- ss, PR_FALSE, maxBytes, &ss->xtnData.certificateSenders[0]);
-
if (!ss->sec.isServer) {
- PORT_Assert(ss->ssl3.hs.certificateRequest);
- context = ss->ssl3.hs.certificateRequest->context;
+ PORT_Assert(ss->ssl3.hs.clientCertRequested);
+ context = ss->xtnData.certReqContext;
}
if (certChain) {
for (i = 0; i < certChain->len; i++) {
- certChainLen +=
- 3 + certChain->certs[i].len + /* cert length + cert */
- 2 + (!i ? extensionsLen : 0); /* extensions length + extensions */
+ /* Each cert is 3 octet length, cert, and extensions */
+ certChainLen += 3 + certChain->certs[i].len + 2;
+ }
+
+ /* Build the extensions. This only applies to the leaf cert, because we
+ * don't yet send extensions for non-leaf certs. */
+ rv = ssl_ConstructExtensions(ss, &extensionBuf, ssl_hs_certificate);
+ if (rv != SECSuccess) {
+ return SECFailure; /* code already set */
}
+ /* extensionBuf.len is only added once, for the leaf cert. */
+ certChainLen += SSL_BUFFER_LEN(&extensionBuf);
}
- rv = ssl3_AppendHandshakeHeader(ss, certificate,
- 1 + context.len +
- 3 + certChainLen);
+ rv = ssl3_AppendHandshakeHeader(ss, ssl_hs_certificate,
+ 1 + context.len + 3 + certChainLen);
if (rv != SECSuccess) {
return SECFailure; /* err set by AppendHandshake. */
}
@@ -2222,50 +2738,44 @@ tls13_SendCertificate(sslSocket *ss)
rv = ssl3_AppendHandshakeVariable(ss, context.data,
context.len, 1);
if (rv != SECSuccess) {
- return SECFailure; /* err set by AppendHandshake. */
+ goto loser; /* err set by AppendHandshake. */
}
rv = ssl3_AppendHandshakeNumber(ss, certChainLen, 3);
if (rv != SECSuccess) {
- return SECFailure; /* err set by AppendHandshake. */
+ goto loser; /* err set by AppendHandshake. */
}
if (certChain) {
for (i = 0; i < certChain->len; i++) {
- PRInt32 sentLen;
-
rv = ssl3_AppendHandshakeVariable(ss, certChain->certs[i].data,
certChain->certs[i].len, 3);
if (rv != SECSuccess) {
- return SECFailure; /* err set by AppendHandshake. */
+ goto loser; /* err set by AppendHandshake. */
}
if (i) {
/* Not end-entity. */
rv = ssl3_AppendHandshakeNumber(ss, 0, 2);
if (rv != SECSuccess) {
- return SECFailure; /* err set by AppendHandshake. */
+ goto loser; /* err set by AppendHandshake. */
}
continue;
}
/* End-entity, send extensions. */
- rv = ssl3_AppendHandshakeNumber(ss, extensionsLen, 2);
+ rv = ssl3_AppendBufferToHandshakeVariable(ss, &extensionBuf, 2);
if (rv != SECSuccess) {
- return SECFailure; /* err set by AppendHandshake. */
- }
-
- sentLen = ssl3_CallHelloExtensionSenders(
- ss, PR_TRUE, extensionsLen,
- &ss->xtnData.certificateSenders[0]);
- PORT_Assert(sentLen == extensionsLen);
- if (sentLen != extensionsLen) {
- LOG_ERROR(ss, SEC_ERROR_LIBRARY_FAILURE);
- return SECFailure;
+ goto loser; /* err set by AppendHandshake. */
}
}
}
+ sslBuffer_Clear(&extensionBuf);
return SECSuccess;
+
+loser:
+ sslBuffer_Clear(&extensionBuf);
+ return SECFailure;
}
static SECStatus
@@ -2293,7 +2803,7 @@ tls13_HandleCertificateEntry(sslSocket *ss, SECItem *data, PRBool first,
if (first && !ss->sec.isServer) {
rv = ssl3_HandleExtensions(ss, &extensionsData.data,
&extensionsData.len,
- certificate);
+ ssl_hs_certificate);
if (rv != SECSuccess) {
return SECFailure;
}
@@ -2351,6 +2861,11 @@ tls13_HandleCertificate(sslSocket *ss, PRUint8 *b, PRUint32 length)
if (rv != SECSuccess)
return SECFailure;
+ /* We can ignore any other cleartext from the client. */
+ if (ss->sec.isServer && IS_DTLS(ss)) {
+ ssl_CipherSpecReleaseByEpoch(ss, CipherSpecRead, TrafficKeyClearText);
+ dtls_ReceivedFirstMessageInFlight(ss);
+ }
/* Process the context string */
rv = ssl3_ConsumeHandshakeVariable(ss, &context, 1, &b, &length);
if (rv != SECSuccess)
@@ -2445,32 +2960,6 @@ tls13_HandleCertificate(sslSocket *ss, PRUint8 *b, PRUint32 length)
return ssl3_AuthCertificate(ss); /* sets ss->ssl3.hs.ws */
}
-void
-tls13_CipherSpecAddRef(ssl3CipherSpec *spec)
-{
- ++spec->refCt;
- SSL_TRC(10, ("%d: TLS13[-]: Increment ref ct for spec %d. new ct = %d",
- SSL_GETPID(), spec, spec->refCt));
-}
-
-/* This function is never called on a spec which is on the
- * cipherSpecs list. */
-void
-tls13_CipherSpecRelease(ssl3CipherSpec *spec)
-{
- PORT_Assert(spec->refCt > 0);
- --spec->refCt;
- SSL_TRC(10, ("%d: TLS13[-]: decrement refct for spec %d. phase=%s new ct = %d",
- SSL_GETPID(), spec, spec->phase, spec->refCt));
- if (!spec->refCt) {
- SSL_TRC(10, ("%d: TLS13[-]: Freeing spec %d. phase=%s",
- SSL_GETPID(), spec, spec->phase));
- PR_REMOVE_LINK(&spec->link);
- ssl3_DestroyCipherSpec(spec, PR_TRUE);
- PORT_Free(spec);
- }
-}
-
/* Add context to the hash functions as described in
[draft-ietf-tls-tls13; Section 4.9.1] */
SECStatus
@@ -2539,15 +3028,56 @@ loser:
* HKDF-Expand-Label(Secret, Label,
* Hash(Messages) + Hash(resumption_context), L))
*/
-static SECStatus
+SECStatus
tls13_DeriveSecret(sslSocket *ss, PK11SymKey *key,
- const char *prefix,
- const char *suffix,
+ const char *label,
+ unsigned int labelLen,
const SSL3Hashes *hashes,
PK11SymKey **dest)
{
SECStatus rv;
- SSL3Hashes hashesTmp;
+
+ rv = tls13_HkdfExpandLabel(key, tls13_GetHash(ss),
+ hashes->u.raw, hashes->len,
+ label, labelLen,
+ tls13_GetHkdfMechanism(ss),
+ tls13_GetHashSize(ss), dest);
+ if (rv != SECSuccess) {
+ LOG_ERROR(ss, SEC_ERROR_LIBRARY_FAILURE);
+ return SECFailure;
+ }
+ return SECSuccess;
+}
+
+/* Convenience wrapper for the empty hash. */
+SECStatus
+tls13_DeriveSecretNullHash(sslSocket *ss, PK11SymKey *key,
+ const char *label,
+ unsigned int labelLen,
+ PK11SymKey **dest)
+{
+ SSL3Hashes hashes;
+ SECStatus rv;
+ PRUint8 buf[] = { 0 };
+
+ rv = tls13_ComputeHash(ss, &hashes, buf, 0);
+ if (rv != SECSuccess) {
+ return SECFailure;
+ }
+
+ return tls13_DeriveSecret(ss, key, label, labelLen, &hashes, dest);
+}
+
+/* Convenience wrapper that lets us supply a separate prefix and suffix. */
+static SECStatus
+tls13_DeriveSecretWrap(sslSocket *ss, PK11SymKey *key,
+ const char *prefix,
+ const char *suffix,
+ const char *keylogLabel,
+ PK11SymKey **dest)
+{
+ SECStatus rv;
+ SSL3Hashes hashes;
char buf[100];
const char *label;
@@ -2566,25 +3096,22 @@ tls13_DeriveSecret(sslSocket *ss, PK11SymKey *key,
SSL_TRC(3, ("%d: TLS13[%d]: deriving secret '%s'",
SSL_GETPID(), ss->fd, label));
- if (!hashes) {
- rv = tls13_ComputeHandshakeHashes(ss, &hashesTmp);
- if (rv != SECSuccess) {
- PORT_Assert(0); /* Should never fail */
- ssl_MapLowLevelError(SEC_ERROR_LIBRARY_FAILURE);
- return SECFailure;
- }
- hashes = &hashesTmp;
+ rv = tls13_ComputeHandshakeHashes(ss, &hashes);
+ if (rv != SECSuccess) {
+ PORT_Assert(0); /* Should never fail */
+ ssl_MapLowLevelError(SEC_ERROR_LIBRARY_FAILURE);
+ return SECFailure;
}
- rv = tls13_HkdfExpandLabel(key, tls13_GetHash(ss),
- hashes->u.raw, hashes->len,
- label, strlen(label),
- tls13_GetHkdfMechanism(ss),
- tls13_GetHashSize(ss), dest);
+ rv = tls13_DeriveSecret(ss, key, label, strlen(label),
+ &hashes, dest);
if (rv != SECSuccess) {
- LOG_ERROR(ss, SEC_ERROR_LIBRARY_FAILURE);
return SECFailure;
}
+
+ if (keylogLabel) {
+ ssl3_RecordKeyLog(ss, keylogLabel, *dest);
+ }
return SECSuccess;
}
@@ -2592,49 +3119,41 @@ tls13_DeriveSecret(sslSocket *ss, PK11SymKey *key,
static SECStatus
tls13_DeriveTrafficKeys(sslSocket *ss, ssl3CipherSpec *spec,
TrafficKeyType type,
- CipherSpecDirection direction,
PRBool deleteSecret)
{
- size_t keySize = spec->cipher_def->key_size;
- size_t ivSize = spec->cipher_def->iv_size +
- spec->cipher_def->explicit_nonce_size; /* This isn't always going to
- * work, but it does for
- * AES-GCM */
- CK_MECHANISM_TYPE bulkAlgorithm = ssl3_Alg2Mech(spec->cipher_def->calg);
+ size_t keySize = spec->cipherDef->key_size;
+ size_t ivSize = spec->cipherDef->iv_size +
+ spec->cipherDef->explicit_nonce_size; /* This isn't always going to
+ * work, but it does for
+ * AES-GCM */
+ CK_MECHANISM_TYPE bulkAlgorithm = ssl3_Alg2Mech(spec->cipherDef->calg);
PK11SymKey **prkp = NULL;
PK11SymKey *prk = NULL;
- PRBool clientKey;
- ssl3KeyMaterial *target;
- const char *phase;
+ PRBool clientSecret;
SECStatus rv;
/* These labels are just used for debugging. */
static const char kHkdfPhaseEarlyApplicationDataKeys[] = "early application data";
static const char kHkdfPhaseHandshakeKeys[] = "handshake data";
static const char kHkdfPhaseApplicationDataKeys[] = "application data";
- if (ss->sec.isServer ^ (direction == CipherSpecWrite)) {
- clientKey = PR_TRUE;
- target = &spec->client;
- } else {
- clientKey = PR_FALSE;
- target = &spec->server;
- }
-
PORT_Assert(ss->opt.noLocks || ssl_HaveSSL3HandshakeLock(ss));
+ clientSecret = !tls13_UseServerSecret(ss, spec->direction);
switch (type) {
case TrafficKeyEarlyApplicationData:
- PORT_Assert(clientKey);
- phase = kHkdfPhaseEarlyApplicationDataKeys;
+ PORT_Assert(clientSecret);
prkp = &ss->ssl3.hs.clientEarlyTrafficSecret;
+ spec->phase = kHkdfPhaseEarlyApplicationDataKeys;
break;
case TrafficKeyHandshake:
- phase = kHkdfPhaseHandshakeKeys;
- prkp = clientKey ? &ss->ssl3.hs.clientHsTrafficSecret : &ss->ssl3.hs.serverHsTrafficSecret;
+ prkp = clientSecret ? &ss->ssl3.hs.clientHsTrafficSecret
+ : &ss->ssl3.hs.serverHsTrafficSecret;
+ spec->phase = kHkdfPhaseHandshakeKeys;
break;
case TrafficKeyApplicationData:
- phase = kHkdfPhaseApplicationDataKeys;
- prkp = clientKey ? &ss->ssl3.hs.clientTrafficSecret : &ss->ssl3.hs.serverTrafficSecret;
+ prkp = clientSecret ? &ss->ssl3.hs.clientTrafficSecret
+ : &ss->ssl3.hs.serverTrafficSecret;
+ spec->phase = kHkdfPhaseApplicationDataKeys;
break;
default:
LOG_ERROR(ss, SEC_ERROR_LIBRARY_FAILURE);
@@ -2644,17 +3163,15 @@ tls13_DeriveTrafficKeys(sslSocket *ss, ssl3CipherSpec *spec,
PORT_Assert(prkp != NULL);
prk = *prkp;
- SSL_TRC(3, ("%d: TLS13[%d]: deriving %s traffic keys phase='%s'",
- SSL_GETPID(), ss->fd,
- (direction == CipherSpecWrite) ? "write" : "read", phase));
- PORT_Assert(phase);
- spec->phase = phase;
+ SSL_TRC(3, ("%d: TLS13[%d]: deriving %s traffic keys epoch=%d (%s)",
+ SSL_GETPID(), ss->fd, SPEC_DIR(spec),
+ spec->epoch, spec->phase));
rv = tls13_HkdfExpandLabel(prk, tls13_GetHash(ss),
NULL, 0,
kHkdfPurposeKey, strlen(kHkdfPurposeKey),
bulkAlgorithm, keySize,
- &target->write_key);
+ &spec->keyMaterial.key);
if (rv != SECSuccess) {
LOG_ERROR(ss, SEC_ERROR_LIBRARY_FAILURE);
PORT_Assert(0);
@@ -2664,7 +3181,7 @@ tls13_DeriveTrafficKeys(sslSocket *ss, ssl3CipherSpec *spec,
rv = tls13_HkdfExpandLabelRaw(prk, tls13_GetHash(ss),
NULL, 0,
kHkdfPurposeIv, strlen(kHkdfPurposeIv),
- target->write_iv, ivSize);
+ spec->keyMaterial.iv, ivSize);
if (rv != SECSuccess) {
LOG_ERROR(ss, SEC_ERROR_LIBRARY_FAILURE);
PORT_Assert(0);
@@ -2681,38 +3198,111 @@ loser:
return SECFailure;
}
+void
+tls13_SetSpecRecordVersion(sslSocket *ss, ssl3CipherSpec *spec)
+{
+ /* Set the record version to pretend to be (D)TLS 1.2. */
+ if (IS_DTLS(ss)) {
+ spec->recordVersion = SSL_LIBRARY_VERSION_DTLS_1_2_WIRE;
+ } else {
+ spec->recordVersion = SSL_LIBRARY_VERSION_TLS_1_2;
+ }
+ SSL_TRC(10, ("%d: TLS13[%d]: set spec=%d record version to 0x%04x",
+ SSL_GETPID(), ss->fd, spec, spec->recordVersion));
+}
+
static SECStatus
-tls13_SetupPendingCipherSpec(sslSocket *ss)
+tls13_SetupPendingCipherSpec(sslSocket *ss, ssl3CipherSpec *spec)
{
- ssl3CipherSpec *pSpec;
ssl3CipherSuite suite = ss->ssl3.hs.cipher_suite;
- const ssl3BulkCipherDef *bulk = ssl_GetBulkCipherDef(
- ssl_LookupCipherSuiteDef(suite));
PORT_Assert(ss->opt.noLocks || ssl_HaveSSL3HandshakeLock(ss));
+ PORT_Assert(spec->epoch);
- ssl_GetSpecWriteLock(ss); /*******************************/
-
- pSpec = ss->ssl3.pwSpec;
/* Version isn't set when we send 0-RTT data. */
- pSpec->version = PR_MAX(SSL_LIBRARY_VERSION_TLS_1_3, ss->version);
+ spec->version = PR_MAX(SSL_LIBRARY_VERSION_TLS_1_3, ss->version);
+
+ ssl_SaveCipherSpec(ss, 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) {
+ ssl_CipherSpecAddRef(spec);
+ }
SSL_TRC(3, ("%d: TLS13[%d]: Set Pending Cipher Suite to 0x%04x",
SSL_GETPID(), ss->fd, suite));
- pSpec->cipher_def = bulk;
- ssl_ReleaseSpecWriteLock(ss); /*******************************/
+ spec->cipherDef = ssl_GetBulkCipherDef(ssl_LookupCipherSuiteDef(suite));
+ switch (spec->cipherDef->calg) {
+ case ssl_calg_aes_gcm:
+ spec->aead = tls13_AESGCM;
+ break;
+ case ssl_calg_chacha20:
+ spec->aead = tls13_ChaCha20Poly1305;
+ break;
+ default:
+ PORT_Assert(0);
+ return SECFailure;
+ }
+
+ if (spec->epoch == TrafficKeyEarlyApplicationData) {
+ spec->earlyDataRemaining =
+ ss->sec.ci.sid->u.ssl3.locked.sessionTicket.max_early_data_size;
+ }
+
+ tls13_SetSpecRecordVersion(ss, spec);
+ return SECSuccess;
+}
+
+/*
+ * Called before sending alerts to set up the right key on the client.
+ * We might encounter errors during the handshake where the current
+ * key is ClearText or EarlyApplicationData. This
+ * function switches to the Handshake key if possible.
+ */
+SECStatus
+tls13_SetAlertCipherSpec(sslSocket *ss)
+{
+ SECStatus rv;
+
+ if (ss->sec.isServer) {
+ return SECSuccess;
+ }
+ if (ss->version < SSL_LIBRARY_VERSION_TLS_1_3) {
+ return SECSuccess;
+ }
+ if (TLS13_IN_HS_STATE(ss, wait_server_hello)) {
+ return SECSuccess;
+ }
+ if ((ss->ssl3.cwSpec->epoch != TrafficKeyClearText) &&
+ (ss->ssl3.cwSpec->epoch != TrafficKeyEarlyApplicationData)) {
+ return SECSuccess;
+ }
+
+ rv = tls13_SetCipherSpec(ss, TrafficKeyHandshake,
+ CipherSpecWrite, PR_FALSE);
+ if (rv != SECSuccess) {
+ PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
+ return SECFailure;
+ }
return SECSuccess;
}
-/* Install a new cipher spec for this direction. */
+/* Install a new cipher spec for this direction.
+ *
+ * During the handshake, the values for |epoch| take values from the
+ * TrafficKeyType enum. Afterwards, key update increments them.
+ */
static SECStatus
-tls13_SetCipherSpec(sslSocket *ss, TrafficKeyType type,
+tls13_SetCipherSpec(sslSocket *ss, PRUint16 epoch,
CipherSpecDirection direction, PRBool deleteSecret)
{
+ TrafficKeyType type;
SECStatus rv;
ssl3CipherSpec *spec = NULL;
- ssl3CipherSpec **specp = (direction == CipherSpecRead) ? &ss->ssl3.crSpec : &ss->ssl3.cwSpec;
+ ssl3CipherSpec **specp;
+
/* Flush out old handshake data. */
ssl_GetXmitBufLock(ss);
rv = ssl3_FlushHandshake(ss, ssl_SEND_FLAG_FORCE_INTO_BUFFER);
@@ -2722,81 +3312,52 @@ tls13_SetCipherSpec(sslSocket *ss, TrafficKeyType type,
}
/* Create the new spec. */
- spec = PORT_ZNew(ssl3CipherSpec);
+ spec = ssl_CreateCipherSpec(ss, direction);
if (!spec) {
- PORT_SetError(SEC_ERROR_NO_MEMORY);
return SECFailure;
}
- spec->refCt = 1;
- PR_APPEND_LINK(&spec->link, &ss->ssl3.hs.cipherSpecs);
- ss->ssl3.pwSpec = ss->ssl3.prSpec = spec;
-
- rv = tls13_SetupPendingCipherSpec(ss);
- if (rv != SECSuccess)
- return SECFailure;
-
- switch (spec->cipher_def->calg) {
- case calg_aes_gcm:
- spec->aead = tls13_AESGCM;
- break;
- case calg_chacha20:
- spec->aead = tls13_ChaCha20Poly1305;
- break;
- default:
- PORT_Assert(0);
- return SECFailure;
- break;
+ spec->epoch = epoch;
+ spec->seqNum = 0;
+ if (IS_DTLS(ss)) {
+ dtls_InitRecvdRecords(&spec->recvdRecords);
}
- rv = tls13_DeriveTrafficKeys(ss, spec, type, direction,
- deleteSecret);
+ /* This depends on spec having a valid direction and epoch. */
+ rv = tls13_SetupPendingCipherSpec(ss, spec);
if (rv != SECSuccess) {
- return SECFailure;
- }
-
- /* We use the epoch for cipher suite identification, so increment
- * it in both TLS and DTLS. */
- if ((*specp)->epoch == PR_UINT16_MAX) {
- return SECFailure;
- }
- spec->epoch = (PRUint16)type;
-
- if (!IS_DTLS(ss)) {
- spec->read_seq_num = spec->write_seq_num = 0;
- } else {
- /* The sequence number has the high 16 bits as the epoch. */
- spec->read_seq_num = spec->write_seq_num =
- (sslSequenceNumber)spec->epoch << 48;
-
- dtls_InitRecvdRecords(&spec->recvdRecords);
+ goto loser;
}
- if (type == TrafficKeyEarlyApplicationData) {
- spec->earlyDataRemaining =
- ss->sec.ci.sid->u.ssl3.locked.sessionTicket.max_early_data_size;
+ type = (TrafficKeyType)PR_MIN(TrafficKeyApplicationData, epoch);
+ rv = tls13_DeriveTrafficKeys(ss, spec, type, deleteSecret);
+ if (rv != SECSuccess) {
+ goto loser;
}
/* Now that we've set almost everything up, finally cut over. */
+ specp = (direction == CipherSpecRead) ? &ss->ssl3.crSpec : &ss->ssl3.cwSpec;
ssl_GetSpecWriteLock(ss);
- tls13_CipherSpecRelease(*specp); /* May delete old cipher. */
- *specp = spec; /* Overwrite. */
+ ssl_CipherSpecRelease(*specp); /* May delete old cipher. */
+ *specp = spec; /* Overwrite. */
ssl_ReleaseSpecWriteLock(ss);
- SSL_TRC(3, ("%d: TLS13[%d]: %s installed key for phase='%s'.%d dir=%s",
- SSL_GETPID(), ss->fd, SSL_ROLE(ss),
- spec->phase, spec->epoch,
- direction == CipherSpecRead ? "read" : "write"));
+ 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:
+ ssl_CipherSpecRelease(spec);
+ return SECFailure;
}
-static SECStatus
-tls13_ComputeHandshakeHashes(sslSocket *ss,
- SSL3Hashes *hashes)
+SECStatus
+tls13_ComputeHandshakeHashes(sslSocket *ss, SSL3Hashes *hashes)
{
SECStatus rv;
PK11Context *ctx = NULL;
@@ -2816,7 +3377,7 @@ tls13_ComputeHandshakeHashes(sslSocket *ss,
goto loser;
}
- PRINT_BUF(10, (NULL, "Handshake hash computed over saved messages",
+ PRINT_BUF(10, (ss, "Handshake hash computed over saved messages",
ss->ssl3.hs.messages.buf,
ss->ssl3.hs.messages.len));
@@ -2841,6 +3402,8 @@ tls13_ComputeHandshakeHashes(sslSocket *ss,
ssl_MapLowLevelError(SSL_ERROR_DIGEST_FAILURE);
goto loser;
}
+
+ PRINT_BUF(10, (ss, "Handshake hash", hashes->u.raw, hashes->len));
PORT_Assert(hashes->len == tls13_GetHashSize(ss));
PK11_DestroyContext(ctx, PR_TRUE);
@@ -2890,19 +3453,6 @@ tls13_DestroyEarlyData(PRCList *list)
}
}
-void
-tls13_DestroyCipherSpecs(PRCList *list)
-{
- PRCList *cur_p;
-
- while (!PR_CLIST_IS_EMPTY(list)) {
- cur_p = PR_LIST_TAIL(list);
- PR_REMOVE_LINK(cur_p);
- ssl3_DestroyCipherSpec((ssl3CipherSpec *)cur_p, PR_FALSE);
- PORT_Free(cur_p);
- }
-}
-
/* draft-ietf-tls-tls13 Section 5.2.2 specifies the following
* nonce algorithm:
*
@@ -2932,7 +3482,7 @@ tls13_WriteNonce(ssl3KeyMaterial *keys,
size_t i;
PORT_Assert(nonceLen == 12);
- memcpy(nonce, keys->write_iv, 12);
+ memcpy(nonce, keys->iv, 12);
/* XOR the last 8 bytes of the IV with the sequence number. */
PORT_Assert(seqNumLen == 8);
@@ -2962,10 +3512,10 @@ tls13_AEAD(ssl3KeyMaterial *keys, PRBool doDecrypt,
};
if (doDecrypt) {
- rv = PK11_Decrypt(keys->write_key, mechanism, &param,
+ rv = PK11_Decrypt(keys->key, mechanism, &param,
out, &uOutLen, maxout, in, inlen);
} else {
- rv = PK11_Encrypt(keys->write_key, mechanism, &param,
+ rv = PK11_Encrypt(keys->key, mechanism, &param,
out, &uOutLen, maxout, in, inlen);
}
*outlen = (int)uOutLen;
@@ -3062,7 +3612,7 @@ tls13_HandleEncryptedExtensions(sslSocket *ss, PRUint8 *b, PRUint32 length)
ss->xtnData.nextProto.data = NULL;
ss->xtnData.nextProtoState = SSL_NEXT_PROTO_NO_SUPPORT;
}
- rv = ssl3_HandleExtensions(ss, &b, &length, encrypted_extensions);
+ rv = ssl3_HandleExtensions(ss, &b, &length, ssl_hs_encrypted_extensions);
if (rv != SECSuccess) {
return SECFailure; /* Error code set below */
}
@@ -3114,10 +3664,8 @@ tls13_HandleEncryptedExtensions(sslSocket *ss, PRUint8 *b, PRUint32 length)
static SECStatus
tls13_SendEncryptedExtensions(sslSocket *ss)
{
+ sslBuffer extensions = SSL_BUFFER_EMPTY;
SECStatus rv;
- PRInt32 extensions_len = 0;
- PRInt32 sent_len = 0;
- PRUint32 maxBytes = 65535;
SSL_TRC(3, ("%d: TLS13[%d]: send encrypted extensions handshake",
SSL_GETPID(), ss->fd));
@@ -3125,31 +3673,28 @@ tls13_SendEncryptedExtensions(sslSocket *ss)
PORT_Assert(ss->opt.noLocks || ssl_HaveSSL3HandshakeLock(ss));
PORT_Assert(ss->opt.noLocks || ssl_HaveXmitBufLock(ss));
- extensions_len = ssl3_CallHelloExtensionSenders(
- ss, PR_FALSE, maxBytes, &ss->xtnData.encryptedExtensionsSenders[0]);
-
- rv = ssl3_AppendHandshakeHeader(ss, encrypted_extensions,
- extensions_len + 2);
+ rv = ssl_ConstructExtensions(ss, &extensions, ssl_hs_encrypted_extensions);
if (rv != SECSuccess) {
- LOG_ERROR(ss, SEC_ERROR_LIBRARY_FAILURE);
return SECFailure;
}
- rv = ssl3_AppendHandshakeNumber(ss, extensions_len, 2);
+
+ rv = ssl3_AppendHandshakeHeader(ss, ssl_hs_encrypted_extensions,
+ SSL_BUFFER_LEN(&extensions) + 2);
if (rv != SECSuccess) {
LOG_ERROR(ss, SEC_ERROR_LIBRARY_FAILURE);
- return SECFailure;
+ goto loser;
}
- sent_len = ssl3_CallHelloExtensionSenders(
- ss, PR_TRUE, extensions_len,
- &ss->xtnData.encryptedExtensionsSenders[0]);
- PORT_Assert(sent_len == extensions_len);
- if (sent_len != extensions_len) {
+ rv = ssl3_AppendBufferToHandshakeVariable(ss, &extensions, 2);
+ if (rv != SECSuccess) {
LOG_ERROR(ss, SEC_ERROR_LIBRARY_FAILURE);
- PORT_Assert(sent_len == 0);
- return SECFailure;
+ goto loser;
}
-
+ sslBuffer_Clear(&extensions);
return SECSuccess;
+
+loser:
+ sslBuffer_Clear(&extensions);
+ return SECFailure;
}
SECStatus
@@ -3210,7 +3755,7 @@ tls13_SendCertificateVerify(sslSocket *ss, SECKEYPrivateKey *privKey)
len = buf.len + 2 + 2;
- rv = ssl3_AppendHandshakeHeader(ss, certificate_verify, len);
+ rv = ssl3_AppendHandshakeHeader(ss, ssl_hs_certificate_verify, len);
if (rv != SECSuccess) {
goto done; /* error code set by AppendHandshake */
}
@@ -3238,14 +3783,14 @@ done:
* Caller must hold Handshake and RecvBuf locks.
*/
SECStatus
-tls13_HandleCertificateVerify(sslSocket *ss, PRUint8 *b, PRUint32 length,
- SSL3Hashes *hashes)
+tls13_HandleCertificateVerify(sslSocket *ss, PRUint8 *b, PRUint32 length)
{
SECItem signed_hash = { siBuffer, NULL, 0 };
SECStatus rv;
SSLSignatureScheme sigScheme;
SSLHashType hashAlg;
SSL3Hashes tbsHash;
+ SSL3Hashes hashes;
SSL_TRC(3, ("%d: TLS13[%d]: handle certificate_verify handshake",
SSL_GETPID(), ss->fd));
@@ -3257,7 +3802,17 @@ tls13_HandleCertificateVerify(sslSocket *ss, PRUint8 *b, PRUint32 length,
if (rv != SECSuccess) {
return SECFailure;
}
- PORT_Assert(hashes);
+
+ rv = tls13_ComputeHandshakeHashes(ss, &hashes);
+ if (rv != SECSuccess) {
+ return SECFailure;
+ }
+
+ rv = ssl_HashHandshakeMessage(ss, ssl_hs_certificate_verify, b, length);
+ if (rv != SECSuccess) {
+ PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
+ return SECFailure;
+ }
rv = ssl_ConsumeSignatureScheme(ss, &b, &length, &sigScheme);
if (rv != SECSuccess) {
@@ -3272,7 +3827,7 @@ tls13_HandleCertificateVerify(sslSocket *ss, PRUint8 *b, PRUint32 length,
}
hashAlg = ssl_SignatureSchemeToHashType(sigScheme);
- rv = tls13_AddContextToHashes(ss, hashes, hashAlg, PR_FALSE, &tbsHash);
+ rv = tls13_AddContextToHashes(ss, &hashes, hashAlg, PR_FALSE, &tbsHash);
if (rv != SECSuccess) {
FATAL_ERROR(ss, SSL_ERROR_DIGEST_FAILURE, internal_error);
return SECFailure;
@@ -3301,13 +3856,11 @@ tls13_HandleCertificateVerify(sslSocket *ss, PRUint8 *b, PRUint32 length,
}
/* Request a client certificate now if one was requested. */
- if (ss->ssl3.hs.certificateRequest) {
- TLS13CertificateRequest *req = ss->ssl3.hs.certificateRequest;
-
+ if (ss->ssl3.hs.clientCertRequested) {
PORT_Assert(!ss->sec.isServer);
- rv = ssl3_CompleteHandleCertificateRequest(ss, req->signatureSchemes,
- req->signatureSchemeCount,
- &req->ca_list);
+ 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;
@@ -3320,7 +3873,7 @@ tls13_HandleCertificateVerify(sslSocket *ss, PRUint8 *b, PRUint32 length,
}
static SECStatus
-tls13_ComputePskBinderHash(sslSocket *ss, unsigned long prefixLength,
+tls13_ComputePskBinderHash(sslSocket *ss, unsigned int prefixLength,
SSL3Hashes *hashes)
{
SECStatus rv;
@@ -3332,38 +3885,75 @@ tls13_ComputePskBinderHash(sslSocket *ss, unsigned long prefixLength,
PRINT_BUF(10, (NULL, "Handshake hash computed over ClientHello prefix",
ss->ssl3.hs.messages.buf, prefixLength));
rv = PK11_HashBuf(ssl3_HashTypeToOID(tls13_GetHash(ss)),
- hashes->u.raw,
- ss->ssl3.hs.messages.buf, prefixLength);
+ hashes->u.raw, ss->ssl3.hs.messages.buf, prefixLength);
if (rv != SECSuccess) {
ssl_MapLowLevelError(SSL_ERROR_SHA_DIGEST_FAILURE);
- goto loser;
+ return SECFailure;
}
- hashes->len = tls13_GetHashSize(ss);
- PRINT_BUF(10, (NULL, "PSK Binder hash",
- hashes->u.raw, hashes->len));
+ hashes->len = tls13_GetHashSize(ss);
+ PRINT_BUF(10, (NULL, "PSK Binder hash", hashes->u.raw, hashes->len));
return SECSuccess;
-
-loser:
- return SECFailure;
}
-/* Compute the PSK Binder This is kind of sneaky.*/
+
+/* Compute and inject the PSK Binder for sending.
+ *
+ * When sending a ClientHello, we construct all the extensions with a dummy
+ * value for the binder. To construct the binder, we commit the entire message
+ * up to the point where the binders start. Then we calculate the hash using
+ * the saved message (in ss->ssl3.hs.messages). This is written over the dummy
+ * binder, after which we write the remainder of the binder extension. */
SECStatus
-tls13_ComputePskBinder(sslSocket *ss, PRBool sending,
- unsigned int prefixLength,
- PRUint8 *output, unsigned int *outputLen,
- unsigned int maxOutputLen)
+tls13_WriteExtensionsWithBinder(sslSocket *ss, sslBuffer *extensions)
{
SSL3Hashes hashes;
SECStatus rv;
+ unsigned int size = tls13_GetHashSize(ss);
+ unsigned int prefixLen = extensions->len - size - 3;
+ unsigned int finishedLen;
- rv = tls13_ComputePskBinderHash(ss, prefixLength, &hashes);
- if (rv != SECSuccess)
+ PORT_Assert(extensions->len >= size + 3);
+
+ rv = ssl3_AppendHandshakeNumber(ss, extensions->len, 2);
+ if (rv != SECSuccess) {
return SECFailure;
+ }
- return tls13_ComputeFinished(ss, ss->ssl3.hs.pskBinderKey, &hashes,
- sending, output, outputLen, maxOutputLen);
+ /* Only write the extension up to the point before the binders. Assume that
+ * the pre_shared_key extension is at the end of the buffer. Don't write
+ * the binder, or the lengths that precede it (a 2 octet length for the list
+ * of all binders, plus a 1 octet length for the binder length). */
+ rv = ssl3_AppendHandshake(ss, extensions->buf, prefixLen);
+ if (rv != SECSuccess) {
+ return SECFailure;
+ }
+
+ /* Calculate the binder based on what has been written out. */
+ rv = tls13_ComputePskBinderHash(ss, ss->ssl3.hs.messages.len, &hashes);
+ if (rv != SECSuccess) {
+ return SECFailure;
+ }
+
+ /* Write the binder into the extensions buffer, over the zeros we reserved
+ * previously. This avoids an allocation and means that we don't need a
+ * separate write for the extra bits that precede the binder. */
+ rv = tls13_ComputeFinished(ss, ss->ssl3.hs.pskBinderKey, &hashes, PR_TRUE,
+ extensions->buf + extensions->len - size,
+ &finishedLen, size);
+ if (rv != SECSuccess) {
+ return SECFailure;
+ }
+ PORT_Assert(finishedLen == size);
+
+ /* Write out the remainder of the extension. */
+ rv = ssl3_AppendHandshake(ss, extensions->buf + prefixLen,
+ extensions->len - prefixLen);
+ if (rv != SECSuccess) {
+ return SECFailure;
+ }
+
+ return SECSuccess;
}
static SECStatus
@@ -3462,7 +4052,7 @@ tls13_SendFinished(sslSocket *ss, PK11SymKey *baseKey)
return SECFailure;
}
- rv = ssl3_AppendHandshakeHeader(ss, finished, finishedLen);
+ rv = ssl3_AppendHandshakeHeader(ss, ssl_hs_finished, finishedLen);
if (rv != SECSuccess) {
return SECFailure; /* Error code already set. */
}
@@ -3477,7 +4067,7 @@ tls13_SendFinished(sslSocket *ss, PK11SymKey *baseKey)
}
static SECStatus
-tls13_VerifyFinished(sslSocket *ss, SSL3HandshakeType message,
+tls13_VerifyFinished(sslSocket *ss, SSLHandshakeType message,
PK11SymKey *secret,
PRUint8 *b, PRUint32 length,
const SSL3Hashes *hashes)
@@ -3500,7 +4090,7 @@ tls13_VerifyFinished(sslSocket *ss, SSL3HandshakeType message,
if (length != finishedLen) {
#ifndef UNSAFE_FUZZER_MODE
- FATAL_ERROR(ss, message == finished ? SSL_ERROR_RX_MALFORMED_FINISHED : SSL_ERROR_RX_MALFORMED_CLIENT_HELLO, illegal_parameter);
+ FATAL_ERROR(ss, message == ssl_hs_finished ? SSL_ERROR_RX_MALFORMED_FINISHED : SSL_ERROR_RX_MALFORMED_CLIENT_HELLO, illegal_parameter);
return SECFailure;
#endif
}
@@ -3517,8 +4107,37 @@ tls13_VerifyFinished(sslSocket *ss, SSL3HandshakeType message,
}
static SECStatus
-tls13_ClientHandleFinished(sslSocket *ss, PRUint8 *b, PRUint32 length,
- const SSL3Hashes *hashes)
+tls13_CommonHandleFinished(sslSocket *ss, PK11SymKey *key,
+ PRUint8 *b, PRUint32 length)
+{
+ SECStatus rv;
+ SSL3Hashes hashes;
+
+ rv = TLS13_CHECK_HS_STATE(ss, SSL_ERROR_RX_UNEXPECTED_FINISHED,
+ wait_finished);
+ if (rv != SECSuccess) {
+ return SECFailure;
+ }
+ ss->ssl3.hs.endOfFlight = PR_TRUE;
+
+ rv = tls13_ComputeHandshakeHashes(ss, &hashes);
+ if (rv != SECSuccess) {
+ LOG_ERROR(ss, SEC_ERROR_LIBRARY_FAILURE);
+ return SECFailure;
+ }
+
+ rv = ssl_HashHandshakeMessage(ss, ssl_hs_finished, b, length);
+ if (rv != SECSuccess) {
+ PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
+ return SECFailure;
+ }
+
+ return tls13_VerifyFinished(ss, ssl_hs_finished,
+ key, b, length, &hashes);
+}
+
+static SECStatus
+tls13_ClientHandleFinished(sslSocket *ss, PRUint8 *b, PRUint32 length)
{
SECStatus rv;
@@ -3528,27 +4147,19 @@ tls13_ClientHandleFinished(sslSocket *ss, PRUint8 *b, PRUint32 length,
SSL_TRC(3, ("%d: TLS13[%d]: client handle finished handshake",
SSL_GETPID(), ss->fd));
- rv = TLS13_CHECK_HS_STATE(ss, SSL_ERROR_RX_UNEXPECTED_FINISHED,
- wait_finished);
+ rv = tls13_CommonHandleFinished(ss, ss->ssl3.hs.serverHsTrafficSecret,
+ b, length);
if (rv != SECSuccess) {
return SECFailure;
}
- rv = tls13_VerifyFinished(ss, finished,
- ss->ssl3.hs.serverHsTrafficSecret,
- b, length, hashes);
- if (rv != SECSuccess)
- return SECFailure;
-
return tls13_SendClientSecondRound(ss);
}
static SECStatus
-tls13_ServerHandleFinished(sslSocket *ss, PRUint8 *b, PRUint32 length,
- const SSL3Hashes *hashes)
+tls13_ServerHandleFinished(sslSocket *ss, PRUint8 *b, PRUint32 length)
{
SECStatus rv;
- PK11SymKey *secret;
PORT_Assert(ss->opt.noLocks || ssl_HaveRecvBufLock(ss));
PORT_Assert(ss->opt.noLocks || ssl_HaveSSL3HandshakeLock(ss));
@@ -3556,61 +4167,68 @@ tls13_ServerHandleFinished(sslSocket *ss, PRUint8 *b, PRUint32 length,
SSL_TRC(3, ("%d: TLS13[%d]: server handle finished handshake",
SSL_GETPID(), ss->fd));
- rv = TLS13_CHECK_HS_STATE(ss, SSL_ERROR_RX_UNEXPECTED_FINISHED, wait_finished);
+ rv = tls13_CommonHandleFinished(ss, ss->ssl3.hs.clientHsTrafficSecret,
+ b, length);
if (rv != SECSuccess) {
return SECFailure;
}
- if (TLS13_IN_HS_STATE(ss, wait_finished)) {
- secret = ss->ssl3.hs.clientHsTrafficSecret;
- } else {
- secret = ss->ssl3.hs.clientEarlyTrafficSecret;
+ if (!ss->opt.requestCertificate &&
+ (ss->ssl3.hs.zeroRttState != ssl_0rtt_done)) {
+ dtls_ReceivedFirstMessageInFlight(ss);
}
- rv = tls13_VerifyFinished(ss, finished, secret, b, length, hashes);
- if (rv != SECSuccess)
- return SECFailure;
-
rv = tls13_SetCipherSpec(ss, TrafficKeyApplicationData,
- CipherSpecRead, PR_TRUE);
+ CipherSpecRead, PR_FALSE);
if (rv != SECSuccess) {
FATAL_ERROR(ss, SEC_ERROR_LIBRARY_FAILURE, internal_error);
return SECFailure;
}
- rv = tls13_FinishHandshake(ss);
+ if (IS_DTLS(ss)) {
+ ssl_CipherSpecReleaseByEpoch(ss, CipherSpecRead, 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,
+ DTLS_RETRANSMIT_FINISHED_MS,
+ dtls13_HolddownTimerCb);
+ if (rv != SECSuccess) {
+ return SECFailure;
+ }
+ }
+
+ rv = tls13_ComputeFinalSecrets(ss);
if (rv != SECSuccess) {
- return SECFailure; /* Error code and alerts handled below */
+ return SECFailure;
}
+
ssl_GetXmitBufLock(ss);
if (ss->opt.enableSessionTickets) {
- rv = tls13_SendNewSessionTicket(ss);
+ rv = tls13_SendNewSessionTicket(ss, NULL, 0);
if (rv != SECSuccess) {
- ssl_ReleaseXmitBufLock(ss);
- return SECFailure; /* Error code and alerts handled below */
+ goto loser;
}
rv = ssl3_FlushHandshake(ss, 0);
+ if (rv != SECSuccess) {
+ goto loser;
+ }
}
ssl_ReleaseXmitBufLock(ss);
- if (rv != SECSuccess)
- return SECFailure;
- return SECSuccess;
+ return tls13_FinishHandshake(ss);
+
+loser:
+ ssl_ReleaseXmitBufLock(ss);
+ return SECFailure;
}
static SECStatus
tls13_FinishHandshake(sslSocket *ss)
{
- SECStatus rv;
-
PORT_Assert(ss->opt.noLocks || ssl_HaveRecvBufLock(ss));
PORT_Assert(ss->opt.noLocks || ssl_HaveSSL3HandshakeLock(ss));
PORT_Assert(ss->ssl3.hs.restartTarget == NULL);
- rv = tls13_ComputeFinalSecrets(ss);
- if (rv != SECSuccess)
- return SECFailure;
-
/* The first handshake is now completed. */
ss->handshake = NULL;
@@ -3652,9 +4270,15 @@ tls13_SendClientSecondFlight(sslSocket *ss, PRBool sendClientCert,
return SECFailure; /* error code is set. */
}
}
- if (ss->ssl3.hs.certificateRequest) {
- PORT_FreeArena(ss->ssl3.hs.certificateRequest->arena, PR_FALSE);
- ss->ssl3.hs.certificateRequest = NULL;
+ if (ss->ssl3.hs.clientCertRequested) {
+ SECITEM_FreeItem(&ss->xtnData.certReqContext, PR_FALSE);
+ if (ss->xtnData.certReqAuthorities.arena) {
+ PORT_FreeArena(ss->xtnData.certReqAuthorities.arena, PR_FALSE);
+ ss->xtnData.certReqAuthorities.arena = NULL;
+ }
+ PORT_Memset(&ss->xtnData.certReqAuthorities, 0,
+ sizeof(ss->xtnData.certReqAuthorities));
+ ss->ssl3.hs.clientCertRequested = PR_FALSE;
}
if (sendClientCert) {
@@ -3670,7 +4294,7 @@ tls13_SendClientSecondFlight(sslSocket *ss, PRBool sendClientCert,
if (rv != SECSuccess) {
return SECFailure; /* err code was set. */
}
- rv = ssl3_FlushHandshake(ss, IS_DTLS(ss) ? ssl_SEND_FLAG_NO_RETRANSMIT : 0);
+ rv = ssl3_FlushHandshake(ss, 0);
if (rv != SECSuccess) {
/* No point in sending an alert here because we're not going to
* be able to send it if we couldn't flush the handshake. */
@@ -3678,11 +4302,6 @@ tls13_SendClientSecondFlight(sslSocket *ss, PRBool sendClientCert,
return SECFailure;
}
- rv = dtls_StartHolddownTimer(ss);
- if (rv != SECSuccess) {
- return SECFailure; /* err code was set. */
- }
-
return SECSuccess;
}
@@ -3717,11 +4336,28 @@ tls13_SendClientSecondRound(sslSocket *ss)
return SECWouldBlock;
}
+ rv = tls13_ComputeApplicationSecrets(ss);
+ if (rv != SECSuccess) {
+ FATAL_ERROR(ss, SEC_ERROR_LIBRARY_FAILURE, internal_error);
+ return SECFailure;
+ }
+
if (ss->ssl3.hs.zeroRttState == ssl_0rtt_accepted) {
+ ssl_GetXmitBufLock(ss); /*******************************/
rv = tls13_SendEndOfEarlyData(ss);
+ ssl_ReleaseXmitBufLock(ss); /*******************************/
if (rv != SECSuccess) {
return SECFailure; /* Error code already set. */
}
+ } else if (ss->opt.enableTls13CompatMode && !IS_DTLS(ss) &&
+ ss->ssl3.hs.zeroRttState == ssl_0rtt_none &&
+ !ss->ssl3.hs.helloRetry) {
+ ssl_GetXmitBufLock(ss); /*******************************/
+ rv = ssl3_SendChangeCipherSpecsInt(ss);
+ ssl_ReleaseXmitBufLock(ss); /*******************************/
+ if (rv != SECSuccess) {
+ return rv;
+ }
}
rv = tls13_SetCipherSpec(ss, TrafficKeyHandshake,
@@ -3731,12 +4367,6 @@ tls13_SendClientSecondRound(sslSocket *ss)
return SECFailure;
}
- rv = tls13_ComputeApplicationSecrets(ss);
- if (rv != SECSuccess) {
- FATAL_ERROR(ss, SEC_ERROR_LIBRARY_FAILURE, internal_error);
- return SECFailure;
- }
-
rv = tls13_SetCipherSpec(ss, TrafficKeyApplicationData,
CipherSpecRead, PR_FALSE);
if (rv != SECSuccess) {
@@ -3756,12 +4386,17 @@ tls13_SendClientSecondRound(sslSocket *ss)
return SECFailure;
}
rv = tls13_SetCipherSpec(ss, TrafficKeyApplicationData,
- CipherSpecWrite, PR_TRUE);
+ CipherSpecWrite, PR_FALSE);
if (rv != SECSuccess) {
PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
return SECFailure;
}
+ rv = tls13_ComputeFinalSecrets(ss);
+ if (rv != SECSuccess) {
+ return SECFailure;
+ }
+
/* The handshake is now finished */
return tls13_FinishHandshake(ss);
}
@@ -3777,6 +4412,7 @@ tls13_SendClientSecondRound(sslSocket *ss)
* struct {
* uint32 ticket_lifetime;
* uint32 ticket_age_add;
+ * opaque ticket_nonce<1..255>;
* opaque ticket<1..2^16-1>;
* TicketExtension extensions<0..2^16-2>;
* } NewSessionTicket;
@@ -3784,14 +4420,22 @@ tls13_SendClientSecondRound(sslSocket *ss)
PRUint32 ssl_max_early_data_size = (2 << 16); /* Arbitrary limit. */
-SECStatus
-tls13_SendNewSessionTicket(sslSocket *ss)
+static SECStatus
+tls13_SendNewSessionTicket(sslSocket *ss, const PRUint8 *appToken,
+ unsigned int appTokenLen)
{
PRUint16 message_length;
+ PK11SymKey *secret;
SECItem ticket_data = { 0, NULL, 0 };
SECStatus rv;
NewSessionTicket ticket = { 0 };
PRUint32 max_early_data_size_len = 0;
+ PRUint8 ticketNonce[sizeof(ss->ssl3.hs.ticketNonce)];
+ sslBuffer ticketNonceBuf = SSL_BUFFER(ticketNonce);
+
+ SSL_TRC(3, ("%d: TLS13[%d]: send new session ticket message %d",
+ SSL_GETPID(), ss->fd, ss->ssl3.hs.ticketNonce));
+
ticket.flags = 0;
if (ss->opt.enable0RttData) {
ticket.flags |= ticket_allow_early_data;
@@ -3799,18 +4443,44 @@ tls13_SendNewSessionTicket(sslSocket *ss)
}
ticket.ticket_lifetime_hint = ssl_ticket_lifetime;
- rv = ssl3_EncodeSessionTicket(ss, &ticket, &ticket_data);
+ /* The ticket age obfuscator. */
+ rv = PK11_GenerateRandom((PRUint8 *)&ticket.ticket_age_add,
+ sizeof(ticket.ticket_age_add));
+ if (rv != SECSuccess)
+ goto loser;
+
+ rv = sslBuffer_AppendNumber(&ticketNonceBuf, ss->ssl3.hs.ticketNonce,
+ sizeof(ticketNonce));
+ if (rv != SECSuccess) {
+ goto loser;
+ }
+ ++ss->ssl3.hs.ticketNonce;
+ rv = tls13_HkdfExpandLabel(ss->ssl3.hs.resumptionMasterSecret,
+ tls13_GetHash(ss),
+ ticketNonce, sizeof(ticketNonce),
+ kHkdfLabelResumption,
+ strlen(kHkdfLabelResumption),
+ tls13_GetHkdfMechanism(ss),
+ tls13_GetHashSize(ss), &secret);
+ if (rv != SECSuccess) {
+ goto loser;
+ }
+
+ rv = ssl3_EncodeSessionTicket(ss, &ticket, appToken, appTokenLen,
+ secret, &ticket_data);
+ PK11_FreeSymKey(secret);
if (rv != SECSuccess)
goto loser;
message_length =
4 + /* lifetime */
4 + /* ticket_age_add */
+ 1 + sizeof(ticketNonce) + /* ticket_nonce */
2 + max_early_data_size_len + /* max_early_data_size_len */
2 + /* ticket length */
ticket_data.len;
- rv = ssl3_AppendHandshakeHeader(ss, new_session_ticket,
+ rv = ssl3_AppendHandshakeHeader(ss, ssl_hs_new_session_ticket,
message_length);
if (rv != SECSuccess)
goto loser;
@@ -3820,13 +4490,12 @@ tls13_SendNewSessionTicket(sslSocket *ss)
if (rv != SECSuccess)
goto loser;
- /* The ticket age obfuscator. */
- rv = PK11_GenerateRandom((PRUint8 *)&ticket.ticket_age_add,
- sizeof(ticket.ticket_age_add));
+ rv = ssl3_AppendHandshakeNumber(ss, ticket.ticket_age_add, 4);
if (rv != SECSuccess)
goto loser;
- rv = ssl3_AppendHandshakeNumber(ss, ticket.ticket_age_add, 4);
+ /* The ticket nonce. */
+ rv = ssl3_AppendHandshakeVariable(ss, ticketNonce, sizeof(ticketNonce), 1);
if (rv != SECSuccess)
goto loser;
@@ -3843,7 +4512,7 @@ tls13_SendNewSessionTicket(sslSocket *ss)
if (max_early_data_size_len) {
rv = ssl3_AppendHandshakeNumber(
- ss, ssl_tls13_ticket_early_data_info_xtn, 2);
+ ss, ssl_tls13_early_data_xtn, 2);
if (rv != SECSuccess)
goto loser;
@@ -3867,6 +4536,42 @@ loser:
return SECFailure;
}
+SECStatus
+SSLExp_SendSessionTicket(PRFileDesc *fd, const PRUint8 *token,
+ unsigned int tokenLen)
+{
+ sslSocket *ss;
+ SECStatus rv;
+
+ ss = ssl_FindSocket(fd);
+ if (!ss) {
+ return SECFailure;
+ }
+
+ if (IS_DTLS(ss)) {
+ PORT_SetError(SSL_ERROR_FEATURE_NOT_SUPPORTED_FOR_VERSION);
+ return SECFailure;
+ }
+
+ if (!ss->sec.isServer || !ss->firstHsDone ||
+ ss->version < SSL_LIBRARY_VERSION_TLS_1_3 ||
+ tokenLen > 0xffff) {
+ PORT_SetError(SEC_ERROR_INVALID_ARGS);
+ return SECFailure;
+ }
+
+ ssl_GetSSL3HandshakeLock(ss);
+ ssl_GetXmitBufLock(ss);
+ rv = tls13_SendNewSessionTicket(ss, token, tokenLen);
+ if (rv == SECSuccess) {
+ rv = ssl3_FlushHandshake(ss, 0);
+ }
+ ssl_ReleaseXmitBufLock(ss);
+ ssl_ReleaseSSL3HandshakeLock(ss);
+
+ return rv;
+}
+
static SECStatus
tls13_HandleNewSessionTicket(sslSocket *ss, PRUint8 *b, PRUint32 length)
{
@@ -3874,6 +4579,7 @@ tls13_HandleNewSessionTicket(sslSocket *ss, PRUint8 *b, PRUint32 length)
PRUint32 utmp;
NewSessionTicket ticket = { 0 };
SECItem data;
+ SECItem ticket_nonce;
SECItem ticket_data;
SSL_TRC(3, ("%d: TLS13[%d]: handle new session ticket message",
@@ -3890,7 +4596,7 @@ tls13_HandleNewSessionTicket(sslSocket *ss, PRUint8 *b, PRUint32 length)
return SECFailure;
}
- ticket.received_timestamp = PR_Now();
+ ticket.received_timestamp = ssl_TimeUsec();
rv = ssl3_ConsumeHandshakeNumber(ss, &ticket.ticket_lifetime_hint, 4, &b,
&length);
if (rv != SECSuccess) {
@@ -3908,6 +4614,14 @@ tls13_HandleNewSessionTicket(sslSocket *ss, PRUint8 *b, PRUint32 length)
}
ticket.ticket_age_add = PR_ntohl(utmp);
+ /* The nonce. */
+ rv = ssl3_ConsumeHandshakeVariable(ss, &ticket_nonce, 1, &b, &length);
+ if (rv != SECSuccess) {
+ FATAL_ERROR(ss, SSL_ERROR_RX_MALFORMED_NEW_SESSION_TICKET,
+ decode_error);
+ return SECFailure;
+ }
+
/* Get the ticket value. */
rv = ssl3_ConsumeHandshakeVariable(ss, &ticket_data, 2, &b, &length);
if (rv != SECSuccess || !ticket_data.len) {
@@ -3918,14 +4632,14 @@ tls13_HandleNewSessionTicket(sslSocket *ss, PRUint8 *b, PRUint32 length)
/* Parse extensions. */
rv = ssl3_ConsumeHandshakeVariable(ss, &data, 2, &b, &length);
- if (rv != SECSuccess) {
+ if (rv != SECSuccess || length) {
FATAL_ERROR(ss, SSL_ERROR_RX_MALFORMED_NEW_SESSION_TICKET,
decode_error);
return SECFailure;
}
rv = ssl3_HandleExtensions(ss, &data.data,
- &data.len, new_session_ticket);
+ &data.len, ssl_hs_new_session_ticket);
if (rv != SECSuccess) {
FATAL_ERROR(ss, SSL_ERROR_RX_MALFORMED_NEW_SESSION_TICKET,
decode_error);
@@ -3936,13 +4650,9 @@ tls13_HandleNewSessionTicket(sslSocket *ss, PRUint8 *b, PRUint32 length)
ticket.max_early_data_size = ss->xtnData.max_early_data_size;
}
- if (length != 0) {
- FATAL_ERROR(ss, SSL_ERROR_RX_MALFORMED_NEW_SESSION_TICKET,
- decode_error);
- return SECFailure;
- }
-
if (!ss->opt.noCache) {
+ PK11SymKey *secret;
+
PORT_Assert(ss->sec.ci.sid);
rv = SECITEM_CopyItem(NULL, &ticket.ticket, &ticket_data);
if (rv != SECSuccess) {
@@ -3979,9 +4689,22 @@ tls13_HandleNewSessionTicket(sslSocket *ss, PRUint8 *b, PRUint32 length)
ssl3_SetSIDSessionTicket(ss->sec.ci.sid, &ticket);
PORT_Assert(!ticket.ticket.data);
- rv = ssl3_FillInCachedSID(ss, ss->sec.ci.sid);
- if (rv != SECSuccess)
+ rv = tls13_HkdfExpandLabel(ss->ssl3.hs.resumptionMasterSecret,
+ tls13_GetHash(ss),
+ ticket_nonce.data, ticket_nonce.len,
+ kHkdfLabelResumption,
+ strlen(kHkdfLabelResumption),
+ tls13_GetHkdfMechanism(ss),
+ tls13_GetHashSize(ss), &secret);
+ if (rv != SECSuccess) {
return SECFailure;
+ }
+
+ rv = ssl3_FillInCachedSID(ss, ss->sec.ci.sid, secret);
+ PK11_FreeSymKey(secret);
+ if (rv != SECSuccess) {
+ return SECFailure;
+ }
/* Cache the session. */
ss->sec.cache(ss->sec.ci.sid);
@@ -3990,111 +4713,103 @@ tls13_HandleNewSessionTicket(sslSocket *ss, PRUint8 *b, PRUint32 length)
return SECSuccess;
}
-typedef enum {
- ExtensionNotUsed,
- ExtensionClientOnly,
- ExtensionSendClear,
- ExtensionSendClearOrHrr,
- ExtensionSendHrr,
- ExtensionSendEncrypted,
- ExtensionSendCertificate,
- ExtensionNewSessionTicket
-} Tls13ExtensionStatus;
+#define _M(a) (1 << PR_MIN(a, 31))
+#define _M1(a) (_M(ssl_hs_##a))
+#define _M2(a, b) (_M1(a) | _M1(b))
+#define _M3(a, b, c) (_M1(a) | _M2(b, c))
static const struct {
PRUint16 ex_value;
- Tls13ExtensionStatus status;
+ PRUint32 messages;
} KnownExtensions[] = {
- { ssl_server_name_xtn, ExtensionSendEncrypted },
- { ssl_supported_groups_xtn, ExtensionSendEncrypted },
- { ssl_ec_point_formats_xtn, ExtensionNotUsed },
- { ssl_signature_algorithms_xtn, ExtensionClientOnly },
- { ssl_use_srtp_xtn, ExtensionSendEncrypted },
- { ssl_app_layer_protocol_xtn, ExtensionSendEncrypted },
- { ssl_padding_xtn, ExtensionNotUsed },
- { ssl_extended_master_secret_xtn, ExtensionNotUsed },
- { ssl_session_ticket_xtn, ExtensionClientOnly },
- { ssl_tls13_key_share_xtn, ExtensionSendClearOrHrr },
- { ssl_tls13_pre_shared_key_xtn, ExtensionSendClear },
- { ssl_tls13_early_data_xtn, ExtensionSendEncrypted },
- { ssl_next_proto_nego_xtn, ExtensionNotUsed },
- { ssl_renegotiation_info_xtn, ExtensionNotUsed },
- { ssl_signed_cert_timestamp_xtn, ExtensionSendCertificate },
- { ssl_cert_status_xtn, ExtensionSendCertificate },
- { ssl_tls13_ticket_early_data_info_xtn, ExtensionNewSessionTicket },
- { ssl_tls13_cookie_xtn, ExtensionSendHrr },
- { ssl_tls13_short_header_xtn, ExtensionSendClear }
+ { ssl_server_name_xtn, _M2(client_hello, encrypted_extensions) },
+ { ssl_supported_groups_xtn, _M2(client_hello, encrypted_extensions) },
+ { ssl_signature_algorithms_xtn, _M2(client_hello, certificate_request) },
+ { ssl_signature_algorithms_cert_xtn, _M2(client_hello,
+ certificate_request) },
+ { ssl_use_srtp_xtn, _M2(client_hello, encrypted_extensions) },
+ { ssl_app_layer_protocol_xtn, _M2(client_hello, encrypted_extensions) },
+ { ssl_padding_xtn, _M1(client_hello) },
+ { ssl_tls13_key_share_xtn, _M3(client_hello, server_hello,
+ hello_retry_request) },
+ { ssl_tls13_pre_shared_key_xtn, _M2(client_hello, server_hello) },
+ { ssl_tls13_psk_key_exchange_modes_xtn, _M1(client_hello) },
+ { ssl_tls13_early_data_xtn, _M3(client_hello, encrypted_extensions,
+ new_session_ticket) },
+ { ssl_signed_cert_timestamp_xtn, _M3(client_hello, certificate_request,
+ certificate) },
+ { ssl_cert_status_xtn, _M3(client_hello, certificate_request,
+ 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) }
};
-PRBool
-tls13_ExtensionAllowed(PRUint16 extension, SSL3HandshakeType message)
+tls13ExtensionStatus
+tls13_ExtensionStatus(PRUint16 extension, SSLHandshakeType message)
{
unsigned int i;
- PORT_Assert((message == client_hello) ||
- (message == server_hello) ||
- (message == hello_retry_request) ||
- (message == encrypted_extensions) ||
- (message == new_session_ticket) ||
- (message == certificate) ||
- (message == certificate_request));
+ PORT_Assert((message == ssl_hs_client_hello) ||
+ (message == ssl_hs_server_hello) ||
+ (message == ssl_hs_hello_retry_request) ||
+ (message == ssl_hs_encrypted_extensions) ||
+ (message == ssl_hs_new_session_ticket) ||
+ (message == ssl_hs_certificate) ||
+ (message == ssl_hs_certificate_request));
for (i = 0; i < PR_ARRAY_SIZE(KnownExtensions); i++) {
- if (KnownExtensions[i].ex_value == extension)
+ /* Hacky check for message numbers > 30. */
+ PORT_Assert(!(KnownExtensions[i].messages & (1U << 31)));
+ if (KnownExtensions[i].ex_value == extension) {
break;
+ }
}
- if (i == PR_ARRAY_SIZE(KnownExtensions)) {
- /* We have never heard of this extension which is OK
- * in client_hello and new_session_ticket. */
- return (message == client_hello) ||
- (message == new_session_ticket);
- }
-
- switch (KnownExtensions[i].status) {
- case ExtensionNotUsed:
- return PR_FALSE;
- case ExtensionClientOnly:
- return message == client_hello;
- case ExtensionSendClear:
- return message == client_hello ||
- message == server_hello;
- case ExtensionSendClearOrHrr:
- return message == client_hello ||
- message == server_hello ||
- message == hello_retry_request;
- case ExtensionSendHrr:
- return message == client_hello ||
- message == hello_retry_request;
- case ExtensionSendEncrypted:
- return message == client_hello ||
- message == encrypted_extensions;
- case ExtensionNewSessionTicket:
- return message == new_session_ticket;
- case ExtensionSendCertificate:
- return message == client_hello ||
- message == certificate;
+ if (i >= PR_ARRAY_SIZE(KnownExtensions)) {
+ return tls13_extension_unknown;
}
- PORT_Assert(0);
+ /* Return "disallowed" if the message mask bit isn't set. */
+ if (!(_M(message) & KnownExtensions[i].messages)) {
+ SSL_TRC(3, ("%d: TLS13: unexpected extension %d in message %d",
+ SSL_GETPID(), extension, message));
- /* Not reached */
- return PR_TRUE;
+ return tls13_extension_disallowed;
+ }
+
+ return tls13_extension_allowed;
}
+#undef _M
+#undef _M1
+#undef _M2
+#undef _M3
+
/* TLS 1.3 doesn't actually have additional data but the aead function
* signature overloads additional data to carry the record sequence
* number and that's what we put here. The TLS 1.3 AEAD functions
* just use this input as the sequence number and not as additional
* data. */
-static void
-tls13_FormatAdditionalData(PRUint8 *aad, unsigned int length,
- sslSequenceNumber seqNum)
+static SECStatus
+tls13_FormatAdditionalData(sslSocket *ss, PRUint8 *aad, unsigned int length,
+ DTLSEpoch epoch, sslSequenceNumber seqNum)
{
- PRUint8 *ptr = aad;
+ SECStatus rv;
+ sslBuffer buf = SSL_BUFFER_FIXED(aad, length);
PORT_Assert(length == 8);
- ptr = ssl_EncodeUintX(seqNum, 8, ptr);
- PORT_Assert((ptr - aad) == length);
+ if (IS_DTLS(ss)) {
+ rv = sslBuffer_AppendNumber(&buf, epoch, 2);
+ if (rv != SECSuccess) {
+ return SECFailure;
+ }
+ }
+ rv = sslBuffer_AppendNumber(&buf, seqNum, IS_DTLS(ss) ? 6 : 8);
+ if (rv != SECSuccess) {
+ return SECFailure;
+ }
+ return SECSuccess;
}
PRInt32
@@ -4127,13 +4842,14 @@ tls13_ProtectRecord(sslSocket *ss,
PRUint32 contentLen,
sslBuffer *wrBuf)
{
- const ssl3BulkCipherDef *cipher_def = cwSpec->cipher_def;
+ const ssl3BulkCipherDef *cipher_def = cwSpec->cipherDef;
const int tagLen = cipher_def->tag_size;
SECStatus rv;
- SSL_TRC(3, ("%d: TLS13[%d]: spec=%d (%s) protect record 0x%0llx len=%u",
- SSL_GETPID(), ss->fd, cwSpec, cwSpec->phase,
- cwSpec->write_seq_num, contentLen));
+ PORT_Assert(cwSpec->direction == CipherSpecWrite);
+ 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->seqNum, contentLen));
if (contentLen + 1 + tagLen > wrBuf->space) {
PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
@@ -4154,15 +4870,18 @@ tls13_ProtectRecord(sslSocket *ss,
/* Add the content type at the end. */
wrBuf->buf[contentLen] = type;
- tls13_FormatAdditionalData(aad, sizeof(aad), cwSpec->write_seq_num);
- rv = cwSpec->aead(
- ss->sec.isServer ? &cwSpec->server : &cwSpec->client,
- PR_FALSE, /* do encrypt */
- wrBuf->buf, /* output */
- (int *)&wrBuf->len, /* out len */
- wrBuf->space, /* max out */
- wrBuf->buf, contentLen + 1, /* input */
- aad, sizeof(aad));
+ rv = tls13_FormatAdditionalData(ss, aad, sizeof(aad), cwSpec->epoch,
+ cwSpec->seqNum);
+ if (rv != SECSuccess) {
+ return SECFailure;
+ }
+ rv = cwSpec->aead(&cwSpec->keyMaterial,
+ PR_FALSE, /* do encrypt */
+ wrBuf->buf, /* output */
+ (int *)&wrBuf->len, /* out len */
+ wrBuf->space, /* max out */
+ wrBuf->buf, contentLen + 1, /* input */
+ aad, sizeof(aad));
if (rv != SECSuccess) {
PORT_SetError(SSL_ERROR_ENCRYPTION_FAILURE);
return SECFailure;
@@ -4182,19 +4901,27 @@ tls13_ProtectRecord(sslSocket *ss,
* 2. Call PORT_SetError() witn an appropriate code.
*/
SECStatus
-tls13_UnprotectRecord(sslSocket *ss, SSL3Ciphertext *cText, sslBuffer *plaintext,
+tls13_UnprotectRecord(sslSocket *ss,
+ ssl3CipherSpec *spec,
+ SSL3Ciphertext *cText, sslBuffer *plaintext,
SSL3AlertDescription *alert)
{
- ssl3CipherSpec *crSpec = ss->ssl3.crSpec;
- const ssl3BulkCipherDef *cipher_def = crSpec->cipher_def;
+ const ssl3BulkCipherDef *cipher_def = spec->cipherDef;
+ sslSequenceNumber seqNum;
PRUint8 aad[8];
SECStatus rv;
*alert = bad_record_mac; /* Default alert for most issues. */
- SSL_TRC(3, ("%d: TLS13[%d]: spec=%d (%s) unprotect record 0x%0llx len=%u",
- SSL_GETPID(), ss->fd, crSpec, crSpec->phase,
- crSpec->read_seq_num, cText->buf->len));
+ PORT_Assert(spec->direction == CipherSpecRead);
+ if (IS_DTLS(ss)) {
+ seqNum = cText->seq_num & RECORD_SEQ_MASK;
+ } else {
+ seqNum = spec->seqNum;
+ }
+ 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, seqNum,
+ cText->buf->len));
/* We can perform this test in variable time because the record's total
* length and the ciphersuite are both public knowledge. */
@@ -4216,9 +4943,8 @@ tls13_UnprotectRecord(sslSocket *ss, SSL3Ciphertext *cText, sslBuffer *plaintext
return SECFailure;
}
- /* Check the version number in the record */
- if ((IS_DTLS(ss) && cText->version != kDtlsRecordVersion) ||
- (!IS_DTLS(ss) && cText->version != kTlsRecordVersion)) {
+ /* Check the version number in the record. */
+ if (cText->version != spec->recordVersion) {
/* Do we need a better error here? */
SSL_TRC(3,
("%d: TLS13[%d]: record has bogus version",
@@ -4228,18 +4954,18 @@ tls13_UnprotectRecord(sslSocket *ss, SSL3Ciphertext *cText, sslBuffer *plaintext
/* Decrypt */
PORT_Assert(cipher_def->type == type_aead);
- tls13_FormatAdditionalData(aad, sizeof(aad),
- IS_DTLS(ss) ? cText->seq_num
- : crSpec->read_seq_num);
- rv = crSpec->aead(
- ss->sec.isServer ? &crSpec->client : &crSpec->server,
- PR_TRUE, /* do decrypt */
- plaintext->buf, /* out */
- (int *)&plaintext->len, /* outlen */
- plaintext->space, /* maxout */
- cText->buf->buf, /* in */
- cText->buf->len, /* inlen */
- aad, sizeof(aad));
+ rv = tls13_FormatAdditionalData(ss, aad, sizeof(aad), spec->epoch, seqNum);
+ if (rv != SECSuccess) {
+ 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 */
+ aad, sizeof(aad));
if (rv != SECSuccess) {
SSL_TRC(3,
("%d: TLS13[%d]: record has bogus MAC",
@@ -4271,14 +4997,14 @@ tls13_UnprotectRecord(sslSocket *ss, SSL3Ciphertext *cText, sslBuffer *plaintext
--plaintext->len;
/* Check that we haven't received too much 0-RTT data. */
- if (crSpec->epoch == TrafficKeyEarlyApplicationData &&
+ if (spec->epoch == TrafficKeyEarlyApplicationData &&
cText->type == content_application_data) {
- if (plaintext->len > crSpec->earlyDataRemaining) {
+ if (plaintext->len > spec->earlyDataRemaining) {
*alert = unexpected_message;
PORT_SetError(SSL_ERROR_TOO_MUCH_EARLY_DATA);
return SECFailure;
}
- crSpec->earlyDataRemaining -= plaintext->len;
+ spec->earlyDataRemaining -= plaintext->len;
}
SSL_TRC(10,
@@ -4326,7 +5052,7 @@ tls13_MaybeDo0RTTHandshake(sslSocket *ss)
/* Don't do anything if there is no early_data xtn, which means we're
* not doing early data. */
- if (!ssl3_ClientExtensionAdvertised(ss, ssl_tls13_early_data_xtn)) {
+ if (!ssl3_ExtensionAdvertised(ss, ssl_tls13_early_data_xtn)) {
return SECSuccess;
}
@@ -4341,25 +5067,41 @@ tls13_MaybeDo0RTTHandshake(sslSocket *ss)
ss->xtnData.nextProtoState = SSL_NEXT_PROTO_EARLY_VALUE;
rv = SECITEM_CopyItem(NULL, &ss->xtnData.nextProto,
&ss->sec.ci.sid->u.ssl3.alpnSelection);
- if (rv != SECSuccess)
- return rv;
+ if (rv != SECSuccess) {
+ return SECFailure;
+ }
+ }
+
+ if (ss->opt.enableTls13CompatMode && !IS_DTLS(ss)) {
+ /* Pretend that this is a proper ChangeCipherSpec even though it is sent
+ * before receiving the ServerHello. */
+ ssl_GetSpecWriteLock(ss);
+ tls13_SetSpecRecordVersion(ss, ss->ssl3.cwSpec);
+ ssl_ReleaseSpecWriteLock(ss);
+ ssl_GetXmitBufLock(ss);
+ rv = ssl3_SendChangeCipherSpecsInt(ss);
+ ssl_ReleaseXmitBufLock(ss);
+ if (rv != SECSuccess) {
+ return SECFailure;
+ }
}
/* Cipher suite already set in tls13_SetupClientHello. */
ss->ssl3.hs.preliminaryInfo = 0;
- rv = tls13_DeriveSecret(ss, ss->ssl3.hs.currentSecret,
- kHkdfLabelClient,
- kHkdfLabelEarlyTrafficSecret,
- NULL,
- &ss->ssl3.hs.clientEarlyTrafficSecret);
- if (rv != SECSuccess)
+ rv = tls13_DeriveEarlySecrets(ss);
+ if (rv != SECSuccess) {
return SECFailure;
+ }
+
+ /* Save cwSpec in case we get a HelloRetryRequest and have to send another
+ * ClientHello. */
+ ssl_CipherSpecAddRef(ss->ssl3.cwSpec);
rv = tls13_SetCipherSpec(ss, TrafficKeyEarlyApplicationData,
CipherSpecWrite, PR_TRUE);
if (rv != SECSuccess) {
- return rv;
+ return SECFailure;
}
return SECSuccess;
@@ -4392,32 +5134,45 @@ tls13_SendEndOfEarlyData(sslSocket *ss)
{
SECStatus rv;
- SSL_TRC(3, ("%d: TLS13[%d]: send end_of_early_data extension",
- SSL_GETPID(), ss->fd));
+ SSL_TRC(3, ("%d: TLS13[%d]: send EndOfEarlyData", SSL_GETPID(), ss->fd));
+ PORT_Assert(ss->opt.noLocks || ssl_HaveXmitBufLock(ss));
- rv = SSL3_SendAlert(ss, alert_warning, end_of_early_data);
+ rv = ssl3_AppendHandshakeHeader(ss, ssl_hs_end_of_early_data, 0);
if (rv != SECSuccess) {
- FATAL_ERROR(ss, SEC_ERROR_LIBRARY_FAILURE, internal_error);
- return SECFailure;
+ return rv; /* err set by AppendHandshake. */
}
ss->ssl3.hs.zeroRttState = ssl_0rtt_done;
return SECSuccess;
}
-SECStatus
-tls13_HandleEndOfEarlyData(sslSocket *ss)
+static SECStatus
+tls13_HandleEndOfEarlyData(sslSocket *ss, PRUint8 *b, PRUint32 length)
{
SECStatus rv;
- if (ss->version < SSL_LIBRARY_VERSION_TLS_1_3 ||
- ss->ssl3.hs.zeroRttState != ssl_0rtt_accepted) {
- (void)SSL3_SendAlert(ss, alert_fatal, unexpected_message);
- PORT_SetError(SSL_ERROR_END_OF_EARLY_DATA_ALERT);
+ PORT_Assert(ss->version >= SSL_LIBRARY_VERSION_TLS_1_3);
+
+ rv = TLS13_CHECK_HS_STATE(ss, SSL_ERROR_RX_UNEXPECTED_END_OF_EARLY_DATA,
+ wait_end_of_early_data);
+ if (rv != SECSuccess) {
return SECFailure;
}
- PORT_Assert(TLS13_IN_HS_STATE(ss, ss->opt.requestCertificate ? wait_client_cert : wait_finished));
+ /* 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,
+ TrafficKeyEarlyApplicationData);
+ dtls_ReceivedFirstMessageInFlight(ss);
+ }
+
+ PORT_Assert(ss->ssl3.hs.zeroRttState == ssl_0rtt_accepted);
+
+ if (length) {
+ FATAL_ERROR(ss, SSL_ERROR_RX_MALFORMED_END_OF_EARLY_DATA, decode_error);
+ return SECFailure;
+ }
rv = tls13_SetCipherSpec(ss, TrafficKeyHandshake,
CipherSpecRead, PR_FALSE);
@@ -4427,6 +5182,9 @@ tls13_HandleEndOfEarlyData(sslSocket *ss)
}
ss->ssl3.hs.zeroRttState = ssl_0rtt_done;
+ TLS13_SET_HS_STATE(ss,
+ ss->opt.requestCertificate ? wait_client_cert
+ : wait_finished);
return SECSuccess;
}
@@ -4477,11 +5235,11 @@ tls13_EncodeDraftVersion(SSL3ProtocolVersion version)
/* Pick the highest version we support that is also advertised. */
SECStatus
-tls13_NegotiateVersion(sslSocket *ss, const TLSExtension *supported_versions)
+tls13_NegotiateVersion(sslSocket *ss, const TLSExtension *supportedVersions)
{
PRUint16 version;
- /* Make a copy so we're nondestructive*/
- SECItem data = supported_versions->data;
+ /* Make a copy so we're nondestructive. */
+ SECItem data = supportedVersions->data;
SECItem versions;
SECStatus rv;
@@ -4511,3 +5269,22 @@ tls13_NegotiateVersion(sslSocket *ss, const TLSExtension *supported_versions)
FATAL_ERROR(ss, SSL_ERROR_UNSUPPORTED_VERSION, protocol_version);
return SECFailure;
}
+
+/* This is TLS 1.3 or might negotiate to it. */
+PRBool
+tls13_MaybeTls13(sslSocket *ss)
+{
+ if (ss->version >= SSL_LIBRARY_VERSION_TLS_1_3) {
+ return PR_TRUE;
+ }
+
+ if (ss->vrange.max < SSL_LIBRARY_VERSION_TLS_1_3) {
+ return PR_FALSE;
+ }
+
+ if (!(ss->ssl3.hs.preliminaryInfo & ssl_preinfo_version)) {
+ return PR_TRUE;
+ }
+
+ return PR_FALSE;
+}