summaryrefslogtreecommitdiffstats
path: root/security/nss/lib/ssl
diff options
context:
space:
mode:
authorMoonchild <mcwerewolf@gmail.com>2018-06-12 00:58:35 +0200
committerGitHub <noreply@github.com>2018-06-12 00:58:35 +0200
commitb0f5f9bc6bb3c8b5ab7b5120dbf7ec48f8445387 (patch)
tree40d946c5ff23b3c0c09558f478cc68e87cc71448 /security/nss/lib/ssl
parentb1d82a62259c6888ea6f3f71f3e0973ea4b4e85e (diff)
parent505a561549b5226fd3c7905eaa61fe787dfad243 (diff)
downloadUXP-b0f5f9bc6bb3c8b5ab7b5120dbf7ec48f8445387.tar
UXP-b0f5f9bc6bb3c8b5ab7b5120dbf7ec48f8445387.tar.gz
UXP-b0f5f9bc6bb3c8b5ab7b5120dbf7ec48f8445387.tar.lz
UXP-b0f5f9bc6bb3c8b5ab7b5120dbf7ec48f8445387.tar.xz
UXP-b0f5f9bc6bb3c8b5ab7b5120dbf7ec48f8445387.zip
Merge pull request #477 from JustOff/PR_nss-3.36
Update NSS/NSPR to 3.36.4/4.19
Diffstat (limited to 'security/nss/lib/ssl')
-rw-r--r--security/nss/lib/ssl/SSLerrs.h3
-rw-r--r--security/nss/lib/ssl/selfencrypt.c44
-rw-r--r--security/nss/lib/ssl/ssl3con.c180
-rw-r--r--security/nss/lib/ssl/ssl3encode.c85
-rw-r--r--security/nss/lib/ssl/ssl3encode.h26
-rw-r--r--security/nss/lib/ssl/ssl3ext.c2
-rw-r--r--security/nss/lib/ssl/ssl3exthandle.c14
-rw-r--r--security/nss/lib/ssl/ssl3gthr.c7
-rw-r--r--security/nss/lib/ssl/sslcon.c17
-rw-r--r--security/nss/lib/ssl/sslencode.c64
-rw-r--r--security/nss/lib/ssl/sslencode.h30
-rw-r--r--security/nss/lib/ssl/sslerr.h2
-rw-r--r--security/nss/lib/ssl/sslexp.h107
-rw-r--r--security/nss/lib/ssl/sslimpl.h63
-rw-r--r--security/nss/lib/ssl/sslinit.c1
-rw-r--r--security/nss/lib/ssl/sslnonce.c756
-rw-r--r--security/nss/lib/ssl/sslsecur.c5
-rw-r--r--security/nss/lib/ssl/sslsnce.c20
-rw-r--r--security/nss/lib/ssl/sslsock.c231
-rw-r--r--security/nss/lib/ssl/sslt.h24
-rw-r--r--security/nss/lib/ssl/tls13con.c30
-rw-r--r--security/nss/lib/ssl/tls13hashstate.c34
22 files changed, 1377 insertions, 368 deletions
diff --git a/security/nss/lib/ssl/SSLerrs.h b/security/nss/lib/ssl/SSLerrs.h
index c95fe661a..d3f087544 100644
--- a/security/nss/lib/ssl/SSLerrs.h
+++ b/security/nss/lib/ssl/SSLerrs.h
@@ -540,3 +540,6 @@ ER3(SSL_ERROR_RX_MALFORMED_KEY_UPDATE, (SSL_ERROR_BASE + 170),
ER3(SSL_ERROR_TOO_MANY_KEY_UPDATES, (SSL_ERROR_BASE + 171),
"SSL attempted too many key updates.")
+
+ER3(SSL_ERROR_HANDSHAKE_FAILED, (SSL_ERROR_BASE + 172),
+ "SSL handshake has already failed. No more operations possible.")
diff --git a/security/nss/lib/ssl/selfencrypt.c b/security/nss/lib/ssl/selfencrypt.c
index 97217b4a6..1c70f7635 100644
--- a/security/nss/lib/ssl/selfencrypt.c
+++ b/security/nss/lib/ssl/selfencrypt.c
@@ -192,75 +192,71 @@ ssl_SelfEncryptUnprotectInt(
const PRUint8 *in, unsigned int inLen,
PRUint8 *out, unsigned int *outLen, unsigned int maxOutLen)
{
- unsigned char *encodedKeyName;
- unsigned char *iv;
- SECItem ivItem = { siBuffer, NULL, 0 };
- SECItem inItem = { siBuffer, (unsigned char *)in, inLen };
- unsigned char *cipherText;
- PRUint32 cipherTextLen;
- unsigned char *encodedMac;
- unsigned char computedMac[SHA256_LENGTH];
- unsigned int computedMacLen;
- unsigned int bytesToMac;
- SECStatus rv;
+ sslReader reader = SSL_READER(in, inLen);
- rv = ssl3_ConsumeFromItem(&inItem, &encodedKeyName,
- SELF_ENCRYPT_KEY_NAME_LEN);
+ sslReadBuffer encodedKeyNameBuffer = { 0 };
+ SECStatus rv = sslRead_Read(&reader, SELF_ENCRYPT_KEY_NAME_LEN,
+ &encodedKeyNameBuffer);
if (rv != SECSuccess) {
return SECFailure;
}
- rv = ssl3_ConsumeFromItem(&inItem, &iv, AES_BLOCK_SIZE);
+ sslReadBuffer ivBuffer = { 0 };
+ rv = sslRead_Read(&reader, AES_BLOCK_SIZE, &ivBuffer);
if (rv != SECSuccess) {
return SECFailure;
}
- rv = ssl3_ConsumeNumberFromItem(&inItem, &cipherTextLen, 2);
+ PRUint64 cipherTextLen = 0;
+ rv = sslRead_ReadNumber(&reader, 2, &cipherTextLen);
if (rv != SECSuccess) {
return SECFailure;
}
- rv = ssl3_ConsumeFromItem(&inItem, &cipherText, cipherTextLen);
+ sslReadBuffer cipherTextBuffer = { 0 };
+ rv = sslRead_Read(&reader, (unsigned int)cipherTextLen, &cipherTextBuffer);
if (rv != SECSuccess) {
return SECFailure;
}
- bytesToMac = inItem.data - in;
+ unsigned int bytesToMac = reader.offset;
- rv = ssl3_ConsumeFromItem(&inItem, &encodedMac, SHA256_LENGTH);
+ sslReadBuffer encodedMacBuffer = { 0 };
+ rv = sslRead_Read(&reader, SHA256_LENGTH, &encodedMacBuffer);
if (rv != SECSuccess) {
return SECFailure;
}
/* Make sure we're at the end of the block. */
- if (inItem.len) {
+ if (reader.offset != reader.buf.len) {
PORT_SetError(SEC_ERROR_BAD_DATA);
return SECFailure;
}
/* Now that everything is decoded, we can make progress. */
/* 1. Check that we have the right key. */
- if (PORT_Memcmp(keyName, encodedKeyName, SELF_ENCRYPT_KEY_NAME_LEN)) {
+ if (PORT_Memcmp(keyName, encodedKeyNameBuffer.buf, SELF_ENCRYPT_KEY_NAME_LEN)) {
PORT_SetError(SEC_ERROR_NOT_A_RECIPIENT);
return SECFailure;
}
/* 2. Check the MAC */
+ unsigned char computedMac[SHA256_LENGTH];
+ unsigned int computedMacLen = 0;
rv = ssl_MacBuffer(macKey, CKM_SHA256_HMAC, in, bytesToMac,
computedMac, &computedMacLen, sizeof(computedMac));
if (rv != SECSuccess) {
return SECFailure;
}
PORT_Assert(computedMacLen == SHA256_LENGTH);
- if (NSS_SecureMemcmp(computedMac, encodedMac, computedMacLen) != 0) {
+ if (NSS_SecureMemcmp(computedMac, encodedMacBuffer.buf, computedMacLen) != 0) {
PORT_SetError(SEC_ERROR_BAD_DATA);
return SECFailure;
}
/* 3. OK, it verifies, now decrypt. */
- ivItem.data = iv;
- ivItem.len = AES_BLOCK_SIZE;
+ SECItem ivItem = { siBuffer, (unsigned char *)ivBuffer.buf, AES_BLOCK_SIZE };
rv = PK11_Decrypt(encKey, CKM_AES_CBC_PAD, &ivItem,
- out, outLen, maxOutLen, cipherText, cipherTextLen);
+ out, outLen, maxOutLen, cipherTextBuffer.buf, cipherTextLen);
if (rv != SECSuccess) {
return SECFailure;
}
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;
}
diff --git a/security/nss/lib/ssl/ssl3encode.c b/security/nss/lib/ssl/ssl3encode.c
deleted file mode 100644
index 960208a0f..000000000
--- a/security/nss/lib/ssl/ssl3encode.c
+++ /dev/null
@@ -1,85 +0,0 @@
-/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
-/*
- * This file is PRIVATE to SSL.
- *
- * This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this
- * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
-
-#include "prnetdb.h"
-#include "seccomon.h"
-#include "secerr.h"
-#include "ssl3encode.h"
-
-SECStatus
-ssl3_AppendToItem(SECItem *item, const unsigned char *buf, PRUint32 bytes)
-{
- if (bytes > item->len) {
- PORT_SetError(SEC_ERROR_INVALID_ARGS);
- return SECFailure;
- }
-
- PORT_Memcpy(item->data, buf, bytes);
- item->data += bytes;
- item->len -= bytes;
- return SECSuccess;
-}
-
-SECStatus
-ssl3_AppendNumberToItem(SECItem *item, PRUint32 num, PRInt32 lenSize)
-{
- SECStatus rv;
- PRUint8 b[4];
-
- ssl_EncodeUintX(num, lenSize, b);
- rv = ssl3_AppendToItem(item, &b[0], lenSize);
- return rv;
-}
-
-SECStatus
-ssl3_ConsumeFromItem(SECItem *item, unsigned char **buf, PRUint32 bytes)
-{
- if (bytes > item->len) {
- PORT_SetError(SEC_ERROR_BAD_DATA);
- return SECFailure;
- }
-
- *buf = item->data;
- item->data += bytes;
- item->len -= bytes;
- return SECSuccess;
-}
-
-SECStatus
-ssl3_ConsumeNumberFromItem(SECItem *item, PRUint32 *num, PRUint32 bytes)
-{
- int i;
-
- if (bytes > item->len || bytes > sizeof(*num)) {
- PORT_SetError(SEC_ERROR_BAD_DATA);
- return SECFailure;
- }
-
- *num = 0;
- for (i = 0; i < bytes; i++) {
- *num = (*num << 8) + item->data[i];
- }
-
- item->data += bytes;
- item->len -= bytes;
-
- return SECSuccess;
-}
-
-/* Helper function to encode an unsigned integer into a buffer. */
-PRUint8 *
-ssl_EncodeUintX(PRUint64 value, unsigned int bytes, PRUint8 *to)
-{
- PRUint64 encoded;
-
- PORT_Assert(bytes > 0 && bytes <= sizeof(encoded));
-
- encoded = PR_htonll(value);
- memcpy(to, ((unsigned char *)(&encoded)) + (sizeof(encoded) - bytes), bytes);
- return to + bytes;
-}
diff --git a/security/nss/lib/ssl/ssl3encode.h b/security/nss/lib/ssl/ssl3encode.h
deleted file mode 100644
index 3b88f7e7b..000000000
--- a/security/nss/lib/ssl/ssl3encode.h
+++ /dev/null
@@ -1,26 +0,0 @@
-/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
-/*
- * This file is PRIVATE to SSL.
- *
- * 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/. */
-
-#ifndef __ssl3encode_h_
-#define __ssl3encode_h_
-
-#include "seccomon.h"
-
-/* All of these functions modify the underlying SECItem, and so should
- * be performed on a shallow copy.*/
-SECStatus ssl3_AppendToItem(SECItem *item,
- const unsigned char *buf, PRUint32 bytes);
-SECStatus ssl3_AppendNumberToItem(SECItem *item,
- PRUint32 num, PRInt32 lenSize);
-SECStatus ssl3_ConsumeFromItem(SECItem *item,
- unsigned char **buf, PRUint32 bytes);
-SECStatus ssl3_ConsumeNumberFromItem(SECItem *item,
- PRUint32 *num, PRUint32 bytes);
-PRUint8 *ssl_EncodeUintX(PRUint64 value, unsigned int bytes, PRUint8 *to);
-
-#endif
diff --git a/security/nss/lib/ssl/ssl3ext.c b/security/nss/lib/ssl/ssl3ext.c
index ade280903..5a5077998 100644
--- a/security/nss/lib/ssl/ssl3ext.c
+++ b/security/nss/lib/ssl/ssl3ext.c
@@ -519,6 +519,8 @@ ssl3_HandleParsedExtensions(sslSocket *ss, SSLHandshakeType message)
}
/* Fall through. */
case tls13_extension_disallowed:
+ SSL_TRC(3, ("%d: TLS13: unexpected extension %d in message %d",
+ SSL_GETPID(), extension, message));
tls13_FatalError(ss, SSL_ERROR_EXTENSION_DISALLOWED_FOR_VERSION,
unsupported_extension);
return SECFailure;
diff --git a/security/nss/lib/ssl/ssl3exthandle.c b/security/nss/lib/ssl/ssl3exthandle.c
index c0fbda7ab..e6388945e 100644
--- a/security/nss/lib/ssl/ssl3exthandle.c
+++ b/security/nss/lib/ssl/ssl3exthandle.c
@@ -182,7 +182,7 @@ ssl3_ClientSendSessionTicketXtn(const sslSocket *ss, TLSExtensionData *xtnData,
/* Never send an extension with a ticket for TLS 1.3, but
* OK to send the empty one in case the server does 1.2. */
- if (sid->cached == in_client_cache &&
+ if ((sid->cached == in_client_cache || sid->cached == in_external_cache) &&
sid->version >= SSL_LIBRARY_VERSION_TLS_1_3) {
return SECSuccess;
}
@@ -821,7 +821,7 @@ ssl3_EncodeSessionTicket(sslSocket *ss, const NewSessionTicket *ticket,
if (rv != SECSuccess)
goto loser;
- rv = sslBuffer_AppendNumber(&plaintext, ssl_max_early_data_size, 4);
+ rv = sslBuffer_AppendNumber(&plaintext, ss->opt.maxEarlyDataSize, 4);
if (rv != SECSuccess)
goto loser;
@@ -1219,6 +1219,7 @@ ssl_CreateSIDFromTicket(sslSocket *ss, const SECItem *rawTicket,
}
}
if (parsedTicket->alpnSelection.data != NULL) {
+ SECITEM_FreeItem(&sid->u.ssl3.alpnSelection, PR_FALSE);
rv = SECITEM_CopyItem(NULL, &sid->u.ssl3.alpnSelection,
&parsedTicket->alpnSelection);
if (rv != SECSuccess) {
@@ -1245,7 +1246,7 @@ ssl3_ProcessSessionTicketCommon(sslSocket *ss, const SECItem *ticket,
SECStatus rv;
if (ss->sec.ci.sid != NULL) {
- ss->sec.uncache(ss->sec.ci.sid);
+ ssl_UncacheSessionID(ss);
ssl_FreeSID(ss->sec.ci.sid);
ss->sec.ci.sid = NULL;
}
@@ -1652,11 +1653,16 @@ ssl3_HandleSigAlgsXtn(const sslSocket *ss, TLSExtensionData *xtnData,
&xtnData->sigSchemes,
&xtnData->numSigSchemes,
&data->data, &data->len);
- if (rv != SECSuccess || xtnData->numSigSchemes == 0) {
+ if (rv != SECSuccess) {
ssl3_ExtSendAlert(ss, alert_fatal, decode_error);
PORT_SetError(SSL_ERROR_RX_MALFORMED_CLIENT_HELLO);
return SECFailure;
}
+ if (xtnData->numSigSchemes == 0) {
+ ssl3_ExtSendAlert(ss, alert_fatal, handshake_failure);
+ PORT_SetError(SSL_ERROR_UNSUPPORTED_SIGNATURE_ALGORITHM);
+ return SECFailure;
+ }
/* Check for trailing data. */
if (data->len != 0) {
ssl3_ExtSendAlert(ss, alert_fatal, decode_error);
diff --git a/security/nss/lib/ssl/ssl3gthr.c b/security/nss/lib/ssl/ssl3gthr.c
index 20404f4da..8b323bb05 100644
--- a/security/nss/lib/ssl/ssl3gthr.c
+++ b/security/nss/lib/ssl/ssl3gthr.c
@@ -386,6 +386,13 @@ ssl3_GatherCompleteHandshake(sslSocket *ss, int flags)
SSL3Ciphertext cText;
PRBool keepGoing = PR_TRUE;
+ if (ss->ssl3.fatalAlertSent) {
+ SSL_TRC(3, ("%d: SSL3[%d] Cannot gather data; fatal alert already sent",
+ SSL_GETPID(), ss->fd));
+ PORT_SetError(SSL_ERROR_HANDSHAKE_FAILED);
+ return SECFailure;
+ }
+
SSL_TRC(30, ("%d: SSL3[%d]: ssl3_GatherCompleteHandshake",
SSL_GETPID(), ss->fd));
diff --git a/security/nss/lib/ssl/sslcon.c b/security/nss/lib/ssl/sslcon.c
index 448170640..bc63e1537 100644
--- a/security/nss/lib/ssl/sslcon.c
+++ b/security/nss/lib/ssl/sslcon.c
@@ -119,13 +119,12 @@ ssl_CheckConfigSanity(sslSocket *ss)
SECStatus
ssl_BeginClientHandshake(sslSocket *ss)
{
- sslSessionID *sid;
+ sslSessionID *sid = NULL;
SECStatus rv;
PORT_Assert(ss->opt.noLocks || ssl_Have1stHandshakeLock(ss));
ss->sec.isServer = PR_FALSE;
- ssl_ChooseSessionIDProcs(&ss->sec);
rv = ssl_CheckConfigSanity(ss);
if (rv != SECSuccess)
@@ -156,19 +155,22 @@ ssl_BeginClientHandshake(sslSocket *ss)
SSL_TRC(3, ("%d: SSL[%d]: sending client-hello", SSL_GETPID(), ss->fd));
- /* Try to find server in our session-id cache */
- if (ss->opt.noCache) {
- sid = NULL;
- } else {
+ /* If there's an sid set from an external cache, use it. */
+ if (ss->sec.ci.sid && ss->sec.ci.sid->cached == in_external_cache) {
+ sid = ss->sec.ci.sid;
+ SSL_TRC(3, ("%d: SSL[%d]: using external token", SSL_GETPID(), ss->fd));
+ } else if (!ss->opt.noCache) {
+ /* Try to find server in our session-id cache */
sid = ssl_LookupSID(&ss->sec.ci.peer, ss->sec.ci.port, ss->peerID,
ss->url);
}
+
if (sid) {
if (sid->version >= ss->vrange.min && sid->version <= ss->vrange.max) {
PORT_Assert(!ss->sec.localCert);
ss->sec.localCert = CERT_DupCertificate(sid->localCert);
} else {
- ss->sec.uncache(sid);
+ ssl_UncacheSessionID(ss);
ssl_FreeSID(sid);
sid = NULL;
}
@@ -218,7 +220,6 @@ ssl_BeginServerHandshake(sslSocket *ss)
ss->sec.isServer = PR_TRUE;
ss->ssl3.hs.ws = wait_client_hello;
- ssl_ChooseSessionIDProcs(&ss->sec);
rv = ssl_CheckConfigSanity(ss);
if (rv != SECSuccess)
diff --git a/security/nss/lib/ssl/sslencode.c b/security/nss/lib/ssl/sslencode.c
index 2f127fe8f..e50880451 100644
--- a/security/nss/lib/ssl/sslencode.c
+++ b/security/nss/lib/ssl/sslencode.c
@@ -29,6 +29,7 @@ ssl_EncodeUintX(PRUint8 *to, PRUint64 value, unsigned int bytes)
SECStatus
sslBuffer_Grow(sslBuffer *b, unsigned int newLen)
{
+ PORT_Assert(b);
if (b->fixed) {
PORT_Assert(newLen <= b->space);
if (newLen > b->space) {
@@ -84,6 +85,7 @@ sslBuffer_AppendVariable(sslBuffer *b, const PRUint8 *data, unsigned int len,
unsigned int size)
{
PORT_Assert(size <= 4 && size > 0);
+ PORT_Assert(b);
if (len >= (1ULL << (8 * size))) {
PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
return SECFailure;
@@ -95,7 +97,11 @@ sslBuffer_AppendVariable(sslBuffer *b, const PRUint8 *data, unsigned int len,
ssl_EncodeUintX(SSL_BUFFER_NEXT(b), len, size);
b->len += size;
- PORT_Memcpy(SSL_BUFFER_NEXT(b), data, len);
+ if (len != 0) {
+ PORT_Assert(data);
+ /* We sometimes pass NULL, 0 and memcpy() doesn't want NULL. */
+ PORT_Memcpy(SSL_BUFFER_NEXT(b), data, len);
+ }
b->len += len;
return SECSuccess;
}
@@ -169,37 +175,63 @@ sslBuffer_Clear(sslBuffer *b)
}
SECStatus
-ssl3_ConsumeFromItem(SECItem *item, unsigned char **buf, unsigned int size)
+sslRead_Read(sslReader *reader, unsigned int count, sslReadBuffer *out)
{
- if (size > item->len) {
+ if (!reader || !out) {
+ PORT_SetError(SEC_ERROR_INVALID_ARGS);
+ return SECFailure;
+ }
+ if (reader->buf.len < reader->offset ||
+ count > SSL_READER_REMAINING(reader)) {
PORT_SetError(SEC_ERROR_BAD_DATA);
return SECFailure;
}
- *buf = item->data;
- item->data += size;
- item->len -= size;
+ out->buf = SSL_READER_CURRENT(reader);
+ out->len = count;
+ reader->offset += count;
+
return SECSuccess;
}
SECStatus
-ssl3_ConsumeNumberFromItem(SECItem *item, PRUint32 *num, unsigned int size)
+sslRead_ReadVariable(sslReader *reader, unsigned int sizeLen, sslReadBuffer *out)
{
- int i;
-
- if (size > item->len || size > sizeof(*num)) {
+ PRUint64 variableLen = 0;
+ SECStatus rv = sslRead_ReadNumber(reader, sizeLen, &variableLen);
+ if (rv != SECSuccess) {
PORT_SetError(SEC_ERROR_BAD_DATA);
return SECFailure;
}
-
- *num = 0;
- for (i = 0; i < size; i++) {
- *num = (*num << 8) + item->data[i];
+ if (!variableLen) {
+ // It is ok to have an empty variable.
+ out->len = variableLen;
+ return SECSuccess;
}
+ return sslRead_Read(reader, variableLen, out);
+}
- item->data += size;
- item->len -= size;
+SECStatus
+sslRead_ReadNumber(sslReader *reader, unsigned int bytes, PRUint64 *num)
+{
+ if (!reader || !num) {
+ PORT_SetError(SEC_ERROR_INVALID_ARGS);
+ return SECFailure;
+ }
+ if (reader->buf.len < reader->offset ||
+ bytes > SSL_READER_REMAINING(reader) ||
+ bytes > 8) {
+ PORT_SetError(SEC_ERROR_BAD_DATA);
+ return SECFailure;
+ }
+ unsigned int i;
+ PRUint64 number = 0;
+ for (i = 0; i < bytes; i++) {
+ number = (number << 8) + reader->buf.buf[i + reader->offset];
+ }
+ reader->offset = reader->offset + bytes;
+ *num = number;
return SECSuccess;
}
diff --git a/security/nss/lib/ssl/sslencode.h b/security/nss/lib/ssl/sslencode.h
index a1b04d88f..f43e1c54b 100644
--- a/security/nss/lib/ssl/sslencode.h
+++ b/security/nss/lib/ssl/sslencode.h
@@ -47,13 +47,6 @@ SECStatus sslBuffer_InsertLength(sslBuffer *b, unsigned int at,
unsigned int size);
void sslBuffer_Clear(sslBuffer *b);
-/* All of these functions modify the underlying SECItem, and so should
- * be performed on a shallow copy.*/
-SECStatus ssl3_ConsumeFromItem(SECItem *item,
- PRUint8 **buf, unsigned int size);
-SECStatus ssl3_ConsumeNumberFromItem(SECItem *item,
- PRUint32 *num, unsigned int size);
-
SECStatus ssl3_AppendHandshake(sslSocket *ss, const void *void_src,
unsigned int bytes);
SECStatus ssl3_AppendHandshakeHeader(sslSocket *ss,
@@ -66,4 +59,27 @@ SECStatus ssl3_AppendBufferToHandshake(sslSocket *ss, sslBuffer *buf);
SECStatus ssl3_AppendBufferToHandshakeVariable(sslSocket *ss, sslBuffer *buf,
unsigned int lenSize);
+typedef struct {
+ const PRUint8 *buf;
+ unsigned int len;
+} sslReadBuffer;
+typedef struct {
+ sslReadBuffer buf;
+ unsigned int offset;
+} sslReader;
+#define SSL_READER(b, l) \
+ { \
+ { b, l }, 0 \
+ }
+#define SSL_READER_CURRENT(r) \
+ ((r)->buf.buf + (r)->offset)
+#define SSL_READER_REMAINING(r) \
+ ((r)->buf.len - (r)->offset)
+SECStatus sslRead_Read(sslReader *reader, unsigned int count,
+ sslReadBuffer *out);
+SECStatus sslRead_ReadVariable(sslReader *reader, unsigned int sizeLen,
+ sslReadBuffer *out);
+SECStatus sslRead_ReadNumber(sslReader *reader, unsigned int bytes,
+ PRUint64 *val);
+
#endif /* __sslencode_h_ */
diff --git a/security/nss/lib/ssl/sslerr.h b/security/nss/lib/ssl/sslerr.h
index 90815dd79..b94d0cc62 100644
--- a/security/nss/lib/ssl/sslerr.h
+++ b/security/nss/lib/ssl/sslerr.h
@@ -260,6 +260,8 @@ typedef enum {
SSL_ERROR_RX_UNEXPECTED_KEY_UPDATE = (SSL_ERROR_BASE + 169),
SSL_ERROR_RX_MALFORMED_KEY_UPDATE = (SSL_ERROR_BASE + 170),
SSL_ERROR_TOO_MANY_KEY_UPDATES = (SSL_ERROR_BASE + 171),
+ SSL_ERROR_HANDSHAKE_FAILED = (SSL_ERROR_BASE + 172),
+ SSL_ERROR_BAD_RESUMPTION_TOKEN_ERROR = (SSL_ERROR_BASE + 173),
SSL_ERROR_END_OF_LIST /* let the c compiler determine the value of this. */
} SSLErrorCodes;
#endif /* NO_SECURITY_ERROR_ENUM */
diff --git a/security/nss/lib/ssl/sslexp.h b/security/nss/lib/ssl/sslexp.h
index 569add861..08654f885 100644
--- a/security/nss/lib/ssl/sslexp.h
+++ b/security/nss/lib/ssl/sslexp.h
@@ -350,8 +350,111 @@ typedef SSLHelloRetryRequestAction(PR_CALLBACK *SSLHelloRetryRequestCallback)(
(PRFileDesc * _fd, PRBool _requestUpdate), \
(fd, requestUpdate))
-#define SSL_UseAltServerHelloType(fd, enable) \
- SSL_DEPRECATED_EXPERIMENTAL_API
+/*
+ * Session cache API.
+ */
+
+/*
+ * Information that can be retrieved about a resumption token.
+ * See SSL_GetResumptionTokenInfo for details about how to use this API.
+ * Note that peerCert points to a certificate in the NSS database and must be
+ * copied by the application if it should be used after NSS shutdown or after
+ * calling SSL_DestroyResumptionTokenInfo.
+ */
+typedef struct SSLResumptionTokenInfoStr {
+ PRUint16 length;
+ CERTCertificate *peerCert;
+ PRUint8 *alpnSelection;
+ PRUint32 alpnSelectionLen;
+ PRUint32 maxEarlyDataSize;
+} SSLResumptionTokenInfo;
+
+/*
+ * Allows applications to retrieve information about a resumption token.
+ * This does not require a TLS session.
+ *
+ * - The |tokenData| argument is a pointer to the resumption token as byte array
+ * of length |tokenLen|.
+ * - The |token| argument is a pointer to a SSLResumptionTokenInfo struct of
+ * of |len|. The struct gets filled by this function.
+ * See SSL_DestroyResumptionTokenInfo for information about how to manage the
+ * |token| memory.
+ */
+#define SSL_GetResumptionTokenInfo(tokenData, tokenLen, token, len) \
+ SSL_EXPERIMENTAL_API("SSL_GetResumptionTokenInfo", \
+ (const PRUint8 *_tokenData, unsigned int _tokenLen, \
+ SSLResumptionTokenInfo *_token, PRUintn _len), \
+ (tokenData, tokenLen, token, len))
+
+/*
+ * SSL_GetResumptionTokenInfo allocates memory in order to populate |tokenInfo|.
+ * Any SSLResumptionTokenInfo struct filled with SSL_GetResumptionTokenInfo
+ * has to be freed with SSL_DestroyResumptionTokenInfo.
+ */
+#define SSL_DestroyResumptionTokenInfo(tokenInfo) \
+ SSL_EXPERIMENTAL_API( \
+ "SSL_DestroyResumptionTokenInfo", \
+ (SSLResumptionTokenInfo * _tokenInfo), \
+ (tokenInfo))
+
+/*
+ * This is the function signature for function pointers used as resumption
+ * token callback. The caller has to copy the memory at |resumptionToken| with
+ * length |len| before returning.
+ *
+ * - The |fd| argument is the socket file descriptor.
+ * - The |resumptionToken| is a pointer to the resumption token as byte array
+ * of length |len|.
+ * - The |ctx| is a void pointer to the context set by the application in
+ * SSL_SetResumptionTokenCallback.
+ */
+typedef SECStatus(PR_CALLBACK *SSLResumptionTokenCallback)(
+ PRFileDesc *fd, const PRUint8 *resumptionToken, unsigned int len,
+ void *ctx);
+
+/*
+ * This allows setting a callback for external session caches to store
+ * resumption tokens.
+ *
+ * - The |fd| argument is the socket file descriptor.
+ * - The |cb| is a function pointer to an implementation of
+ * SSLResumptionTokenCallback.
+ * - The |ctx| is a pointer to some application specific context, which is
+ * returned when |cb| is called.
+ */
+#define SSL_SetResumptionTokenCallback(fd, cb, ctx) \
+ SSL_EXPERIMENTAL_API( \
+ "SSL_SetResumptionTokenCallback", \
+ (PRFileDesc * _fd, SSLResumptionTokenCallback _cb, void *_ctx), \
+ (fd, cb, ctx))
+
+/*
+ * This allows setting a resumption token for a session.
+ * The function returns SECSuccess iff the resumption token can be used,
+ * SECFailure in any other case. The caller should remove the |token| from its
+ * cache when the function returns SECFailure.
+ *
+ * - The |fd| argument is the socket file descriptor.
+ * - The |token| is a pointer to the resumption token as byte array
+ * of length |len|.
+ */
+#define SSL_SetResumptionToken(fd, token, len) \
+ SSL_EXPERIMENTAL_API( \
+ "SSL_SetResumptionToken", \
+ (PRFileDesc * _fd, const PRUint8 *_token, const unsigned int _len), \
+ (fd, token, len))
+
+/* TLS 1.3 allows a server to set a limit on the number of bytes of early data
+ * that can be received. This allows that limit to be set. This function has no
+ * effect on a client. */
+#define SSL_SetMaxEarlyDataSize(fd, size) \
+ SSL_EXPERIMENTAL_API("SSL_SetMaxEarlyDataSize", \
+ (PRFileDesc * _fd, PRUint32 _size), \
+ (fd, size))
+
+/* Deprecated experimental APIs */
+
+#define SSL_UseAltServerHelloType(fd, enable) SSL_DEPRECATED_EXPERIMENTAL_API
SEC_END_PROTOS
diff --git a/security/nss/lib/ssl/sslimpl.h b/security/nss/lib/ssl/sslimpl.h
index dee9aa20f..10d0333d9 100644
--- a/security/nss/lib/ssl/sslimpl.h
+++ b/security/nss/lib/ssl/sslimpl.h
@@ -168,8 +168,11 @@ struct ssl3CertNodeStr {
typedef SECStatus (*sslHandshakeFunc)(sslSocket *ss);
-typedef void (*sslSessionIDCacheFunc)(sslSessionID *sid);
-typedef void (*sslSessionIDUncacheFunc)(sslSessionID *sid);
+void ssl_CacheSessionID(sslSocket *ss);
+void ssl_UncacheSessionID(sslSocket *ss);
+void ssl_ServerCacheSessionID(sslSessionID *sid);
+void ssl_ServerUncacheSessionID(sslSessionID *sid);
+
typedef sslSessionID *(*sslSessionIDLookupFunc)(const PRIPv6Addr *addr,
unsigned char *sid,
unsigned int sidLen,
@@ -230,6 +233,7 @@ typedef struct sslOptionsStr {
* list of supported protocols. */
SECItem nextProtoNego;
+ PRUint32 maxEarlyDataSize;
unsigned int useSecurity : 1;
unsigned int useSocks : 1;
unsigned int requestCertificate : 1;
@@ -341,9 +345,11 @@ struct sslGatherStr {
#define GS_HEADER 1
#define GS_DATA 2
+#define WRAPPED_MASTER_SECRET_SIZE 48
+
typedef struct {
- PRUint8 wrapped_master_secret[48];
- PRUint16 wrapped_master_secret_len;
+ PRUint8 wrapped_master_secret[WRAPPED_MASTER_SECRET_SIZE];
+ PRUint8 wrapped_master_secret_len;
PRUint8 resumable;
PRUint8 extendedMasterSecretUsed;
} ssl3SidKeys; /* 52 bytes */
@@ -351,7 +357,8 @@ typedef struct {
typedef enum { never_cached,
in_client_cache,
in_server_cache,
- invalid_cache /* no longer in any cache. */
+ invalid_cache, /* no longer in any cache. */
+ in_external_cache
} Cached;
#include "sslcert.h"
@@ -398,17 +405,11 @@ struct sslSessionIDStr {
PRUint8 sessionID[SSL3_SESSIONID_BYTES];
ssl3CipherSuite cipherSuite;
- int policy;
+ PRUint8 policy;
ssl3SidKeys keys;
/* mechanism used to wrap master secret */
CK_MECHANISM_TYPE masterWrapMech;
- /* The following values are NOT restored from the server's on-disk
- * session cache, but are restored from the client's cache.
- */
- PK11SymKey *clientWriteKey;
- PK11SymKey *serverWriteKey;
-
/* The following values pertain to the slot that wrapped the
** master secret. (used only in client)
*/
@@ -740,7 +741,7 @@ struct ssl3StateStr {
CERTCertificateList *clientCertChain; /* used by client */
PRBool sendEmptyCert; /* used by client */
- int policy;
+ PRUint8 policy;
/* This says what cipher suites we can do, and should
* be either SSL_ALLOWED or SSL_RESTRICTED
*/
@@ -897,14 +898,6 @@ struct sslSecurityInfoStr {
/* The selected certificate (for servers only). */
const sslServerCert *serverCert;
- /*
- ** Procs used for SID cache (nonce) management.
- ** Different implementations exist for clients/servers
- ** The lookup proc is only used for servers. Baloney!
- */
- sslSessionIDCacheFunc cache;
- sslSessionIDUncacheFunc uncache;
-
/* These are used during a connection handshake */
sslConnectInfo ci;
};
@@ -982,6 +975,8 @@ struct sslSocketStr {
SSLHelloRetryRequestCallback hrrCallback;
void *hrrCallbackArg;
PRCList extensionHooks;
+ SSLResumptionTokenCallback resumptionTokenCallback;
+ void *resumptionTokenContext;
PRIntervalTime rTimeout; /* timeout for NSPR I/O */
PRIntervalTime wTimeout; /* timeout for NSPR I/O */
@@ -1075,13 +1070,10 @@ extern FILE *ssl_keylog_iob;
extern PZLock *ssl_keylog_lock;
extern PRUint32 ssl3_sid_timeout;
extern PRUint32 ssl_ticket_lifetime;
-extern PRUint32 ssl_max_early_data_size;
extern const char *const ssl3_cipherName[];
extern sslSessionIDLookupFunc ssl_sid_lookup;
-extern sslSessionIDCacheFunc ssl_sid_cache;
-extern sslSessionIDUncacheFunc ssl_sid_uncache;
extern const sslNamedGroupDef ssl_named_groups[];
@@ -1163,14 +1155,13 @@ extern SECStatus ssl_BeginClientHandshake(sslSocket *ss);
extern SECStatus ssl_BeginServerHandshake(sslSocket *ss);
extern int ssl_Do1stHandshake(sslSocket *ss);
-extern void ssl_ChooseSessionIDProcs(sslSecurityInfo *sec);
-
extern SECStatus ssl3_InitPendingCipherSpecs(sslSocket *ss, PK11SymKey *secret,
PRBool derive);
extern sslSessionID *ssl3_NewSessionID(sslSocket *ss, PRBool is_server);
extern sslSessionID *ssl_LookupSID(const PRIPv6Addr *addr, PRUint16 port,
const char *peerID, const char *urlSvrName);
extern void ssl_FreeSID(sslSessionID *sid);
+extern void ssl_DestroySID(sslSessionID *sid, PRBool freeIt);
extern int ssl3_SendApplicationData(sslSocket *ss, const PRUint8 *in,
int len, int flags);
@@ -1692,6 +1683,26 @@ PRBool ssl_AlpnTagAllowed(const sslSocket *ss, const SECItem *tag);
void ssl_Trace(const char *format, ...);
+void ssl_CacheExternalToken(sslSocket *ss);
+SECStatus ssl_DecodeResumptionToken(sslSessionID *sid, const PRUint8 *encodedTicket,
+ PRUint32 encodedTicketLen);
+PRBool ssl_IsResumptionTokenValid(sslSocket *ss);
+
+/* Remove when stable. */
+
+SECStatus SSLExp_SetResumptionTokenCallback(PRFileDesc *fd,
+ SSLResumptionTokenCallback cb,
+ void *ctx);
+SECStatus SSLExp_SetResumptionToken(PRFileDesc *fd, const PRUint8 *token,
+ unsigned int len);
+
+SECStatus SSLExp_GetResumptionTokenInfo(const PRUint8 *tokenData, unsigned int tokenLen,
+ SSLResumptionTokenInfo *token, unsigned int version);
+
+SECStatus SSLExp_DestroyResumptionTokenInfo(SSLResumptionTokenInfo *token);
+
+#define SSLResumptionTokenVersion 2
+
SEC_END_PROTOS
#if defined(XP_UNIX) || defined(XP_OS2) || defined(XP_BEOS)
diff --git a/security/nss/lib/ssl/sslinit.c b/security/nss/lib/ssl/sslinit.c
index 0f38c0b57..07d57ce6e 100644
--- a/security/nss/lib/ssl/sslinit.c
+++ b/security/nss/lib/ssl/sslinit.c
@@ -15,6 +15,7 @@
static int ssl_isInited = 0;
static PRCallOnceType ssl_init = { 0 };
+PR_STATIC_ASSERT(sizeof(unsigned long) <= sizeof(PRUint64));
PRStatus
ssl_InitCallOnce(void *arg)
diff --git a/security/nss/lib/ssl/sslnonce.c b/security/nss/lib/ssl/sslnonce.c
index 228834e3d..f79c23fc7 100644
--- a/security/nss/lib/ssl/sslnonce.c
+++ b/security/nss/lib/ssl/sslnonce.c
@@ -15,6 +15,7 @@
#include "sslimpl.h"
#include "sslproto.h"
#include "nssilock.h"
+#include "sslencode.h"
#if defined(XP_UNIX) || defined(XP_WIN) || defined(_WINDOWS) || defined(XP_BEOS)
#include <time.h>
#endif
@@ -24,12 +25,13 @@ PRUint32 ssl3_sid_timeout = 86400L; /* 24 hours */
static sslSessionID *cache = NULL;
static PZLock *cacheLock = NULL;
-/* sids can be in one of 4 states:
+/* sids can be in one of 5 states:
*
* never_cached, created, but not yet put into cache.
* in_client_cache, in the client cache's linked list.
* in_server_cache, entry came from the server's cache file.
* invalid_cache has been removed from the cache.
+ * in_external_cache sid comes from an external cache.
*/
#define LOCK_CACHE lock_cache()
@@ -164,8 +166,8 @@ lock_cache(void)
/* BEWARE: This function gets called for both client and server SIDs !!
* If the unreferenced sid is not in the cache, Free sid and its contents.
*/
-static void
-ssl_DestroySID(sslSessionID *sid)
+void
+ssl_DestroySID(sslSessionID *sid, PRBool freeIt)
{
SSL_TRC(8, ("SSL: destroy sid: sid=0x%x cached=%d", sid, sid->cached));
PORT_Assert(sid->references == 0);
@@ -186,11 +188,8 @@ ssl_DestroySID(sslSessionID *sid)
PR_DestroyRWLock(sid->u.ssl3.lock);
}
- if (sid->peerID != NULL)
- PORT_Free((void *)sid->peerID); /* CONST */
-
- if (sid->urlSvrName != NULL)
- PORT_Free((void *)sid->urlSvrName); /* CONST */
+ PORT_Free((void *)sid->peerID);
+ PORT_Free((void *)sid->urlSvrName);
if (sid->peerCert) {
CERT_DestroyCertificate(sid->peerCert);
@@ -205,7 +204,9 @@ ssl_DestroySID(sslSessionID *sid)
SECITEM_FreeItem(&sid->u.ssl3.alpnSelection, PR_FALSE);
- PORT_ZFree(sid, sizeof(sslSessionID));
+ if (freeIt) {
+ PORT_ZFree(sid, sizeof(sslSessionID));
+ }
}
/* BEWARE: This function gets called for both client and server SIDs !!
@@ -220,7 +221,7 @@ ssl_FreeLockedSID(sslSessionID *sid)
{
PORT_Assert(sid->references >= 1);
if (--sid->references == 0) {
- ssl_DestroySID(sid);
+ ssl_DestroySID(sid, PR_TRUE);
}
}
@@ -306,6 +307,7 @@ ssl_LookupSID(const PRIPv6Addr *addr, PRUint16 port, const char *peerID,
static void
CacheSID(sslSessionID *sid)
{
+ PORT_Assert(sid);
PORT_Assert(sid->cached == never_cached);
SSL_TRC(8, ("SSL: Cache: sid=0x%x cached=%d addr=0x%08x%08x%08x%08x port=0x%04x "
@@ -400,7 +402,7 @@ UncacheSID(sslSessionID *zap)
/* If sid "zap" is in the cache,
* removes sid from cache, and decrements reference count.
* Although this function is static, it is called externally via
- * ss->sec.uncache().
+ * ssl_UncacheSessionID.
*/
static void
LockAndUncacheSID(sslSessionID *zap)
@@ -410,16 +412,734 @@ LockAndUncacheSID(sslSessionID *zap)
UNLOCK_CACHE;
}
-/* choose client or server cache functions for this sslsocket. */
+SECStatus
+ReadVariableFromBuffer(sslReader *reader, sslReadBuffer *readerBuffer,
+ uint8_t lenBytes, SECItem *dest)
+{
+ if (sslRead_ReadVariable(reader, lenBytes, readerBuffer) != SECSuccess) {
+ PORT_SetError(SEC_ERROR_INVALID_ARGS);
+ return SECFailure;
+ }
+ if (readerBuffer->len) {
+ SECItem tempItem = { siBuffer, (unsigned char *)readerBuffer->buf,
+ readerBuffer->len };
+ SECStatus rv = SECITEM_CopyItem(NULL, dest, &tempItem);
+ if (rv != SECSuccess) {
+ return rv;
+ }
+ }
+ return SECSuccess;
+}
+
+/* Fill sid with the values from the encoded resumption token.
+ * sid has to be allocated.
+ * We don't care about locks here as this cache entry is externally stored.
+ */
+SECStatus
+ssl_DecodeResumptionToken(sslSessionID *sid, const PRUint8 *encodedToken,
+ PRUint32 encodedTokenLen)
+{
+ PORT_Assert(encodedTokenLen);
+ PORT_Assert(encodedToken);
+ PORT_Assert(sid);
+ if (!sid || !encodedToken || !encodedTokenLen) {
+ PORT_SetError(SEC_ERROR_INVALID_ARGS);
+ return SECFailure;
+ }
+
+ if (encodedToken[0] != SSLResumptionTokenVersion) {
+ /* Unknown token format version. */
+ PORT_SetError(SSL_ERROR_BAD_RESUMPTION_TOKEN_ERROR);
+ return SECFailure;
+ }
+
+ /* These variables are used across macros. Don't use them outside. */
+ sslReader reader = SSL_READER(encodedToken, encodedTokenLen);
+ reader.offset += 1; // We read the version already. Skip the first byte.
+ sslReadBuffer readerBuffer = { 0 };
+ PRUint64 tmpInt = 0;
+
+ if (sslRead_ReadNumber(&reader, 8, &tmpInt) != SECSuccess) {
+ return SECFailure;
+ }
+ sid->lastAccessTime = (PRTime)tmpInt;
+ if (sslRead_ReadNumber(&reader, 8, &tmpInt) != SECSuccess) {
+ return SECFailure;
+ }
+ sid->expirationTime = (PRTime)tmpInt;
+ if (sslRead_ReadNumber(&reader, 8, &tmpInt) != SECSuccess) {
+ return SECFailure;
+ }
+ sid->u.ssl3.locked.sessionTicket.received_timestamp = (PRTime)tmpInt;
+
+ if (sslRead_ReadNumber(&reader, 4, &tmpInt) != SECSuccess) {
+ return SECFailure;
+ }
+ sid->u.ssl3.locked.sessionTicket.ticket_lifetime_hint = (PRUint32)tmpInt;
+ if (sslRead_ReadNumber(&reader, 4, &tmpInt) != SECSuccess) {
+ return SECFailure;
+ }
+ sid->u.ssl3.locked.sessionTicket.flags = (PRUint32)tmpInt;
+ if (sslRead_ReadNumber(&reader, 4, &tmpInt) != SECSuccess) {
+ return SECFailure;
+ }
+ sid->u.ssl3.locked.sessionTicket.ticket_age_add = (PRUint32)tmpInt;
+ if (sslRead_ReadNumber(&reader, 4, &tmpInt) != SECSuccess) {
+ return SECFailure;
+ }
+ sid->u.ssl3.locked.sessionTicket.max_early_data_size = (PRUint32)tmpInt;
+
+ if (sslRead_ReadVariable(&reader, 3, &readerBuffer) != SECSuccess) {
+ PORT_SetError(SEC_ERROR_INVALID_ARGS);
+ return SECFailure;
+ }
+ if (readerBuffer.len) {
+ PORT_Assert(!sid->peerCert);
+ SECItem tempItem = { siBuffer, (unsigned char *)readerBuffer.buf,
+ readerBuffer.len };
+ sid->peerCert = CERT_NewTempCertificate(NULL, /* dbHandle */
+ &tempItem,
+ NULL, PR_FALSE, PR_TRUE);
+ if (!sid->peerCert) {
+ return SECFailure;
+ }
+ }
+
+ if (sslRead_ReadVariable(&reader, 2, &readerBuffer) != SECSuccess) {
+ PORT_SetError(SEC_ERROR_INVALID_ARGS);
+ return SECFailure;
+ }
+ if (readerBuffer.len) {
+ SECITEM_AllocArray(NULL, &sid->peerCertStatus, 1);
+ if (!sid->peerCertStatus.items) {
+ return SECFailure;
+ }
+ SECItem tempItem = { siBuffer, (unsigned char *)readerBuffer.buf,
+ readerBuffer.len };
+ SECITEM_CopyItem(NULL, &sid->peerCertStatus.items[0], &tempItem);
+ }
+
+ if (sslRead_ReadVariable(&reader, 1, &readerBuffer) != SECSuccess) {
+ PORT_SetError(SEC_ERROR_INVALID_ARGS);
+ return SECFailure;
+ }
+ if (readerBuffer.len) {
+ PORT_Assert(readerBuffer.buf);
+ sid->peerID = PORT_Strdup((const char *)readerBuffer.buf);
+ }
+
+ if (sslRead_ReadVariable(&reader, 1, &readerBuffer) != SECSuccess) {
+ PORT_SetError(SEC_ERROR_INVALID_ARGS);
+ return SECFailure;
+ }
+ if (readerBuffer.len) {
+ if (sid->urlSvrName) {
+ PORT_Free((void *)sid->urlSvrName);
+ }
+ PORT_Assert(readerBuffer.buf);
+ sid->urlSvrName = PORT_Strdup((const char *)readerBuffer.buf);
+ }
+
+ if (sslRead_ReadVariable(&reader, 3, &readerBuffer) != SECSuccess) {
+ PORT_SetError(SEC_ERROR_INVALID_ARGS);
+ return SECFailure;
+ }
+ if (readerBuffer.len) {
+ PORT_Assert(!sid->localCert);
+ SECItem tempItem = { siBuffer, (unsigned char *)readerBuffer.buf,
+ readerBuffer.len };
+ sid->localCert = CERT_NewTempCertificate(NULL, /* dbHandle */
+ &tempItem,
+ NULL, PR_FALSE, PR_TRUE);
+ }
+
+ if (sslRead_ReadNumber(&reader, 8, &sid->addr.pr_s6_addr64[0]) != SECSuccess) {
+ return SECFailure;
+ }
+ if (sslRead_ReadNumber(&reader, 8, &sid->addr.pr_s6_addr64[1]) != SECSuccess) {
+ return SECFailure;
+ }
+
+ if (sslRead_ReadNumber(&reader, 2, &tmpInt) != SECSuccess) {
+ return SECFailure;
+ }
+ sid->port = (PRUint16)tmpInt;
+ if (sslRead_ReadNumber(&reader, 2, &tmpInt) != SECSuccess) {
+ return SECFailure;
+ }
+ sid->version = (PRUint16)tmpInt;
+
+ if (sslRead_ReadNumber(&reader, 8, &tmpInt) != SECSuccess) {
+ return SECFailure;
+ }
+ sid->creationTime = (PRTime)tmpInt;
+
+ if (sslRead_ReadNumber(&reader, 2, &tmpInt) != SECSuccess) {
+ return SECFailure;
+ }
+ sid->authType = (SSLAuthType)tmpInt;
+ if (sslRead_ReadNumber(&reader, 4, &tmpInt) != SECSuccess) {
+ return SECFailure;
+ }
+ sid->authKeyBits = (PRUint32)tmpInt;
+ if (sslRead_ReadNumber(&reader, 2, &tmpInt) != SECSuccess) {
+ return SECFailure;
+ }
+ sid->keaType = (SSLKEAType)tmpInt;
+ if (sslRead_ReadNumber(&reader, 4, &tmpInt) != SECSuccess) {
+ return SECFailure;
+ }
+ sid->keaKeyBits = (PRUint32)tmpInt;
+ if (sslRead_ReadNumber(&reader, 3, &tmpInt) != SECSuccess) {
+ return SECFailure;
+ }
+ sid->keaGroup = (SSLNamedGroup)tmpInt;
+
+ if (sslRead_ReadNumber(&reader, 3, &tmpInt) != SECSuccess) {
+ return SECFailure;
+ }
+ sid->sigScheme = (SSLSignatureScheme)tmpInt;
+
+ if (sslRead_ReadNumber(&reader, 1, &tmpInt) != SECSuccess) {
+ return SECFailure;
+ }
+ sid->u.ssl3.sessionIDLength = (PRUint8)tmpInt;
+
+ if (sslRead_ReadVariable(&reader, 1, &readerBuffer) != SECSuccess) {
+ PORT_SetError(SEC_ERROR_INVALID_ARGS);
+ return SECFailure;
+ }
+ if (readerBuffer.len) {
+ PORT_Assert(readerBuffer.buf);
+ PORT_Memcpy(sid->u.ssl3.sessionID, readerBuffer.buf, readerBuffer.len);
+ }
+
+ if (sslRead_ReadNumber(&reader, 2, &tmpInt) != SECSuccess) {
+ return SECFailure;
+ }
+ sid->u.ssl3.cipherSuite = (PRUint16)tmpInt;
+ if (sslRead_ReadNumber(&reader, 1, &tmpInt) != SECSuccess) {
+ return SECFailure;
+ }
+ sid->u.ssl3.policy = (PRUint8)tmpInt;
+
+ if (sslRead_ReadVariable(&reader, 1, &readerBuffer) != SECSuccess) {
+ PORT_SetError(SEC_ERROR_INVALID_ARGS);
+ return SECFailure;
+ }
+ PORT_Assert(readerBuffer.len == WRAPPED_MASTER_SECRET_SIZE);
+ if (readerBuffer.len != WRAPPED_MASTER_SECRET_SIZE) {
+ PORT_SetError(SEC_ERROR_INVALID_ARGS);
+ return SECFailure;
+ }
+ PORT_Assert(readerBuffer.buf);
+ PORT_Memcpy(sid->u.ssl3.keys.wrapped_master_secret, readerBuffer.buf,
+ readerBuffer.len);
+
+ if (sslRead_ReadNumber(&reader, 1, &tmpInt) != SECSuccess) {
+ return SECFailure;
+ }
+ sid->u.ssl3.keys.wrapped_master_secret_len = (PRUint8)tmpInt;
+ if (sslRead_ReadNumber(&reader, 1, &tmpInt) != SECSuccess) {
+ return SECFailure;
+ }
+ sid->u.ssl3.keys.extendedMasterSecretUsed = (PRUint8)tmpInt;
+
+ if (sslRead_ReadNumber(&reader, 8, &tmpInt) != SECSuccess) {
+ return SECFailure;
+ }
+ sid->u.ssl3.masterWrapMech = (unsigned long)tmpInt;
+ if (sslRead_ReadNumber(&reader, 8, &tmpInt) != SECSuccess) {
+ return SECFailure;
+ }
+ sid->u.ssl3.masterModuleID = (unsigned long)tmpInt;
+ if (sslRead_ReadNumber(&reader, 8, &tmpInt) != SECSuccess) {
+ return SECFailure;
+ }
+ sid->u.ssl3.masterSlotID = (unsigned long)tmpInt;
+
+ if (sslRead_ReadNumber(&reader, 4, &tmpInt) != SECSuccess) {
+ return SECFailure;
+ }
+ sid->u.ssl3.masterWrapIndex = (PRUint32)tmpInt;
+ if (sslRead_ReadNumber(&reader, 2, &tmpInt) != SECSuccess) {
+ return SECFailure;
+ }
+ sid->u.ssl3.masterWrapSeries = (PRUint16)tmpInt;
+
+ if (sslRead_ReadNumber(&reader, 1, &tmpInt) != SECSuccess) {
+ return SECFailure;
+ }
+ sid->u.ssl3.masterValid = (char)tmpInt;
+
+ if (ReadVariableFromBuffer(&reader, &readerBuffer, 1,
+ &sid->u.ssl3.srvName) != SECSuccess) {
+ return SECFailure;
+ }
+ if (ReadVariableFromBuffer(&reader, &readerBuffer, 2,
+ &sid->u.ssl3.signedCertTimestamps) != SECSuccess) {
+ return SECFailure;
+ }
+ if (ReadVariableFromBuffer(&reader, &readerBuffer, 1,
+ &sid->u.ssl3.alpnSelection) != SECSuccess) {
+ return SECFailure;
+ }
+ if (ReadVariableFromBuffer(&reader, &readerBuffer, 2,
+ &sid->u.ssl3.locked.sessionTicket.ticket) != SECSuccess) {
+ return SECFailure;
+ }
+ if (!sid->u.ssl3.locked.sessionTicket.ticket.len) {
+ PORT_SetError(SEC_ERROR_INVALID_ARGS);
+ return SECFailure;
+ }
+
+ /* At this point we must have read everything. */
+ PORT_Assert(reader.offset == reader.buf.len);
+ if (reader.offset != reader.buf.len) {
+ PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
+ return SECFailure;
+ }
+
+ return SECSuccess;
+}
+
+PRBool
+ssl_IsResumptionTokenValid(sslSocket *ss)
+{
+ PORT_Assert(ss);
+ sslSessionID *sid = ss->sec.ci.sid;
+ PORT_Assert(sid);
+
+ // Check that the ticket didn't expire.
+ PRTime endTime = 0;
+ NewSessionTicket *ticket = &sid->u.ssl3.locked.sessionTicket;
+ if (ticket->ticket_lifetime_hint != 0) {
+ endTime = ticket->received_timestamp +
+ (PRTime)(ticket->ticket_lifetime_hint * PR_USEC_PER_SEC);
+ if (endTime < ssl_TimeUsec()) {
+ return PR_FALSE;
+ }
+ }
+
+ // Check that the session entry didn't expire.
+ if (sid->expirationTime < ssl_TimeUsec()) {
+ return PR_FALSE;
+ }
+
+ // Check that the server name (SNI) matches the one set for this session.
+ // Don't use the token if there's no server name.
+ if (sid->urlSvrName == NULL || PORT_Strcmp(ss->url, sid->urlSvrName) != 0) {
+ return PR_FALSE;
+ }
+
+ // This shouldn't be false, but let's check it anyway.
+ if (!sid->u.ssl3.keys.resumable) {
+ return PR_FALSE;
+ }
+
+ return PR_TRUE;
+}
+
+/* Encode a session ticket into a byte array that can be handed out to a cache.
+ * Needed memory in encodedToken has to be allocated according to
+ * *encodedTokenLen. */
+static SECStatus
+ssl_EncodeResumptionToken(sslSessionID *sid, sslBuffer *encodedTokenBuf)
+{
+ PORT_Assert(encodedTokenBuf);
+ PORT_Assert(sid);
+ if (!sid || !sid->u.ssl3.locked.sessionTicket.ticket.len ||
+ !encodedTokenBuf || !sid->u.ssl3.keys.resumable || !sid->urlSvrName) {
+ PORT_SetError(SEC_ERROR_INVALID_ARGS);
+ return SECFailure;
+ }
+
+ /* Encoding format:
+ * 0-byte: version
+ * Integers are encoded according to their length.
+ * SECItems are prepended with a 64-bit length field followed by the bytes.
+ * Optional bytes are encoded as a 0-length item if not present.
+ */
+ SECStatus rv = sslBuffer_AppendNumber(encodedTokenBuf,
+ SSLResumptionTokenVersion, 1);
+ if (rv != SECSuccess) {
+ return SECFailure;
+ }
+
+ rv = sslBuffer_AppendNumber(encodedTokenBuf, sid->lastAccessTime, 8);
+ if (rv != SECSuccess) {
+ PORT_SetError(SEC_ERROR_INVALID_ARGS);
+ return SECFailure;
+ }
+ rv = sslBuffer_AppendNumber(encodedTokenBuf, sid->expirationTime, 8);
+ if (rv != SECSuccess) {
+ PORT_SetError(SEC_ERROR_INVALID_ARGS);
+ return SECFailure;
+ }
+
+ // session ticket
+ rv = sslBuffer_AppendNumber(encodedTokenBuf,
+ sid->u.ssl3.locked.sessionTicket.received_timestamp,
+ 8);
+ if (rv != SECSuccess) {
+ PORT_SetError(SEC_ERROR_INVALID_ARGS);
+ return SECFailure;
+ }
+ rv = sslBuffer_AppendNumber(encodedTokenBuf,
+ sid->u.ssl3.locked.sessionTicket.ticket_lifetime_hint,
+ 4);
+ if (rv != SECSuccess) {
+ PORT_SetError(SEC_ERROR_INVALID_ARGS);
+ return SECFailure;
+ }
+ rv = sslBuffer_AppendNumber(encodedTokenBuf,
+ sid->u.ssl3.locked.sessionTicket.flags,
+ 4);
+ if (rv != SECSuccess) {
+ PORT_SetError(SEC_ERROR_INVALID_ARGS);
+ return SECFailure;
+ }
+ rv = sslBuffer_AppendNumber(encodedTokenBuf,
+ sid->u.ssl3.locked.sessionTicket.ticket_age_add,
+ 4);
+ if (rv != SECSuccess) {
+ PORT_SetError(SEC_ERROR_INVALID_ARGS);
+ return SECFailure;
+ }
+ rv = sslBuffer_AppendNumber(encodedTokenBuf,
+ sid->u.ssl3.locked.sessionTicket.max_early_data_size,
+ 4);
+ if (rv != SECSuccess) {
+ PORT_SetError(SEC_ERROR_INVALID_ARGS);
+ return SECFailure;
+ }
+
+ rv = sslBuffer_AppendVariable(encodedTokenBuf, sid->peerCert->derCert.data,
+ sid->peerCert->derCert.len, 3);
+ if (rv != SECSuccess) {
+ return SECFailure;
+ }
+
+ if (sid->peerCertStatus.len > 1) {
+ /* This is not implemented so it shouldn't happen.
+ * If it gets implemented, this has to change.
+ */
+ PORT_Assert(0);
+ PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
+ return SECFailure;
+ }
+
+ if (sid->peerCertStatus.len == 1 && sid->peerCertStatus.items[0].len) {
+ rv = sslBuffer_AppendVariable(encodedTokenBuf,
+ sid->peerCertStatus.items[0].data,
+ sid->peerCertStatus.items[0].len, 2);
+ if (rv != SECSuccess) {
+ return SECFailure;
+ }
+ } else {
+ rv = sslBuffer_AppendVariable(encodedTokenBuf, NULL, 0, 2);
+ if (rv != SECSuccess) {
+ return SECFailure;
+ }
+ }
+
+ PRUint64 len = sid->peerID ? strlen(sid->peerID) : 0;
+ if (len > PR_UINT8_MAX) {
+ // This string really shouldn't be that long.
+ PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
+ return SECFailure;
+ }
+ rv = sslBuffer_AppendVariable(encodedTokenBuf,
+ (const unsigned char *)sid->peerID, len, 1);
+ if (rv != SECSuccess) {
+ return SECFailure;
+ }
+
+ len = sid->urlSvrName ? strlen(sid->urlSvrName) : 0;
+ if (!len) {
+ PORT_SetError(SEC_ERROR_INVALID_ARGS);
+ return SECFailure;
+ }
+ if (len > PR_UINT8_MAX) {
+ // This string really shouldn't be that long.
+ PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
+ return SECFailure;
+ }
+ rv = sslBuffer_AppendVariable(encodedTokenBuf,
+ (const unsigned char *)sid->urlSvrName,
+ len, 1);
+ if (rv != SECSuccess) {
+ return SECFailure;
+ }
+
+ if (sid->localCert) {
+ rv = sslBuffer_AppendVariable(encodedTokenBuf,
+ sid->localCert->derCert.data,
+ sid->localCert->derCert.len, 3);
+ if (rv != SECSuccess) {
+ return SECFailure;
+ }
+ } else {
+ rv = sslBuffer_AppendVariable(encodedTokenBuf, NULL, 0, 3);
+ if (rv != SECSuccess) {
+ return SECFailure;
+ }
+ }
+
+ rv = sslBuffer_AppendNumber(encodedTokenBuf, sid->addr.pr_s6_addr64[0], 8);
+ if (rv != SECSuccess) {
+ PORT_SetError(SEC_ERROR_INVALID_ARGS);
+ return SECFailure;
+ }
+ rv = sslBuffer_AppendNumber(encodedTokenBuf, sid->addr.pr_s6_addr64[1], 8);
+ if (rv != SECSuccess) {
+ PORT_SetError(SEC_ERROR_INVALID_ARGS);
+ return SECFailure;
+ }
+ rv = sslBuffer_AppendNumber(encodedTokenBuf, sid->port, 2);
+ if (rv != SECSuccess) {
+ PORT_SetError(SEC_ERROR_INVALID_ARGS);
+ return SECFailure;
+ }
+ rv = sslBuffer_AppendNumber(encodedTokenBuf, sid->version, 2);
+ if (rv != SECSuccess) {
+ PORT_SetError(SEC_ERROR_INVALID_ARGS);
+ return SECFailure;
+ }
+ rv = sslBuffer_AppendNumber(encodedTokenBuf, sid->creationTime, 8);
+ if (rv != SECSuccess) {
+ PORT_SetError(SEC_ERROR_INVALID_ARGS);
+ return SECFailure;
+ }
+ rv = sslBuffer_AppendNumber(encodedTokenBuf, sid->authType, 2);
+ if (rv != SECSuccess) {
+ PORT_SetError(SEC_ERROR_INVALID_ARGS);
+ return SECFailure;
+ }
+ rv = sslBuffer_AppendNumber(encodedTokenBuf, sid->authKeyBits, 4);
+ if (rv != SECSuccess) {
+ PORT_SetError(SEC_ERROR_INVALID_ARGS);
+ return SECFailure;
+ }
+ rv = sslBuffer_AppendNumber(encodedTokenBuf, sid->keaType, 2);
+ if (rv != SECSuccess) {
+ PORT_SetError(SEC_ERROR_INVALID_ARGS);
+ return SECFailure;
+ }
+ rv = sslBuffer_AppendNumber(encodedTokenBuf, sid->keaKeyBits, 4);
+ if (rv != SECSuccess) {
+ PORT_SetError(SEC_ERROR_INVALID_ARGS);
+ return SECFailure;
+ }
+ rv = sslBuffer_AppendNumber(encodedTokenBuf, sid->keaGroup, 3);
+ if (rv != SECSuccess) {
+ PORT_SetError(SEC_ERROR_INVALID_ARGS);
+ return SECFailure;
+ }
+ rv = sslBuffer_AppendNumber(encodedTokenBuf, sid->sigScheme, 3);
+ if (rv != SECSuccess) {
+ PORT_SetError(SEC_ERROR_INVALID_ARGS);
+ return SECFailure;
+ }
+
+ rv = sslBuffer_AppendNumber(encodedTokenBuf, sid->u.ssl3.sessionIDLength, 1);
+ if (rv != SECSuccess) {
+ PORT_SetError(SEC_ERROR_INVALID_ARGS);
+ return SECFailure;
+ }
+ rv = sslBuffer_AppendVariable(encodedTokenBuf, sid->u.ssl3.sessionID,
+ SSL3_SESSIONID_BYTES, 1);
+ if (rv != SECSuccess) {
+ return SECFailure;
+ }
+
+ rv = sslBuffer_AppendNumber(encodedTokenBuf, sid->u.ssl3.cipherSuite, 2);
+ if (rv != SECSuccess) {
+ PORT_SetError(SEC_ERROR_INVALID_ARGS);
+ return SECFailure;
+ }
+ rv = sslBuffer_AppendNumber(encodedTokenBuf, sid->u.ssl3.policy, 1);
+ if (rv != SECSuccess) {
+ PORT_SetError(SEC_ERROR_INVALID_ARGS);
+ return SECFailure;
+ }
+
+ rv = sslBuffer_AppendVariable(encodedTokenBuf,
+ sid->u.ssl3.keys.wrapped_master_secret,
+ WRAPPED_MASTER_SECRET_SIZE, 1);
+ if (rv != SECSuccess) {
+ return SECFailure;
+ }
+
+ rv = sslBuffer_AppendNumber(encodedTokenBuf,
+ sid->u.ssl3.keys.wrapped_master_secret_len,
+ 1);
+ if (rv != SECSuccess) {
+ PORT_SetError(SEC_ERROR_INVALID_ARGS);
+ return SECFailure;
+ }
+ rv = sslBuffer_AppendNumber(encodedTokenBuf,
+ sid->u.ssl3.keys.extendedMasterSecretUsed,
+ 1);
+ if (rv != SECSuccess) {
+ PORT_SetError(SEC_ERROR_INVALID_ARGS);
+ return SECFailure;
+ }
+
+ rv = sslBuffer_AppendNumber(encodedTokenBuf, sid->u.ssl3.masterWrapMech, 8);
+ if (rv != SECSuccess) {
+ PORT_SetError(SEC_ERROR_INVALID_ARGS);
+ return SECFailure;
+ }
+ rv = sslBuffer_AppendNumber(encodedTokenBuf, sid->u.ssl3.masterModuleID, 8);
+ if (rv != SECSuccess) {
+ PORT_SetError(SEC_ERROR_INVALID_ARGS);
+ return SECFailure;
+ }
+ rv = sslBuffer_AppendNumber(encodedTokenBuf, sid->u.ssl3.masterSlotID, 8);
+ if (rv != SECSuccess) {
+ PORT_SetError(SEC_ERROR_INVALID_ARGS);
+ return SECFailure;
+ }
+ rv = sslBuffer_AppendNumber(encodedTokenBuf, sid->u.ssl3.masterWrapIndex, 4);
+ if (rv != SECSuccess) {
+ PORT_SetError(SEC_ERROR_INVALID_ARGS);
+ return SECFailure;
+ }
+ rv = sslBuffer_AppendNumber(encodedTokenBuf, sid->u.ssl3.masterWrapSeries, 2);
+ if (rv != SECSuccess) {
+ PORT_SetError(SEC_ERROR_INVALID_ARGS);
+ return SECFailure;
+ }
+
+ rv = sslBuffer_AppendNumber(encodedTokenBuf, sid->u.ssl3.masterValid, 1);
+ if (rv != SECSuccess) {
+ PORT_SetError(SEC_ERROR_INVALID_ARGS);
+ return SECFailure;
+ }
+
+ rv = sslBuffer_AppendVariable(encodedTokenBuf, sid->u.ssl3.srvName.data,
+ sid->u.ssl3.srvName.len, 1);
+ if (rv != SECSuccess) {
+ return SECFailure;
+ }
+ rv = sslBuffer_AppendVariable(encodedTokenBuf,
+ sid->u.ssl3.signedCertTimestamps.data,
+ sid->u.ssl3.signedCertTimestamps.len, 2);
+ if (rv != SECSuccess) {
+ return SECFailure;
+ }
+
+ rv = sslBuffer_AppendVariable(encodedTokenBuf,
+ sid->u.ssl3.alpnSelection.data,
+ sid->u.ssl3.alpnSelection.len, 1);
+ if (rv != SECSuccess) {
+ return SECFailure;
+ }
+
+ PORT_Assert(sid->u.ssl3.locked.sessionTicket.ticket.len > 1);
+ rv = sslBuffer_AppendVariable(encodedTokenBuf,
+ sid->u.ssl3.locked.sessionTicket.ticket.data,
+ sid->u.ssl3.locked.sessionTicket.ticket.len,
+ 2);
+ if (rv != SECSuccess) {
+ return SECFailure;
+ }
+
+ return SECSuccess;
+}
+
void
-ssl_ChooseSessionIDProcs(sslSecurityInfo *sec)
+ssl_CacheExternalToken(sslSocket *ss)
{
+ PORT_Assert(ss);
+ sslSessionID *sid = ss->sec.ci.sid;
+ PORT_Assert(sid);
+ PORT_Assert(sid->cached == never_cached);
+ PORT_Assert(ss->resumptionTokenCallback);
+
+ SSL_TRC(8, ("SSL [%d]: Cache External: sid=0x%x cached=%d "
+ "addr=0x%08x%08x%08x%08x port=0x%04x time=%x cached=%d",
+ ss->fd,
+ sid, sid->cached, sid->addr.pr_s6_addr32[0],
+ sid->addr.pr_s6_addr32[1], sid->addr.pr_s6_addr32[2],
+ sid->addr.pr_s6_addr32[3], sid->port, sid->creationTime,
+ sid->cached));
+
+ /* This is only available for stateless resumption. */
+ if (sid->u.ssl3.locked.sessionTicket.ticket.data == NULL) {
+ return;
+ }
+
+ /* Don't export token if the session used client authentication. */
+ if (sid->u.ssl3.clAuthValid) {
+ return;
+ }
+
+ if (!sid->creationTime) {
+ sid->lastAccessTime = sid->creationTime = ssl_TimeUsec();
+ }
+ if (!sid->expirationTime) {
+ sid->expirationTime = sid->creationTime + ssl3_sid_timeout;
+ }
+
+ sslBuffer encodedToken = SSL_BUFFER_EMPTY;
+
+ if (ssl_EncodeResumptionToken(sid, &encodedToken) != SECSuccess) {
+ SSL_TRC(3, ("SSL [%d]: encoding resumption token failed", ss->fd));
+ return;
+ }
+ PORT_Assert(SSL_BUFFER_LEN(&encodedToken) > 0);
+ PRINT_BUF(40, (ss, "SSL: encoded resumption token",
+ SSL_BUFFER_BASE(&encodedToken),
+ SSL_BUFFER_LEN(&encodedToken)));
+ ss->resumptionTokenCallback(ss->fd, SSL_BUFFER_BASE(&encodedToken),
+ SSL_BUFFER_LEN(&encodedToken),
+ ss->resumptionTokenContext);
+
+ sslBuffer_Clear(&encodedToken);
+}
+
+void
+ssl_CacheSessionID(sslSocket *ss)
+{
+ sslSecurityInfo *sec = &ss->sec;
+ PORT_Assert(sec);
+
+ if (sec->ci.sid && !sec->ci.sid->u.ssl3.keys.resumable) {
+ return;
+ }
+
+ if (!ss->sec.isServer && ss->resumptionTokenCallback) {
+ ssl_CacheExternalToken(ss);
+ return;
+ }
+
+ PORT_Assert(!ss->resumptionTokenCallback);
if (sec->isServer) {
- sec->cache = ssl_sid_cache;
- sec->uncache = ssl_sid_uncache;
- } else {
- sec->cache = CacheSID;
- sec->uncache = LockAndUncacheSID;
+ ssl_ServerCacheSessionID(sec->ci.sid);
+ return;
+ }
+
+ CacheSID(sec->ci.sid);
+}
+
+void
+ssl_UncacheSessionID(sslSocket *ss)
+{
+ if (ss->opt.noCache) {
+ return;
+ }
+
+ sslSecurityInfo *sec = &ss->sec;
+ PORT_Assert(sec);
+
+ if (sec->ci.sid) {
+ if (sec->isServer) {
+ ssl_ServerUncacheSessionID(sec->ci.sid);
+ } else if (!ss->resumptionTokenCallback) {
+ LockAndUncacheSID(sec->ci.sid);
+ }
}
}
diff --git a/security/nss/lib/ssl/sslsecur.c b/security/nss/lib/ssl/sslsecur.c
index 3f7060f22..f09ec067c 100644
--- a/security/nss/lib/ssl/sslsecur.c
+++ b/security/nss/lib/ssl/sslsecur.c
@@ -599,9 +599,6 @@ ssl_CopySecurityInfo(sslSocket *ss, sslSocket *os)
if (os->sec.peerCert && !ss->sec.peerCert)
goto loser;
- ss->sec.cache = os->sec.cache;
- ss->sec.uncache = os->sec.uncache;
-
return SECSuccess;
loser:
@@ -1159,7 +1156,7 @@ SSL_InvalidateSession(PRFileDesc *fd)
ssl_GetSSL3HandshakeLock(ss);
if (ss->sec.ci.sid) {
- ss->sec.uncache(ss->sec.ci.sid);
+ ssl_UncacheSessionID(ss);
rv = SECSuccess;
}
diff --git a/security/nss/lib/ssl/sslsnce.c b/security/nss/lib/ssl/sslsnce.c
index 279f3c015..d7abb3dc3 100644
--- a/security/nss/lib/ssl/sslsnce.c
+++ b/security/nss/lib/ssl/sslsnce.c
@@ -495,12 +495,6 @@ ConvertToSID(sidCacheEntry *from,
PORT_Memcpy(to->u.ssl3.sessionID, from->sessionID, from->sessionIDLength);
- /* the portions of the SID that are only restored on the client
- * are set to invalid values on the server.
- */
- to->u.ssl3.clientWriteKey = NULL;
- to->u.ssl3.serverWriteKey = NULL;
-
to->urlSvrName = NULL;
to->u.ssl3.masterModuleID = (SECMODModuleID)-1; /* invalid value */
@@ -735,9 +729,11 @@ ServerSessionIDLookup(const PRIPv6Addr *addr,
/*
** Place a sid into the cache, if it isn't already there.
*/
-static void
-ServerSessionIDCache(sslSessionID *sid)
+void
+ssl_ServerCacheSessionID(sslSessionID *sid)
{
+ PORT_Assert(sid);
+
sidCacheEntry sce;
PRUint32 now = 0;
cacheDesc *cache = &globalCache;
@@ -800,8 +796,8 @@ ServerSessionIDCache(sslSessionID *sid)
** Although this is static, it is called from ssl via global function pointer
** ssl_sid_uncache. This invalidates the referenced cache entry.
*/
-static void
-ServerSessionIDUncache(sslSessionID *sid)
+void
+ssl_ServerUncacheSessionID(sslSessionID *sid)
{
cacheDesc *cache = &globalCache;
PRUint8 *sessionID;
@@ -1172,8 +1168,6 @@ ssl_ConfigServerSessionIDCacheInstanceWithOpt(cacheDesc *cache,
}
ssl_sid_lookup = ServerSessionIDLookup;
- ssl_sid_cache = ServerSessionIDCache;
- ssl_sid_uncache = ServerSessionIDUncache;
return SECSuccess;
}
@@ -1356,8 +1350,6 @@ SSL_InheritMPServerSIDCacheInstance(cacheDesc *cache, const char *envString)
ssl_InitSessionCacheLocks(PR_FALSE);
ssl_sid_lookup = ServerSessionIDLookup;
- ssl_sid_cache = ServerSessionIDCache;
- ssl_sid_uncache = ServerSessionIDUncache;
if (!envString) {
envString = PR_GetEnvSecure(envVarName);
diff --git a/security/nss/lib/ssl/sslsock.c b/security/nss/lib/ssl/sslsock.c
index 4893cb9f9..e08d5e232 100644
--- a/security/nss/lib/ssl/sslsock.c
+++ b/security/nss/lib/ssl/sslsock.c
@@ -53,34 +53,35 @@ static const sslSocketOps ssl_secure_ops = { /* SSL. */
** default settings for socket enables
*/
static sslOptions ssl_defaults = {
- { siBuffer, NULL, 0 }, /* nextProtoNego */
- PR_TRUE, /* useSecurity */
- PR_FALSE, /* useSocks */
- PR_FALSE, /* requestCertificate */
- 2, /* requireCertificate */
- PR_FALSE, /* handshakeAsClient */
- PR_FALSE, /* handshakeAsServer */
- PR_FALSE, /* noCache */
- PR_FALSE, /* fdx */
- PR_TRUE, /* detectRollBack */
- PR_FALSE, /* noLocks */
- PR_FALSE, /* enableSessionTickets */
- PR_FALSE, /* enableDeflate */
- 2, /* enableRenegotiation (default: requires extension) */
- PR_FALSE, /* requireSafeNegotiation */
- PR_FALSE, /* enableFalseStart */
- PR_TRUE, /* cbcRandomIV */
- PR_FALSE, /* enableOCSPStapling */
- PR_FALSE, /* enableNPN */
- PR_TRUE, /* enableALPN */
- PR_TRUE, /* reuseServerECDHEKey */
- PR_FALSE, /* enableFallbackSCSV */
- PR_TRUE, /* enableServerDhe */
- PR_FALSE, /* enableExtendedMS */
- PR_FALSE, /* enableSignedCertTimestamps */
- PR_FALSE, /* requireDHENamedGroups */
- PR_FALSE, /* enable0RttData */
- PR_FALSE /* enableTls13CompatMode */
+ .nextProtoNego = { siBuffer, NULL, 0 },
+ .maxEarlyDataSize = 1 << 16,
+ .useSecurity = PR_TRUE,
+ .useSocks = PR_FALSE,
+ .requestCertificate = PR_FALSE,
+ .requireCertificate = SSL_REQUIRE_FIRST_HANDSHAKE,
+ .handshakeAsClient = PR_FALSE,
+ .handshakeAsServer = PR_FALSE,
+ .noCache = PR_FALSE,
+ .fdx = PR_FALSE,
+ .detectRollBack = PR_TRUE,
+ .noLocks = PR_FALSE,
+ .enableSessionTickets = PR_FALSE,
+ .enableDeflate = PR_FALSE,
+ .enableRenegotiation = SSL_RENEGOTIATE_REQUIRES_XTN,
+ .requireSafeNegotiation = PR_FALSE,
+ .enableFalseStart = PR_FALSE,
+ .cbcRandomIV = PR_TRUE,
+ .enableOCSPStapling = PR_FALSE,
+ .enableNPN = PR_FALSE,
+ .enableALPN = PR_TRUE,
+ .reuseServerECDHEKey = PR_TRUE,
+ .enableFallbackSCSV = PR_FALSE,
+ .enableServerDhe = PR_TRUE,
+ .enableExtendedMS = PR_FALSE,
+ .enableSignedCertTimestamps = PR_FALSE,
+ .requireDHENamedGroups = PR_FALSE,
+ .enable0RttData = PR_FALSE,
+ .enableTls13CompatMode = PR_FALSE
};
/*
@@ -104,8 +105,6 @@ static SSLVersionRange versions_defaults_datagram = {
(variant == ssl_variant_stream ? NSS_TLS_VERSION_MAX_POLICY : NSS_DTLS_VERSION_MAX_POLICY)
sslSessionIDLookupFunc ssl_sid_lookup;
-sslSessionIDCacheFunc ssl_sid_cache;
-sslSessionIDUncacheFunc ssl_sid_uncache;
static PRDescIdentity ssl_layer_id;
@@ -356,6 +355,8 @@ ssl_DupSocket(sslSocket *os)
os->namedGroupPreferences,
sizeof(ss->namedGroupPreferences));
ss->additionalShares = os->additionalShares;
+ ss->resumptionTokenCallback = os->resumptionTokenCallback;
+ ss->resumptionTokenContext = os->resumptionTokenContext;
/* Create security data */
rv = ssl_CopySecurityInfo(ss, os);
@@ -1252,6 +1253,18 @@ SSL_OptionSetDefault(PRInt32 which, PRIntn val)
return SECSuccess;
}
+SECStatus
+SSLExp_SetMaxEarlyDataSize(PRFileDesc *fd, PRUint32 size)
+{
+ sslSocket *ss = ssl_FindSocket(fd);
+ if (!ss) {
+ return SECFailure; /* Error code already set. */
+ }
+
+ ss->opt.maxEarlyDataSize = size;
+ return SECSuccess;
+}
+
/* function tells us if the cipher suite is one that we no longer support. */
static PRBool
ssl_IsRemovedCipherSuite(PRInt32 suite)
@@ -3932,7 +3945,12 @@ struct {
EXP(InstallExtensionHooks),
EXP(KeyUpdate),
EXP(SendSessionTicket),
+ EXP(SetMaxEarlyDataSize),
EXP(SetupAntiReplay),
+ EXP(SetResumptionTokenCallback),
+ EXP(SetResumptionToken),
+ EXP(GetResumptionTokenInfo),
+ EXP(DestroyResumptionTokenInfo),
#endif
{ "", NULL }
};
@@ -3967,3 +3985,156 @@ ssl_ClearPRCList(PRCList *list, void (*f)(void *))
PORT_Free(cursor);
}
}
+
+/* Experimental APIs for session cache handling. */
+
+SECStatus
+SSLExp_SetResumptionTokenCallback(PRFileDesc *fd,
+ SSLResumptionTokenCallback cb,
+ void *ctx)
+{
+ sslSocket *ss = ssl_FindSocket(fd);
+
+ if (!ss) {
+ SSL_DBG(("%d: SSL[%d]: bad socket in SSL_SetResumptionTokenCallback",
+ SSL_GETPID(), fd));
+ return SECFailure;
+ }
+
+ ssl_Get1stHandshakeLock(ss);
+ ssl_GetSSL3HandshakeLock(ss);
+ ss->resumptionTokenCallback = cb;
+ ss->resumptionTokenContext = ctx;
+ ssl_ReleaseSSL3HandshakeLock(ss);
+ ssl_Release1stHandshakeLock(ss);
+
+ return SECSuccess;
+}
+
+SECStatus
+SSLExp_SetResumptionToken(PRFileDesc *fd, const PRUint8 *token,
+ unsigned int len)
+{
+ sslSocket *ss = ssl_FindSocket(fd);
+
+ if (!ss) {
+ SSL_DBG(("%d: SSL[%d]: bad socket in SSL_SetResumptionToken",
+ SSL_GETPID(), fd));
+ return SECFailure;
+ }
+
+ ssl_Get1stHandshakeLock(ss);
+ ssl_GetSSL3HandshakeLock(ss);
+
+ if (ss->firstHsDone || ss->ssl3.hs.ws != idle_handshake ||
+ ss->sec.isServer || len == 0 || !token) {
+ PORT_SetError(SEC_ERROR_INVALID_ARGS);
+ goto done;
+ }
+
+ // We override any previously set session.
+ if (ss->sec.ci.sid) {
+ ssl_FreeSID(ss->sec.ci.sid);
+ ss->sec.ci.sid = NULL;
+ }
+
+ PRINT_BUF(50, (ss, "incoming resumption token", token, len));
+
+ ss->sec.ci.sid = ssl3_NewSessionID(ss, PR_FALSE);
+ if (!ss->sec.ci.sid) {
+ goto done;
+ }
+
+ /* Populate NewSessionTicket values */
+ SECStatus rv = ssl_DecodeResumptionToken(ss->sec.ci.sid, token, len);
+ if (rv != SECSuccess) {
+ // If decoding fails, we assume the token is bad.
+ PORT_SetError(SSL_ERROR_BAD_RESUMPTION_TOKEN_ERROR);
+ ssl_FreeSID(ss->sec.ci.sid);
+ ss->sec.ci.sid = NULL;
+ goto done;
+ }
+
+ // Make sure that the token is valid.
+ if (!ssl_IsResumptionTokenValid(ss)) {
+ ssl_FreeSID(ss->sec.ci.sid);
+ ss->sec.ci.sid = NULL;
+ PORT_SetError(SSL_ERROR_BAD_RESUMPTION_TOKEN_ERROR);
+ goto done;
+ }
+
+ /* Use the sid->cached as marker that this is from an external cache and
+ * we don't have to look up anything in the NSS internal cache. */
+ ss->sec.ci.sid->cached = in_external_cache;
+ // This has to be 2 to not free this in sendClientHello.
+ ss->sec.ci.sid->references = 2;
+ ss->sec.ci.sid->lastAccessTime = ssl_TimeSec();
+
+ ssl_ReleaseSSL3HandshakeLock(ss);
+ ssl_Release1stHandshakeLock(ss);
+ return SECSuccess;
+
+done:
+ ssl_ReleaseSSL3HandshakeLock(ss);
+ ssl_Release1stHandshakeLock(ss);
+
+ return SECFailure;
+}
+
+SECStatus
+SSLExp_DestroyResumptionTokenInfo(SSLResumptionTokenInfo *token)
+{
+ if (!token) {
+ PORT_SetError(SEC_ERROR_INVALID_ARGS);
+ return SECFailure;
+ }
+ if (token->peerCert) {
+ CERT_DestroyCertificate(token->peerCert);
+ }
+ PORT_Free(token->alpnSelection);
+ PORT_Memset(token, 0, token->length);
+ return SECSuccess;
+}
+
+SECStatus
+SSLExp_GetResumptionTokenInfo(const PRUint8 *tokenData, unsigned int tokenLen,
+ SSLResumptionTokenInfo *tokenOut, PRUintn len)
+{
+ if (!tokenData || !tokenOut || !tokenLen ||
+ len > sizeof(SSLResumptionTokenInfo)) {
+ PORT_SetError(SEC_ERROR_INVALID_ARGS);
+ return SECFailure;
+ }
+ sslSessionID sid = { 0 };
+ SSLResumptionTokenInfo token;
+
+ /* Populate sid values */
+ if (ssl_DecodeResumptionToken(&sid, tokenData, tokenLen) != SECSuccess) {
+ // If decoding fails, we assume the token is bad.
+ PORT_SetError(SSL_ERROR_BAD_RESUMPTION_TOKEN_ERROR);
+ return SECFailure;
+ }
+
+ token.peerCert = CERT_DupCertificate(sid.peerCert);
+
+ token.alpnSelectionLen = sid.u.ssl3.alpnSelection.len;
+ token.alpnSelection = PORT_ZAlloc(token.alpnSelectionLen);
+ if (!token.alpnSelection) {
+ return SECFailure;
+ }
+ PORT_Memcpy(token.alpnSelection, sid.u.ssl3.alpnSelection.data,
+ token.alpnSelectionLen);
+
+ if (sid.u.ssl3.locked.sessionTicket.flags & ticket_allow_early_data) {
+ token.maxEarlyDataSize =
+ sid.u.ssl3.locked.sessionTicket.max_early_data_size;
+ } else {
+ token.maxEarlyDataSize = 0;
+ }
+
+ token.length = PR_MIN(sizeof(SSLResumptionTokenInfo), len);
+ PORT_Memcpy(tokenOut, &token, token.length);
+
+ ssl_DestroySID(&sid, PR_FALSE);
+ return SECSuccess;
+}
diff --git a/security/nss/lib/ssl/sslt.h b/security/nss/lib/ssl/sslt.h
index ce8f6e281..e2b80fb43 100644
--- a/security/nss/lib/ssl/sslt.h
+++ b/security/nss/lib/ssl/sslt.h
@@ -123,11 +123,14 @@ typedef enum {
ssl_sig_ecdsa_secp256r1_sha256 = 0x0403,
ssl_sig_ecdsa_secp384r1_sha384 = 0x0503,
ssl_sig_ecdsa_secp521r1_sha512 = 0x0603,
- ssl_sig_rsa_pss_sha256 = 0x0804,
- ssl_sig_rsa_pss_sha384 = 0x0805,
- ssl_sig_rsa_pss_sha512 = 0x0806,
+ ssl_sig_rsa_pss_rsae_sha256 = 0x0804,
+ ssl_sig_rsa_pss_rsae_sha384 = 0x0805,
+ ssl_sig_rsa_pss_rsae_sha512 = 0x0806,
ssl_sig_ed25519 = 0x0807,
ssl_sig_ed448 = 0x0808,
+ ssl_sig_rsa_pss_pss_sha256 = 0x0809,
+ ssl_sig_rsa_pss_pss_sha384 = 0x080a,
+ ssl_sig_rsa_pss_pss_sha512 = 0x080b,
ssl_sig_dsa_sha1 = 0x0202,
ssl_sig_dsa_sha256 = 0x0402,
@@ -143,20 +146,25 @@ typedef enum {
ssl_sig_rsa_pkcs1_sha1md5 = 0x10101,
} SSLSignatureScheme;
+/* Deprecated names maintained only for source compatibility. */
+#define ssl_sig_rsa_pss_sha256 ssl_sig_rsa_pss_rsae_sha256
+#define ssl_sig_rsa_pss_sha384 ssl_sig_rsa_pss_rsae_sha384
+#define ssl_sig_rsa_pss_sha512 ssl_sig_rsa_pss_rsae_sha512
+
/*
** SSLAuthType describes the type of key that is used to authenticate a
** connection. That is, the type of key in the end-entity certificate.
*/
typedef enum {
ssl_auth_null = 0,
- ssl_auth_rsa_decrypt = 1, /* static RSA */
+ ssl_auth_rsa_decrypt = 1, /* RSA key exchange. */
ssl_auth_dsa = 2,
ssl_auth_kea = 3, /* unused */
ssl_auth_ecdsa = 4,
- ssl_auth_ecdh_rsa = 5, /* ECDH cert with an RSA signature */
- ssl_auth_ecdh_ecdsa = 6, /* ECDH cert with an ECDSA signature */
- ssl_auth_rsa_sign = 7, /* RSA PKCS#1.5 signing */
- ssl_auth_rsa_pss = 8,
+ ssl_auth_ecdh_rsa = 5, /* ECDH cert with an RSA signature. */
+ ssl_auth_ecdh_ecdsa = 6, /* ECDH cert with an ECDSA signature. */
+ ssl_auth_rsa_sign = 7, /* RSA signing with an rsaEncryption key. */
+ ssl_auth_rsa_pss = 8, /* RSA signing with a PSS key. */
ssl_auth_psk = 9,
ssl_auth_tls13_any = 10,
ssl_auth_size /* number of authentication types */
diff --git a/security/nss/lib/ssl/tls13con.c b/security/nss/lib/ssl/tls13con.c
index 1fecaf3f8..c06acc83a 100644
--- a/security/nss/lib/ssl/tls13con.c
+++ b/security/nss/lib/ssl/tls13con.c
@@ -462,7 +462,7 @@ tls13_SetupClientHello(sslSocket *ss)
if (rv != SECSuccess) {
FATAL_ERROR(ss, SEC_ERROR_LIBRARY_FAILURE, internal_error);
SSL_AtomicIncrementLong(&ssl3stats->sch_sid_cache_not_ok);
- ss->sec.uncache(ss->sec.ci.sid);
+ ssl_UncacheSessionID(ss);
ssl_FreeSID(ss->sec.ci.sid);
ss->sec.ci.sid = NULL;
return SECFailure;
@@ -1426,9 +1426,9 @@ ssl_SignatureSchemeToAuthType(SSLSignatureScheme scheme)
case ssl_sig_rsa_pkcs1_sha384:
case ssl_sig_rsa_pkcs1_sha512:
/* We report PSS signatures as being just RSA signatures. */
- 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 ssl_auth_rsa_sign;
case ssl_sig_ecdsa_secp256r1_sha256:
case ssl_sig_ecdsa_secp384r1_sha384:
@@ -1719,7 +1719,7 @@ tls13_HandleClientHelloPart2(sslSocket *ss,
}
if (hrr) {
if (sid) { /* Free the sid. */
- ss->sec.uncache(sid);
+ ssl_UncacheSessionID(ss);
ssl_FreeSID(sid);
}
PORT_Assert(ss->ssl3.hs.helloRetry);
@@ -1769,8 +1769,7 @@ tls13_HandleClientHelloPart2(sslSocket *ss,
} else {
if (sid) { /* we had a sid, but it's no longer valid, free it */
SSL_AtomicIncrementLong(&ssl3stats->hch_sid_cache_not_ok);
- if (ss->sec.uncache)
- ss->sec.uncache(sid);
+ ssl_UncacheSessionID(ss);
ssl_FreeSID(sid);
sid = NULL;
}
@@ -1830,7 +1829,7 @@ tls13_HandleClientHelloPart2(sslSocket *ss,
if (sid) {
/* We had a sid, but it's no longer valid, free it. */
SSL_AtomicIncrementLong(&ssl3stats->hch_sid_cache_not_ok);
- ss->sec.uncache(sid);
+ ssl_UncacheSessionID(ss);
ssl_FreeSID(sid);
} else {
SSL_AtomicIncrementLong(&ssl3stats->hch_sid_cache_misses);
@@ -1866,7 +1865,7 @@ tls13_HandleClientHelloPart2(sslSocket *ss,
loser:
if (sid) {
- ss->sec.uncache(sid);
+ ssl_UncacheSessionID(ss);
ssl_FreeSID(sid);
}
return SECFailure;
@@ -2539,7 +2538,7 @@ tls13_HandleServerHelloPart2(sslSocket *ss)
}
if (sid->cached == in_client_cache) {
/* If we tried to resume and failed, let's not try again. */
- ss->sec.uncache(sid);
+ ssl_UncacheSessionID(ss);
}
}
@@ -4418,8 +4417,6 @@ tls13_SendClientSecondRound(sslSocket *ss)
* } NewSessionTicket;
*/
-PRUint32 ssl_max_early_data_size = (2 << 16); /* Arbitrary limit. */
-
static SECStatus
tls13_SendNewSessionTicket(sslSocket *ss, const PRUint8 *appToken,
unsigned int appTokenLen)
@@ -4521,7 +4518,7 @@ tls13_SendNewSessionTicket(sslSocket *ss, const PRUint8 *appToken,
if (rv != SECSuccess)
goto loser;
- rv = ssl3_AppendHandshakeNumber(ss, ssl_max_early_data_size, 4);
+ rv = ssl3_AppendHandshakeNumber(ss, ss->opt.maxEarlyDataSize, 4);
if (rv != SECSuccess)
goto loser;
}
@@ -4681,7 +4678,7 @@ tls13_HandleNewSessionTicket(sslSocket *ss, PRUint8 *b, PRUint32 length)
}
/* Destroy the old SID. */
- ss->sec.uncache(ss->sec.ci.sid);
+ ssl_UncacheSessionID(ss);
ssl_FreeSID(ss->sec.ci.sid);
ss->sec.ci.sid = sid;
}
@@ -4707,7 +4704,7 @@ tls13_HandleNewSessionTicket(sslSocket *ss, PRUint8 *b, PRUint32 length)
}
/* Cache the session. */
- ss->sec.cache(ss->sec.ci.sid);
+ ssl_CacheSessionID(ss);
}
return SECSuccess;
@@ -4772,9 +4769,6 @@ tls13_ExtensionStatus(PRUint16 extension, SSLHandshakeType message)
/* Return "disallowed" if the message mask bit isn't set. */
if (!(_M(message) & KnownExtensions[i].messages)) {
- SSL_TRC(3, ("%d: TLS13: unexpected extension %d in message %d",
- SSL_GETPID(), extension, message));
-
return tls13_extension_disallowed;
}
diff --git a/security/nss/lib/ssl/tls13hashstate.c b/security/nss/lib/ssl/tls13hashstate.c
index e3232f524..cc0ed286b 100644
--- a/security/nss/lib/ssl/tls13hashstate.c
+++ b/security/nss/lib/ssl/tls13hashstate.c
@@ -88,36 +88,37 @@ tls13_RecoverHashState(sslSocket *ss,
{
SECStatus rv;
unsigned char plaintext[1024];
- SECItem ptItem = { siBuffer, plaintext, 0 };
+ unsigned int plaintextLen = 0;
sslBuffer messageBuf = SSL_BUFFER_EMPTY;
- PRUint32 sentinel;
- PRUint32 cipherSuite;
- PRUint32 group;
+ PRUint64 sentinel;
+ PRUint64 cipherSuite;
+ PRUint64 group;
const sslNamedGroupDef *selectedGroup;
- PRUint32 appTokenLen;
- PRUint8 *appToken;
+ PRUint64 appTokenLen;
rv = ssl_SelfEncryptUnprotect(ss, cookie, cookieLen,
- ptItem.data, &ptItem.len, sizeof(plaintext));
+ plaintext, &plaintextLen, sizeof(plaintext));
if (rv != SECSuccess) {
return SECFailure;
}
+ sslReader reader = SSL_READER(plaintext, plaintextLen);
+
/* Should start with 0xff. */
- rv = ssl3_ConsumeNumberFromItem(&ptItem, &sentinel, 1);
+ rv = sslRead_ReadNumber(&reader, 1, &sentinel);
if ((rv != SECSuccess) || (sentinel != 0xff)) {
FATAL_ERROR(ss, SSL_ERROR_RX_MALFORMED_CLIENT_HELLO, illegal_parameter);
return SECFailure;
}
/* The cipher suite should be the same or there are some shenanigans. */
- rv = ssl3_ConsumeNumberFromItem(&ptItem, &cipherSuite, 2);
+ rv = sslRead_ReadNumber(&reader, 2, &cipherSuite);
if (rv != SECSuccess) {
FATAL_ERROR(ss, SSL_ERROR_RX_MALFORMED_CLIENT_HELLO, illegal_parameter);
return SECFailure;
}
/* The named group, if any. */
- rv = ssl3_ConsumeNumberFromItem(&ptItem, &group, 2);
+ rv = sslRead_ReadNumber(&reader, 2, &group);
if (rv != SECSuccess) {
FATAL_ERROR(ss, SSL_ERROR_RX_MALFORMED_CLIENT_HELLO, illegal_parameter);
return SECFailure;
@@ -126,7 +127,7 @@ tls13_RecoverHashState(sslSocket *ss,
/* Application token. */
PORT_Assert(ss->xtnData.applicationToken.len == 0);
- rv = ssl3_ConsumeNumberFromItem(&ptItem, &appTokenLen, 2);
+ rv = sslRead_ReadNumber(&reader, 2, &appTokenLen);
if (rv != SECSuccess) {
FATAL_ERROR(ss, SSL_ERROR_RX_MALFORMED_CLIENT_HELLO, illegal_parameter);
return SECFailure;
@@ -137,15 +138,18 @@ tls13_RecoverHashState(sslSocket *ss,
return SECFailure;
}
ss->xtnData.applicationToken.len = appTokenLen;
- rv = ssl3_ConsumeFromItem(&ptItem, &appToken, appTokenLen);
+ sslReadBuffer appTokenReader = { 0 };
+ rv = sslRead_Read(&reader, appTokenLen, &appTokenReader);
if (rv != SECSuccess) {
FATAL_ERROR(ss, SSL_ERROR_RX_MALFORMED_CLIENT_HELLO, illegal_parameter);
return SECFailure;
}
- PORT_Memcpy(ss->xtnData.applicationToken.data, appToken, appTokenLen);
+ PORT_Assert(appTokenReader.len == appTokenLen);
+ PORT_Memcpy(ss->xtnData.applicationToken.data, appTokenReader.buf, appTokenLen);
/* The remainder is the hash. */
- if (ptItem.len != tls13_GetHashSize(ss)) {
+ unsigned int hashLen = SSL_READER_REMAINING(&reader);
+ if (hashLen != tls13_GetHashSize(ss)) {
FATAL_ERROR(ss, SSL_ERROR_RX_MALFORMED_CLIENT_HELLO, illegal_parameter);
return SECFailure;
}
@@ -153,7 +157,7 @@ tls13_RecoverHashState(sslSocket *ss,
/* Now reinject the message. */
SSL_ASSERT_HASHES_EMPTY(ss);
rv = ssl_HashHandshakeMessageInt(ss, ssl_hs_message_hash, 0,
- ptItem.data, ptItem.len);
+ SSL_READER_CURRENT(&reader), hashLen);
if (rv != SECSuccess) {
return SECFailure;
}