Source code

Revision control

Other Tools

/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
/*
* TLS 1.3 Protocol
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "stdarg.h"
#include "cert.h"
#include "ssl.h"
#include "keyhi.h"
#include "pk11func.h"
#include "prerr.h"
#include "secitem.h"
#include "secmod.h"
#include "sslimpl.h"
#include "sslproto.h"
#include "sslerr.h"
#include "ssl3exthandle.h"
#include "tls13hkdf.h"
#include "tls13con.h"
#include "tls13err.h"
#include "tls13ech.h"
#include "tls13exthandle.h"
#include "tls13hashstate.h"
#include "tls13subcerts.h"
#include "tls13psk.h"
static SECStatus tls13_SetCipherSpec(sslSocket *ss, PRUint16 epoch,
SSLSecretDirection install,
PRBool deleteSecret);
static SECStatus tls13_SendServerHelloSequence(sslSocket *ss);
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,
const PRUint8 *token, unsigned int tokenLen);
static SECStatus tls13_HandleServerKeyShare(sslSocket *ss);
static SECStatus tls13_HandleEncryptedExtensions(sslSocket *ss, PRUint8 *b,
PRUint32 length);
static SECStatus tls13_SendCertificate(sslSocket *ss);
static SECStatus tls13_HandleCertificate(
sslSocket *ss, PRUint8 *b, PRUint32 length);
static SECStatus tls13_ReinjectHandshakeTranscript(sslSocket *ss);
static SECStatus tls13_SendCertificateRequest(sslSocket *ss);
static SECStatus tls13_HandleCertificateRequest(sslSocket *ss, PRUint8 *b,
PRUint32 length);
static SECStatus
tls13_SendCertificateVerify(sslSocket *ss, SECKEYPrivateKey *privKey);
static SECStatus tls13_HandleCertificateVerify(
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);
SECStatus
tls13_DeriveSecret(sslSocket *ss, PK11SymKey *key,
const char *label,
unsigned int labelLen,
const SSL3Hashes *hashes,
PK11SymKey **dest,
SSLHashType hash);
static SECStatus tls13_SendEndOfEarlyData(sslSocket *ss);
static SECStatus tls13_HandleEndOfEarlyData(sslSocket *ss, const PRUint8 *b,
PRUint32 length);
static SECStatus tls13_MaybeHandleSuppressedEndOfEarlyData(sslSocket *ss);
static SECStatus tls13_SendFinished(sslSocket *ss, PK11SymKey *baseKey);
static SECStatus tls13_ComputePskBinderHash(sslSocket *ss, PRUint8 *b, size_t length,
SSL3Hashes *hashes, SSLHashType type);
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);
static SECStatus tls13_ServerHandleFinished(sslSocket *ss,
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_ComputeEarlySecretsWithPsk(sslSocket *ss);
static SECStatus tls13_ComputeHandshakeSecrets(sslSocket *ss);
static SECStatus tls13_ComputeApplicationSecrets(sslSocket *ss);
static SECStatus tls13_ComputeFinalSecrets(sslSocket *ss);
static SECStatus tls13_ComputeFinished(
sslSocket *ss, PK11SymKey *baseKey, SSLHashType hashType,
const SSL3Hashes *hashes, PRBool sending, PRUint8 *output,
unsigned int *outputLen, unsigned int maxOutputLen);
static SECStatus tls13_SendClientSecondRound(sslSocket *ss);
static SECStatus tls13_SendClientSecondFlight(sslSocket *ss,
PRBool sendClientCert,
SSL3AlertDescription *sendAlert);
static SECStatus tls13_FinishHandshake(sslSocket *ss);
const char kHkdfLabelClient[] = "c";
const char kHkdfLabelServer[] = "s";
const char kHkdfLabelDerivedSecret[] = "derived";
const char kHkdfLabelResPskBinderKey[] = "res binder";
const char kHkdfLabelExtPskBinderKey[] = "ext 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[] = "res master";
const char kHkdfLabelExporterMasterSecret[] = "exp master";
const char kHkdfLabelResumption[] = "resumption";
const char kHkdfLabelTrafficUpdate[] = "traffic upd";
const char kHkdfPurposeKey[] = "key";
const char kHkdfPurposeSn[] = "sn";
const char kHkdfPurposeIv[] = "iv";
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 <=
SSL_LIBRARY_VERSION_TLS_1_3);
void
tls13_FatalError(sslSocket *ss, PRErrorCode prError, SSL3AlertDescription desc)
{
PORT_Assert(desc != internal_error); /* These should never happen */
(void)SSL3_SendAlert(ss, alert_fatal, desc);
PORT_SetError(prError);
}
#ifdef TRACE
#define STATE_CASE(a) \
case a: \
return #a
static char *
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);
STATE_CASE(wait_change_cipher);
STATE_CASE(wait_finished);
STATE_CASE(wait_server_hello);
STATE_CASE(wait_certificate_status);
STATE_CASE(wait_server_cert);
STATE_CASE(wait_server_key);
STATE_CASE(wait_cert_request);
STATE_CASE(wait_hello_done);
STATE_CASE(wait_new_session_ticket);
STATE_CASE(wait_encrypted_extensions);
default:
break;
}
PORT_Assert(0);
return "unknown";
}
#endif
#define TLS13_WAIT_STATE_MASK 0x80
#define TLS13_BASE_WAIT_STATE(ws) (ws & ~TLS13_WAIT_STATE_MASK)
/* We don't mask idle_handshake because other parts of the code use it*/
#define TLS13_WAIT_STATE(ws) (((ws == idle_handshake) || (ws == wait_server_hello)) ? ws : ws | TLS13_WAIT_STATE_MASK)
#define TLS13_CHECK_HS_STATE(ss, err, ...) \
tls13_CheckHsState(ss, err, #err, __func__, __FILE__, __LINE__, \
__VA_ARGS__, \
wait_invalid)
void
tls13_SetHsState(sslSocket *ss, SSL3WaitState ws,
const char *func, const char *file, int line)
{
#ifdef TRACE
const char *new_state_name =
tls13_HandshakeState(ws);
SSL_TRC(3, ("%d: TLS13[%d]: %s state change from %s->%s in %s (%s:%d)",
SSL_GETPID(), ss->fd, SSL_ROLE(ss),
tls13_HandshakeState(TLS13_BASE_WAIT_STATE(ss->ssl3.hs.ws)),
new_state_name,
func, file, line));
#endif
ss->ssl3.hs.ws = TLS13_WAIT_STATE(ws);
}
static PRBool
tls13_InHsStateV(sslSocket *ss, va_list ap)
{
SSL3WaitState ws;
while ((ws = va_arg(ap, SSL3WaitState)) != wait_invalid) {
if (TLS13_WAIT_STATE(ws) == ss->ssl3.hs.ws) {
return PR_TRUE;
}
}
return PR_FALSE;
}
PRBool
tls13_InHsState(sslSocket *ss, ...)
{
PRBool found;
va_list ap;
va_start(ap, ss);
found = tls13_InHsStateV(ss, ap);
va_end(ap);
return found;
}
static SECStatus
tls13_CheckHsState(sslSocket *ss, int err, const char *error_name,
const char *func, const char *file, int line,
...)
{
va_list ap;
va_start(ap, line);
if (tls13_InHsStateV(ss, ap)) {
va_end(ap);
return SECSuccess;
}
va_end(ap);
SSL_TRC(3, ("%d: TLS13[%d]: error %s state is (%s) at %s (%s:%d)",
SSL_GETPID(), ss->fd,
error_name,
tls13_HandshakeState(TLS13_BASE_WAIT_STATE(ss->ssl3.hs.ws)),
func, file, line));
tls13_FatalError(ss, err, unexpected_message);
return SECFailure;
}
PRBool
tls13_IsPostHandshake(const sslSocket *ss)
{
return ss->version >= SSL_LIBRARY_VERSION_TLS_1_3 && ss->firstHsDone;
}
SSLHashType
tls13_GetHashForCipherSuite(ssl3CipherSuite suite)
{
const ssl3CipherSuiteDef *cipherDef =
ssl_LookupCipherSuiteDef(suite);
PORT_Assert(cipherDef);
if (!cipherDef) {
return ssl_hash_none;
}
return cipherDef->prf_hash;
}
SSLHashType
tls13_GetHash(const sslSocket *ss)
{
/* suite_def may not be set yet when doing EPSK 0-Rtt. */
if (!ss->ssl3.hs.suite_def) {
if (ss->xtnData.selectedPsk) {
return ss->xtnData.selectedPsk->hash;
}
/* This should never happen. */
PORT_Assert(0);
return ssl_hash_none;
}
/* All TLS 1.3 cipher suites must have an explict PRF hash. */
PORT_Assert(ss->ssl3.hs.suite_def->prf_hash != ssl_hash_none);
return ss->ssl3.hs.suite_def->prf_hash;
}
SECStatus
tls13_GetHashAndCipher(PRUint16 version, PRUint16 cipherSuite,
SSLHashType *hash, const ssl3BulkCipherDef **cipher)
{
if (version < SSL_LIBRARY_VERSION_TLS_1_3) {
PORT_SetError(SEC_ERROR_INVALID_ARGS);
return SECFailure;
}
// Lookup and check the suite.
SSLVersionRange vrange = { version, version };
if (!ssl3_CipherSuiteAllowedForVersionRange(cipherSuite, &vrange)) {
PORT_SetError(SEC_ERROR_INVALID_ARGS);
return SECFailure;
}
const ssl3CipherSuiteDef *suiteDef = ssl_LookupCipherSuiteDef(cipherSuite);
const ssl3BulkCipherDef *cipherDef = ssl_GetBulkCipherDef(suiteDef);
if (cipherDef->type != type_aead) {
PORT_SetError(SEC_ERROR_INVALID_ARGS);
return SECFailure;
}
*hash = suiteDef->prf_hash;
if (cipher != NULL) {
*cipher = cipherDef;
}
return SECSuccess;
}
unsigned int
tls13_GetHashSizeForHash(SSLHashType hash)
{
switch (hash) {
case ssl_hash_sha256:
return 32;
case ssl_hash_sha384:
return 48;
default:
PORT_Assert(0);
}
return 32;
}
unsigned int
tls13_GetHashSize(const sslSocket *ss)
{
return tls13_GetHashSizeForHash(tls13_GetHash(ss));
}
static CK_MECHANISM_TYPE
tls13_GetHmacMechanismFromHash(SSLHashType hashType)
{
switch (hashType) {
case ssl_hash_sha256:
return CKM_SHA256_HMAC;
case ssl_hash_sha384:
return CKM_SHA384_HMAC;
default:
PORT_Assert(0);
}
return CKM_SHA256_HMAC;
}
static CK_MECHANISM_TYPE
tls13_GetHmacMechanism(const sslSocket *ss)
{
return tls13_GetHmacMechanismFromHash(tls13_GetHash(ss));
}
SECStatus
tls13_ComputeHash(sslSocket *ss, SSL3Hashes *hashes,
const PRUint8 *buf, unsigned int len,
SSLHashType hash)
{
SECStatus rv;
rv = PK11_HashBuf(ssl3_HashTypeToOID(hash), hashes->u.raw, buf, len);
if (rv != SECSuccess) {
FATAL_ERROR(ss, SEC_ERROR_LIBRARY_FAILURE, internal_error);
return SECFailure;
}
hashes->len = tls13_GetHashSizeForHash(hash);
return SECSuccess;
}
SECStatus
tls13_CreateKeyShare(sslSocket *ss, const sslNamedGroupDef *groupDef,
sslEphemeralKeyPair **keyPair)
{
SECStatus rv;
const ssl3DHParams *params;
PORT_Assert(groupDef);
switch (groupDef->keaType) {
case ssl_kea_ecdh:
rv = ssl_CreateECDHEphemeralKeyPair(ss, groupDef, keyPair);
if (rv != SECSuccess) {
return SECFailure;
}
break;
case ssl_kea_dh:
params = ssl_GetDHEParams(groupDef);
PORT_Assert(params->name != ssl_grp_ffdhe_custom);
rv = ssl_CreateDHEKeyPair(groupDef, params, keyPair);
if (rv != SECSuccess) {
return SECFailure;
}
break;
default:
PORT_Assert(0);
PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
return SECFailure;
}
return rv;
}
SECStatus
tls13_AddKeyShare(sslSocket *ss, const sslNamedGroupDef *groupDef)
{
sslEphemeralKeyPair *keyPair = NULL;
SECStatus rv;
rv = tls13_CreateKeyShare(ss, groupDef, &keyPair);
if (rv != SECSuccess) {
return SECFailure;
}
PR_APPEND_LINK(&keyPair->link, &ss->ephemeralKeyPairs);
return SECSuccess;
}
SECStatus
SSL_SendAdditionalKeyShares(PRFileDesc *fd, unsigned int count)
{
sslSocket *ss = ssl_FindSocket(fd);
if (!ss) {
PORT_SetError(SEC_ERROR_INVALID_ARGS);
return SECFailure;
}
ss->additionalShares = count;
return SECSuccess;
}
/*
* Generate shares for ECDHE and FFDHE. This picks the first enabled group of
* the requisite type and creates a share for that.
*
* Called from ssl3_SendClientHello.
*/
SECStatus
tls13_SetupClientHello(sslSocket *ss, sslClientHelloType chType)
{
unsigned int i;
SSL3Statistics *ssl3stats = SSL_GetStatistics();
NewSessionTicket *session_ticket = NULL;
sslSessionID *sid = ss->sec.ci.sid;
unsigned int numShares = 0;
SECStatus rv;
PORT_Assert(ss->opt.noLocks || ssl_HaveSSL3HandshakeLock(ss));
PORT_Assert(ss->opt.noLocks || ssl_HaveXmitBufLock(ss));
rv = tls13_ClientSetupEch(ss, chType);
if (rv != SECSuccess) {
return SECFailure;
}
/* Everything below here is only run on the first CH. */
if (chType != client_hello_initial) {
return SECSuccess;
}
/* Select the first enabled group.
* TODO(ekr@rtfm.com): be smarter about offering the group
* that the other side negotiated if we are resuming. */
PORT_Assert(PR_CLIST_IS_EMPTY(&ss->ephemeralKeyPairs));
for (i = 0; i < SSL_NAMED_GROUP_COUNT; ++i) {
if (!ss->namedGroupPreferences[i]) {
continue;
}
rv = tls13_AddKeyShare(ss, ss->namedGroupPreferences[i]);
if (rv != SECSuccess) {
return SECFailure;
}
if (++numShares > ss->additionalShares) {
break;
}
}
if (PR_CLIST_IS_EMPTY(&ss->ephemeralKeyPairs)) {
PORT_SetError(SSL_ERROR_NO_CIPHERS_SUPPORTED);
return SECFailure;
}
/* Try to do stateless resumption, if we can. */
if (sid->cached != never_cached &&
sid->version >= SSL_LIBRARY_VERSION_TLS_1_3) {
/* The caller must be holding sid->u.ssl3.lock for reading. */
session_ticket = &sid->u.ssl3.locked.sessionTicket;
PORT_Assert(session_ticket && session_ticket->ticket.data);
if (ssl_TicketTimeValid(ss, session_ticket)) {
ss->statelessResume = PR_TRUE;
}
if (ss->statelessResume) {
PORT_Assert(ss->sec.ci.sid);
rv = tls13_RecoverWrappedSharedSecret(ss, ss->sec.ci.sid);
if (rv != SECSuccess) {
FATAL_ERROR(ss, SEC_ERROR_LIBRARY_FAILURE, internal_error);
SSL_AtomicIncrementLong(&ssl3stats->sch_sid_cache_not_ok);
ssl_UncacheSessionID(ss);
ssl_FreeSID(ss->sec.ci.sid);
ss->sec.ci.sid = NULL;
return SECFailure;
}
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;
}
PORT_Assert(!PR_CLIST_IS_EMPTY(&ss->ssl3.hs.psks));
}
}
/* Derive the binder keys if any PSKs. */
if (!PR_CLIST_IS_EMPTY(&ss->ssl3.hs.psks)) {
/* If an External PSK specified a suite, use that. */
sslPsk *psk = (sslPsk *)PR_LIST_HEAD(&ss->ssl3.hs.psks);
if (!ss->statelessResume &&
psk->type == ssl_psk_external &&
psk->zeroRttSuite != TLS_NULL_WITH_NULL_NULL) {
ss->ssl3.hs.cipher_suite = psk->zeroRttSuite;
}
rv = tls13_ComputeEarlySecretsWithPsk(ss);
if (rv != SECSuccess) {
FATAL_ERROR(ss, SEC_ERROR_LIBRARY_FAILURE, internal_error);
return SECFailure;
}
}
return SECSuccess;
}
static SECStatus
tls13_ImportDHEKeyShare(SECKEYPublicKey *peerKey,
PRUint8 *b, PRUint32 length,
SECKEYPublicKey *pubKey)
{
SECStatus rv;
SECItem publicValue = { siBuffer, NULL, 0 };
publicValue.data = b;
publicValue.len = length;
if (!ssl_IsValidDHEShare(&pubKey->u.dh.prime, &publicValue)) {
PORT_SetError(SSL_ERROR_RX_MALFORMED_DHE_KEY_SHARE);
return SECFailure;
}
peerKey->keyType = dhKey;
rv = SECITEM_CopyItem(peerKey->arena, &peerKey->u.dh.prime,
&pubKey->u.dh.prime);
if (rv != SECSuccess)
return SECFailure;
rv = SECITEM_CopyItem(peerKey->arena, &peerKey->u.dh.base,
&pubKey->u.dh.base);
if (rv != SECSuccess)
return SECFailure;
rv = SECITEM_CopyItem(peerKey->arena, &peerKey->u.dh.publicValue,
&publicValue);
if (rv != SECSuccess)
return SECFailure;
return SECSuccess;
}
SECStatus
tls13_HandleKeyShare(sslSocket *ss,
TLS13KeyShareEntry *entry,
sslKeyPair *keyPair,
SSLHashType hash,
PK11SymKey **out)
{
PORTCheapArenaPool arena;
SECKEYPublicKey *peerKey;
CK_MECHANISM_TYPE mechanism;
PRErrorCode errorCode;
PK11SymKey *key;
SECStatus rv;
int keySize = 0;
PORT_InitCheapArena(&arena, DER_DEFAULT_CHUNKSIZE);
peerKey = PORT_ArenaZNew(&arena.arena, SECKEYPublicKey);
if (peerKey == NULL) {
goto loser;
}
peerKey->arena = &arena.arena;
peerKey->pkcs11Slot = NULL;
peerKey->pkcs11ID = CK_INVALID_HANDLE;
switch (entry->group->keaType) {
case ssl_kea_ecdh:
rv = ssl_ImportECDHKeyShare(peerKey,
entry->key_exchange.data,
entry->key_exchange.len,
entry->group);
mechanism = CKM_ECDH1_DERIVE;
break;
case ssl_kea_dh:
rv = tls13_ImportDHEKeyShare(peerKey,
entry->key_exchange.data,
entry->key_exchange.len,
keyPair->pubKey);
mechanism = CKM_DH_PKCS_DERIVE;
keySize = peerKey->u.dh.publicValue.len;
break;
default:
PORT_Assert(0);
goto loser;
}
if (rv != SECSuccess) {
goto loser;
}
key = PK11_PubDeriveWithKDF(
keyPair->privKey, peerKey, PR_FALSE, NULL, NULL, mechanism,
CKM_HKDF_DERIVE, CKA_DERIVE, keySize, CKD_NULL, NULL, NULL);
if (!key) {
ssl_MapLowLevelError(SSL_ERROR_KEY_EXCHANGE_FAILURE);
goto loser;
}
*out = key;
PORT_DestroyCheapArena(&arena);
return SECSuccess;
loser:
PORT_DestroyCheapArena(&arena);
errorCode = PORT_GetError(); /* don't overwrite the error code */
tls13_FatalError(ss, errorCode, illegal_parameter);
return SECFailure;
}
static PRBool
tls13_UseServerSecret(sslSocket *ss, SSLSecretDirection direction)
{
return ss->sec.isServer == (direction == ssl_secret_write);
}
static PK11SymKey **
tls13_TrafficSecretRef(sslSocket *ss, SSLSecretDirection direction)
{
if (tls13_UseServerSecret(ss, direction)) {
return &ss->ssl3.hs.serverTrafficSecret;
}
return &ss->ssl3.hs.clientTrafficSecret;
}
SECStatus
tls13_UpdateTrafficKeys(sslSocket *ss, SSLSecretDirection direction)
{
PK11SymKey **secret;
PK11SymKey *updatedSecret;
PRUint16 epoch;
SECStatus rv;
secret = tls13_TrafficSecretRef(ss, direction);
rv = tls13_HkdfExpandLabel(*secret, tls13_GetHash(ss),
NULL, 0,
kHkdfLabelTrafficUpdate,
strlen(kHkdfLabelTrafficUpdate),
tls13_GetHmacMechanism(ss),
tls13_GetHashSize(ss),
ss->protocolVariant,
&updatedSecret);
if (rv != SECSuccess) {
return SECFailure;
}
PK11_FreeSymKey(*secret);
*secret = updatedSecret;
ssl_GetSpecReadLock(ss);
if (direction == ssl_secret_read) {
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;
if (ss->secretCallback) {
ss->secretCallback(ss->fd, epoch, direction, updatedSecret,
ss->secretCallbackArg);
}
rv = tls13_SetCipherSpec(ss, epoch, direction, PR_FALSE);
if (rv != SECSuccess) {
FATAL_ERROR(ss, SEC_ERROR_LIBRARY_FAILURE, internal_error);
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));
PORT_Assert(!ss->sec.isServer || !ss->ssl3.clientCertRequested);
if (!tls13_IsPostHandshake(ss)) {
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, ssl_secret_write);
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 (!tls13_IsPostHandshake(ss)) {
PORT_SetError(SEC_ERROR_INVALID_ARGS);
return SECFailure;
}
if (ss->ssl3.clientCertRequested) {
PORT_SetError(PR_WOULD_BLOCK_ERROR);
return SECFailure;
}
rv = TLS13_CHECK_HS_STATE(ss, SEC_ERROR_INVALID_ARGS,
idle_handshake);
if (rv != SECSuccess) {
return SECFailure;
}
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));
if (!tls13_IsPostHandshake(ss)) {
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, ssl_secret_read);
if (rv != SECSuccess) {
return SECFailure; /* Error code set by tls13_UpdateTrafficKeys. */
}
if (update == update_requested) {
PRBool sendUpdate;
if (ss->ssl3.clientCertRequested) {
/* Post-handshake auth is in progress; defer sending a key update. */
ss->ssl3.keyUpdateDeferred = PR_TRUE;
ss->ssl3.deferredKeyUpdateRequest = update_not_requested;
sendUpdate = PR_FALSE;
} else if (ss->ssl3.peerRequestedKeyUpdate) {
/* Only send an update if we have sent with the current spec. This
* prevents us from being forced to crank forward pointlessly. */
ssl_GetSpecReadLock(ss);
sendUpdate = ss->ssl3.cwSpec->nextSeqNum > 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
SSLExp_SendCertificateRequest(PRFileDesc *fd)
{
SECStatus rv;
sslSocket *ss = ssl_FindSocket(fd);
if (!ss) {
return SECFailure;
}
/* Not supported. */
if (IS_DTLS(ss)) {
PORT_SetError(SSL_ERROR_FEATURE_NOT_SUPPORTED_FOR_VERSION);
return SECFailure;
}
if (!tls13_IsPostHandshake(ss)) {
PORT_SetError(SEC_ERROR_INVALID_ARGS);
return SECFailure;
}
if (ss->ssl3.clientCertRequested) {
PORT_SetError(PR_WOULD_BLOCK_ERROR);
return SECFailure;
}
/* Disallow a CertificateRequest if this connection uses an external PSK. */
if (ss->sec.authType == ssl_auth_psk) {
PORT_SetError(SSL_ERROR_FEATURE_DISABLED);
return SECFailure;
}
rv = TLS13_CHECK_HS_STATE(ss, SEC_ERROR_INVALID_ARGS,
idle_handshake);
if (rv != SECSuccess) {
return SECFailure;
}
if (!ssl3_ExtensionNegotiated(ss, ssl_tls13_post_handshake_auth_xtn)) {
PORT_SetError(SSL_ERROR_MISSING_POST_HANDSHAKE_AUTH_EXTENSION);
return SECFailure;
}
ssl_GetSSL3HandshakeLock(ss);
rv = tls13_SendCertificateRequest(ss);
if (rv == SECSuccess) {
ssl_GetXmitBufLock(ss);
rv = ssl3_FlushHandshake(ss, 0);
ssl_ReleaseXmitBufLock(ss);
ss->ssl3.clientCertRequested = PR_TRUE;
}
ssl_ReleaseSSL3HandshakeLock(ss);
return rv;
}
SECStatus
tls13_HandlePostHelloHandshakeMessage(sslSocket *ss, PRUint8 *b, PRUint32 length)
{
if (ss->sec.isServer && ss->ssl3.hs.zeroRttIgnore != ssl_0rtt_ignore_none) {
SSL_TRC(3, ("%d: TLS13[%d]: successfully decrypted handshake after "
"failed 0-RTT",
SSL_GETPID(), ss->fd));
ss->ssl3.hs.zeroRttIgnore = ssl_0rtt_ignore_none;
}
/* TODO(ekr@rtfm.com): Would it be better to check all the states here? */
switch (ss->ssl3.hs.msg_type) {
case ssl_hs_certificate:
return tls13_HandleCertificate(ss, b, length);
case ssl_hs_certificate_request:
return tls13_HandleCertificateRequest(ss, b, length);
case ssl_hs_certificate_verify:
return tls13_HandleCertificateVerify(ss, b, length);
case ssl_hs_encrypted_extensions:
return tls13_HandleEncryptedExtensions(ss, b, length);
case ssl_hs_new_session_ticket:
return tls13_HandleNewSessionTicket(ss, b, length);
case ssl_hs_finished:
if (ss->sec.isServer) {
return tls13_ServerHandleFinished(ss, b, length);
} else {
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;
}
PORT_Assert(0); /* Unreached */
return SECFailure;
}
static SECStatus
tls13_RecoverWrappedSharedSecret(sslSocket *ss, sslSessionID *sid)
{
PK11SymKey *wrapKey; /* wrapping key */
SECItem wrappedMS = { siBuffer, NULL, 0 };
SSLHashType hashType;
SSL_TRC(3, ("%d: TLS13[%d]: recovering static secret (%s)",
SSL_GETPID(), ss->fd, SSL_ROLE(ss)));
/* Now find the hash used as the PRF for the previous handshake. */
hashType = tls13_GetHashForCipherSuite(sid->u.ssl3.cipherSuite);
/* If we are the server, we compute the wrapping key, but if we
* are the client, its coordinates are stored with the ticket. */
if (ss->sec.isServer) {
wrapKey = ssl3_GetWrappingKey(ss, NULL,
sid->u.ssl3.masterWrapMech,
ss->pkcs11PinArg);
} else {
PK11SlotInfo *slot = SECMOD_LookupSlot(sid->u.ssl3.masterModuleID,
sid->u.ssl3.masterSlotID);
if (!slot)
return SECFailure;
wrapKey = PK11_GetWrapKey(slot,
sid->u.ssl3.masterWrapIndex,
sid->u.ssl3.masterWrapMech,
sid->u.ssl3.masterWrapSeries,
ss->pkcs11PinArg);
PK11_FreeSlot(slot);
}
if (!wrapKey) {
return SECFailure;
}
wrappedMS.data = sid->u.ssl3.keys.wrapped_master_secret;
wrappedMS.len = sid->u.ssl3.keys.wrapped_master_secret_len;
PK11SymKey *unwrappedPsk = ssl_unwrapSymKey(wrapKey, sid->u.ssl3.masterWrapMech,
NULL, &wrappedMS, CKM_SSL3_MASTER_KEY_DERIVE,
CKA_DERIVE, tls13_GetHashSizeForHash(hashType),
CKF_SIGN | CKF_VERIFY, ss->pkcs11PinArg);
PK11_FreeSymKey(wrapKey);
if (!unwrappedPsk) {
return SECFailure;
}
sslPsk *rpsk = tls13_MakePsk(unwrappedPsk, ssl_psk_resume, hashType, NULL);
if (!rpsk) {
PK11_FreeSymKey(unwrappedPsk);
return SECFailure;
}
if (sid->u.ssl3.locked.sessionTicket.flags & ticket_allow_early_data) {
rpsk->maxEarlyData = sid->u.ssl3.locked.sessionTicket.max_early_data_size;
rpsk->zeroRttSuite = sid->u.ssl3.cipherSuite;
}
PRINT_KEY(50, (ss, "Recovered RMS", rpsk->key));
PORT_Assert(PR_CLIST_IS_EMPTY(&ss->ssl3.hs.psks) ||
((sslPsk *)PR_LIST_HEAD(&ss->ssl3.hs.psks))->type != ssl_psk_resume);
if (ss->sec.isServer) {
/* In server, we couldn't select the RPSK in the extension handler
* since it was not unwrapped yet. We're committed now, so select
* it and add it to the list (to ensure it is freed). */
ss->xtnData.selectedPsk = rpsk;
}
PR_APPEND_LINK(&rpsk->link, &ss->ssl3.hs.psks);
return SECSuccess;
}
/* Key Derivation Functions.
*
* 0
* |
* v
* PSK -> HKDF-Extract = Early Secret
* |
* +-----> 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
* Derive-Secret(., "derived", "")
* |
* v
*(EC)DHE -> HKDF-Extract = Handshake Secret
* |
* +-----> Derive-Secret(., "c hs traffic",
* | ClientHello...ServerHello)
* | = client_handshake_traffic_secret
* |
* +-----> Derive-Secret(., "s hs traffic",
* | ClientHello...ServerHello)
* | = server_handshake_traffic_secret
* v
* Derive-Secret(., "derived", "")
* |
* v
* 0 -> HKDF-Extract = Master Secret
* |
* +-----> Derive-Secret(., "c ap traffic",
* | ClientHello...Server Finished)
* | = client_traffic_secret_0
* |
* +-----> Derive-Secret(., "s ap traffic",
* | ClientHello...Server Finished)
* | = server_traffic_secret_0
* |
* +-----> Derive-Secret(., "exp master",
* | ClientHello...Server Finished)
* | = exporter_secret
* |
* +-----> Derive-Secret(., "res master",
* ClientHello...Client Finished)
* = resumption_master_secret
*
*/
static SECStatus
tls13_ComputeEarlySecretsWithPsk(sslSocket *ss)
{
SECStatus rv;
SSL_TRC(5, ("%d: TLS13[%d]: compute early secrets (%s)",
SSL_GETPID(), ss->fd, SSL_ROLE(ss)));
PORT_Assert(!ss->ssl3.hs.currentSecret);
sslPsk *psk = NULL;
if (ss->sec.isServer) {
psk = ss->xtnData.selectedPsk;
} else {
/* Client to use the first PSK for early secrets. */
PORT_Assert(!PR_CLIST_IS_EMPTY(&ss->ssl3.hs.psks));
psk = (sslPsk *)PR_LIST_HEAD(&ss->ssl3.hs.psks);
}
PORT_Assert(psk && psk->key);
PORT_Assert(psk->hash != ssl_hash_none);
PK11SymKey *earlySecret = NULL;
rv = tls13_HkdfExtract(NULL, psk->key, psk->hash, &earlySecret);
if (rv != SECSuccess) {
return SECFailure;
}
/* No longer need the raw input key */
PK11_FreeSymKey(psk->key);
psk->key = NULL;
const char *label = (psk->type == ssl_psk_resume) ? kHkdfLabelResPskBinderKey : kHkdfLabelExtPskBinderKey;
rv = tls13_DeriveSecretNullHash(ss, earlySecret,
label, strlen(label),
&psk->binderKey, psk->hash);
if (rv != SECSuccess) {
PK11_FreeSymKey(earlySecret);
return SECFailure;
}
ss->ssl3.hs.currentSecret = earlySecret;
return SECSuccess;
}
/* This derives the early traffic and early exporter secrets. */
static SECStatus
tls13_DeriveEarlySecrets(sslSocket *ss)
{
SECStatus rv;
PORT_Assert(ss->ssl3.hs.currentSecret);
rv = tls13_DeriveSecretWrap(ss, ss->ssl3.hs.currentSecret,
kHkdfLabelClient,
kHkdfLabelEarlyTrafficSecret,
keylogLabelClientEarlyTrafficSecret,
&ss->ssl3.hs.clientEarlyTrafficSecret);
if (rv != SECSuccess) {
return SECFailure;
}
if (ss->secretCallback) {
ss->secretCallback(ss->fd, (PRUint16)TrafficKeyEarlyApplicationData,
ss->sec.isServer ? ssl_secret_read : ssl_secret_write,
ss->ssl3.hs.clientEarlyTrafficSecret,
ss->secretCallbackArg);
}
rv = tls13_DeriveSecretWrap(ss, ss->ssl3.hs.currentSecret,
NULL, kHkdfLabelEarlyExporterSecret,
keylogLabelEarlyExporterSecret,
&ss->ssl3.hs.earlyExporterSecret);
if (rv != SECSuccess) {
return SECFailure;
}
return SECSuccess;
}
static SECStatus
tls13_ComputeHandshakeSecret(sslSocket *ss)
{
SECStatus rv;
PK11SymKey *derivedSecret = NULL;
PK11SymKey *newSecret = NULL;
SSL_TRC(5, ("%d: TLS13[%d]: compute handshake secret (%s)",
SSL_GETPID(), ss->fd, SSL_ROLE(ss)));
/* If no PSK, generate the default early secret. */
if (!ss->ssl3.hs.currentSecret) {
PORT_Assert(!ss->xtnData.selectedPsk);
rv = tls13_HkdfExtract(NULL, NULL,
tls13_GetHash(ss), &ss->ssl3.hs.currentSecret);
if (rv != SECSuccess) {
return SECFailure;
}
}
PORT_Assert(ss->ssl3.hs.currentSecret);
PORT_Assert(ss->ssl3.hs.dheSecret);
/* Derive-Secret(., "derived", "") */
rv = tls13_DeriveSecretNullHash(ss, ss->ssl3.hs.currentSecret,
kHkdfLabelDerivedSecret,
strlen(kHkdfLabelDerivedSecret),
&derivedSecret, tls13_GetHash(ss));
if (rv != SECSuccess) {
LOG_ERROR(ss, SEC_ERROR_LIBRARY_FAILURE);
return rv;
}
/* HKDF-Extract(ECDHE, .) = Handshake Secret */
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;
}
PK11_FreeSymKey(ss->ssl3.hs.currentSecret);
ss->ssl3.hs.currentSecret = newSecret;
return SECSuccess;
}
static SECStatus
tls13_ComputeHandshakeSecrets(sslSocket *ss)
{
SECStatus rv;
PK11SymKey *derivedSecret = NULL;
PK11SymKey *newSecret = NULL;
PK11_FreeSymKey(ss->ssl3.hs.dheSecret);
ss->ssl3.hs.dheSecret = NULL;
SSL_TRC(5, ("%d: TLS13[%d]: compute handshake secrets (%s)",
SSL_GETPID(), ss->fd, SSL_ROLE(ss)));
/* Now compute |*HsTrafficSecret| */
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_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;
}
if (ss->secretCallback) {
SSLSecretDirection dir =
ss->sec.isServer ? ssl_secret_read : ssl_secret_write;
ss->secretCallback(ss->fd, (PRUint16)TrafficKeyHandshake, dir,
ss->ssl3.hs.clientHsTrafficSecret,
ss->secretCallbackArg);
dir = ss->sec.isServer ? ssl_secret_write : ssl_secret_read;
ss->secretCallback(ss->fd, (PRUint16)TrafficKeyHandshake, dir,
ss->ssl3.hs.serverHsTrafficSecret,
ss->secretCallbackArg);
}
SSL_TRC(5, ("%d: TLS13[%d]: compute master secret (%s)",
SSL_GETPID(), ss->fd, SSL_ROLE(ss)));
/* Crank HKDF forward to make master secret, which we
* stuff in current secret. */
rv = tls13_DeriveSecretNullHash(ss, ss->ssl3.hs.currentSecret,
kHkdfLabelDerivedSecret,
strlen(kHkdfLabelDerivedSecret),
&derivedSecret, tls13_GetHash(ss));
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;
}
PK11_FreeSymKey(ss->ssl3.hs.currentSecret);
ss->ssl3.hs.currentSecret = newSecret;
return SECSuccess;
}
static SECStatus
tls13_ComputeApplicationSecrets(sslSocket *ss)
{
SECStatus rv;
rv = tls13_DeriveSecretWrap(ss, ss->ssl3.hs.currentSecret,
kHkdfLabelClient,
kHkdfLabelApplicationTrafficSecret,
keylogLabelClientTrafficSecret,
&ss->ssl3.hs.clientTrafficSecret);
if (rv != SECSuccess) {
return SECFailure;
}
rv = tls13_DeriveSecretWrap(ss, ss->ssl3.hs.currentSecret,
kHkdfLabelServer,
kHkdfLabelApplicationTrafficSecret,
keylogLabelServerTrafficSecret,
&ss->ssl3.hs.serverTrafficSecret);
if (rv != SECSuccess) {
return SECFailure;
}
if (ss->secretCallback) {
SSLSecretDirection dir =
ss->sec.isServer ? ssl_secret_read : ssl_secret_write;
ss->secretCallback(ss->fd, (PRUint16)TrafficKeyApplicationData,
dir, ss->ssl3.hs.clientTrafficSecret,
ss->secretCallbackArg);
dir = ss->sec.isServer ? ssl_secret_write : ssl_secret_read;
ss->secretCallback(ss->fd, (PRUint16)TrafficKeyApplicationData,
dir, ss->ssl3.hs.serverTrafficSecret,
ss->secretCallbackArg);
}
rv = tls13_DeriveSecretWrap(ss, ss->ssl3.hs.currentSecret,
NULL, kHkdfLabelExporterMasterSecret,
keylogLabelExporterSecret,
&ss->ssl3.hs.exporterSecret);
if (rv != SECSuccess) {
return SECFailure;
}
return SECSuccess;
}
static SECStatus
tls13_ComputeFinalSecrets(sslSocket *ss)
{
SECStatus rv;
PORT_Assert(!ss->ssl3.crSpec->masterSecret);
PORT_Assert(!ss->ssl3.cwSpec->masterSecret);
PORT_Assert(ss->ssl3.hs.currentSecret);
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;
}
return SECSuccess;
}
static void
tls13_RestoreCipherInfo(sslSocket *ss, sslSessionID *sid)
{
/* Set these to match the cached value.
* TODO(ekr@rtfm.com): Make a version with the "true" values.
*/
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. */
static PRBool
tls13_CanResume(sslSocket *ss, const sslSessionID *sid)
{
const sslServerCert *sc;
if (!sid) {
return PR_FALSE;
}
if (sid->version != ss->version) {
return PR_FALSE;
}
#ifdef UNSAFE_FUZZER_MODE
/* When fuzzing, sid could contain garbage that will crash tls13_GetHashForCipherSuite.
* Do a direct comparison of cipher suites. This makes us refuse to resume when the
* protocol allows it, but resumption is discretionary anyway. */
if (sid->u.ssl3.cipherSuite != ss->ssl3.hs.cipher_suite) {
#else
if (tls13_GetHashForCipherSuite(sid->u.ssl3.cipherSuite) != tls13_GetHashForCipherSuite(ss->ssl3.hs.cipher_suite)) {
#endif
return PR_FALSE;
}
/* Server sids don't remember the server cert we previously sent, but they
* do remember the type of certificate we originally used, so we can locate
* it again, provided that the current ssl socket has had its server certs
* configured the same as the previous one. */
sc = ssl_FindServerCert(ss, sid->authType, sid->namedCurve);
if (!sc || !sc->serverCert) {
return PR_FALSE;
}
return PR_TRUE;
}
static PRBool
tls13_CanNegotiateZeroRtt(sslSocket *ss, const sslSessionID *sid)
{
PORT_Assert(ss->ssl3.hs.zeroRttState == ssl_0rtt_sent);
sslPsk *psk = ss->xtnData.selectedPsk;
if (!ss->opt.enable0RttData) {
return PR_FALSE;
}
if (!psk) {
return PR_FALSE;
}
if (psk->zeroRttSuite == TLS_NULL_WITH_NULL_NULL) {
return PR_FALSE;
}
if (!psk->maxEarlyData) {
return PR_FALSE;
}
if (ss->ssl3.hs.cipher_suite != psk->zeroRttSuite) {
return PR_FALSE;
}
if (psk->type == ssl_psk_resume) {
if (!sid) {
return PR_FALSE;
}
PORT_Assert(sid->u.ssl3.locked.sessionTicket.flags & ticket_allow_early_data);
PORT_Assert(ss->statelessResume);
if (!ss->statelessResume) {
return PR_FALSE;
}
if (SECITEM_CompareItem(&ss->xtnData.nextProto,
&sid->u.ssl3.alpnSelection) != 0) {
return PR_FALSE;
}
} else if (psk->type != ssl_psk_external) {
PORT_Assert(0);
return PR_FALSE;
}
if (tls13_IsReplay(ss, sid)) {
return PR_FALSE;
}
return PR_TRUE;
}
/* Called from tls13_HandleClientHelloPart2 to update the state of 0-RTT handling.
*
* 0-RTT is only permitted if:
* 1. The early data extension was present.
* 2. We are resuming a session.
* 3. The 0-RTT option is set.
* 4. The ticket allowed 0-RTT.
* 5. We negotiated the same ALPN value as in the ticket.
*/
static void
tls13_NegotiateZeroRtt(sslSocket *ss, const sslSessionID *sid)
{
SSL_TRC(3, ("%d: TLS13[%d]: negotiate 0-RTT %p",
SSL_GETPID(), ss->fd, sid));
/* tls13_ServerHandleEarlyDataXtn sets this to ssl_0rtt_sent, so this will
* be ssl_0rtt_none unless early_data is present. */
if (ss->ssl3.hs.zeroRttState == ssl_0rtt_none) {
return;
}
if (ss->ssl3.hs.zeroRttState == ssl_0rtt_ignored) {
/* HelloRetryRequest causes 0-RTT to be ignored. On the second
* ClientHello, reset the ignore state so that decryption failure is
* handled normally. */
if (ss->ssl3.hs.zeroRttIgnore == ssl_0rtt_ignore_hrr) {
PORT_Assert(ss->ssl3.hs.helloRetry);
ss->ssl3.hs.zeroRttState = ssl_0rtt_none;
ss->ssl3.hs.zeroRttIgnore = ssl_0rtt_ignore_none;
} else {
SSL_TRC(3, ("%d: TLS13[%d]: application ignored 0-RTT",
SSL_GETPID(), ss->fd));
}
return;
}
if (!tls13_CanNegotiateZeroRtt(ss, sid)) {
SSL_TRC(3, ("%d: TLS13[%d]: ignore 0-RTT", SSL_GETPID(), ss->fd));
ss->ssl3.hs.zeroRttState = ssl_0rtt_ignored;
ss->ssl3.hs.zeroRttIgnore = ssl_0rtt_ignore_trial;
return;
}
SSL_TRC(3, ("%d: TLS13[%d]: enable 0-RTT", SSL_GETPID(), ss->fd));
PORT_Assert(ss->xtnData.selectedPsk);
ss->ssl3.hs.zeroRttState = ssl_0rtt_accepted;
ss->ssl3.hs.zeroRttIgnore = ssl_0rtt_ignore_none;
ss->ssl3.hs.zeroRttSuite = ss->ssl3.hs.cipher_suite;
ss->ssl3.hs.preliminaryInfo |= ssl_preinfo_0rtt_cipher_suite;
}
/* Check if the offered group is acceptable. */
static PRBool
tls13_isGroupAcceptable(const sslNamedGroupDef *offered,
const sslNamedGroupDef *preferredGroup)
{
/* We accept epsilon (e) bits around the offered group size. */
const unsigned int e = 2;
PORT_Assert(offered);
PORT_Assert(preferredGroup);
if (offered->bits >= preferredGroup->bits - e &&
offered->bits <= preferredGroup->bits + e) {
return PR_TRUE;
}
return PR_FALSE;
}
/* Find remote key share for given group and return it.
* Returns NULL if no key share is found. */
static TLS13KeyShareEntry *
tls13_FindKeyShareEntry(sslSocket *ss, const sslNamedGroupDef *group)
{
PRCList *cur_p = PR_NEXT_LINK(&ss->xtnData.remoteKeyShares);
while (cur_p != &ss->xtnData.remoteKeyShares) {
TLS13KeyShareEntry *offer = (TLS13KeyShareEntry *)cur_p;
if (offer->group == group) {
return offer;
}
cur_p = PR_NEXT_LINK(cur_p);
}
return NULL;
}
static SECStatus
tls13_NegotiateKeyExchange(sslSocket *ss,
const sslNamedGroupDef **requestedGroup,
TLS13KeyShareEntry **clientShare)
{
unsigned int index;
TLS13KeyShareEntry *entry = NULL;
const sslNamedGroupDef *preferredGroup = NULL;
/* We insist on DHE. */
if (ssl3_ExtensionNegotiated(ss, ssl_tls13_pre_shared_key_xtn)) {
if (!ssl3_ExtensionNegotiated(ss, ssl_tls13_psk_key_exchange_modes_xtn)) {
FATAL_ERROR(ss, SSL_ERROR_MISSING_PSK_KEY_EXCHANGE_MODES,
missing_extension);
return SECFailure;
}
if (!memchr(ss->xtnData.psk_ke_modes.data, tls13_psk_dh_ke,
ss->xtnData.psk_ke_modes.len)) {
SSL_TRC(3, ("%d: TLS13[%d]: client offered PSK without DH",
SSL_GETPID(), ss->fd));
ss->statelessResume = PR_FALSE;
}
}
/* Now figure out which key share we like the best out of the
* mutually supported groups, regardless of what the client offered
* for key shares.
*/
if (!ssl3_ExtensionNegotiated(ss, ssl_supported_groups_xtn)) {
FATAL_ERROR(ss, SSL_ERROR_MISSING_SUPPORTED_GROUPS_EXTENSION,
missing_extension);
return SECFailure;
}
SSL_TRC(3, ("%d: TLS13[%d]: selected KE = %s", SSL_GETPID(),
ss->fd, ss->statelessResume || ss->xtnData.selectedPsk ? "PSK + (EC)DHE" : "(EC)DHE"));
/* Find the preferred group and an according client key share available. */
for (index = 0; index < SSL_NAMED_GROUP_COUNT; ++index) {
/* Continue to the next group if this one is not enabled. */
if (!ss->namedGroupPreferences[index]) {
/* There's a gap in the preferred groups list. Assume this is a group
* that's not supported by the client but preferred by the server. */
if (preferredGroup) {
entry = NULL;
break;
}
continue;
}
/* Check if the client sent a key share for this group. */
entry = tls13_FindKeyShareEntry(ss, ss->namedGroupPreferences[index]);
if (preferredGroup) {
/* We already found our preferred group but the group didn't have a share. */
if (entry) {
/* The client sent a key share with group ss->namedGroupPreferences[index] */
if (tls13_isGroupAcceptable(ss->namedGroupPreferences[index],
preferredGroup)) {
/* This is not the preferred group, but it's acceptable */
preferredGroup = ss->namedGroupPreferences[index];
} else {
/* The proposed group is not acceptable. */
entry = NULL;
}
}
break;
} else {
/* The first enabled group is the preferred group. */
preferredGroup = ss->namedGroupPreferences[index];
if (entry) {
break;
}
}
}
if (!preferredGroup) {
FATAL_ERROR(ss, SSL_ERROR_NO_CYPHER_OVERLAP, handshake_failure);
return SECFailure;
}
SSL_TRC(3, ("%d: TLS13[%d]: group = %d", SSL_GETPID(), ss->fd,
preferredGroup->name));
/* 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;
}
return SECSuccess;
}
SECStatus
tls13_SelectServerCert(sslSocket *ss)
{
PRCList *cursor;
SECStatus rv;
if (!ssl3_ExtensionNegotiated(ss, ssl_signature_algorithms_xtn)) {
FATAL_ERROR(ss, SSL_ERROR_MISSING_SIGNATURE_ALGORITHMS_EXTENSION,
missing_extension);
return SECFailure;
}
/* This picks the first certificate that has:
* a) the right authentication method, and
* b) the right named curve (EC only)
*
* We might want to do some sort of ranking here later. For now, it's all
* based on what order they are configured in. */
for (cursor = PR_NEXT_LINK(&ss->serverCerts);
cursor != &ss->serverCerts;
cursor = PR_NEXT_LINK(cursor)) {
sslServerCert *cert = (sslServerCert *)cursor;
if (SSL_CERT_IS_ONLY(cert, ssl_auth_rsa_decrypt)) {
continue;
}
rv = ssl_PickSignatureScheme(ss,
cert->serverCert,
cert->serverKeyPair->pubKey,
cert->serverKeyPair->privKey,
ss->xtnData.sigSchemes,
ss->xtnData.numSigSchemes,
PR_FALSE);
if (rv == SECSuccess) {
/* Found one. */
ss->sec.serverCert = cert;
/* If we can use a delegated credential (DC) for authentication in
* the current handshake, then commit to using it now. We'll send a
* DC as an extension and use the DC private key to sign the
* handshake.
*
* This sets the signature scheme to be the signature scheme
* indicated by the DC.
*/
rv = tls13_MaybeSetDelegatedCredential(ss);
if (rv != SECSuccess) {
return SECFailure; /* Failure indicates an internal error. */
}
ss->sec.authType = ss->ssl3.hs.kea_def_mutable.authKeyType =
ssl_SignatureSchemeToAuthType(ss->ssl3.hs.signatureScheme);
ss->sec.authKeyBits = cert->serverKeyBits;
return SECSuccess;
}
}
FATAL_ERROR(ss, SSL_ERROR_UNSUPPORTED_SIGNATURE_ALGORITHM,
handshake_failure);
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);