summaryrefslogtreecommitdiffstats
path: root/security/nss/lib/ssl/ssl3con.c
diff options
context:
space:
mode:
Diffstat (limited to 'security/nss/lib/ssl/ssl3con.c')
-rw-r--r--security/nss/lib/ssl/ssl3con.c180
1 files changed, 117 insertions, 63 deletions
diff --git a/security/nss/lib/ssl/ssl3con.c b/security/nss/lib/ssl/ssl3con.c
index 61878ae99..2593bbacc 100644
--- a/security/nss/lib/ssl/ssl3con.c
+++ b/security/nss/lib/ssl/ssl3con.c
@@ -183,9 +183,9 @@ static const SSLSignatureScheme defaultSignatureSchemes[] = {
ssl_sig_ecdsa_secp384r1_sha384,
ssl_sig_ecdsa_secp521r1_sha512,
ssl_sig_ecdsa_sha1,
- ssl_sig_rsa_pss_sha256,
- ssl_sig_rsa_pss_sha384,
- ssl_sig_rsa_pss_sha512,
+ ssl_sig_rsa_pss_rsae_sha256,
+ ssl_sig_rsa_pss_rsae_sha384,
+ ssl_sig_rsa_pss_rsae_sha512,
ssl_sig_rsa_pkcs1_sha256,
ssl_sig_rsa_pkcs1_sha384,
ssl_sig_rsa_pkcs1_sha512,
@@ -852,7 +852,7 @@ ssl3_config_match_init(sslSocket *ss)
* enabled, has a certificate (as needed), has a viable key agreement method, is
* usable with the negotiated TLS version, and is otherwise usable. */
static PRBool
-config_match(const ssl3CipherSuiteCfg *suite, int policy,
+config_match(const ssl3CipherSuiteCfg *suite, PRUint8 policy,
const SSLVersionRange *vrange, const sslSocket *ss)
{
const ssl3CipherSuiteDef *cipher_def;
@@ -888,7 +888,7 @@ config_match(const ssl3CipherSuiteCfg *suite, int policy,
/* Return the number of cipher suites that are usable. */
/* called from ssl3_SendClientHello */
static unsigned int
-count_cipher_suites(sslSocket *ss, int policy)
+count_cipher_suites(sslSocket *ss, PRUint8 policy)
{
unsigned int i, count = 0;
@@ -2336,6 +2336,11 @@ ssl3_SendRecord(sslSocket *ss,
if (ss->ssl3.fatalAlertSent) {
SSL_TRC(3, ("%d: SSL3[%d] Suppress write, fatal alert already sent",
SSL_GETPID(), ss->fd));
+ if (type != content_alert) {
+ /* If we are sending an alert, then we already have an
+ * error, so don't overwrite. */
+ PORT_SetError(SSL_ERROR_HANDSHAKE_FAILED);
+ }
return SECFailure;
}
@@ -2647,9 +2652,7 @@ ssl3_HandleNoCertificate(sslSocket *ss)
(ss->opt.requireCertificate == SSL_REQUIRE_FIRST_HANDSHAKE))) {
PRFileDesc *lower;
- if (!ss->opt.noCache) {
- ss->sec.uncache(ss->sec.ci.sid);
- }
+ ssl_UncacheSessionID(ss);
SSL3_SendAlert(ss, alert_fatal, bad_certificate);
lower = ss->fd->lower;
@@ -2711,8 +2714,8 @@ SSL3_SendAlert(sslSocket *ss, SSL3AlertLevel level, SSL3AlertDescription desc)
ssl_GetSSL3HandshakeLock(ss);
}
if (level == alert_fatal) {
- if (!ss->opt.noCache && ss->sec.ci.sid) {
- ss->sec.uncache(ss->sec.ci.sid);
+ if (ss->sec.ci.sid) {
+ ssl_UncacheSessionID(ss);
}
}
@@ -2976,9 +2979,7 @@ ssl3_HandleAlert(sslSocket *ss, sslBuffer *buf)
}
}
if (level == alert_fatal) {
- if (!ss->opt.noCache) {
- ss->sec.uncache(ss->sec.ci.sid);
- }
+ ssl_UncacheSessionID(ss);
if ((ss->ssl3.hs.ws == wait_server_hello) &&
(desc == handshake_failure)) {
/* XXX This is a hack. We're assuming that any handshake failure
@@ -3962,17 +3963,20 @@ ssl_SignatureSchemeToHashType(SSLSignatureScheme scheme)
return ssl_hash_sha1;
case ssl_sig_rsa_pkcs1_sha256:
case ssl_sig_ecdsa_secp256r1_sha256:
- case ssl_sig_rsa_pss_sha256:
+ case ssl_sig_rsa_pss_rsae_sha256:
+ case ssl_sig_rsa_pss_pss_sha256:
case ssl_sig_dsa_sha256:
return ssl_hash_sha256;
case ssl_sig_rsa_pkcs1_sha384:
case ssl_sig_ecdsa_secp384r1_sha384:
- case ssl_sig_rsa_pss_sha384:
+ case ssl_sig_rsa_pss_rsae_sha384:
+ case ssl_sig_rsa_pss_pss_sha384:
case ssl_sig_dsa_sha384:
return ssl_hash_sha384;
case ssl_sig_rsa_pkcs1_sha512:
case ssl_sig_ecdsa_secp521r1_sha512:
- case ssl_sig_rsa_pss_sha512:
+ case ssl_sig_rsa_pss_rsae_sha512:
+ case ssl_sig_rsa_pss_pss_sha512:
case ssl_sig_dsa_sha512:
return ssl_hash_sha512;
case ssl_sig_rsa_pkcs1_sha1md5:
@@ -3994,9 +3998,12 @@ ssl_SignatureSchemeToKeyType(SSLSignatureScheme scheme)
case ssl_sig_rsa_pkcs1_sha384:
case ssl_sig_rsa_pkcs1_sha512:
case ssl_sig_rsa_pkcs1_sha1:
- case ssl_sig_rsa_pss_sha256:
- case ssl_sig_rsa_pss_sha384:
- case ssl_sig_rsa_pss_sha512:
+ case ssl_sig_rsa_pss_rsae_sha256:
+ case ssl_sig_rsa_pss_rsae_sha384:
+ case ssl_sig_rsa_pss_rsae_sha512:
+ case ssl_sig_rsa_pss_pss_sha256:
+ case ssl_sig_rsa_pss_pss_sha384:
+ case ssl_sig_rsa_pss_pss_sha512:
case ssl_sig_rsa_pkcs1_sha1md5:
return rsaKey;
case ssl_sig_ecdsa_secp256r1_sha256:
@@ -4131,9 +4138,9 @@ ssl_IsSupportedSignatureScheme(SSLSignatureScheme scheme)
case ssl_sig_rsa_pkcs1_sha256:
case ssl_sig_rsa_pkcs1_sha384:
case ssl_sig_rsa_pkcs1_sha512:
- case ssl_sig_rsa_pss_sha256:
- case ssl_sig_rsa_pss_sha384:
- case ssl_sig_rsa_pss_sha512:
+ case ssl_sig_rsa_pss_rsae_sha256:
+ case ssl_sig_rsa_pss_rsae_sha384:
+ case ssl_sig_rsa_pss_rsae_sha512:
case ssl_sig_ecdsa_secp256r1_sha256:
case ssl_sig_ecdsa_secp384r1_sha384:
case ssl_sig_ecdsa_secp521r1_sha512:
@@ -4145,6 +4152,9 @@ ssl_IsSupportedSignatureScheme(SSLSignatureScheme scheme)
return PR_TRUE;
case ssl_sig_rsa_pkcs1_sha1md5:
+ case ssl_sig_rsa_pss_pss_sha256:
+ case ssl_sig_rsa_pss_pss_sha384:
+ case ssl_sig_rsa_pss_pss_sha512:
case ssl_sig_none:
case ssl_sig_ed25519:
case ssl_sig_ed448:
@@ -4157,9 +4167,9 @@ PRBool
ssl_IsRsaPssSignatureScheme(SSLSignatureScheme scheme)
{
switch (scheme) {
- case ssl_sig_rsa_pss_sha256:
- case ssl_sig_rsa_pss_sha384:
- case ssl_sig_rsa_pss_sha512:
+ case ssl_sig_rsa_pss_rsae_sha256:
+ case ssl_sig_rsa_pss_rsae_sha384:
+ case ssl_sig_rsa_pss_rsae_sha512:
return PR_TRUE;
default:
@@ -4262,6 +4272,7 @@ ssl3_ComputeHandshakeHashes(sslSocket *ss,
sizeof(stackBuf), &stateLen);
if (stateBuf == NULL) {
ssl_MapLowLevelError(SSL_ERROR_DIGEST_FAILURE);
+ rv = SECFailure;
goto tls12_loser;
}
rv |= PK11_DigestFinal(h, hashes->u.raw, &hashes->len,
@@ -4273,7 +4284,6 @@ ssl3_ComputeHandshakeHashes(sslSocket *ss,
}
hashes->hashAlg = ssl3_GetSuitePrfHash(ss);
- rv = SECSuccess;
tls12_loser:
if (stateBuf) {
@@ -4305,6 +4315,7 @@ ssl3_ComputeHandshakeHashes(sslSocket *ss,
sizeof md5StackBuf, &md5StateLen);
if (md5StateBuf == NULL) {
ssl_MapLowLevelError(SSL_ERROR_MD5_DIGEST_FAILURE);
+ rv = SECFailure;
goto loser;
}
md5 = ss->ssl3.hs.md5;
@@ -4313,6 +4324,7 @@ ssl3_ComputeHandshakeHashes(sslSocket *ss,
sizeof shaStackBuf, &shaStateLen);
if (shaStateBuf == NULL) {
ssl_MapLowLevelError(SSL_ERROR_SHA_DIGEST_FAILURE);
+ rv = SECFailure;
goto loser;
}
sha = ss->ssl3.hs.sha;
@@ -4408,7 +4420,6 @@ ssl3_ComputeHandshakeHashes(sslSocket *ss,
PRINT_BUF(60, (NULL, "SHA outer: result", hashes->u.s.sha, SHA1_LENGTH));
hashes->len = MD5_LENGTH + SHA1_LENGTH;
- rv = SECSuccess;
loser:
if (md5StateBuf) {
@@ -4589,13 +4600,24 @@ ssl3_SendClientHello(sslSocket *ss, sslClientHelloType type)
}
}
- /* We ignore ss->sec.ci.sid here, and use ssl_Lookup because Lookup
- * handles expired entries and other details.
- * XXX If we've been called from ssl_BeginClientHandshake, then
- * this lookup is duplicative and wasteful.
- */
- sid = (ss->opt.noCache) ? NULL
- : ssl_LookupSID(&ss->sec.ci.peer, ss->sec.ci.port, ss->peerID, ss->url);
+ /* Check if we have a ss->sec.ci.sid.
+ * Check that it's not expired.
+ * If we have an sid and it comes from an external cache, we use it. */
+ if (ss->sec.ci.sid && ss->sec.ci.sid->cached == in_external_cache) {
+ PORT_Assert(!ss->sec.isServer);
+ sid = ss->sec.ci.sid;
+ SSL_TRC(3, ("%d: SSL3[%d]: using external resumption token in ClientHello",
+ SSL_GETPID(), ss->fd));
+ } else if (!ss->opt.noCache) {
+ /* We ignore ss->sec.ci.sid here, and use ssl_Lookup because Lookup
+ * handles expired entries and other details.
+ * XXX If we've been called from ssl_BeginClientHandshake, then
+ * this lookup is duplicative and wasteful.
+ */
+ sid = ssl_LookupSID(&ss->sec.ci.peer, ss->sec.ci.port, ss->peerID, ss->url);
+ } else {
+ sid = NULL;
+ }
/* We can't resume based on a different token. If the sid exists,
* make sure the token that holds the master secret still exists ...
@@ -4686,7 +4708,7 @@ ssl3_SendClientHello(sslSocket *ss, sslClientHelloType type)
if (!sidOK) {
SSL_AtomicIncrementLong(&ssl3stats.sch_sid_cache_not_ok);
- ss->sec.uncache(sid);
+ ssl_UncacheSessionID(ss);
ssl_FreeSID(sid);
sid = NULL;
}
@@ -5017,7 +5039,7 @@ ssl3_HandleHelloRequest(sslSocket *ss)
}
if (sid) {
- ss->sec.uncache(sid);
+ ssl_UncacheSessionID(ss);
ssl_FreeSID(sid);
ss->sec.ci.sid = NULL;
}
@@ -6130,6 +6152,48 @@ ssl_ClientSetCipherSuite(sslSocket *ss, SSL3ProtocolVersion version,
return ssl3_SetupCipherSuite(ss, initHashes);
}
+/* Check that session ID we received from the server, if any, matches our
+ * expectations, depending on whether we're in compat mode and whether we
+ * negotiated TLS 1.3+ or TLS 1.2-.
+ */
+static PRBool
+ssl_CheckServerSessionIdCorrectness(sslSocket *ss, SECItem *sidBytes)
+{
+ sslSessionID *sid = ss->sec.ci.sid;
+ PRBool sidMatch = PR_FALSE;
+ PRBool sentFakeSid = PR_FALSE;
+ PRBool sentRealSid = sid && sid->version < SSL_LIBRARY_VERSION_TLS_1_3;
+
+ /* If attempting to resume a TLS 1.2 connection, the session ID won't be a
+ * fake. Check for the real value. */
+ if (sentRealSid) {
+ sidMatch = (sidBytes->len == sid->u.ssl3.sessionIDLength) &&
+ PORT_Memcmp(sid->u.ssl3.sessionID, sidBytes->data, sidBytes->len) == 0;
+ } else {
+ /* Otherwise, the session ID was a fake if TLS 1.3 compat mode is
+ * enabled. If so, check for the fake value. */
+ sentFakeSid = ss->opt.enableTls13CompatMode && !IS_DTLS(ss);
+ if (sentFakeSid && sidBytes->len == SSL3_SESSIONID_BYTES) {
+ PRUint8 buf[SSL3_SESSIONID_BYTES];
+ ssl_MakeFakeSid(ss, buf);
+ sidMatch = PORT_Memcmp(buf, sidBytes->data, sidBytes->len) == 0;
+ }
+ }
+
+ /* TLS 1.2: Session ID shouldn't match if we sent a fake. */
+ if (ss->version < SSL_LIBRARY_VERSION_TLS_1_3) {
+ return !sentFakeSid || !sidMatch;
+ }
+
+ /* TLS 1.3: We sent a session ID. The server's should match. */
+ if (sentRealSid || sentFakeSid) {
+ return sidMatch;
+ }
+
+ /* TLS 1.3: The server shouldn't send a session ID. */
+ return sidBytes->len == 0;
+}
+
/* Called from ssl3_HandleHandshakeMessage() when it has deciphered a complete
* ssl3 ServerHello message.
* Caller must hold Handshake and RecvBuf locks.
@@ -6337,22 +6401,10 @@ ssl3_HandleServerHello(sslSocket *ss, PRUint8 *b, PRUint32 length)
}
/* Check that the session ID is as expected. */
- if (ss->version >= SSL_LIBRARY_VERSION_TLS_1_3) {
- PRUint8 buf[SSL3_SESSIONID_BYTES];
- unsigned int expectedSidLen;
- if (ss->opt.enableTls13CompatMode && !IS_DTLS(ss)) {
- expectedSidLen = SSL3_SESSIONID_BYTES;
- ssl_MakeFakeSid(ss, buf);
- } else {
- expectedSidLen = 0;
- }
- if (sidBytes.len != expectedSidLen ||
- (expectedSidLen > 0 &&
- PORT_Memcmp(buf, sidBytes.data, expectedSidLen) != 0)) {
- desc = illegal_parameter;
- errCode = SSL_ERROR_RX_MALFORMED_SERVER_HELLO;
- goto alert_loser;
- }
+ if (!ssl_CheckServerSessionIdCorrectness(ss, &sidBytes)) {
+ desc = illegal_parameter;
+ errCode = SSL_ERROR_RX_MALFORMED_SERVER_HELLO;
+ goto alert_loser;
}
/* Only initialize hashes if this isn't a Hello Retry. */
@@ -6592,7 +6644,7 @@ ssl3_HandleServerHelloPart2(sslSocket *ss, const SECItem *sidBytes,
/* throw the old one away */
sid->u.ssl3.keys.resumable = PR_FALSE;
- ss->sec.uncache(sid);
+ ssl_UncacheSessionID(ss);
ssl_FreeSID(sid);
/* get a new sid */
@@ -7502,8 +7554,6 @@ ssl3_NewSessionID(sslSocket *ss, PRBool is_server)
sid->u.ssl3.keys.resumable = PR_TRUE;
sid->u.ssl3.policy = SSL_ALLOWED;
- sid->u.ssl3.clientWriteKey = NULL;
- sid->u.ssl3.serverWriteKey = NULL;
sid->u.ssl3.keys.extendedMasterSecretUsed = PR_FALSE;
if (is_server) {
@@ -8102,6 +8152,9 @@ ssl3_HandleClientHello(sslSocket *ss, PRUint8 *b, PRUint32 length)
rv = ssl3_HandleParsedExtensions(ss, ssl_hs_client_hello);
ssl3_DestroyRemoteExtensions(&ss->ssl3.hs.remoteExtensions);
if (rv != SECSuccess) {
+ if (PORT_GetError() == SSL_ERROR_UNSUPPORTED_SIGNATURE_ALGORITHM) {
+ errCode = SSL_ERROR_UNSUPPORTED_SIGNATURE_ALGORITHM;
+ }
goto loser; /* malformed */
}
@@ -8229,7 +8282,7 @@ ssl3_HandleClientHello(sslSocket *ss, PRUint8 *b, PRUint32 length)
!ss->firstHsDone))) {
SSL_AtomicIncrementLong(&ssl3stats.hch_sid_cache_not_ok);
- ss->sec.uncache(sid);
+ ssl_UncacheSessionID(ss);
ssl_FreeSID(sid);
sid = NULL;
}
@@ -8435,7 +8488,7 @@ cipher_found:
}
if (ss->sec.ci.sid) {
- ss->sec.uncache(ss->sec.ci.sid);
+ ssl_UncacheSessionID(ss);
PORT_Assert(ss->sec.ci.sid != sid); /* should be impossible, but ... */
if (ss->sec.ci.sid != sid) {
ssl_FreeSID(ss->sec.ci.sid);
@@ -8531,7 +8584,7 @@ cipher_found:
if (sid) { /* we had a sid, but it's no longer valid, free it */
ss->statelessResume = PR_FALSE;
SSL_AtomicIncrementLong(&ssl3stats.hch_sid_cache_not_ok);
- ss->sec.uncache(sid);
+ ssl_UncacheSessionID(ss);
ssl_FreeSID(sid);
sid = NULL;
}
@@ -8597,7 +8650,7 @@ alert_loser:
/* FALLTHRU */
loser:
if (sid && sid != ss->sec.ci.sid) {
- ss->sec.uncache(sid);
+ ssl_UncacheSessionID(ss);
ssl_FreeSID(sid);
}
@@ -11137,6 +11190,7 @@ ssl3_FillInCachedSID(sslSocket *ss, sslSessionID *sid, PK11SymKey *secret)
if (ss->xtnData.nextProtoState != SSL_NEXT_PROTO_NO_SUPPORT &&
ss->xtnData.nextProto.data) {
+ SECITEM_FreeItem(&sid->u.ssl3.alpnSelection, PR_FALSE);
if (SECITEM_CopyItem(
NULL, &sid->u.ssl3.alpnSelection, &ss->xtnData.nextProto) != SECSuccess) {
return SECFailure; /* error already set. */
@@ -11166,7 +11220,7 @@ ssl3_FinishHandshake(sslSocket *ss)
* the handshake is finished (we have verified the server's Finished
* AND the server's certificate) before we update the ticket in the sid.
*
- * This must be done before we call ss->sec.cache(ss->sec.ci.sid)
+ * This must be done before we call ssl_CacheSessionID(ss)
* because CacheSID requires the session ticket to already be set, and also
* because of the lazy lock creation scheme used by CacheSID and
* ssl3_SetSIDSessionTicket.
@@ -11181,7 +11235,7 @@ ssl3_FinishHandshake(sslSocket *ss)
if (ss->ssl3.hs.cacheSID) {
PORT_Assert(ss->sec.ci.sid->cached == never_cached);
- ss->sec.cache(ss->sec.ci.sid);
+ ssl_CacheSessionID(ss);
ss->ssl3.hs.cacheSID = PR_FALSE;
}
@@ -12645,8 +12699,8 @@ ssl3_RedoHandshake(sslSocket *ss, PRBool flushCache)
}
if (sid && flushCache) {
- ss->sec.uncache(sid); /* remove it from whichever cache it's in. */
- ssl_FreeSID(sid); /* dec ref count and free if zero. */
+ ssl_UncacheSessionID(ss); /* remove it from whichever cache it's in. */
+ ssl_FreeSID(sid); /* dec ref count and free if zero. */
ss->sec.ci.sid = NULL;
}