/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ /* * TLS 1.3 Protocol * * This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
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;
}
PORT_Assert(groupDef); switch (groupDef->keaType) { case ssl_kea_ecdh_hybrid: if (groupDef->name != ssl_grp_kem_xyber768d00 && groupDef->name != ssl_grp_kem_mlkem768x25519) {
PORT_SetError(SEC_ERROR_LIBRARY_FAILURE); return SECFailure;
} const sslNamedGroupDef *x25519 = ssl_LookupNamedGroup(ssl_grp_ec_curve25519);
sslEphemeralKeyPair *x25519Pair = ssl_LookupEphemeralKeyPair(ss, x25519); if (x25519Pair) {
keyPair = ssl_CopyEphemeralKeyPair(x25519Pair);
} if (!keyPair) {
rv = ssl_CreateECDHEphemeralKeyPair(ss, x25519, &keyPair); if (rv != SECSuccess) { return SECFailure;
}
}
keyPair->group = groupDef; break; case ssl_kea_ecdh: if (groupDef->name == ssl_grp_ec_curve25519) {
sslEphemeralKeyPair *hybridPair = ssl_LookupEphemeralKeyPair(ss, ssl_LookupNamedGroup(ssl_grp_kem_mlkem768x25519)); if (!hybridPair) {
hybridPair = ssl_LookupEphemeralKeyPair(ss, ssl_LookupNamedGroup(ssl_grp_kem_xyber768d00));
} if (hybridPair) { // We could use ssl_CopyEphemeralKeyPair here, but we would need to free // the KEM components. We should pull this out into a utility function when // we refactor to support multiple hybrid mechanisms.
keyPair = PORT_ZNew(sslEphemeralKeyPair); if (!keyPair) { return SECFailure;
}
PR_INIT_CLIST(&keyPair->link);
keyPair->group = groupDef;
keyPair->keys = ssl_GetKeyPairRef(hybridPair->keys);
}
} 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;
}
}
/* * 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)
{ unsignedint i;
SSL3Statistics *ssl3stats = SSL_GetStatistics();
NewSessionTicket *session_ticket = NULL;
sslSessionID *sid = ss->sec.ci.sid; unsignedint numShares = 0;
SECStatus rv;
/* 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;
}
/* 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;
}
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 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 */
}
/* Remember that we are the ones that initiated this KeyUpdate. */ if (rv == SECSuccess) {
ss->ssl3.peerRequestedKeyUpdate = PR_FALSE;
}
ssl_ReleaseSSL3HandshakeLock(ss); return rv;
}
/* 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;
}
}
/* 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, unsignedint length)
{
SECStatus rv;
PRUint32 update;
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;
}
/* 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;
}
/* 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);
/* 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;
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);
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);
staticvoid
tls13_RestoreCipherInfo(sslSocket *ss, sslSessionID *sid)
{ /* Set these to match the cached value. * TODO(ekr@rtfm.com): Make a version with the "true" values. * Bug 1256137.
*/
ss->sec.authType = sid->authType;
ss->sec.authKeyBits = sid->authKeyBits;
ss->sec.originalKeaGroup = ssl_LookupNamedGroup(sid->keaGroup);
ss->sec.signatureScheme = sid->sigScheme;
}
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;
}
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;
}
} elseif (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.
*/ staticvoid
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;
}
/* 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. */ constunsignedint e = 2;
/* 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
--> --------------------
--> maximum size reached
--> --------------------
Messung V0.5
¤ Dauer der Verarbeitung: 0.28 Sekunden
(vorverarbeitet)
¤
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.