diff options
author | wolfbeast <mcwerewolf@gmail.com> | 2018-06-06 21:27:04 +0200 |
---|---|---|
committer | wolfbeast <mcwerewolf@gmail.com> | 2018-06-06 21:27:04 +0200 |
commit | 4a71b30364a4b6d1eaf16fcfdc8e873e6697f293 (patch) | |
tree | a47014077c14579249859ad34afcc5a8f2f0730a /security/nss/lib/ssl/tls13con.c | |
parent | d7da72799521386c110dbba73b1e483b00a0a56a (diff) | |
parent | 2dad0ec41d0b69c0a815012e6ea4bdde81b2875b (diff) | |
download | UXP-4a71b30364a4b6d1eaf16fcfdc8e873e6697f293.tar UXP-4a71b30364a4b6d1eaf16fcfdc8e873e6697f293.tar.gz UXP-4a71b30364a4b6d1eaf16fcfdc8e873e6697f293.tar.lz UXP-4a71b30364a4b6d1eaf16fcfdc8e873e6697f293.tar.xz UXP-4a71b30364a4b6d1eaf16fcfdc8e873e6697f293.zip |
Merge branch 'NSS-335'
Diffstat (limited to 'security/nss/lib/ssl/tls13con.c')
-rw-r--r-- | security/nss/lib/ssl/tls13con.c | 2419 |
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, ¶m, + rv = PK11_Decrypt(keys->key, mechanism, ¶m, out, &uOutLen, maxout, in, inlen); } else { - rv = PK11_Encrypt(keys->write_key, mechanism, ¶m, + rv = PK11_Encrypt(keys->key, mechanism, ¶m, 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; +} |