Source code
Revision control
Copy as Markdown
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
#include "sslt.h"
#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_HandleCertificateDecode(
sslSocket *ss, PRUint8 *b, PRUint32 length);
static SECStatus tls13_HandleCertificate(
sslSocket *ss, PRUint8 *b, PRUint32 length, PRBool alreadyHashed);
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);
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;
}
static SECStatus
tls13_CreateKEMKeyPair(sslSocket *ss, const sslNamedGroupDef *groupDef,
sslKeyPair **outKeyPair)
{
PORT_Assert(groupDef);
sslKeyPair *keyPair = NULL;
SECKEYPrivateKey *privKey = NULL;
SECKEYPublicKey *pubKey = NULL;
CK_MECHANISM_TYPE mechanism;
CK_NSS_KEM_PARAMETER_SET_TYPE paramSet;
switch (groupDef->name) {
case ssl_grp_kem_xyber768d00:
mechanism = CKM_NSS_KYBER_KEY_PAIR_GEN;
paramSet = CKP_NSS_KYBER_768_ROUND3;
break;
case ssl_grp_kem_mlkem768x25519:
case ssl_grp_kem_secp256r1mlkem768:
mechanism = CKM_ML_KEM_KEY_PAIR_GEN;
paramSet = CKP_ML_KEM_768;
break;
case ssl_grp_kem_secp384r1mlkem1024:
mechanism = CKM_ML_KEM_KEY_PAIR_GEN;
paramSet = CKP_ML_KEM_1024;
break;
default:
PORT_Assert(0);
PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
return SECFailure;
}
PK11SlotInfo *slot = PK11_GetBestSlot(mechanism, ss->pkcs11PinArg);
if (!slot) {
goto loser;
}
/* avoid pairwise check in non-FIPS mode */
/* the only difference between CKM_ML_KEM_KEY_PAIR_GEN and
* CKM_NSS_ML_KEM_KEY_PAIR_GEN is the latter skips the pairwise consistency
* check and is only supported by softoken */
if ((mechanism == CKM_ML_KEM_KEY_PAIR_GEN) && !PK11_IsFIPS() &&
PK11_DoesMechanism(slot, CKM_NSS_ML_KEM_KEY_PAIR_GEN)) {
mechanism = CKM_NSS_ML_KEM_KEY_PAIR_GEN;
}
privKey = PK11_GenerateKeyPairWithOpFlags(slot, mechanism,
¶mSet, &pubKey,
PK11_ATTR_SESSION | PK11_ATTR_INSENSITIVE | PK11_ATTR_PUBLIC,
CKF_ENCAPSULATE | CKF_DECAPSULATE,
CKF_ENCAPSULATE | CKF_DECAPSULATE,
ss->pkcs11PinArg);
if (!privKey) {
privKey = PK11_GenerateKeyPairWithOpFlags(slot, mechanism,
¶mSet, &pubKey,
PK11_ATTR_SESSION | PK11_ATTR_SENSITIVE | PK11_ATTR_PRIVATE,
CKF_ENCAPSULATE | CKF_DECAPSULATE,
CKF_ENCAPSULATE | CKF_DECAPSULATE,
ss->pkcs11PinArg);
}
PK11_FreeSlot(slot);
if (!privKey || !pubKey) {
goto loser;
}
keyPair = ssl_NewKeyPair(privKey, pubKey);
if (!keyPair) {
goto loser;
}
SSL_TRC(50, ("%d: SSL[%d]: Create Kyber ephemeral key %d",
SSL_GETPID(), ss ? ss->fd : NULL, groupDef->name));
PRINT_BUF(50, (ss, "Public Key", pubKey->u.kyber.publicValue.data,
pubKey->u.kyber.publicValue.len));
#ifdef TRACE
if (ssl_trace >= 50) {
SECItem d = { siBuffer, NULL, 0 };
SECStatus rv = PK11_ReadRawAttribute(PK11_TypePrivKey, privKey, CKA_VALUE, &d);
if (rv == SECSuccess) {
PRINT_BUF(50, (ss, "Private Key", d.data, d.len));
SECITEM_FreeItem(&d, PR_FALSE);
} else {
SSL_TRC(50, ("Error extracting private key"));
}
}
#endif
*outKeyPair = keyPair;
return SECSuccess;
loser:
SECKEY_DestroyPrivateKey(privKey);
SECKEY_DestroyPublicKey(pubKey);
ssl_MapLowLevelError(SEC_ERROR_KEYGEN_FAIL);
return SECFailure;
}
/* only copy the ECDH component of an ephemeral KeyPair */
sslEphemeralKeyPair *
tls13_CopyECDHKeyFromHybrid(sslEphemeralKeyPair *copyKeyPair,
const sslNamedGroupDef *groupDef)
{
/* We could use ssl_CopyEphemeralKeyPair here, but we would need to free
* the KEM components. So we only copy the ECDH keys */
sslEphemeralKeyPair *keyPair = PORT_ZNew(sslEphemeralKeyPair);
if (!keyPair) {
return NULL;
}
PR_INIT_CLIST(&keyPair->link);
keyPair->group = groupDef;
keyPair->keys = ssl_GetKeyPairRef(copyKeyPair->keys);
return keyPair;
}
/*
* find a hybrid key Pair they might contain the same ecdh key so we
* can reuse them. Each ec group can map to more than one hybrid Pair
*/
sslEphemeralKeyPair *
tls13_FindHybridKeyPair(sslSocket *ss, const sslNamedGroupDef *groupDef)
{
sslEphemeralKeyPair *hybridPair = NULL;
switch (groupDef->name) {
case ssl_grp_ec_secp256r1:
/* future, this may be a loop to check multiple named groups */
hybridPair = ssl_LookupEphemeralKeyPair(ss,
ssl_LookupNamedGroup(ssl_grp_kem_secp256r1mlkem768));
break;
case ssl_grp_ec_secp384r1:
hybridPair = ssl_LookupEphemeralKeyPair(ss,
ssl_LookupNamedGroup(ssl_grp_kem_secp384r1mlkem1024));
break;
case ssl_grp_ec_curve25519: {
/* a loop to check multiple named groups */
SSLNamedGroup gnames[] = { ssl_grp_kem_xyber768d00,
ssl_grp_kem_mlkem768x25519 };
for (int i = 0; i < PR_ARRAY_SIZE(gnames); i++) {
hybridPair = ssl_LookupEphemeralKeyPair(ss,
ssl_LookupNamedGroup(gnames[i]));
if (hybridPair != NULL) {
break;
}
}
break;
}
default:
PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
return NULL;
}
return hybridPair;
}
SECStatus
tls13_CreateKeyShare(sslSocket *ss, const sslNamedGroupDef *groupDef,
sslEphemeralKeyPair **outKeyPair)
{
SECStatus rv;
const ssl3DHParams *params;
sslEphemeralKeyPair *keyPair = NULL;
const sslNamedGroupDef *ecGroup = NULL;
PORT_Assert(groupDef);
switch (groupDef->keaType) {
case ssl_kea_ecdh_hybrid:
switch (groupDef->name) {
case ssl_grp_kem_secp256r1mlkem768:
ecGroup = ssl_LookupNamedGroup(ssl_grp_ec_secp256r1);
break;
case ssl_grp_kem_secp384r1mlkem1024:
ecGroup = ssl_LookupNamedGroup(ssl_grp_ec_secp384r1);
break;
case ssl_grp_kem_xyber768d00:
case ssl_grp_kem_mlkem768x25519:
ecGroup = ssl_LookupNamedGroup(ssl_grp_ec_curve25519);
break;
default:
PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
return SECFailure;
}
if (ecGroup == NULL) {
PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
return SECFailure;
}
keyPair = ssl_LookupEphemeralKeyPair(ss, ecGroup);
if (keyPair) {
keyPair = ssl_CopyEphemeralKeyPair(keyPair);
}
if (!keyPair) {
rv = ssl_CreateECDHEphemeralKeyPair(ss, ecGroup, &keyPair);
if (rv != SECSuccess) {
return SECFailure;
}
}
keyPair->group = groupDef;
break;
case ssl_kea_ecdh:
keyPair = tls13_FindHybridKeyPair(ss, groupDef);
if (keyPair) {
keyPair = tls13_CopyECDHKeyFromHybrid(keyPair, groupDef);
}
if (!keyPair) {
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;
}
// If we're creating an ECDH + KEM hybrid share and we're the client, then
// we still need to generate the KEM key pair. Otherwise we're done.
if (groupDef->keaType == ssl_kea_ecdh_hybrid && !ss->sec.isServer) {
rv = tls13_CreateKEMKeyPair(ss, groupDef, &keyPair->kemKeys);
if (rv != SECSuccess) {
ssl_FreeEphemeralKeyPair(keyPair);
return SECFailure;
}
}
*outKeyPair = keyPair;
return SECSuccess;
}
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;
}
rv = tls13_ClientGreaseSetup(ss);
if (rv != SECSuccess) {
return SECFailure;
}
/* 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;
}
}
tls13_EchKeyLog(ss);
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;
}
static SECStatus
tls13_ImportKEMKeyShare(SECKEYPublicKey *peerKey, TLS13KeyShareEntry *entry)
{
SECItem pk = { siBuffer, NULL, 0 };
SECStatus rv;
size_t expected_len;
switch (entry->group->name) {
case ssl_grp_kem_xyber768d00:
expected_len = X25519_PUBLIC_KEY_BYTES + KYBER768_PUBLIC_KEY_BYTES;
break;
case ssl_grp_kem_mlkem768x25519:
expected_len = X25519_PUBLIC_KEY_BYTES + KYBER768_PUBLIC_KEY_BYTES;
break;
case ssl_grp_kem_secp256r1mlkem768:
expected_len = SECP256_PUBLIC_KEY_BYTES + KYBER768_PUBLIC_KEY_BYTES;
break;
case ssl_grp_kem_secp384r1mlkem1024:
expected_len = SECP384_PUBLIC_KEY_BYTES + MLKEM1024_PUBLIC_KEY_BYTES;
break;
default:
PORT_SetError(SEC_ERROR_UNSUPPORTED_KEYALG);
return SECFailure;
}
if (entry->key_exchange.len != expected_len) {
PORT_SetError(SSL_ERROR_RX_MALFORMED_HYBRID_KEY_SHARE);
return SECFailure;
}
switch (entry->group->name) {
case ssl_grp_kem_xyber768d00:
peerKey->keyType = kyberKey;
peerKey->u.kyber.params = params_kyber768_round3;
// key_exchange.data is `x25519 || kyber768`
pk.data = entry->key_exchange.data + X25519_PUBLIC_KEY_BYTES;
pk.len = KYBER768_PUBLIC_KEY_BYTES;
break;
case ssl_grp_kem_mlkem768x25519:
peerKey->keyType = kyberKey;
peerKey->u.kyber.params = params_ml_kem768;
// key_exchange.data is `mlkem768 || x25519`
pk.data = entry->key_exchange.data;
pk.len = KYBER768_PUBLIC_KEY_BYTES;
break;
case ssl_grp_kem_secp256r1mlkem768:
peerKey->keyType = kyberKey;
peerKey->u.kyber.params = params_ml_kem768;
/* key_exchange.data is `secp256 || mlkem768` */
pk.data = entry->key_exchange.data + SECP256_PUBLIC_KEY_BYTES;
pk.len = KYBER768_PUBLIC_KEY_BYTES;
break;
case ssl_grp_kem_secp384r1mlkem1024:
peerKey->keyType = kyberKey;
peerKey->u.kyber.params = params_ml_kem1024;
/* key_exchange.data is `secp384 || mlkem1024` */
pk.data = entry->key_exchange.data + SECP384_PUBLIC_KEY_BYTES;
pk.len = MLKEM1024_PUBLIC_KEY_BYTES;
break;
default:
PORT_Assert(0);
PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
return SECFailure;
}
rv = SECITEM_CopyItem(peerKey->arena, &peerKey->u.kyber.publicValue, &pk);
if (rv != SECSuccess) {
PORT_SetError(SEC_ERROR_NO_MEMORY);
return SECFailure;
}
return SECSuccess;
}
static SECStatus
tls13_HandleKEMCiphertext(sslSocket *ss, TLS13KeyShareEntry *entry, sslKeyPair *keyPair, PK11SymKey **outKey)
{
SECItem ct = { siBuffer, NULL, 0 };
SECStatus rv;
switch (entry->group->name) {
case ssl_grp_kem_xyber768d00:
if (entry->key_exchange.len != X25519_PUBLIC_KEY_BYTES + KYBER768_CIPHERTEXT_BYTES) {
ssl_MapLowLevelError(SSL_ERROR_RX_MALFORMED_HYBRID_KEY_SHARE);
return SECFailure;
}
ct.data = entry->key_exchange.data + X25519_PUBLIC_KEY_BYTES;
ct.len = KYBER768_CIPHERTEXT_BYTES;
break;
case ssl_grp_kem_mlkem768x25519:
if (entry->key_exchange.len != X25519_PUBLIC_KEY_BYTES + KYBER768_CIPHERTEXT_BYTES) {
ssl_MapLowLevelError(SSL_ERROR_RX_MALFORMED_HYBRID_KEY_SHARE);
return SECFailure;
}
ct.data = entry->key_exchange.data;
ct.len = KYBER768_CIPHERTEXT_BYTES;
break;
case ssl_grp_kem_secp256r1mlkem768:
if (entry->key_exchange.len != SECP256_PUBLIC_KEY_BYTES + KYBER768_CIPHERTEXT_BYTES) {
ssl_MapLowLevelError(SSL_ERROR_RX_MALFORMED_HYBRID_KEY_SHARE);
return SECFailure;
}
ct.data = entry->key_exchange.data + SECP256_PUBLIC_KEY_BYTES;
ct.len = KYBER768_CIPHERTEXT_BYTES;
break;
case ssl_grp_kem_secp384r1mlkem1024:
if (entry->key_exchange.len != SECP384_PUBLIC_KEY_BYTES + MLKEM1024_CIPHERTEXT_BYTES) {
ssl_MapLowLevelError(SSL_ERROR_RX_MALFORMED_HYBRID_KEY_SHARE);
return SECFailure;
}
ct.data = entry->key_exchange.data + SECP384_PUBLIC_KEY_BYTES;
ct.len = MLKEM1024_CIPHERTEXT_BYTES;
break;
default:
PORT_Assert(0);
ssl_MapLowLevelError(SEC_ERROR_LIBRARY_FAILURE);
return SECFailure;
}
rv = PK11_Decapsulate(keyPair->privKey, &ct, CKM_HKDF_DERIVE,
PK11_ATTR_SESSION | PK11_ATTR_INSENSITIVE,
CKF_DERIVE, outKey);
if (rv != SECSuccess) {
rv = PK11_Decapsulate(keyPair->privKey, &ct, CKM_HKDF_DERIVE,
PK11_ATTR_SESSION | PK11_ATTR_SENSITIVE,
CKF_DERIVE, outKey);
if (rv != SECSuccess) {
ssl_MapLowLevelError(SSL_ERROR_KEY_EXCHANGE_FAILURE);
}
}
return rv;
}
static SECStatus
tls13_HandleKEMKey(sslSocket *ss,
TLS13KeyShareEntry *entry,
PK11SymKey **key,
SECItem **ciphertext)
{
PORTCheapArenaPool arena;
SECKEYPublicKey *peerKey;
CK_OBJECT_HANDLE handle;
SECStatus rv;
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;
rv = tls13_ImportKEMKeyShare(peerKey, entry);
if (rv != SECSuccess) {
goto loser;
}
PK11SlotInfo *slot = PK11_GetBestSlot(CKM_ML_KEM, ss->pkcs11PinArg);
if (!slot) {
goto loser;
}
handle = PK11_ImportPublicKey(slot, peerKey, PR_FALSE);
PK11_FreeSlot(slot); /* peerKey holds a slot reference on success. */
if (handle == CK_INVALID_HANDLE) {
goto loser;
}
rv = PK11_Encapsulate(peerKey, CKM_HKDF_DERIVE,
PK11_ATTR_SESSION | PK11_ATTR_INSENSITIVE,
CKF_DERIVE, key, ciphertext);
if (rv != SECSuccess) {
rv = PK11_Encapsulate(peerKey, CKM_HKDF_DERIVE,
PK11_ATTR_SESSION | PK11_ATTR_SENSITIVE,
CKF_DERIVE, key, ciphertext);
}
/* Destroy the imported public key */
PORT_Assert(peerKey->pkcs11Slot);
PK11_DestroyObject(peerKey->pkcs11Slot, peerKey->pkcs11ID);
PK11_FreeSlot(peerKey->pkcs11Slot);
PORT_DestroyCheapArena(&arena);
return rv;
loser:
PORT_DestroyCheapArena(&arena);
return SECFailure;
}
SECStatus
tls13_HandleKeyShare(sslSocket *ss,
TLS13KeyShareEntry *entry,
sslKeyPair *keyPair,
SSLHashType hash,
PK11SymKey **out)
{
PORTCheapArenaPool arena;
SECKEYPublicKey *peerKey;
CK_MECHANISM_TYPE mechanism;
PK11SymKey *key;
unsigned char *ec_data;
SECStatus rv;
int keySize = 0;
const sslNamedGroupDef *ecGroup = NULL;
int ec_len = 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_hybrid:
switch (entry->group->name) {
case ssl_grp_kem_xyber768d00:
ec_len = X25519_PUBLIC_KEY_BYTES;
// x25519 share is at the beginning
ec_data = entry->key_exchange.len < ec_len
? NULL
: entry->key_exchange.data;
ecGroup = ssl_LookupNamedGroup(ssl_grp_ec_curve25519);
break;
case ssl_grp_kem_mlkem768x25519:
ec_len = X25519_PUBLIC_KEY_BYTES;
// x25519 share is at the end
ec_data = entry->key_exchange.len < ec_len
? NULL
: entry->key_exchange.data + entry->key_exchange.len - ec_len;
ecGroup = ssl_LookupNamedGroup(ssl_grp_ec_curve25519);
break;
case ssl_grp_kem_secp256r1mlkem768:
ec_len = SECP256_PUBLIC_KEY_BYTES;
/* secp256 share is at the beginning */
ec_data = entry->key_exchange.len < ec_len
? NULL
: entry->key_exchange.data;
ecGroup = ssl_LookupNamedGroup(ssl_grp_ec_secp256r1);
break;
case ssl_grp_kem_secp384r1mlkem1024:
ec_len = SECP384_PUBLIC_KEY_BYTES;
/* secp384 share is at the beginning */
ec_data = entry->key_exchange.len < ec_len
? NULL
: entry->key_exchange.data;
ecGroup = ssl_LookupNamedGroup(ssl_grp_ec_secp256r1);
break;
default:
ec_data = NULL;
break;
}
if (!ec_data) {
PORT_SetError(SSL_ERROR_RX_MALFORMED_HYBRID_KEY_SHARE);
goto loser;
}
rv = ssl_ImportECDHKeyShare(peerKey, ec_data, ec_len, ecGroup);
mechanism = CKM_ECDH1_DERIVE;
break;
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);
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;
}
if (IS_DTLS(ss)) {
rv = dtls13_MaybeSendKeyUpdate(ss, request, buffer);
if (rv != SECSuccess) {
/* Error code set already. */
return SECFailure;
}
return rv;
}
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;
}
SECStatus
SSLExp_SetCertificateCompressionAlgorithm(PRFileDesc *fd, SSLCertificateCompressionAlgorithm alg)
{
sslSocket *ss = ssl_FindSocket(fd);
if (!ss) {
return SECFailure; /* Code already set. */
}
ssl_GetSSL3HandshakeLock(ss);
if (ss->ssl3.supportedCertCompressionAlgorithmsCount == MAX_SUPPORTED_CERTIFICATE_COMPRESSION_ALGS) {
goto loser;
}
/* Reserved ID */
if (alg.id == 0) {
goto loser;
}
if (alg.encode == NULL && alg.decode == NULL) {
goto loser;
}
/* Checking that we have not yet registed an algorithm with the same ID. */
for (int i = 0; i < ss->ssl3.supportedCertCompressionAlgorithmsCount; i++) {
if (ss->ssl3.supportedCertCompressionAlgorithms[i].id == alg.id) {
goto loser;
}
}
PORT_Memcpy(&ss->ssl3.supportedCertCompressionAlgorithms
[ss->ssl3.supportedCertCompressionAlgorithmsCount],
&alg, sizeof(alg));
ss->ssl3.supportedCertCompressionAlgorithmsCount += 1;
ssl_ReleaseSSL3HandshakeLock(ss);
return SECSuccess;
loser:
PORT_SetError(SEC_ERROR_INVALID_ARGS);
ssl_ReleaseSSL3HandshakeLock(ss);
return SECFailure;
}
/*
* enum {
* update_not_requested(0), update_requested(1), (255)
* } KeyUpdateRequest;
*
* struct {
* KeyUpdateRequest request_update;
* } KeyUpdate;
*/
/* If we're handing the DTLS1.3 message, we silently fail if there is a parsing problem. */
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;
}
if (IS_DTLS(ss)) {
return dtls13_HandleKeyUpdate(ss, b, length, update);
}
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.hs.keyUpdateDeferred = PR_TRUE;
ss->ssl3.hs.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, PR_FALSE);
case ssl_hs_compressed_certificate:
return tls13_HandleCertificateDecode(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;
}
/* Since the server insists on DHE to provide forward secracy, for
* every other PskKem value but DHE stateless resumption is disabled,
* this includes other specified and GREASE values. */
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,
&ss->ssl3.hs.signatureScheme);
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);
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 (action == ssl_hello_retry_reject_0rtt) {
ss->ssl3.hs.zeroRttState = ssl_0rtt_ignored;
ss->ssl3.hs.zeroRttIgnore = ssl_0rtt_ignore_trial;
}
if (!requestedGroup && action != ssl_hello_retry_request) {
return SECSuccess;
}
rv = tls13_SendHelloRetryRequest(ss, requestedGroup, token, tokenLen);
if (rv != SECSuccess) {
return SECFailure; /* Code already set. */
}
/* We may have received ECH, but have to start over with CH2. */
ss->ssl3.hs.echAccepted = PR_FALSE;
PK11_HPKE_DestroyContext(ss->ssl3.hs.echHpkeCtx, PR_TRUE);
ss->ssl3.hs.echHpkeCtx = NULL;
*hrrSent = PR_TRUE;
return SECSuccess;
}
static SECStatus
tls13_NegotiateAuthentication(sslSocket *ss)
{
if (ss->statelessResume) {
SSL_TRC(3, ("%d: TLS13[%d]: selected resumption PSK authentication",
SSL_GETPID(), ss->fd));
ss->ssl3.hs.signatureScheme = ssl_sig_none;
ss->ssl3.hs.kea_def_mutable.authKeyType = ssl_auth_psk;
/* Overwritten by tls13_RestoreCipherInfo. */
ss->sec.authType = ssl_auth_psk;
return SECSuccess;
} else if (ss->xtnData.selectedPsk) {
/* If the EPSK doesn't specify a suite, use what was negotiated.
* Else, only use the EPSK if we negotiated that suite. */
if (ss->xtnData.selectedPsk->zeroRttSuite == TLS_NULL_WITH_NULL_NULL ||
ss->ssl3.hs.cipher_suite == ss->xtnData.selectedPsk->zeroRttSuite) {
SSL_TRC(3, ("%d: TLS13[%d]: selected external PSK authentication",
SSL_GETPID(), ss->fd));
ss->ssl3.hs.signatureScheme = ssl_sig_none;
ss->ssl3.hs.kea_def_mutable.authKeyType = ssl_auth_psk;
ss->sec.authType = ssl_auth_psk;
return SECSuccess;
}
}
/* If there were PSKs, they are no longer needed. */
if (ss->xtnData.selectedPsk) {
tls13_DestroyPskList(&ss->ssl3.hs.psks);
ss->xtnData.selectedPsk = NULL;
}
SSL_TRC(3, ("%d: TLS13[%d]: selected certificate authentication",
SSL_GETPID(), ss->fd));
SECStatus rv = tls13_SelectServerCert(ss);
if (rv != SECSuccess) {
return SECFailure;
}
return SECSuccess;
}
/* Called from ssl3_HandleClientHello after we have parsed the
* ClientHello and are sure that we are going to do TLS 1.3
* or fail. */
SECStatus
tls13_HandleClientHelloPart2(sslSocket *ss,
const SECItem *suites,
sslSessionID *sid,
const PRUint8 *msg,
unsigned int len)
{
SECStatus rv;
SSL3Statistics *ssl3stats = SSL_GetStatistics();
const sslNamedGroupDef *requestedGroup = NULL;
TLS13KeyShareEntry *clientShare = NULL;
ssl3CipherSuite previousCipherSuite = 0;
const sslNamedGroupDef *previousGroup = NULL;
PRBool hrr = PR_FALSE;
PRBool previousOfferedEch;
/* If the legacy_version field is set to 0x300 or smaller,
* reject the connection with protocol_version alert. */
if (ss->clientHelloVersion <= SSL_LIBRARY_VERSION_3_0) {
FATAL_ERROR(ss, SSL_ERROR_RX_MALFORMED_CLIENT_HELLO, protocol_version);
goto loser;
}
ss->ssl3.hs.endOfFlight = PR_TRUE;
if (ssl3_ExtensionNegotiated(ss, ssl_tls13_early_data_xtn)) {
ss->ssl3.hs.zeroRttState = ssl_0rtt_sent;
}
/* Negotiate cipher suite. */
rv = ssl3_NegotiateCipherSuite(ss, suites, PR_FALSE);
if (rv != SECSuccess) {
FATAL_ERROR(ss, PORT_GetError(), 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) {
/* 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->nextSeqNum = 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_HandleHrrCookie(ss, ss->xtnData.cookie.data,
ss->xtnData.cookie.len,
&previousCipherSuite,
&previousGroup,
&previousOfferedEch, NULL, PR_TRUE);
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;
}
/* Now create a synthetic kea_def that we can tweak. */
ss->ssl3.hs.kea_def_mutable = *ss->ssl3.hs.kea_def;
ss->ssl3.hs.kea_def = &ss->ssl3.hs.kea_def_mutable;
/* Note: We call this quite a bit earlier than with TLS 1.2 and
* before. */
rv = ssl3_ServerCallSNICallback(ss);
if (rv != SECSuccess) {
goto loser; /* An alert has already been sent. */
}
/* Check if we could in principle resume. */
if (ss->statelessResume) {
PORT_Assert(sid);
if (!sid) {
FATAL_ERROR(ss, SEC_ERROR_LIBRARY_FAILURE, internal_error);
return SECFailure;
}
if (!tls13_CanResume(ss, sid)) {
ss->statelessResume = PR_FALSE;
}
}
/* Select key exchange. */
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));
/* 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;
}
/* CH1/CH2 must either both include ECH, or both exclude it. */
if (previousOfferedEch != (ss->xtnData.ech != NULL)) {
FATAL_ERROR(ss, SSL_ERROR_BAD_2ND_CLIENT_HELLO,
previousOfferedEch ? missing_extension : 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. */
ssl_UncacheSessionID(ss);
ssl_FreeSID(sid);
}
PORT_Assert(ss->ssl3.hs.helloRetry);
return SECSuccess;
}
/* Select the authentication (this is also handshake shape). */
rv = tls13_NegotiateAuthentication(ss);
if (rv != SECSuccess) {
goto loser;
}
if (ss->sec.authType == ssl_auth_psk) {
if (ss->statelessResume) {
/* We are now committed to trying to resume. */
PORT_Assert(sid);
/* Check that the negotiated SNI and the cached SNI match. */
if (SECITEM_CompareItem(&sid->u.ssl3.srvName,
&ss->ssl3.hs.srvVirtName) != SECEqual) {
FATAL_ERROR(ss, SSL_ERROR_RX_MALFORMED_CLIENT_HELLO,
handshake_failure);
goto loser;
}
ss->sec.serverCert = ssl_FindServerCert(ss, sid->authType,
sid->namedCurve);
PORT_Assert(ss->sec.serverCert);
rv = tls13_RecoverWrappedSharedSecret(ss, sid);
if (rv != SECSuccess) {
SSL_AtomicIncrementLong(&ssl3stats->hch_sid_cache_not_ok);
FATAL_ERROR(ss, SEC_ERROR_LIBRARY_FAILURE, internal_error);
goto loser;
}
tls13_RestoreCipherInfo(ss, sid);
PORT_Assert(!ss->sec.localCert);
ss->sec.localCert = CERT_DupCertificate(ss->sec.serverCert->serverCert);
if (sid->peerCert != NULL) {
ss->sec.peerCert = CERT_DupCertificate(sid->peerCert);
}
} else if (sid) {
/* We should never have a SID in the non-resumption case. */
PORT_Assert(0);
ssl_UncacheSessionID(ss);
ssl_FreeSID(sid);
sid = NULL;
}
ssl3_RegisterExtensionSender(
ss, &ss->xtnData,
ssl_tls13_pre_shared_key_xtn, tls13_ServerSendPreSharedKeyXtn);
tls13_NegotiateZeroRtt(ss, sid);
rv = tls13_ComputeEarlySecretsWithPsk(ss);
if (rv != SECSuccess) {
FATAL_ERROR(ss, SEC_ERROR_LIBRARY_FAILURE, internal_error);
return SECFailure;
}
} else {
if (sid) { /* we had a sid, but it's no longer valid, free it */
SSL_AtomicIncrementLong(&ssl3stats->hch_sid_cache_not_ok);
ssl_UncacheSessionID(ss);
ssl_FreeSID(sid);
sid = NULL;
}
tls13_NegotiateZeroRtt(ss, NULL);
}
if (ss->statelessResume) {
PORT_Assert(ss->xtnData.selectedPsk);
PORT_Assert(ss->ssl3.hs.kea_def_mutable.authKeyType == ssl_auth_psk);
}
/* Now that we have the binder key, check the binder. */
if (ss->xtnData.selectedPsk) {
SSL3Hashes hashes;
PORT_Assert(ss->ssl3.hs.messages.len > ss->xtnData.pskBindersLen);
rv = tls13_ComputePskBinderHash(
ss,
ss->ssl3.hs.messages.buf,
ss->ssl3.hs.messages.len - ss->xtnData.pskBindersLen,
&hashes, tls13_GetHash(ss));
if (rv != SECSuccess) {
FATAL_ERROR(ss, SEC_ERROR_LIBRARY_FAILURE, internal_error);
goto loser;
}
PORT_Assert(ss->xtnData.selectedPsk->hash == tls13_GetHash(ss));
PORT_Assert(ss->ssl3.hs.suite_def);
rv = tls13_VerifyFinished(ss, ssl_hs_client_hello,
ss->xtnData.selectedPsk->binderKey,
ss->xtnData.pskBinder.data,
ss->xtnData.pskBinder.len,
&hashes);
}
if (rv != SECSuccess) {
goto loser;
}
/* This needs to go after we verify the psk binder. */
rv = ssl3_InitHandshakeHashes(ss);
if (rv != SECSuccess) {
goto loser;
}
/* If this is TLS 1.3 we are expecting a ClientKeyShare
* extension. Missing/absent extension cause failure
* below. */
rv = tls13_HandleClientKeyShare(ss, clientShare);
if (rv != SECSuccess) {
goto loser; /* An alert was sent already. */
}
/* From this point we are either committed to resumption, or not. */
if (ss->statelessResume) {
SSL_AtomicIncrementLong(&ssl3stats->hch_sid_cache_hits);
SSL_AtomicIncrementLong(&ssl3stats->hch_sid_stateless_resumes);
} else {
if (sid) {
/* We had a sid, but it's no longer valid, free it. */
SSL_AtomicIncrementLong(&ssl3stats->hch_sid_cache_not_ok);
ssl_UncacheSessionID(ss);
ssl_FreeSID(sid);
} else if (!ss->xtnData.selectedPsk) {
SSL_AtomicIncrementLong(&ssl3stats->hch_sid_cache_misses);
}
sid = ssl3_NewSessionID(ss, PR_TRUE);
if (!sid) {
FATAL_ERROR(ss, PORT_GetError(), internal_error);
return SECFailure;
}
}
/* Take ownership of the session. */
ss->sec.ci.sid = sid;
sid = NULL;
if (ss->ssl3.hs.zeroRttState == ssl_0rtt_accepted) {
rv = tls13_DeriveEarlySecrets(ss);
if (rv != SECSuccess) {
FATAL_ERROR(ss, SEC_ERROR_LIBRARY_FAILURE, internal_error);
return SECFailure;
}
}
ssl_GetXmitBufLock(ss);
rv = tls13_SendServerHelloSequence(ss);
ssl_ReleaseXmitBufLock(ss);
if (rv != SECSuccess) {
FATAL_ERROR(ss, PORT_GetError(), handshake_failure);
return SECFailure;
}
/* We're done with PSKs */
tls13_DestroyPskList(&ss->ssl3.hs.psks);
ss->xtnData.selectedPsk = NULL;
return SECSuccess;
loser:
if (sid) {
ssl_UncacheSessionID(ss);
ssl_FreeSID(sid);
}
return SECFailure;
}
SECStatus
SSLExp_HelloRetryRequestCallback(PRFileDesc *fd,
SSLHelloRetryRequestCallback cb, void *arg)
{
sslSocket *ss = ssl_FindSocket(fd);
if (!ss) {
return SECFailure; /* Code already set. */
}
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,
const PRUint8 *cookieGreaseEchSignal,
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;
/* Set restored ss->ssl3.hs.greaseEchBuf value for ECH HRR extension
* reconstruction. */
if (cookieGreaseEchSignal) {
PORT_Assert(!ss->ssl3.hs.greaseEchBuf.len);
rv = sslBuffer_Append(&ss->ssl3.hs.greaseEchBuf,
cookieGreaseEchSignal,
TLS13_ECH_SIGNAL_LEN);
if (rv != SECSuccess) {
goto loser;
}
}
rv = ssl_ConstructExtensions(ss, &extensionsBuf,
ssl_hs_hello_retry_request);
/* Reset ss->ssl3.hs.greaseEchBuf if it was changed. */
if (cookieGreaseEchSignal) {
sslBuffer_Clear(&ss->ssl3.hs.greaseEchBuf);
}
if (rv != SECSuccess) {
goto loser;
}
/* These extensions can't be empty. */
PORT_Assert(SSL_BUFFER_LEN(&extensionsBuf) > 0);
/* 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) {
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;
SSL_TRC(3, ("%d: TLS13[%d]: send hello retry request handshake",
SSL_GETPID(), ss->fd));
PORT_Assert(ss->opt.noLocks || ssl_HaveSSL3HandshakeLock(ss));
/* If an ECH backend or shared-mode server accepted ECH when offered,
* the HRR extension's payload must be set to 8 zero bytes, these are
* overwritten with the accept_confirmation value after the handshake
* transcript calculation.
* If a client-facing or shared-mode server did not accept ECH when offered
* OR if ECH GREASE is enabled on the server and a ECH extension was
* received, a 8 byte random value is set as the extension's payload
* [draft-ietf-tls-esni-14, Section 7].
*
* The (temporary) payload is written to the extension in tls13exthandle.c/
* tls13_ServerSendHrrEchXtn(). */
if (ss->xtnData.ech) {
PRUint8 echGreaseRaw[TLS13_ECH_SIGNAL_LEN] = { 0 };
if (!(ss->ssl3.hs.echAccepted ||
(ss->opt.enableTls13BackendEch &&
ss->xtnData.ech &&
ss->xtnData.ech->receivedInnerXtn))) {
rv = PK11_GenerateRandom(echGreaseRaw, TLS13_ECH_SIGNAL_LEN);
if (rv != SECSuccess) {
return SECFailure;
}
SSL_TRC(100, ("Generated random value for ECH HRR GREASE."));
}
sslBuffer echGreaseBuffer = SSL_BUFFER_EMPTY;
rv = sslBuffer_Append(&echGreaseBuffer, echGreaseRaw, sizeof(echGreaseRaw));
if (rv != SECSuccess) {
return SECFailure;
}
/* HRR GREASE/accept_confirmation zero bytes placeholder buffer. */
ss->ssl3.hs.greaseEchBuf = echGreaseBuffer;
}
/* 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);
return SECFailure;
}
/* Now build the body of the message. */
rv = tls13_ConstructHelloRetryRequest(ss, ss->ssl3.hs.cipher_suite,
requestedGroup,
cookie, cookieLen,
NULL, &messageBuf);
if (rv != SECSuccess) {
FATAL_ERROR(ss, SEC_ERROR_LIBRARY_FAILURE, internal_error);
return SECFailure;
}
/* And send it. */
ssl_GetXmitBufLock(ss);
rv = ssl3_AppendHandshakeHeader(ss, ssl_hs_server_hello,
SSL_BUFFER_LEN(&messageBuf));
if (rv != SECSuccess) {
goto loser;
}
rv = ssl3_AppendBufferToHandshake(ss, &messageBuf);
if (rv != SECSuccess) {
goto loser;
}
sslBuffer_Clear(&messageBuf); /* Done with messageBuf */
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->nextSeqNum == 1));
ssl_ReleaseXmitBufLock(ss);
ss->ssl3.hs.helloRetry = PR_TRUE;
/* We received early data but have to ignore it because we sent a retry. */
if (ss->ssl3.hs.zeroRttState == ssl_0rtt_sent) {
ss->ssl3.hs.zeroRttState = ssl_0rtt_ignored;
ss->ssl3.hs.zeroRttIgnore = ssl_0rtt_ignore_hrr;
}
return SECSuccess;
loser:
sslBuffer_Clear(&messageBuf);
ssl_ReleaseXmitBufLock(ss);
return SECFailure;
}
/* Called from tls13_HandleClientHello.
*
* Caller must hold Handshake and RecvBuf locks.
*/
static SECStatus
tls13_HandleClientKeyShare(sslSocket *ss, TLS13KeyShareEntry *peerShare)
{
SECStatus rv;
sslEphemeralKeyPair *keyPair; /* ours */
SECItem *ciphertext = NULL;
PK11SymKey *dheSecret = NULL;
PK11SymKey *kemSecret = NULL;
SSL_TRC(3, ("%d: TLS13[%d]: handle client_key_share handshake",
SSL_GETPID(), ss->fd));
PORT_Assert(ss->opt.noLocks || ssl_HaveRecvBufLock(ss));
PORT_Assert(ss->opt.noLocks || ssl_HaveSSL3HandshakeLock(ss));
PORT_Assert(peerShare);
tls13_SetKeyExchangeType(ss, peerShare->group);
/* Generate our key */
rv = tls13_AddKeyShare(ss, peerShare->group);
if (rv != SECSuccess) {
return rv;
}
/* We should have exactly one key share. */
PORT_Assert(!PR_CLIST_IS_EMPTY(&ss->ephemeralKeyPairs));
PORT_Assert(PR_PREV_LINK(&ss->ephemeralKeyPairs) ==
PR_NEXT_LINK(&ss->ephemeralKeyPairs));
keyPair = ((sslEphemeralKeyPair *)PR_NEXT_LINK(&ss->ephemeralKeyPairs));
ss->sec.keaKeyBits = SECKEY_PublicKeyStrengthInBits(keyPair->keys->pubKey);
/* Register the sender */
rv = ssl3_RegisterExtensionSender(ss, &ss->xtnData, ssl_tls13_key_share_xtn,
tls13_ServerSendKeyShareXtn);
if (rv != SECSuccess) {
return SECFailure; /* Error code set already. */
}
rv = tls13_HandleKeyShare(ss, peerShare, keyPair->keys,
tls13_GetHash(ss),
&dheSecret);
if (rv != SECSuccess) {
goto loser; /* Error code already set. */
}
if (peerShare->group->keaType == ssl_kea_ecdh_hybrid) {
rv = tls13_HandleKEMKey(ss, peerShare, &kemSecret, &ciphertext);
if (rv != SECSuccess) {
goto loser; /* Error set by tls13_HandleKEMKey */
}
switch (peerShare->group->name) {
case ssl_grp_kem_secp384r1mlkem1024:
case ssl_grp_kem_secp256r1mlkem768:
case ssl_grp_kem_xyber768d00:
ss->ssl3.hs.dheSecret = PK11_ConcatSymKeys(dheSecret, kemSecret, CKM_HKDF_DERIVE, CKA_DERIVE);
break;
case ssl_grp_kem_mlkem768x25519:
ss->ssl3.hs.dheSecret = PK11_ConcatSymKeys(kemSecret, dheSecret, CKM_HKDF_DERIVE, CKA_DERIVE);
break;
default:
PORT_Assert(0);
PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
ss->ssl3.hs.dheSecret = NULL;
break;
}
if (!ss->ssl3.hs.dheSecret) {
goto loser; /* Error set by PK11_ConcatSymKeys */
}
keyPair->kemCt = ciphertext;
PK11_FreeSymKey(dheSecret);
PK11_FreeSymKey(kemSecret);
} else {
ss->ssl3.hs.dheSecret = dheSecret;
}
return SECSuccess;
loser:
SECITEM_FreeItem(ciphertext, PR_TRUE);
PK11_FreeSymKey(dheSecret);
PK11_FreeSymKey(kemSecret);
FATAL_ERROR(ss, PORT_GetError(), illegal_parameter);
return SECFailure;
}
/*
* [draft-ietf-tls-tls13-11] Section 6.3.3.2
*
* opaque DistinguishedName<1..2^16-1>;
*
* struct {
* opaque certificate_extension_oid<1..2^8-1>;
* opaque certificate_extension_values<0..2^16-1>;
* } CertificateExtension;
*
* struct {
* opaque certificate_request_context<0..2^8-1>;
* SignatureAndHashAlgorithm
* supported_signature_algorithms<2..2^16-2>;
* DistinguishedName certificate_authorities<0..2^16-1>;
* CertificateExtension certificate_extensions<0..2^16-1>;
* } CertificateRequest;
*/
static SECStatus
tls13_SendCertificateRequest(sslSocket *ss)
{
SECStatus rv;
sslBuffer extensionBuf = SSL_BUFFER_EMPTY;
unsigned int offset = 0;
SSL_TRC(3, ("%d: TLS13[%d]: begin send certificate_request",
SSL_GETPID(), ss->fd));
if (ss->firstHsDone) {
PORT_Assert(ss->ssl3.hs.shaPostHandshake == NULL);
ss->ssl3.hs.shaPostHandshake = PK11_CloneContext(ss->ssl3.hs.sha);
if (ss->ssl3.hs.shaPostHandshake == NULL) {
ssl_MapLowLevelError(SSL_ERROR_SHA_DIGEST_FAILURE);
return SECFailure;
}
}
rv = ssl_ConstructExtensions(ss, &extensionBuf, ssl_hs_certificate_request);
if (rv != SECSuccess) {
return SECFailure; /* Code already set. */
}
/* We should always have at least one of these. */
PORT_Assert(SSL_BUFFER_LEN(&extensionBuf) > 0);
/* Create a new request context for post-handshake authentication */
if (ss->firstHsDone) {
PRUint8 context[16];
SECItem contextItem = { siBuffer, context, sizeof(context) };
rv = PK11_GenerateRandom(context, sizeof(context));
if (rv != SECSuccess) {
goto loser;
}
SECITEM_FreeItem(&ss->xtnData.certReqContext, PR_FALSE);
rv = SECITEM_CopyItem(NULL, &ss->xtnData.certReqContext, &contextItem);
if (rv != SECSuccess) {
FATAL_ERROR(ss, SEC_ERROR_NO_MEMORY, internal_error);
goto loser;
}
offset = SSL_BUFFER_LEN(&ss->sec.ci.sendBuf);
}
rv = ssl3_AppendHandshakeHeader(ss, ssl_hs_certificate_request,
1 + /* request context length */
ss->xtnData.certReqContext.len +
2 + /* extension length */
SSL_BUFFER_LEN(&extensionBuf));
if (rv != SECSuccess) {
goto loser; /* err set by AppendHandshake. */
}
/* Context. */
rv = ssl3_AppendHandshakeVariable(ss, ss->xtnData.certReqContext.data,
ss->xtnData.certReqContext.len, 1);
if (rv != SECSuccess) {
goto loser; /* err set by AppendHandshake. */
}
/* Extensions. */
rv = ssl3_AppendBufferToHandshakeVariable(ss, &extensionBuf, 2);
if (rv != SECSuccess) {
goto loser; /* err set by AppendHandshake. */
}
if (ss->firstHsDone) {
rv = ssl3_UpdatePostHandshakeHashes(ss,
SSL_BUFFER_BASE(&ss->sec.ci.sendBuf) + offset,
SSL_BUFFER_LEN(&ss->sec.ci.sendBuf) - offset);
if (rv != SECSuccess) {
goto loser;
}
}
sslBuffer_Clear(&extensionBuf);
return SECSuccess;
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)
*
* For an ECH handshake, the process occurs for the outer
* transcript in |ss->ssl3.hs.messages| and the inner
* transcript in |ss->ssl3.hs.echInnerMessages|.
*/
static SECStatus
tls13_ReinjectHandshakeTranscript(sslSocket *ss)
{
SSL3Hashes hashes = { 0 };
SSL3Hashes echInnerHashes = { 0 };
SECStatus rv;
/* First compute the hash. */
rv = tls13_ComputeHash(ss, &hashes,
ss->ssl3.hs.messages.buf,
ss->ssl3.hs.messages.len,
tls13_GetHash(ss));
if (rv != SECSuccess) {
return SECFailure;
}
if (ss->ssl3.hs.echHpkeCtx) {
rv = tls13_ComputeHash(ss, &echInnerHashes,
ss->ssl3.hs.echInnerMessages.buf,
ss->ssl3.hs.echInnerMessages.len,
tls13_GetHash(ss));
if (rv != SECSuccess) {
return SECFailure;
}
}
ssl3_RestartHandshakeHashes(ss);
/* Reinject the message. The Default context variant updates
* the default hash state. Use it for both non-ECH and ECH Outer. */
rv = ssl_HashHandshakeMessageDefault(ss, ssl_hs_message_hash,
hashes.u.raw, hashes.len);
if (rv != SECSuccess) {
return SECFailure;
}
if (ss->ssl3.hs.echHpkeCtx) {
rv = ssl_HashHandshakeMessageEchInner(ss, ssl_hs_message_hash,
echInnerHashes.u.raw,
echInnerHashes.len);
if (rv != SECSuccess) {
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;
}
/*
* savedMsg contains the HelloRetryRequest message. When its extensions are parsed
* in ssl3_HandleParsedExtensions, the handler for ECH HRR extensions (tls13_ClientHandleHrrEchXtn)
* will take a reference into the message buffer.
*
* This reference is then used in tls13_MaybeHandleEchSignal in order to compute
* the transcript for the ECH signal calculation. This was felt to be preferable
* to re-parsing the HelloRetryRequest message in order to create the transcript.
*
* Consequently, savedMsg should not be moved or mutated between these
* function calls.
*/
SECStatus
tls13_HandleHelloRetryRequest(sslSocket *ss, const PRUint8 *savedMsg,
PRUint32 savedLength)
{
SECStatus rv;
SSL_TRC(3, ("%d: TLS13[%d]: handle hello retry request",
SSL_GETPID(), ss->fd));
PORT_Assert(ss->opt.noLocks || ssl_HaveRecvBufLock(ss));
PORT_Assert(ss->opt.noLocks || ssl_HaveSSL3HandshakeLock(ss));
if (ss->vrange.max < SSL_LIBRARY_VERSION_TLS_1_3) {
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);
ssl_CipherSpecRelease(ss->ssl3.cwSpec);
ss->ssl3.cwSpec = ssl_FindCipherSpecByEpoch(ss, ssl_secret_write,
TrafficKeyClearText);
PORT_Assert(ss->ssl3.cwSpec);
ssl_ReleaseSpecWriteLock(ss);
} else {
PORT_Assert(ss->ssl3.hs.zeroRttState == ssl_0rtt_none);
}
/* Set the spec version, because we want to send CH now with 0303 */
tls13_SetSpecRecordVersion(ss, ss->ssl3.cwSpec);
/* 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 should alter our next Client Hello. */
unsigned int requiredExtensions = 1;
/* The ECH HRR extension is a no-op from the client's perspective. */
if (ss->xtnData.ech) {
requiredExtensions++;
}
if (ssl_ListCount(&ss->ssl3.hs.remoteExtensions) <= requiredExtensions) {
FATAL_ERROR(ss, SSL_ERROR_RX_MALFORMED_HELLO_RETRY_REQUEST,
decode_error);
return SECFailure;
}
rv = ssl3_HandleParsedExtensions(ss, ssl_hs_hello_retry_request);
ssl3_DestroyRemoteExtensions(&ss->ssl3.hs.remoteExtensions);
if (rv != SECSuccess) {
return SECFailure; /* Error code set below */
}
rv = tls13_MaybeHandleEchSignal(ss, savedMsg, savedLength, PR_TRUE);
if (rv != SECSuccess) {
return SECFailure;
}
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);
if (rv != SECSuccess) {
goto loser;
}
ssl_ReleaseXmitBufLock(ss);
return SECSuccess;
loser:
ssl_ReleaseXmitBufLock(ss);
return SECFailure;
}
static SECStatus
tls13_SendPostHandshakeCertificate(sslSocket *ss)
{
SECStatus rv;
if (ss->ssl3.hs.restartTarget) {
PR_NOT_REACHED("unexpected ss->ssl3.hs.restartTarget");
PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
return SECFailure;
}
if (ss->ssl3.hs.clientCertificatePending) {
SSL_TRC(3, ("%d: TLS13[%d]: deferring tls13_SendClientSecondFlight because"
" certificate authentication is still pending.",
SSL_GETPID(), ss->fd));
ss->ssl3.hs.restartTarget = tls13_SendPostHandshakeCertificate;
PORT_SetError(PR_WOULD_BLOCK_ERROR);
return SECFailure;
}
ssl_GetXmitBufLock(ss);
rv = tls13_SendClientSecondFlight(ss);
ssl_ReleaseXmitBufLock(ss);
PORT_Assert(ss->ssl3.hs.ws == idle_handshake);
PORT_Assert(ss->ssl3.hs.shaPostHandshake != NULL);
PK11_DestroyContext(ss->ssl3.hs.shaPostHandshake, PR_TRUE);
ss->ssl3.hs.shaPostHandshake = NULL;
if (rv != SECSuccess) {
return SECFailure;
}
return rv;
}
static SECStatus
tls13_HandleCertificateRequest(sslSocket *ss, PRUint8 *b, PRUint32 length)
{
SECStatus rv;
SECItem context = { siBuffer, NULL, 0 };
SECItem extensionsData = { siBuffer, NULL, 0 };
SSL_TRC(3, ("%d: TLS13[%d]: handle certificate_request sequence",
SSL_GETPID(), ss->fd));
PORT_Assert(ss->opt.noLocks || ssl_HaveRecvBufLock(ss));
PORT_Assert(ss->opt.noLocks || ssl_HaveSSL3HandshakeLock(ss));
/* Client */
if (ss->opt.enablePostHandshakeAuth) {
rv = TLS13_CHECK_HS_STATE(ss, SSL_ERROR_RX_UNEXPECTED_CERT_REQUEST,
wait_cert_request, idle_handshake);
} else {
rv = TLS13_CHECK_HS_STATE(ss, SSL_ERROR_RX_UNEXPECTED_CERT_REQUEST,
wait_cert_request);
}
if (rv != SECSuccess) {
return SECFailure;
}
/* MUST NOT combine external PSKs with certificate authentication. */
if (ss->sec.authType == ssl_auth_psk) {
FATAL_ERROR(ss, SSL_ERROR_RX_UNEXPECTED_CERT_REQUEST, unexpected_message);
return SECFailure;
}
if (tls13_IsPostHandshake(ss)) {
PORT_Assert(ss->ssl3.hs.shaPostHandshake == NULL);
ss->ssl3.hs.shaPostHandshake = PK11_CloneContext(ss->ssl3.hs.sha);
if (ss->ssl3.hs.shaPostHandshake == NULL) {
ssl_MapLowLevelError(SSL_ERROR_SHA_DIGEST_FAILURE);
return SECFailure;
}
rv = ssl_HashPostHandshakeMessage(ss, ssl_hs_certificate_request, b, length);
if (rv != SECSuccess) {
FATAL_ERROR(ss, SEC_ERROR_LIBRARY_FAILURE, internal_error);
return SECFailure;
}
/* clean up anything left from previous handshake. */
if (ss->ssl3.clientCertChain != NULL) {
CERT_DestroyCertificateList(ss->ssl3.clientCertChain);
ss->ssl3.clientCertChain = NULL;
}
if (ss->ssl3.clientCertificate != NULL) {
CERT_DestroyCertificate(ss->ssl3.clientCertificate);
ss->ssl3.clientCertificate = NULL;
}
if (ss->ssl3.clientPrivateKey != NULL) {
SECKEY_DestroyPrivateKey(ss->ssl3.clientPrivateKey);
ss->ssl3.clientPrivateKey = NULL;
}
if (ss->ssl3.hs.clientAuthSignatureSchemes != NULL) {
PORT_Free(ss->ssl3.hs.clientAuthSignatureSchemes);
ss->ssl3.hs.clientAuthSignatureSchemes = NULL;
ss->ssl3.hs.clientAuthSignatureSchemesLen = 0;
}
SECITEM_FreeItem(&ss->xtnData.certReqContext, PR_FALSE);
ss->xtnData.certReqContext.data = NULL;
} else {
PORT_Assert(ss->ssl3.clientCertChain == NULL);
PORT_Assert(ss->ssl3.clientCertificate == NULL);
PORT_Assert(ss->ssl3.clientPrivateKey == NULL);
PORT_Assert(ss->ssl3.hs.clientAuthSignatureSchemes == NULL);
PORT_Assert(ss->ssl3.hs.clientAuthSignatureSchemesLen == 0);
PORT_Assert(!ss->ssl3.hs.clientCertRequested);
PORT_Assert(ss->xtnData.certReqContext.data == NULL);
}
rv = ssl3_ConsumeHandshakeVariable(ss, &context, 1, &b, &length);
if (rv != SECSuccess) {
return SECFailure;
}
/* Unless it is a post-handshake client auth, the certificate
* request context must be empty. */
if (!tls13_IsPostHandshake(ss) && context.len > 0) {
FATAL_ERROR(ss, SSL_ERROR_RX_MALFORMED_CERT_REQUEST, illegal_parameter);
return SECFailure;
}
rv = ssl3_ConsumeHandshakeVariable(ss, &extensionsData, 2, &b, &length);
if (rv != SECSuccess) {
return SECFailure;
}
if (length) {
FATAL_ERROR(ss, SSL_ERROR_RX_MALFORMED_CERT_REQUEST, decode_error);
return SECFailure;
}
/* Process all the extensions. */
rv = ssl3_HandleExtensions(ss, &extensionsData.data, &extensionsData.len,
ssl_hs_certificate_request);
if (rv != SECSuccess) {
return SECFailure;
}
if (!ss->xtnData.numSigSchemes) {
FATAL_ERROR(ss, SSL_ERROR_MISSING_SIGNATURE_ALGORITHMS_EXTENSION,
missing_extension);
return SECFailure;
}
rv = SECITEM_CopyItem(NULL, &ss->xtnData.certReqContext, &context);
if (rv != SECSuccess) {
return SECFailure;
}
ss->ssl3.hs.clientCertRequested = PR_TRUE;
if (ss->firstHsDone) {
/* Request a client certificate. */
rv = ssl3_BeginHandleCertificateRequest(
ss, ss->xtnData.sigSchemes, ss->xtnData.numSigSchemes,
&ss->xtnData.certReqAuthorities);
if (rv != SECSuccess) {
FATAL_ERROR(ss, SEC_ERROR_LIBRARY_FAILURE, internal_error);
return rv;
}
rv = tls13_SendPostHandshakeCertificate(ss);
if (rv != SECSuccess) {
return rv; /* error code is set. */
}
} else {
TLS13_SET_HS_STATE(ss, wait_server_cert);
}
return SECSuccess;
}
PRBool
tls13_ShouldRequestClientAuth(sslSocket *ss)
{
/* Even if we are configured to request a certificate, we can't
* if this handshake used a PSK, even when we are resuming. */
return ss->opt.requestCertificate &&
ss->ssl3.hs.kea_def->authKeyType != ssl_auth_psk;
}
static SECStatus
tls13_SendEncryptedServerSequence(sslSocket *ss)
{
SECStatus rv;
rv = tls13_ComputeHandshakeSecrets(ss);
if (rv != SECSuccess) {
return SECFailure; /* error code is set. */
}
rv = tls13_SetCipherSpec(ss, TrafficKeyHandshake,
ssl_secret_write, PR_FALSE);
if (rv != SECSuccess) {
LOG_ERROR(ss, SEC_ERROR_LIBRARY_FAILURE);
return SECFailure;
}
if (ss->ssl3.hs.zeroRttState == ssl_0rtt_accepted) {
rv = ssl3_RegisterExtensionSender(ss, &ss->xtnData,
ssl_tls13_early_data_xtn,
ssl_SendEmptyExtension);
if (rv != SECSuccess) {
return SECFailure; /* Error code set already. */
}
}
rv = tls13_SendEncryptedExtensions(ss);
if (rv != SECSuccess) {
return SECFailure; /* error code is set. */
}
if (tls13_ShouldRequestClientAuth(ss)) {
rv = tls13_SendCertificateRequest(ss);
if (rv != SECSuccess) {
return SECFailure; /* error code is set. */
}
}
if (ss->ssl3.hs.signatureScheme != ssl_sig_none) {
SECKEYPrivateKey *svrPrivKey;
rv = tls13_SendCertificate(ss);
if (rv != SECSuccess) {
return SECFailure; /* error code is set. */
}
if (tls13_IsSigningWithDelegatedCredential(ss)) {
SSL_TRC(3, ("%d: TLS13[%d]: Signing with delegated credential",
SSL_GETPID(), ss->fd));
svrPrivKey = ss->sec.serverCert->delegCredKeyPair->privKey;
} else {
svrPrivKey = ss->sec.serverCert->serverKeyPair->privKey;
}
rv = tls13_SendCertificateVerify(ss, svrPrivKey);
if (rv != SECSuccess) {
return SECFailure; /* err code is set. */
}
}
rv = tls13_SendFinished(ss, ss->ssl3.hs.serverHsTrafficSecret);
if (rv != SECSuccess) {
return SECFailure; /* error code is set. */
}
return SECSuccess;
}
/* Called from: ssl3_HandleClientHello */
static SECStatus
tls13_SendServerHelloSequence(sslSocket *ss)
{
SECStatus rv;
PRErrorCode err = 0;
SSL_TRC(3, ("%d: TLS13[%d]: begin send server_hello sequence",
SSL_GETPID(), ss->fd));
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 = tls13_ComputeHandshakeSecret(ss);
if (rv != SECSuccess) {
return SECFailure; /* error code is set. */
}
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();
}
/* Even if we get an error, since the ServerHello was successfully
* serialized, we should give it a chance to reach the network. This gives
* the client a chance to perform the key exchange and decrypt the alert
* we're about to send. */
rv |= ssl3_FlushHandshake(ss, 0);
if (rv != SECSuccess) {
if (err) {
PORT_SetError(err);
}
return SECFailure;
}
/* Compute the rest of the secrets except for the resumption
* and exporter secret. */
rv = tls13_ComputeApplicationSecrets(ss);
if (rv != SECSuccess) {
LOG_ERROR(ss, PORT_GetError());
return SECFailure;
}
rv = tls13_SetCipherSpec(ss, TrafficKeyApplicationData,
ssl_secret_write, PR_FALSE);
if (rv != SECSuccess) {
LOG_ERROR(ss, SEC_ERROR_LIBRARY_FAILURE);
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,
ssl_secret_read, 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);
rv = tls13_SetCipherSpec(ss,
TrafficKeyHandshake,
ssl_secret_read, PR_FALSE);
if (rv != SECSuccess) {
LOG_ERROR(ss, SEC_ERROR_LIBRARY_FAILURE);
return SECFailure;
}
if (tls13_ShouldRequestClientAuth(ss)) {
TLS13_SET_HS_STATE(ss, wait_client_cert);
} else {
TLS13_SET_HS_STATE(ss, wait_finished);
}
}
/* Here we set a baseline value for our RTT estimation.
* This value is updated when we get a response from the client. */
ss->ssl3.hs.rttEstimate = ssl_Time(ss);
return SECSuccess;
}
SECStatus
tls13_HandleServerHelloPart2(sslSocket *ss, const PRUint8 *savedMsg, PRUint32 savedLength)
{
SECStatus rv;
sslSessionID *sid = ss->sec.ci.sid;
SSL3Statistics *ssl3stats = SSL_GetStatistics();
if (ssl3_ExtensionNegotiated(ss, ssl_tls13_pre_shared_key_xtn)) {
PORT_Assert(!PR_CLIST_IS_EMPTY(&ss->ssl3.hs.psks));
PORT_Assert(ss->xtnData.selectedPsk);
if (ss->xtnData.selectedPsk->type != ssl_psk_resume) {
ss->statelessResume = PR_FALSE;
}
} else {
/* We may have offered a PSK. If the server didn't negotiate
* it, clear this state to re-extract the Early Secret. */
if (ss->ssl3.hs.currentSecret) {
/* We might have dropped incompatible PSKs on HRR
* (see RFC8466, Section 4.1.4). */
PORT_Assert(ss->ssl3.hs.helloRetry ||
ssl3_ExtensionAdvertised(ss, ssl_tls13_pre_shared_key_xtn));
PK11_FreeSymKey(ss->ssl3.hs.currentSecret);
ss->ssl3.hs.currentSecret = NULL;
}
ss->statelessResume = PR_FALSE;
ss->xtnData.selectedPsk = NULL;
}
if (ss->statelessResume) {
PORT_Assert(sid->version >= SSL_LIBRARY_VERSION_TLS_1_3);
if (tls13_GetHash(ss) !=
tls13_GetHashForCipherSuite(sid->u.ssl3.cipherSuite)) {
FATAL_ERROR(ss, SSL_ERROR_RX_MALFORMED_SERVER_HELLO,
illegal_parameter);
return SECFailure;
}
}
/* Now create a synthetic kea_def that we can tweak. */
ss->ssl3.hs.kea_def_mutable = *ss->ssl3.hs.kea_def;
ss->ssl3.hs.kea_def = &ss->ssl3.hs.kea_def_mutable;
if (ss->xtnData.selectedPsk) {
ss->ssl3.hs.kea_def_mutable.authKeyType = ssl_auth_psk;
if (ss->statelessResume) {
tls13_RestoreCipherInfo(ss, sid);
if (sid->peerCert) {
ss->sec.peerCert = CERT_DupCertificate(sid->peerCert);
}
SSL_AtomicIncrementLong(&ssl3stats->hsh_sid_cache_hits);
SSL_AtomicIncrementLong(&ssl3stats->hsh_sid_stateless_resumes);
} else {
ss->sec.authType = ssl_auth_psk;
}
} else {
if (ss->statelessResume &&
ssl3_ExtensionAdvertised(ss, ssl_tls13_pre_shared_key_xtn)) {
SSL_AtomicIncrementLong(&ssl3stats->hsh_sid_cache_misses);
}
if (sid->cached == in_client_cache) {
/* If we tried to resume and failed, let's not try again. */
ssl_UncacheSessionID(ss);
}
}
/* Discard current SID and make a new one, though it may eventually
* end up looking a lot like the old one.
*/
ssl_FreeSID(sid);
ss->sec.ci.sid = sid = ssl3_NewSessionID(ss, PR_FALSE);
if (sid == NULL) {
FATAL_ERROR(ss, PORT_GetError(), internal_error);
return SECFailure;
}
if (ss->statelessResume) {
PORT_Assert(ss->sec.peerCert);
sid->peerCert = CERT_DupCertificate(ss->sec.peerCert);
}
sid->version = ss->version;
rv = tls13_HandleServerKeyShare(ss);
if (rv != SECSuccess) {
return SECFailure;
}
rv = tls13_ComputeHandshakeSecret(ss);
if (rv != SECSuccess) {
return SECFailure; /* error code is set. */
}
rv = tls13_MaybeHandleEchSignal(ss, savedMsg, savedLength, PR_FALSE);
if (rv != SECSuccess) {
return SECFailure; /* error code is set. */
}
rv = tls13_ComputeHandshakeSecrets(ss);
if (rv != SECSuccess) {
return SECFailure; /* error code is set. */
}
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, ssl_secret_write, TrafficKeyClearText);
}
rv = tls13_SetCipherSpec(ss, TrafficKeyHandshake,
ssl_secret_read, PR_FALSE);
if (rv != SECSuccess) {
FATAL_ERROR(ss, SSL_ERROR_INIT_CIPHER_SUITE_FAILURE, internal_error);
return SECFailure;
}
TLS13_SET_HS_STATE(ss, wait_encrypted_extensions);
return SECSuccess;
}
static void
tls13_SetKeyExchangeType(sslSocket *ss, const sslNamedGroupDef *group)
{
ss->sec.keaGroup = group;
switch (group->keaType) {
/* Note: These overwrite on resumption.... so if you start with ECDH
* and resume with DH, we report DH. That's fine, since no answer
* is really right. */
case ssl_kea_ecdh:
ss->ssl3.hs.kea_def_mutable.exchKeyType =
ss->statelessResume ? ssl_kea_ecdh_psk : ssl_kea_ecdh;
ss->sec.keaType = ssl_kea_ecdh;
break;
case ssl_kea_ecdh_hybrid:
ss->ssl3.hs.kea_def_mutable.exchKeyType =
ss->statelessResume ? ssl_kea_ecdh_hybrid_psk : ssl_kea_ecdh_hybrid;
ss->sec.keaType = ssl_kea_ecdh_hybrid;
break;
case ssl_kea_dh:
ss->ssl3.hs.kea_def_mutable.exchKeyType =
ss->statelessResume ? ssl_kea_dh_psk : ssl_kea_dh;
ss->sec.keaType = ssl_kea_dh;
break;
default:
PORT_Assert(0);
}
}
/*
* Called from ssl3_HandleServerHello.
*
* Caller must hold Handshake and RecvBuf locks.
*/
static SECStatus
tls13_HandleServerKeyShare(sslSocket *ss)
{
SECStatus rv;
TLS13KeyShareEntry *entry;
sslEphemeralKeyPair *keyPair;
PK11SymKey *dheSecret = NULL;
PK11SymKey *kemSecret = NULL;
SSL_TRC(3, ("%d: TLS13[%d]: handle server_key_share handshake",
SSL_GETPID(), ss->fd));
PORT_Assert(ss->opt.noLocks || ssl_HaveRecvBufLock(ss));
PORT_Assert(ss->opt.noLocks || ssl_HaveSSL3HandshakeLock(ss));
/* This list should have one entry. */
if (PR_CLIST_IS_EMPTY(&ss->xtnData.remoteKeyShares)) {
FATAL_ERROR(ss, SSL_ERROR_MISSING_KEY_SHARE, missing_extension);
return SECFailure;
}
entry = (TLS13KeyShareEntry *)PR_NEXT_LINK(&ss->xtnData.remoteKeyShares);
PORT_Assert(PR_NEXT_LINK(&entry->link) == &ss->xtnData.remoteKeyShares);
/* Now get our matching key. */
keyPair = ssl_LookupEphemeralKeyPair(ss, entry->group);
if (!keyPair) {
FATAL_ERROR(ss, SSL_ERROR_RX_MALFORMED_KEY_SHARE, illegal_parameter);
return SECFailure;
}
PORT_Assert(ssl_NamedGroupEnabled(ss, entry->group));
rv = tls13_HandleKeyShare(ss, entry, keyPair->keys,
tls13_GetHash(ss),
&dheSecret);
if (rv != SECSuccess) {
goto loser; /* Error code already set. */
}
if (entry->group->keaType == ssl_kea_ecdh_hybrid) {
rv = tls13_HandleKEMCiphertext(ss, entry, keyPair->kemKeys, &kemSecret);
if (rv != SECSuccess) {
goto loser; /* Error set by tls13_HandleKEMCiphertext */
}
switch (entry->group->name) {
case ssl_grp_kem_secp384r1mlkem1024:
case ssl_grp_kem_secp256r1mlkem768:
case ssl_grp_kem_xyber768d00:
ss->ssl3.hs.dheSecret = PK11_ConcatSymKeys(dheSecret, kemSecret, CKM_HKDF_DERIVE, CKA_DERIVE);
break;
case ssl_grp_kem_mlkem768x25519:
ss->ssl3.hs.dheSecret = PK11_ConcatSymKeys(kemSecret, dheSecret, CKM_HKDF_DERIVE, CKA_DERIVE);
break;
default:
PORT_Assert(0);
PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
ss->ssl3.hs.dheSecret = NULL;
break;
}
if (!ss->ssl3.hs.dheSecret) {
goto loser; /* Error set by PK11_ConcatSymKeys */
}
PK11_FreeSymKey(dheSecret);
PK11_FreeSymKey(kemSecret);
} else {
ss->ssl3.hs.dheSecret = dheSecret;
}
tls13_SetKeyExchangeType(ss, entry->group);
ss->sec.keaKeyBits = SECKEY_PublicKeyStrengthInBits(keyPair->keys->pubKey);
return SECSuccess;
loser:
PK11_FreeSymKey(dheSecret);
PK11_FreeSymKey(kemSecret);
FATAL_ERROR(ss, PORT_GetError(), illegal_parameter);
return SECFailure;
}
static PRBool
tls13_FindCompressionAlgAndCheckIfSupportsEncoding(sslSocket *ss)
{
PORT_Assert(ss->opt.noLocks || ssl_HaveXmitBufLock(ss));
PORT_Assert(ss->opt.noLocks || ssl_HaveSSL3HandshakeLock(ss));
for (int j = 0; j < ss->ssl3.supportedCertCompressionAlgorithmsCount; j++) {
if (ss->ssl3.supportedCertCompressionAlgorithms[j].id == ss->xtnData.compressionAlg) {
if (ss->ssl3.supportedCertCompressionAlgorithms[j].encode != NULL) {
return PR_TRUE;
}
return PR_FALSE;
}
}
return PR_FALSE;
}
static SECStatus
tls13_FindCompressionAlgAndEncodeCertificate(
sslSocket *ss, SECItem *certificateToEncode, SECItem *encodedCertificate)
{
PORT_Assert(ss->opt.noLocks || ssl_HaveXmitBufLock(ss));
PORT_Assert(ss->opt.noLocks || ssl_HaveSSL3HandshakeLock(ss));
SECStatus rv = SECFailure;
for (int j = 0; j < ss->ssl3.supportedCertCompressionAlgorithmsCount; j++) {
if (ss->ssl3.supportedCertCompressionAlgorithms[j].id == ss->xtnData.compressionAlg &&
ss->ssl3.supportedCertCompressionAlgorithms[j].encode != NULL) {
rv = ss->ssl3.supportedCertCompressionAlgorithms[j].encode(
certificateToEncode, encodedCertificate);
return rv;
}
}
PORT_SetError(SEC_ERROR_CERTIFICATE_COMPRESSION_ALGORITHM_NOT_SUPPORTED);
return SECFailure;
}
static SECStatus
tls13_SendCompressedCertificate(sslSocket *ss, sslBuffer *bufferCertificate)
{
/* TLS Certificate Compression. RFC 8879 */
/* As the encoding function takes as input a SECItem,
* we convert bufferCertificate to certificateToEncode.
*
* encodedCertificate is used to store the certificate
* after encoding.
*/
SECItem encodedCertificate = { siBuffer, NULL, 0 };
SECItem certificateToEncode = { siBuffer, NULL, 0 };
SECStatus rv = SECFailure;
PORT_Assert(ss->opt.noLocks || ssl_HaveXmitBufLock(ss));
PORT_Assert(ss->opt.noLocks || ssl_HaveSSL3HandshakeLock(ss));
SSL_TRC(30, ("%d: TLS13[%d]: %s is encoding the certificate using the %s compression algorithm",
SSL_GETPID(), ss->fd, SSL_ROLE(ss),
ssl3_mapCertificateCompressionAlgorithmToName(ss, ss->xtnData.compressionAlg)));
PRINT_BUF(50, (NULL, "The certificate before encoding:",
bufferCertificate->buf, bufferCertificate->len));
PRUint32 lengthUnencodedMessage = bufferCertificate->len;
rv = ssl3_CopyToSECItem(bufferCertificate, &certificateToEncode);
if (rv != SECSuccess) {
SSL_TRC(50, ("%d: TLS13[%d]: %s has failed encoding the certificate.",
SSL_GETPID(), ss->fd, SSL_ROLE(ss)));
goto loser; /* Code already set. */
}
rv = tls13_FindCompressionAlgAndEncodeCertificate(ss, &certificateToEncode,
&encodedCertificate);
if (rv != SECSuccess) {
SSL_TRC(50, ("%d: TLS13[%d]: %s has failed encoding the certificate.",
SSL_GETPID(), ss->fd, SSL_ROLE(ss)));
PORT_SetError(SEC_ERROR_NO_MEMORY);
goto loser; /* Code already set. */
}
/* The CompressedCertificate message is formed as follows:
* struct {
* CertificateCompressionAlgorithm algorithm;
* uint24 uncompressed_length;
* opaque compressed_certificate_message<1..2^24-1>;
* } CompressedCertificate;
*/
if (encodedCertificate.len < 1) {
PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
goto loser;
}
rv = ssl3_AppendHandshakeHeader(ss, ssl_hs_compressed_certificate,
encodedCertificate.len + 2 + 3 + 3);
if (rv != SECSuccess) {
goto loser; /* err set by AppendHandshake. */
}
rv = ssl3_AppendHandshakeNumber(ss, ss->xtnData.compressionAlg, 2);
if (rv != SECSuccess) {
goto loser; /* err set by AppendHandshake. */
}
rv = ssl3_AppendHandshakeNumber(ss, lengthUnencodedMessage, 3);
if (rv != SECSuccess) {
goto loser; /* err set by AppendHandshake. */
}
PRINT_BUF(30, (NULL, "The encoded certificate: ",
encodedCertificate.data, encodedCertificate.len));
rv = ssl3_AppendHandshakeVariable(ss, encodedCertificate.data, encodedCertificate.len, 3);
if (rv != SECSuccess) {
goto loser; /* err set by AppendHandshake. */
}
SECITEM_FreeItem(&certificateToEncode, PR_FALSE);
SECITEM_FreeItem(&encodedCertificate, PR_FALSE);
return SECSuccess;
loser:
SECITEM_FreeItem(&certificateToEncode, PR_FALSE);
SECITEM_FreeItem(&encodedCertificate, PR_FALSE);
return SECFailure;
}
/*
* opaque ASN1Cert<1..2^24-1>;
*
* struct {
* ASN1Cert cert_data;
* Extension extensions<0..2^16-1>;
* } CertificateEntry;
*
* struct {
* opaque certificate_request_context<0..2^8-1>;
* CertificateEntry certificate_list<0..2^24-1>;
* } Certificate;
*/
static SECStatus
tls13_SendCertificate(sslSocket *ss)
{
SECStatus rv;
CERTCertificateList *certChain;
int certChainLen = 0;
int i;
SECItem context = { siBuffer, NULL, 0 };
sslBuffer extensionBuf = SSL_BUFFER_EMPTY;
sslBuffer bufferCertificate = SSL_BUFFER_EMPTY;
SSL_TRC(3, ("%d: TLS1.3[%d]: send certificate handshake",
SSL_GETPID(), ss->fd));
PORT_Assert(ss->opt.noLocks || ssl_HaveXmitBufLock(ss));
PORT_Assert(ss->opt.noLocks || ssl_HaveSSL3HandshakeLock(ss));
if (ss->sec.isServer) {
PORT_Assert(!ss->sec.localCert);
/* A server certificate is selected in tls13_SelectServerCert(). */
PORT_Assert(ss->sec.serverCert);
certChain = ss->sec.serverCert->serverCertChain;
ss->sec.localCert = CERT_DupCertificate(ss->sec.serverCert->serverCert);
} else {
if (ss->sec.localCert)
CERT_DestroyCertificate(ss->sec.localCert);
certChain = ss->ssl3.clientCertChain;
ss->sec.localCert = CERT_DupCertificate(ss->ssl3.clientCertificate);
}
if (!ss->sec.isServer) {
PORT_Assert(ss->ssl3.hs.clientCertRequested);
context = ss->xtnData.certReqContext;
}
if (certChain) {
for (i = 0; i < certChain->len; i++) {
/* 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 = sslBuffer_AppendVariable(&bufferCertificate, context.data, context.len, 1);
if (rv != SECSuccess) {
goto loser; /* Code already set. */
}
rv = sslBuffer_AppendNumber(&bufferCertificate, certChainLen, 3);
if (rv != SECSuccess) {
goto loser; /* Code already set. */
}
if (certChain) {
for (i = 0; i < certChain->len; i++) {
rv = sslBuffer_AppendVariable(&bufferCertificate, certChain->certs[i].data,
certChain->certs[i].len, 3);
if (rv != SECSuccess) {
goto loser; /* Code already set. */
}
if (i) {
/* Not end-entity. */
rv = sslBuffer_AppendNumber(&bufferCertificate, 0, 2);
if (rv != SECSuccess) {
goto loser; /* Code already set. */
}
continue;
}
rv = sslBuffer_AppendBufferVariable(&bufferCertificate, &extensionBuf, 2);
if (rv != SECSuccess) {
goto loser; /* Code already set. */
}
}
}
/* If no compression mechanism was established or
* the compression mechanism supports only decoding,
* we continue as before. */
if (ss->xtnData.compressionAlg == 0 || !tls13_FindCompressionAlgAndCheckIfSupportsEncoding(ss)) {
rv = ssl3_AppendHandshakeHeader(ss, ssl_hs_certificate,
1 + context.len + 3 + certChainLen);
if (rv != SECSuccess) {
goto loser; /* err set by AppendHandshake. */
}
rv = ssl3_AppendBufferToHandshake(ss, &bufferCertificate);
if (rv != SECSuccess) {
goto loser; /* err set by AppendHandshake. */
}
} else {
rv = tls13_SendCompressedCertificate(ss, &bufferCertificate);
if (rv != SECSuccess) {
goto loser; /* err set by tls13_SendCompressedCertificate. */
}
}
sslBuffer_Clear(&bufferCertificate);
sslBuffer_Clear(&extensionBuf);
return SECSuccess;
loser:
sslBuffer_Clear(&bufferCertificate);
sslBuffer_Clear(&extensionBuf);
return SECFailure;
}
static SECStatus
tls13_HandleCertificateEntry(sslSocket *ss, SECItem *data, PRBool first,
SECItem *certData)
{
SECStatus rv;
SECItem extensionsData;
rv = ssl3_ConsumeHandshakeVariable(ss, certData,
3, &data->data, &data->len);
if (rv != SECSuccess) {
return SECFailure;
}
rv = ssl3_ConsumeHandshakeVariable(ss, &extensionsData,
2, &data->data, &data->len);
if (rv != SECSuccess) {
return SECFailure;
}
/* Parse all the extensions. */
if (first && !ss->sec.isServer) {
rv = ssl3_HandleExtensions(ss, &extensionsData.data,
&extensionsData.len,
ssl_hs_certificate);
if (rv != SECSuccess) {
return SECFailure;
}
}
return SECSuccess;
}
static SECStatus
tls13_EnsureCerticateExpected(sslSocket *ss)
{
SECStatus rv = SECFailure;
PORT_Assert(ss->opt.noLocks || ssl_HaveRecvBufLock(ss));
PORT_Assert(ss->opt.noLocks || ssl_HaveSSL3HandshakeLock(ss));
if (ss->sec.isServer) {
/* Receiving this message might be the first sign we have that
* early data is over, so pretend we received EOED. */
rv = tls13_MaybeHandleSuppressedEndOfEarlyData(ss);
if (rv != SECSuccess) {
return SECFailure; /* Code already set. */
}
if (ss->ssl3.clientCertRequested) {
rv = TLS13_CHECK_HS_STATE(ss, SSL_ERROR_RX_UNEXPECTED_CERTIFICATE,
idle_handshake);
} else {
rv = TLS13_CHECK_HS_STATE(ss, SSL_ERROR_RX_UNEXPECTED_CERTIFICATE,
wait_client_cert);
}
} else {
rv = TLS13_CHECK_HS_STATE(ss, SSL_ERROR_RX_UNEXPECTED_CERTIFICATE,
wait_cert_request, wait_server_cert);
}
return rv;
}
/* RFC 8879 TLS Certificate Compression
* struct {
* CertificateCompressionAlgorithm algorithm;
* uint24 uncompressed_length;
* opaque compressed_certificate_message<1..2^24-1>;
* } CompressedCertificate;
*/
static SECStatus
tls13_HandleCertificateDecode(sslSocket *ss, PRUint8 *b, PRUint32 length)
{
PORT_Assert(ss->opt.noLocks || ssl_HaveRecvBufLock(ss));
PORT_Assert(ss->opt.noLocks || ssl_HaveSSL3HandshakeLock(ss));
SECStatus rv = SECFailure;
if (!ss->xtnData.certificateCompressionAdvertised) {
FATAL_ERROR(ss, SEC_ERROR_UNEXPECTED_COMPRESSED_CERTIFICATE, decode_error);
return SECFailure;
}
rv = tls13_EnsureCerticateExpected(ss);
if (rv != SECSuccess) {
return SECFailure; /* Code already set. */
}
if (ss->firstHsDone) {
rv = ssl_HashPostHandshakeMessage(ss, ssl_hs_compressed_certificate, b, length);
if (rv != SECSuccess) {
return rv;
}
}
SSL_TRC(30, ("%d: TLS1.3[%d]: %s handles certificate compression handshake",
SSL_GETPID(), ss->fd, SSL_ROLE(ss)));
PRINT_BUF(50, (NULL, "The certificate before decoding:", b, length));
/* Reading CertificateCompressionAlgorithm. */
PRUint32 compressionAlg = 0;
rv = ssl3_ConsumeHandshakeNumber(ss, &compressionAlg, 2, &b, &length);
if (rv != SECSuccess) {
return SECFailure; /* Alert already sent. */
}
PRBool compressionAlgorithmIsSupported = PR_FALSE;
SECStatus (*certificateDecodingFunc)(const SECItem *,
unsigned char *output, size_t outputLen, size_t *usedLen) = NULL;
for (int i = 0; i < ss->ssl3.supportedCertCompressionAlgorithmsCount; i++) {
if (ss->ssl3.supportedCertCompressionAlgorithms[i].id == compressionAlg) {
compressionAlgorithmIsSupported = PR_TRUE;
certificateDecodingFunc = ss->ssl3.supportedCertCompressionAlgorithms[i].decode;
}
}
/* Peer selected a compression algorithm we do not support (and did not advertise). */
if (!compressionAlgorithmIsSupported) {
PORT_SetError(SEC_ERROR_CERTIFICATE_COMPRESSION_ALGORITHM_NOT_SUPPORTED);
FATAL_ERROR(ss, PORT_GetError(), illegal_parameter);
return SECFailure;
}
/* The algorithm does not support decoding. */
if (certificateDecodingFunc == NULL) {
PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
FATAL_ERROR(ss, PORT_GetError(), illegal_parameter);
return SECFailure;
}
SSL_TRC(30, ("%d: TLS13[%d]: %s is decoding the certificate using the %s compression algorithm",
SSL_GETPID(), ss->fd, SSL_ROLE(ss),
ssl3_mapCertificateCompressionAlgorithmToName(ss, compressionAlg)));
PRUint32 decodedCertLen = 0;
rv = ssl3_ConsumeHandshakeNumber(ss, &decodedCertLen, 3, &b, &length);
if (rv != SECSuccess) {
return SECFailure; /* alert has been sent */
}
/* If the received CompressedCertificate message cannot be decompressed,
* he connection MUST be terminated with the "bad_certificate" alert.
*/
if (decodedCertLen == 0) {
SSL_TRC(50, ("%d: TLS13[%d]: %s decoded certificate length is incorrect",
SSL_GETPID(), ss->fd, SSL_ROLE(ss),
ssl3_mapCertificateCompressionAlgorithmToName(ss, compressionAlg)));
FATAL_ERROR(ss, SSL_ERROR_RX_MALFORMED_CERTIFICATE, bad_certificate);
return SECFailure;
}
/* opaque compressed_certificate_message<1..2^24-1>; */
PRUint32 compressedCertLen = 0;
rv = ssl3_ConsumeHandshakeNumber(ss, &compressedCertLen, 3, &b, &length);
if (rv != SECSuccess) {
return SECFailure; /* alert has been sent */
}
if (compressedCertLen == 0 || compressedCertLen != length) {
FATAL_ERROR(ss, SSL_ERROR_RX_MALFORMED_CERTIFICATE, bad_certificate);
return SECFailure;
}
/* Decoding received certificate. */
PRUint8 *decodedCert = PORT_ZAlloc(decodedCertLen);
if (!decodedCert) {
return SECFailure;
}
size_t actualCertLen = 0;
SECItem encodedCertAsSecItem = { siBuffer, b, compressedCertLen };
rv = certificateDecodingFunc(&encodedCertAsSecItem,
decodedCert, decodedCertLen, &actualCertLen);
if (rv != SECSuccess) {
SSL_TRC(50, ("%d: TLS13[%d]: %s decoding of the certificate has failed",
SSL_GETPID(), ss->fd, SSL_ROLE(ss),
ssl3_mapCertificateCompressionAlgorithmToName(ss, compressionAlg)));
FATAL_ERROR(ss, SSL_ERROR_RX_MALFORMED_CERTIFICATE, bad_certificate);
goto loser;
}
PRINT_BUF(60, (ss, "consume bytes:", b, compressedCertLen));
*b += compressedCertLen;
length -= compressedCertLen;
/* If, after decompression, the specified length does not match the actual length,
* the party receiving the invalid message MUST abort the connection
* with the "bad_certificate" alert.
*/
if (actualCertLen != decodedCertLen) {
SSL_TRC(50, ("%d: TLS13[%d]: %s certificate length does not correspond to extension length",
SSL_GETPID(), ss->fd, SSL_ROLE(ss),
ssl3_mapCertificateCompressionAlgorithmToName(ss, compressionAlg)));
FATAL_ERROR(ss, SSL_ERROR_RX_MALFORMED_CERTIFICATE, bad_certificate);
goto loser;
}
PRINT_BUF(50, (NULL, "Decoded certificate",
decodedCert, decodedCertLen));
/* compressed_certificate_message: The result of applying the indicated
* compression algorithm to the encoded Certificate message that
* would have been sent if certificate compression was not in use.
*
* After decompression, the Certificate message MUST be processed as if
* it were encoded without being compressed. This way, the parsing and
* the verification have the same security properties as they would have
* in TLS normally.
*/
rv = tls13_HandleCertificate(ss, decodedCert, decodedCertLen, PR_TRUE);
if (rv != SECSuccess) {
goto loser;
}
/* We allow only one compressed certificate to be handled after each
certificate compression advertisement.
See test CertificateCompression_TwoEncodedCertificateRequests. */
ss->xtnData.certificateCompressionAdvertised = PR_FALSE;
PORT_Free(decodedCert);
return SECSuccess;
loser:
PORT_Free(decodedCert);
return SECFailure;
}
/* Called from tls13_CompleteHandleHandshakeMessage() when it has deciphered a complete
* tls13 Certificate message.
* Caller must hold Handshake and RecvBuf locks.
*/
static SECStatus
tls13_HandleCertificate(sslSocket *ss, PRUint8 *b, PRUint32 length, PRBool alreadyHashed)
{
SECStatus rv;
SECItem context = { siBuffer, NULL, 0 };
SECItem certList;
PRBool first = PR_TRUE;
ssl3CertNode *lastCert = NULL;
SSL_TRC(3, ("%d: TLS13[%d]: handle certificate handshake",
SSL_GETPID(), ss->fd));
PORT_Assert(ss->opt.noLocks || ssl_HaveRecvBufLock(ss));
PORT_Assert(ss->opt.noLocks || ssl_HaveSSL3HandshakeLock(ss));
rv = tls13_EnsureCerticateExpected(ss);
if (rv != SECSuccess) {
return SECFailure; /* Code already set. */
}
/* We can ignore any other cleartext from the client. */
if (ss->sec.isServer && IS_DTLS(ss)) {
ssl_CipherSpecReleaseByEpoch(ss, ssl_secret_read, TrafficKeyClearText);
dtls_ReceivedFirstMessageInFlight(ss);
}
/* AlreadyHashed is true only when Certificate Compression is used. */
if (ss->firstHsDone && !alreadyHashed) {
rv = ssl_HashPostHandshakeMessage(ss, ssl_hs_certificate, b, length);
if (rv != SECSuccess) {
PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
return SECFailure;
}
}
if (!ss->firstHsDone && ss->sec.isServer) {
/* Our first shot an getting an RTT estimate. If the client took extra
* time to fetch a certificate, this will be bad, but we can't do much
* about that. */
ss->ssl3.hs.rttEstimate = ssl_Time(ss) - ss->ssl3.hs.rttEstimate;
}
/* Process the context string */
rv = ssl3_ConsumeHandshakeVariable(ss, &context, 1, &b, &length);
if (rv != SECSuccess)
return SECFailure;
if (ss->ssl3.clientCertRequested) {
PORT_Assert(ss->sec.isServer);
if (SECITEM_CompareItem(&context, &ss->xtnData.certReqContext) != 0) {
FATAL_ERROR(ss, SSL_ERROR_RX_MALFORMED_CERTIFICATE, illegal_parameter);
return SECFailure;
}
}
rv = ssl3_ConsumeHandshakeVariable(ss, &certList, 3, &b, &length);
if (rv != SECSuccess) {
return SECFailure;
}
if (length) {
FATAL_ERROR(ss, SSL_ERROR_RX_MALFORMED_CERTIFICATE, illegal_parameter);
return SECFailure;
}
if (!certList.len) {
if (!ss->sec.isServer) {
/* Servers always need to send some cert. */
FATAL_ERROR(ss, SSL_ERROR_RX_MALFORMED_CERTIFICATE, bad_certificate);
return SECFailure;
} else {
/* This is TLS's version of a no_certificate alert. */
/* I'm a server. I've requested a client cert. He hasn't got one. */
rv = ssl3_HandleNoCertificate(ss);
if (rv != SECSuccess) {
return SECFailure;
}
TLS13_SET_HS_STATE(ss, wait_finished);
return SECSuccess;
}
}
/* Now clean up. */
ssl3_CleanupPeerCerts(ss);
ss->ssl3.peerCertArena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
if (ss->ssl3.peerCertArena == NULL) {
FATAL_ERROR(ss, SEC_ERROR_NO_MEMORY, internal_error);
return SECFailure;
}
while (certList.len) {
SECItem derCert; // will hold a weak reference into certList
rv = tls13_HandleCertificateEntry(ss, &certList, first,
&derCert);
if (rv != SECSuccess) {
ss->xtnData.signedCertTimestamps.len = 0;
return SECFailure;
}
if (first) {
ss->sec.peerCert = CERT_NewTempCertificate(ss->dbHandle, &derCert,
NULL, PR_FALSE, PR_TRUE);
if (!ss->sec.peerCert) {
PRErrorCode errCode = PORT_GetError();
switch (errCode) {
case PR_OUT_OF_MEMORY_ERROR:
case SEC_ERROR_BAD_DATABASE:
case SEC_ERROR_NO_MEMORY:
FATAL_ERROR(ss, errCode, internal_error);
return SECFailure;
default:
ssl3_SendAlertForCertError(ss, errCode);
return SECFailure;
}
}
if (ss->xtnData.signedCertTimestamps.len) {
sslSessionID *sid = ss->sec.ci.sid;
rv = SECITEM_CopyItem(NULL, &sid->u.ssl3.signedCertTimestamps,
&ss->xtnData.signedCertTimestamps);
ss->xtnData.signedCertTimestamps.len = 0;
if (rv != SECSuccess) {
FATAL_ERROR(ss, SEC_ERROR_NO_MEMORY, internal_error);
return SECFailure;
}
}
} else {
ssl3CertNode *c = PORT_ArenaNew(ss->ssl3.peerCertArena,
ssl3CertNode);
if (!c) {
FATAL_ERROR(ss, SEC_ERROR_NO_MEMORY, internal_error);
return SECFailure;
}
c->derCert = SECITEM_ArenaDupItem(ss->ssl3.peerCertArena,
&derCert);
c->next = NULL;
if (lastCert) {
lastCert->next = c;
} else {
ss->ssl3.peerCertChain = c;
}
lastCert = c;
}
first = PR_FALSE;
}
SECKEY_UpdateCertPQG(ss->sec.peerCert);
return ssl3_AuthCertificate(ss); /* sets ss->ssl3.hs.ws */
}
/* Add context when signing hashes as described in
[draft-ietf-tls-tls13; Section 4.9.1] */
SECStatus
tls13_SignOrVerifyHashWithContext(sslSocket *ss, const SSL3Hashes *hashes,
SECKEYPrivateKey *privKey, SECKEYPublicKey *pubKey,
SSLSignatureScheme scheme, sslSignOrVerify direction,
SECItem *signature)
{
SECStatus rv = SECSuccess;
tlsSignOrVerifyContext ctx = { sig_verify, { NULL } };
void *pwArg = ss->pkcs11PinArg;
const unsigned char context_padding[] = {
0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20
};
const char *client_cert_verify_string = "TLS 1.3, client CertificateVerify";
const char *server_cert_verify_string = "TLS 1.3, server CertificateVerify";
const char *context_string = ((direction == sig_sign && ss->sec.isServer) ||
(direction == sig_verify && !ss->sec.isServer))
? server_cert_verify_string
: client_cert_verify_string;
/* Double check that we are doing the same hash.*/
PORT_Assert(hashes->len == tls13_GetHashSize(ss));
PRINT_BUF(50, (ss, "TLS 1.3 hash without context", hashes->u.raw, hashes->len));
PRINT_BUF(50, (ss, "Context string", context_string, strlen(context_string)));
ctx = tls_CreateSignOrVerifyContext(privKey, pubKey, scheme,
direction, signature, pwArg);
if (ctx.u.ptr == NULL) {
goto loser;
}
rv = tls_SignOrVerifyUpdate(ctx, context_padding, sizeof(context_padding));
if (rv != SECSuccess) {
goto loser;
}
rv = tls_SignOrVerifyUpdate(ctx, (const unsigned char *)context_string,
/* +1 includes the terminating 0 */
strlen(context_string) + 1);
if (rv != SECSuccess) {
goto loser;
}
rv = tls_SignOrVerifyUpdate(ctx, hashes->u.raw, hashes->len);
if (rv != SECSuccess) {
goto loser;
}
rv = tls_SignOrVerifyEnd(ctx, signature);
if (rv) {
goto loser;
}
/* if we are server & sending or !server & !sending, update the scheme */
/* only update on server cert verify */
if ((direction == sig_sign && ss->sec.isServer) ||
(direction == sig_verify && !ss->sec.isServer)) {
ss->sec.signatureScheme = scheme;
ss->sec.authType = ssl_SignatureSchemeToAuthType(scheme);
}
return SECSuccess;
loser:
tls_DestroySignOrVerifyContext(ctx);
ssl_MapLowLevelError(SSL_ERROR_SIGN_HASHES_FAILURE);
return SECFailure;
}
/*
* Derive-Secret(Secret, Label, Messages) =
* HKDF-Expand-Label(Secret, Label,
* Hash(Messages) + Hash(resumption_context), L))
*/
SECStatus
tls13_DeriveSecret(sslSocket *ss, PK11SymKey *key,
const char *label,
unsigned int labelLen,
const SSL3Hashes *hashes,
PK11SymKey **dest,
SSLHashType hash)
{
SECStatus rv;
rv = tls13_HkdfExpandLabel(key, hash, hashes->u.raw, hashes->len,
label, labelLen, CKM_HKDF_DERIVE,
tls13_GetHashSizeForHash(hash),
ss->protocolVariant, 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,
SSLHashType hash)
{
SSL3Hashes hashes;
SECStatus rv;
PRUint8 buf[] = { 0 };
rv = tls13_ComputeHash(ss, &hashes, buf, 0, hash);
if (rv != SECSuccess) {
return SECFailure;
}
return tls13_DeriveSecret(ss, key, label, labelLen, &hashes, dest, hash);
}
/* 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;
if (prefix) {
if ((strlen(prefix) + strlen(suffix) + 2) > sizeof(buf)) {
PORT_Assert(0);
PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
return SECFailure;
}
(void)PR_snprintf(buf, sizeof(buf), "%s %s",
prefix, suffix);
label = buf;
} else {
label = suffix;
}
SSL_TRC(3, ("%d: TLS13[%d]: deriving secret '%s'",
SSL_GETPID(), ss->fd, label));
rv = tls13_ComputeHandshakeHashes(ss, &hashes);
if (rv != SECSuccess) {
PORT_Assert(0); /* Should never fail */
ssl_MapLowLevelError(SEC_ERROR_LIBRARY_FAILURE);
return SECFailure;
}
rv = tls13_DeriveSecret(ss, key, label, strlen(label),
&hashes, dest, tls13_GetHash(ss));
if (rv != SECSuccess) {
return SECFailure;
}
if (keylogLabel) {
ssl3_RecordKeyLog(ss, keylogLabel, *dest);
}
return SECSuccess;
}
SECStatus
SSLExp_SecretCallback(PRFileDesc *fd, SSLSecretCallback cb, void *arg)
{
sslSocket *ss = ssl_FindSocket(fd);
if (!ss) {
SSL_DBG(("%d: SSL[%d]: bad socket in SSL_SecretCallback",
SSL_GETPID(), fd));
return SECFailure;
}
ssl_Get1stHandshakeLock(ss);
ssl_GetSSL3HandshakeLock(ss);
ss->secretCallback = cb;
ss->secretCallbackArg = arg;
ssl_ReleaseSSL3HandshakeLock(ss);
ssl_Release1stHandshakeLock(ss);
return SECSuccess;
}
/* Derive traffic keys for the next cipher spec in the queue. */
static SECStatus
tls13_DeriveTrafficKeys(sslSocket *ss, ssl3CipherSpec *spec,
TrafficKeyType type,
PRBool deleteSecret)
{
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 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";
PORT_Assert(ss->opt.noLocks || ssl_HaveSSL3HandshakeLock(ss));
clientSecret = !tls13_UseServerSecret(ss, spec->direction);
switch (type) {
case TrafficKeyEarlyApplicationData:
PORT_Assert(clientSecret);
prkp = &ss->ssl3.hs.clientEarlyTrafficSecret;
spec->phase = kHkdfPhaseEarlyApplicationDataKeys;
break;
case TrafficKeyHandshake:
prkp = clientSecret ? &ss->ssl3.hs.clientHsTrafficSecret
: &ss->ssl3.hs.serverHsTrafficSecret;
spec->phase = kHkdfPhaseHandshakeKeys;
break;
case TrafficKeyApplicationData:
prkp = clientSecret ? &ss->ssl3.hs.clientTrafficSecret
: &ss->ssl3.hs.serverTrafficSecret;
spec->phase = kHkdfPhaseApplicationDataKeys;
break;
default:
LOG_ERROR(ss, SEC_ERROR_LIBRARY_FAILURE);
PORT_Assert(0);
return SECFailure;
}
PORT_Assert(prkp != NULL);
prk = *prkp;
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,
ss->protocolVariant,
&spec->keyMaterial.key);
if (rv != SECSuccess) {
LOG_ERROR(ss, SEC_ERROR_LIBRARY_FAILURE);
PORT_Assert(0);
goto loser;
}
if (IS_DTLS(ss) && spec->epoch > 0) {
rv = ssl_CreateMaskingContextInner(spec->version, ss->ssl3.hs.cipher_suite,
ss->protocolVariant, prk, kHkdfPurposeSn,
strlen(kHkdfPurposeSn), &spec->maskContext);
if (rv != SECSuccess) {
LOG_ERROR(ss, SEC_ERROR_LIBRARY_FAILURE);
PORT_Assert(0);
goto loser;
}
}
rv = tls13_HkdfExpandLabelRaw(prk, tls13_GetHash(ss),
NULL, 0,
kHkdfPurposeIv, strlen(kHkdfPurposeIv),
ss->protocolVariant,
spec->keyMaterial.iv, ivSize);
if (rv != SECSuccess) {
LOG_ERROR(ss, SEC_ERROR_LIBRARY_FAILURE);
PORT_Assert(0);
goto loser;
}
if (deleteSecret) {
PK11_FreeSymKey(prk);
*prkp = NULL;
}
return SECSuccess;
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, ssl3CipherSpec *spec)
{
ssl3CipherSuite suite = ss->ssl3.hs.cipher_suite;
PORT_Assert(ss->opt.noLocks || ssl_HaveSSL3HandshakeLock(ss));
PORT_Assert(spec->epoch);
/* Version isn't set when we send 0-RTT data. */
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 == ssl_secret_read) {
ssl_CipherSpecAddRef(spec);
}
SSL_TRC(3, ("%d: TLS13[%d]: Set Pending Cipher Suite to 0x%04x",
SSL_GETPID(), ss->fd, suite));
spec->cipherDef = ssl_GetBulkCipherDef(ssl_LookupCipherSuiteDef(suite));
if (spec->epoch == TrafficKeyEarlyApplicationData) {
if (ss->xtnData.selectedPsk &&
ss->xtnData.selectedPsk->zeroRttSuite != TLS_NULL_WITH_NULL_NULL) {
spec->earlyDataRemaining = ss->xtnData.selectedPsk->maxEarlyData;
}
}
tls13_SetSpecRecordVersion(ss, spec);
/* The record size limit is reduced by one so that the remainder of the
* record handling code can use the same checks for all versions. */
if (ssl3_ExtensionNegotiated(ss, ssl_record_size_limit_xtn)) {
spec->recordSizeLimit = ((spec->direction == ssl_secret_read)
? ss->opt.recordSizeLimit
: ss->xtnData.recordSizeLimit) -
1;
} else {
spec->recordSizeLimit = MAX_FRAGMENT_LENGTH;
}
return SECSuccess;
}
/*
* Initialize the cipher context. All TLS 1.3 operations are AEAD,
* so they are all message contexts.
*/
static SECStatus
tls13_InitPendingContext(sslSocket *ss, ssl3CipherSpec *spec)
{
CK_MECHANISM_TYPE encMechanism;
CK_ATTRIBUTE_TYPE encMode;
SECItem iv;
SSLCipherAlgorithm calg;
calg = spec->cipherDef->calg;
encMechanism = ssl3_Alg2Mech(calg);
encMode = CKA_NSS_MESSAGE | ((spec->direction == ssl_secret_write) ? CKA_ENCRYPT : CKA_DECRYPT);
iv.data = NULL;
iv.len = 0;
/*
* build the context
*/
spec->cipherContext = PK11_CreateContextBySymKey(encMechanism, encMode,
spec->keyMaterial.key,
&iv);
if (!spec->cipherContext) {
ssl_MapLowLevelError(SSL_ERROR_SYM_KEY_CONTEXT_FAILURE);
return SECFailure;
}
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,
ssl_secret_write, PR_FALSE);
if (rv != SECSuccess) {
PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
return SECFailure;
}
return SECSuccess;
}
/* 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, PRUint16 epoch,
SSLSecretDirection direction, PRBool deleteSecret)
{
TrafficKeyType type;
SECStatus rv;
ssl3CipherSpec *spec = NULL;
ssl3CipherSpec **specp;
/* Flush out old handshake data. */
ssl_GetXmitBufLock(ss);
rv = ssl3_FlushHandshake(ss, ssl_SEND_FLAG_FORCE_INTO_BUFFER);
ssl_ReleaseXmitBufLock(ss);
if (rv != SECSuccess) {
return SECFailure;
}
/* Create the new spec. */
spec = ssl_CreateCipherSpec(ss, direction);
if (!spec) {
return SECFailure;
}
spec->epoch = epoch;
spec->nextSeqNum = 0;
if (IS_DTLS(ss)) {
dtls_InitRecvdRecords(&spec->recvdRecords);
}
/* This depends on spec having a valid direction and epoch. */
rv = tls13_SetupPendingCipherSpec(ss, spec);
if (rv != SECSuccess) {
goto loser;
}
type = (TrafficKeyType)PR_MIN(TrafficKeyApplicationData, epoch);
rv = tls13_DeriveTrafficKeys(ss, spec, type, deleteSecret);
if (rv != SECSuccess) {
goto loser;
}
rv = tls13_InitPendingContext(ss, spec);
if (rv != SECSuccess) {
goto loser;
}
/* Now that we've set almost everything up, finally cut over. */
specp = (direction == ssl_secret_read) ? &ss->ssl3.crSpec : &ss->ssl3.cwSpec;
ssl_GetSpecWriteLock(ss);
ssl_CipherSpecRelease(*specp); /* May delete old cipher. */
*specp = spec; /* Overwrite. */
ssl_ReleaseSpecWriteLock(ss);
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)));
return SECSuccess;
loser:
ssl_CipherSpecRelease(spec);
return SECFailure;
}
SECStatus
tls13_ComputeHandshakeHashes(sslSocket *ss, SSL3Hashes *hashes)
{
SECStatus rv;
PK11Context *ctx = NULL;
PRBool useEchInner;
sslBuffer *transcript;
PORT_Assert(ss->opt.noLocks || ssl_HaveSSL3HandshakeLock(ss));
if (ss->ssl3.hs.hashType == handshake_hash_unknown) {
/* Backup: if we haven't done any hashing, then hash now.
* This happens when we are doing 0-RTT on the client. */
ctx = PK11_CreateDigestContext(ssl3_HashTypeToOID(tls13_GetHash(ss)));
if (!ctx) {
ssl_MapLowLevelError(SSL_ERROR_SHA_DIGEST_FAILURE);
return SECFailure;
}
if (PK11_DigestBegin(ctx) != SECSuccess) {
ssl_MapLowLevelError(SSL_ERROR_SHA_DIGEST_FAILURE);
goto loser;
}
/* One might expect this to use ss->ssl3.hs.echAccepted,
* but with 0-RTT we don't know that yet. */
useEchInner = ss->sec.isServer ? PR_FALSE : !!ss->ssl3.hs.echHpkeCtx;
transcript = useEchInner ? &ss->ssl3.hs.echInnerMessages : &ss->ssl3.hs.messages;
PRINT_BUF(10, (ss, "Handshake hash computed over saved messages",
transcript->buf,
transcript->len));
if (PK11_DigestOp(ctx,
transcript->buf,
transcript->len) != SECSuccess) {
ssl_MapLowLevelError(SSL_ERROR_SHA_DIGEST_FAILURE);
goto loser;
}
} else {
if (ss->firstHsDone) {
ctx = PK11_CloneContext(ss->ssl3.hs.shaPostHandshake);
} else {
ctx = PK11_CloneContext(ss->ssl3.hs.sha);
}
if (!ctx) {
ssl_MapLowLevelError(SSL_ERROR_SHA_DIGEST_FAILURE);
return SECFailure;
}
}
rv = PK11_DigestFinal(ctx, hashes->u.raw,
&hashes->len,
sizeof(hashes->u.raw));
if (rv != SECSuccess) {
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);
return SECSuccess;
loser:
PK11_DestroyContext(ctx, PR_TRUE);
return SECFailure;
}
TLS13KeyShareEntry *
tls13_CopyKeyShareEntry(TLS13KeyShareEntry *o)
{
TLS13KeyShareEntry *n;
PORT_Assert(o);
n = PORT_ZNew(TLS13KeyShareEntry);
if (!n) {
return NULL;
}
if (SECSuccess != SECITEM_CopyItem(NULL, &n->key_exchange, &o->key_exchange)) {
PORT_Free(n);
return NULL;
}
n->group = o->group;
return n;
}
void
tls13_DestroyKeyShareEntry(TLS13KeyShareEntry *offer)
{
if (!offer) {
return;
}
SECITEM_ZfreeItem(&offer->key_exchange, PR_FALSE);
PORT_ZFree(offer, sizeof(*offer));
}
void
tls13_DestroyKeyShares(PRCList *list)
{
PRCList *cur_p;
/* The list must be initialized. */
PORT_Assert(PR_LIST_HEAD(list));
while (!PR_CLIST_IS_EMPTY(list)) {
cur_p = PR_LIST_TAIL(list);
PR_REMOVE_LINK(cur_p);
tls13_DestroyKeyShareEntry((TLS13KeyShareEntry *)cur_p);
}
}
void
tls13_DestroyEarlyData(PRCList *list)
{
PRCList *cur_p;
while (!PR_CLIST_IS_EMPTY(list)) {
TLS13EarlyData *msg;
cur_p = PR_LIST_TAIL(list);
msg = (TLS13EarlyData *)cur_p;
PR_REMOVE_LINK(cur_p);
SECITEM_ZfreeItem(&msg->data, PR_FALSE);
PORT_ZFree(msg, sizeof(*msg));
}
}
/* draft-ietf-tls-tls13 Section 5.2.2 specifies the following
* nonce algorithm:
*
* The length of the per-record nonce (iv_length) is set to max(8 bytes,
* N_MIN) for the AEAD algorithm (see [RFC5116] Section 4). An AEAD
* algorithm where N_MAX is less than 8 bytes MUST NOT be used with TLS.
* The per-record nonce for the AEAD construction is formed as follows:
*
* 1. The 64-bit record sequence number is padded to the left with
* zeroes to iv_length.
*
* 2. The padded sequence number is XORed with the static
* client_write_iv or server_write_iv, depending on the role.
*
* The resulting quantity (of length iv_length) is used as the per-
* record nonce.
*
* Existing suites have the same nonce size: N_MIN = N_MAX = 12 bytes
*
*/
static void
tls13_WriteNonce(const unsigned char *ivIn, unsigned int ivInLen,
const unsigned char *nonce, unsigned int nonceLen,
unsigned char *ivOut, unsigned int ivOutLen)
{
size_t i;
unsigned int offset = ivOutLen - nonceLen;
PORT_Assert(ivInLen <= ivOutLen);
PORT_Assert(nonceLen <= ivOutLen);
PORT_Memset(ivOut, 0, ivOutLen);
PORT_Memcpy(ivOut, ivIn, ivInLen);
/* XOR the last n bytes of the IV with the nonce (should be a counter). */
for (i = 0; i < nonceLen; ++i) {
ivOut[offset + i] ^= nonce[i];
}
PRINT_BUF(50, (NULL, "Nonce", ivOut, ivOutLen));
}
/* Setup the IV for AEAD encrypt. The PKCS #11 module will add the
* counter, but it doesn't know about the DTLS epic, so we add it here.
*/
unsigned int
tls13_SetupAeadIv(PRBool isDTLS, SSL3ProtocolVersion v, unsigned char *ivOut, unsigned char *ivIn,
unsigned int offset, unsigned int ivLen, DTLSEpoch epoch)
{
PORT_Memcpy(ivOut, ivIn, ivLen);
if (isDTLS && v < SSL_LIBRARY_VERSION_TLS_1_3) {
/* handle the tls 1.2 counter mode case, the epoc is copied
* instead of xored. We accomplish this by clearing ivOut
* before running xor. */
if (offset >= ivLen) {
ivOut[offset] = ivOut[offset + 1] = 0;
}
ivOut[offset] ^= (unsigned char)(epoch >> BPB) & 0xff;
ivOut[offset + 1] ^= (unsigned char)(epoch)&0xff;
offset += 2;
}
return offset;
}
/*
* Do a single AEAD for TLS. This differs from PK11_AEADOp in the following
* ways.
* 1) If context is not supplied, it treats the operation as a single shot
* and creates a context from symKey and mech.
* 2) It always assumes the tag will be at the end of the buffer
* (in on decrypt, out on encrypt) just like the old single shot.
* 3) If we aren't generating an IV, it uses tls13_WriteNonce to create the
* nonce.
* NOTE is context is supplied, symKey and mech are ignored
*/
SECStatus
tls13_AEAD(PK11Context *context, PRBool decrypt,
CK_GENERATOR_FUNCTION ivGen, unsigned int fixedbits,
const unsigned char *ivIn, unsigned char *ivOut, unsigned int ivLen,
const unsigned char *nonceIn, unsigned int nonceLen,
const unsigned char *aad, unsigned int aadLen,
unsigned char *out, unsigned int *outLen, unsigned int maxout,
unsigned int tagLen, const unsigned char *in, unsigned int inLen)
{
unsigned char *tag;
unsigned char iv[MAX_IV_LENGTH];
unsigned char tagbuf[HASH_LENGTH_MAX];
SECStatus rv;
/* must have either context or the symKey set */
if (!context) {
PORT_SetError(SEC_ERROR_INVALID_ARGS);
return SECFailure;
}
PORT_Assert(ivLen <= MAX_IV_LENGTH);
PORT_Assert(tagLen <= HASH_LENGTH_MAX);
if (!ivOut) {
ivOut = iv; /* caller doesn't need a returned, iv */
}
if (ivGen == CKG_NO_GENERATE) {
tls13_WriteNonce(ivIn, ivLen, nonceIn, nonceLen, ivOut, ivLen);
} else if (ivIn != ivOut) {
PORT_Memcpy(ivOut, ivIn, ivLen);
}
if (decrypt) {
inLen = inLen - tagLen;
tag = (unsigned char *)in + inLen;
/* tag is const on decrypt, but returned on encrypt */
} else {
/* tag is written to a separate buffer, then added to the end
* of the actual output buffer. This allows output buffer to be larger
* than the input buffer and everything still work */
tag = tagbuf;
}
rv = PK11_AEADOp(context, ivGen, fixedbits, ivOut, ivLen, aad, aadLen,
out, (int *)outLen, maxout, tag, tagLen, in, inLen);
/* on encrypt SSL always puts the tag at the end of the buffer */
if ((rv == SECSuccess) && !(decrypt)) {
unsigned int len = *outLen;
/* make sure there is still space */
if (len + tagLen > maxout) {
PORT_SetError(SEC_ERROR_OUTPUT_LEN);
return SECFailure;
}
PORT_Memcpy(out + len, tag, tagLen);
*outLen += tagLen;
}
return rv;
}
static SECStatus
tls13_HandleEncryptedExtensions(sslSocket *ss, PRUint8 *b, PRUint32 length)
{
SECStatus rv;
PRUint32 innerLength;
SECItem oldAlpn = { siBuffer, NULL, 0 };
PORT_Assert(ss->opt.noLocks || ssl_HaveRecvBufLock(ss));
PORT_Assert(ss->opt.noLocks || ssl_HaveSSL3HandshakeLock(ss));
SSL_TRC(3, ("%d: TLS13[%d]: handle encrypted extensions",
SSL_GETPID(), ss->fd));
rv = TLS13_CHECK_HS_STATE(ss, SSL_ERROR_RX_UNEXPECTED_ENCRYPTED_EXTENSIONS,
wait_encrypted_extensions);
if (rv != SECSuccess) {
return SECFailure;
}
rv = ssl3_ConsumeHandshakeNumber(ss, &innerLength, 2, &b, &length);
if (rv != SECSuccess) {
return SECFailure; /* Alert already sent. */
}
if (innerLength != length) {
FATAL_ERROR(ss, SSL_ERROR_RX_MALFORMED_ENCRYPTED_EXTENSIONS,
illegal_parameter);
return SECFailure;
}
/* If we are doing 0-RTT, then we already have an ALPN value. Stash
* it for comparison. */
if (ss->ssl3.hs.zeroRttState == ssl_0rtt_sent &&
ss->xtnData.nextProtoState == SSL_NEXT_PROTO_EARLY_VALUE) {
oldAlpn = ss->xtnData.nextProto;
ss->xtnData.nextProto.data = NULL;
ss->xtnData.nextProtoState = SSL_NEXT_PROTO_NO_SUPPORT;
}
rv = ssl3_ParseExtensions(ss, &b, &length);
if (rv != SECSuccess) {
return SECFailure; /* Error code set below */
}
/* Handle the rest of the extensions. */
rv = ssl3_HandleParsedExtensions(ss, ssl_hs_encrypted_extensions);
if (rv != SECSuccess) {
return SECFailure; /* Error code set below */
}
/* We can only get here if we offered 0-RTT. */
if (ssl3_ExtensionNegotiated(ss, ssl_tls13_early_data_xtn)) {
PORT_Assert(ss->ssl3.hs.zeroRttState == ssl_0rtt_sent);
if (!ss->xtnData.selectedPsk) {
/* Illegal to accept 0-RTT without also accepting PSK. */
FATAL_ERROR(ss, SSL_ERROR_RX_MALFORMED_ENCRYPTED_EXTENSIONS,
illegal_parameter);
}
ss->ssl3.hs.zeroRttState = ssl_0rtt_accepted;
/* Check that the server negotiated the same ALPN (if any). */
if (SECITEM_CompareItem(&oldAlpn, &ss->xtnData.nextProto)) {
SECITEM_FreeItem(&oldAlpn, PR_FALSE);
FATAL_ERROR(ss, SSL_ERROR_NEXT_PROTOCOL_DATA_INVALID,
illegal_parameter);
return SECFailure;
}
/* Check that the server negotiated the same cipher suite. */
if (ss->ssl3.hs.cipher_suite != ss->ssl3.hs.zeroRttSuite) {
FATAL_ERROR(ss, SSL_ERROR_RX_MALFORMED_ENCRYPTED_EXTENSIONS,
illegal_parameter);
return SECFailure;
}
} else if (ss->ssl3.hs.zeroRttState == ssl_0rtt_sent) {
/* Though we sent 0-RTT, the early_data extension wasn't present so the
* state is unmodified; the server must have rejected 0-RTT. */
ss->ssl3.hs.zeroRttState = ssl_0rtt_ignored;
ss->ssl3.hs.zeroRttIgnore = ssl_0rtt_ignore_trial;
} else {
PORT_Assert(ss->ssl3.hs.zeroRttState == ssl_0rtt_none ||
(ss->ssl3.hs.helloRetry &&
ss->ssl3.hs.zeroRttState == ssl_0rtt_ignored));
}
SECITEM_FreeItem(&oldAlpn, PR_FALSE);
if (ss->ssl3.hs.kea_def->authKeyType == ssl_auth_psk) {
TLS13_SET_HS_STATE(ss, wait_finished);
} else {
TLS13_SET_HS_STATE(ss, wait_cert_request);
}
/* Client is done with any PSKs */
tls13_DestroyPskList(&ss->ssl3.hs.psks);
ss->xtnData.selectedPsk = NULL;
return SECSuccess;
}
static SECStatus
tls13_SendEncryptedExtensions(sslSocket *ss)
{
sslBuffer extensions = SSL_BUFFER_EMPTY;
SECStatus rv;
SSL_TRC(3, ("%d: TLS13[%d]: send encrypted extensions handshake",
SSL_GETPID(), ss->fd));
PORT_Assert(ss->opt.noLocks || ssl_HaveSSL3HandshakeLock(ss));
PORT_Assert(ss->opt.noLocks || ssl_HaveXmitBufLock(ss));
rv = ssl_ConstructExtensions(ss, &extensions, ssl_hs_encrypted_extensions);
if (rv != SECSuccess) {
return SECFailure;
}
rv = ssl3_AppendHandshakeHeader(ss, ssl_hs_encrypted_extensions,
SSL_BUFFER_LEN(&extensions) + 2);
if (rv != SECSuccess) {
LOG_ERROR(ss, SEC_ERROR_LIBRARY_FAILURE);
goto loser;
}
rv = ssl3_AppendBufferToHandshakeVariable(ss, &extensions, 2);
if (rv != SECSuccess) {
LOG_ERROR(ss, SEC_ERROR_LIBRARY_FAILURE);
goto loser;
}
sslBuffer_Clear(&extensions);
return SECSuccess;
loser:
sslBuffer_Clear(&extensions);
return SECFailure;
}
SECStatus
tls13_SendCertificateVerify(sslSocket *ss, SECKEYPrivateKey *privKey)
{
SECStatus rv = SECFailure;
SECItem buf = { siBuffer, NULL, 0 };
unsigned int len;
SSL3Hashes hash;
PORT_Assert(ss->opt.noLocks || ssl_HaveXmitBufLock(ss));
PORT_Assert(ss->opt.noLocks || ssl_HaveSSL3HandshakeLock(ss));
SSL_TRC(3, ("%d: TLS13[%d]: send certificate_verify handshake",
SSL_GETPID(), ss->fd));
PORT_Assert(ss->ssl3.hs.hashType == handshake_hash_single);
rv = tls13_ComputeHandshakeHashes(ss, &hash);
if (rv != SECSuccess) {
return SECFailure;
}
/* We should have picked a signature scheme when we received a
* CertificateRequest, or when we picked a server certificate. */
PORT_Assert(ss->ssl3.hs.signatureScheme != ssl_sig_none);
if (ss->ssl3.hs.signatureScheme == ssl_sig_none) {
PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
return SECFailure;
}
rv = tls13_SignOrVerifyHashWithContext(ss, &hash, privKey, NULL,
ss->ssl3.hs.signatureScheme,
sig_sign, &buf);
if (rv == SECSuccess && !ss->sec.isServer) {
/* Remember the info about the slot that did the signing.
* Later, when doing an SSL restart handshake, verify this.
* These calls are mere accessors, and can't fail.
*/
PK11SlotInfo *slot;
sslSessionID *sid = ss->sec.ci.sid;
slot = PK11_GetSlotFromPrivateKey(privKey);
sid->u.ssl3.clAuthSeries = PK11_GetSlotSeries(slot);
sid->u.ssl3.clAuthSlotID = PK11_GetSlotID(slot);
sid->u.ssl3.clAuthModuleID = PK11_GetModuleID(slot);
sid->u.ssl3.clAuthValid = PR_TRUE;
PK11_FreeSlot(slot);
}
if (rv != SECSuccess) {
goto done; /* err code was set by tls13_SignOrVerifyHashWithContext */
}
len = buf.len + 2 + 2;
rv = ssl3_AppendHandshakeHeader(ss, ssl_hs_certificate_verify, len);
if (rv != SECSuccess) {
goto done; /* error code set by AppendHandshake */
}
rv = ssl3_AppendHandshakeNumber(ss, ss->ssl3.hs.signatureScheme, 2);
if (rv != SECSuccess) {
goto done; /* err set by AppendHandshakeNumber */
}
rv = ssl3_AppendHandshakeVariable(ss, buf.data, buf.len, 2);
if (rv != SECSuccess) {
goto done; /* error code set by AppendHandshake */
}
done:
/* For parity with the allocation functions, which don't use
* SECITEM_AllocItem(). */
if (buf.data)
PORT_Free(buf.data);
return rv;
}
/* Called from tls13_CompleteHandleHandshakeMessage() when it has deciphered a complete
* tls13 CertificateVerify message
* Caller must hold Handshake and RecvBuf locks.
*/
SECStatus
tls13_HandleCertificateVerify(sslSocket *ss, PRUint8 *b, PRUint32 length)
{
sslDelegatedCredential *dc = ss->xtnData.peerDelegCred;
CERTSubjectPublicKeyInfo *spki;
SECKEYPublicKey *pubKey = NULL;
SECItem signed_hash = { siBuffer, NULL, 0 };
SECStatus rv;
SSLSignatureScheme sigScheme;
SSL3Hashes hashes;
SSL_TRC(3, ("%d: TLS13[%d]: handle certificate_verify handshake",
SSL_GETPID(), ss->fd));
PORT_Assert(ss->opt.noLocks || ssl_HaveRecvBufLock(ss));
PORT_Assert(ss->opt.noLocks || ssl_HaveSSL3HandshakeLock(ss));
rv = TLS13_CHECK_HS_STATE(ss, SSL_ERROR_RX_UNEXPECTED_CERT_VERIFY,
wait_cert_verify);
if (rv != SECSuccess) {
return SECFailure;
}
rv = tls13_ComputeHandshakeHashes(ss, &hashes);
if (rv != SECSuccess) {
return SECFailure;
}
if (ss->firstHsDone) {
rv = ssl_HashPostHandshakeMessage(ss, ssl_hs_certificate_verify, b, length);
} else {
rv = ssl_HashHandshakeMessage(ss, ssl_hs_certificate_verify, b, length);
}
if (rv != SECSuccess) {
PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
return SECFailure;
}
rv = ssl_ConsumeSignatureScheme(ss, &b, &length, &sigScheme);
if (rv != SECSuccess) {
FATAL_ERROR(ss, SSL_ERROR_RX_MALFORMED_CERT_VERIFY, illegal_parameter);
return SECFailure;
}
/* Set the |spki| used to verify the handshake. When verifying with a
* delegated credential (DC), this corresponds to the DC public key;
* otherwise it correspond to the public key of the peer's end-entity
* certificate.
*/
if (tls13_IsVerifyingWithDelegatedCredential(ss)) {
/* DelegatedCredential.cred.expected_cert_verify_algorithm is expected
* to match CertificateVerify.scheme.
* DelegatedCredential.cred.expected_cert_verify_algorithm must also be
* the same as was reported in ssl3_AuthCertificate.
*/
if (sigScheme != dc->expectedCertVerifyAlg || sigScheme != ss->sec.signatureScheme) {
FATAL_ERROR(ss, SSL_ERROR_DC_CERT_VERIFY_ALG_MISMATCH, illegal_parameter);
return SECFailure;
}
/* Verify the DC has three steps: (1) use the peer's end-entity
* certificate to verify DelegatedCredential.signature, (2) check that
* the certificate has the correct key usage, and (3) check that the DC
* hasn't expired.
*/
rv = tls13_VerifyDelegatedCredential(ss, dc);
if (rv != SECSuccess) { /* Calls FATAL_ERROR() */
return SECFailure;
}
SSL_TRC(3, ("%d: TLS13[%d]: Verifying with delegated credential",
SSL_GETPID(), ss->fd));
spki = dc->spki;
} else {
spki = &ss->sec.peerCert->subjectPublicKeyInfo;
}
rv = ssl_CheckSignatureSchemeConsistency(ss, sigScheme, spki);
if (rv != SECSuccess) {
/* Error set already */
FATAL_ERROR(ss, PORT_GetError(), illegal_parameter);
return SECFailure;
}
rv = ssl3_ConsumeHandshakeVariable(ss, &signed_hash, 2, &b, &length);
if (rv != SECSuccess) {
PORT_SetError(SSL_ERROR_RX_MALFORMED_CERT_VERIFY);
return SECFailure;
}
if (length != 0) {
FATAL_ERROR(ss, SSL_ERROR_RX_MALFORMED_CERT_VERIFY, decode_error);
return SECFailure;
}
pubKey = SECKEY_ExtractPublicKey(spki);
if (pubKey == NULL) {
ssl_MapLowLevelError(SSL_ERROR_EXTRACT_PUBLIC_KEY_FAILURE);
return SECFailure;
}
rv = tls13_SignOrVerifyHashWithContext(ss, &hashes, NULL, pubKey,
sigScheme, sig_verify, &signed_hash);
if (rv != SECSuccess) {
FATAL_ERROR(ss, PORT_GetError(), decrypt_error);
goto loser;
}
/* Set the auth type and verify it is what we captured in ssl3_AuthCertificate */
if (!ss->sec.isServer) {
ss->sec.authType = ssl_SignatureSchemeToAuthType(sigScheme);
uint32_t prelimAuthKeyBits = ss->sec.authKeyBits;
rv = ssl_SetAuthKeyBits(ss, pubKey);
if (rv != SECSuccess) {
goto loser; /* Alert sent and code set. */
}
if (prelimAuthKeyBits != ss->sec.authKeyBits) {
FATAL_ERROR(ss, SSL_ERROR_DC_CERT_VERIFY_ALG_MISMATCH, illegal_parameter);
goto loser;
}
}
/* Request a client certificate now if one was requested. */
if (ss->ssl3.hs.clientCertRequested) {
PORT_Assert(!ss->sec.isServer);
rv = ssl3_BeginHandleCertificateRequest(
ss, ss->xtnData.sigSchemes, ss->xtnData.numSigSchemes,
&ss->xtnData.certReqAuthorities);
if (rv != SECSuccess) {
FATAL_ERROR(ss, SEC_ERROR_LIBRARY_FAILURE, internal_error);
goto loser;
}
}
SECKEY_DestroyPublicKey(pubKey);
TLS13_SET_HS_STATE(ss, wait_finished);
return SECSuccess;
loser:
SECKEY_DestroyPublicKey(pubKey);
return SECFailure;
}
/* Compute the PSK binder hash over:
* Client HRR prefix, if present in ss->ssl3.hs.messages or ss->ssl3.hs.echInnerMessages,
* |len| bytes of |buf| */
static SECStatus
tls13_ComputePskBinderHash(sslSocket *ss, PRUint8 *b, size_t length,
SSL3Hashes *hashes, SSLHashType hashType)
{
SECStatus rv;
PK11Context *ctx = NULL;
sslBuffer *clientResidual = NULL;
if (!ss->sec.isServer) {
/* On the server, HRR residual is already buffered. */
clientResidual = ss->ssl3.hs.echHpkeCtx ? &ss->ssl3.hs.echInnerMessages : &ss->ssl3.hs.messages;
}
PORT_Assert(ss->ssl3.hs.hashType == handshake_hash_unknown);
PORT_Assert(ss->opt.noLocks || ssl_HaveSSL3HandshakeLock(ss));
PRINT_BUF(10, (NULL, "Binder computed over ClientHello",
b, length));
ctx = PK11_CreateDigestContext(ssl3_HashTypeToOID(hashType));
if (!ctx) {
goto loser;
}
rv = PK11_DigestBegin(ctx);
if (rv != SECSuccess) {
ssl_MapLowLevelError(SSL_ERROR_SHA_DIGEST_FAILURE);
goto loser;
}
if (clientResidual && clientResidual->len) {
PRINT_BUF(10, (NULL, " with HRR prefix", clientResidual->buf,
clientResidual->len));
rv = PK11_DigestOp(ctx, clientResidual->buf, clientResidual->len);
if (rv != SECSuccess) {
ssl_MapLowLevelError(SSL_ERROR_SHA_DIGEST_FAILURE);
goto loser;
}
}
if (IS_DTLS(ss) && !ss->sec.isServer) {
/* Removing the unnecessary header fields.
* See ssl3_AppendHandshakeHeader.*/
PORT_Assert(length >= 12);
rv = PK11_DigestOp(ctx, b, 4);
if (rv != SECSuccess) {
ssl_MapLowLevelError(SSL_ERROR_SHA_DIGEST_FAILURE);
goto loser;
}
rv = PK11_DigestOp(ctx, b + 12, length - 12);
} else {
rv = PK11_DigestOp(ctx, b, length);
}
if (rv != SECSuccess) {
ssl_MapLowLevelError(SSL_ERROR_SHA_DIGEST_FAILURE);
goto loser;
}
rv = PK11_DigestFinal(ctx, hashes->u.raw, &hashes->len, sizeof(hashes->u.raw));
if (rv != SECSuccess) {
ssl_MapLowLevelError(SSL_ERROR_SHA_DIGEST_FAILURE);
goto loser;
}
PK11_DestroyContext(ctx, PR_TRUE);
PRINT_BUF(10, (NULL, "PSK Binder hash", hashes->u.raw, hashes->len));
return SECSuccess;
loser:
if (ctx) {
PK11_DestroyContext(ctx, PR_TRUE);
}
return SECFailure;
}
/* 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_WriteExtensionsWithBinder(sslSocket *ss, sslBuffer *extensions, sslBuffer *chBuf)
{
SSL3Hashes hashes;
SECStatus rv;
PORT_Assert(!PR_CLIST_IS_EMPTY(&ss->ssl3.hs.psks));
sslPsk *psk = (sslPsk *)PR_LIST_HEAD(&ss->ssl3.hs.psks);
unsigned int size = tls13_GetHashSizeForHash(psk->hash);
unsigned int prefixLen = extensions->len - size - 3;
unsigned int finishedLen;
PORT_Assert(extensions->len >= size + 3);
rv = sslBuffer_AppendNumber(chBuf, extensions->len, 2);
if (rv != SECSuccess) {
return SECFailure;
}
/* 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 = sslBuffer_Append(chBuf, extensions->buf, prefixLen);
if (rv != SECSuccess) {
return SECFailure;
}
/* Calculate the binder based on what has been written out. */
rv = tls13_ComputePskBinderHash(ss, chBuf->buf, chBuf->len, &hashes, psk->hash);
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. */