summaryrefslogtreecommitdiff
path: root/nss/lib/ssl
diff options
context:
space:
mode:
authorLorry Tar Creator <lorry-tar-importer@lorry>2017-06-08 10:53:01 +0000
committerLorry Tar Creator <lorry-tar-importer@lorry>2017-06-08 10:53:01 +0000
commitf95d45c36e7c7131747259956821d844e8952e5d (patch)
treeeee14f8b212c48f8597c2a4927a167fcc3a15ea5 /nss/lib/ssl
parentdc1565216a5d20ae0d75872151523252309a1292 (diff)
downloadnss-f95d45c36e7c7131747259956821d844e8952e5d.tar.gz
Diffstat (limited to 'nss/lib/ssl')
-rw-r--r--nss/lib/ssl/SSLerrs.h8
-rw-r--r--nss/lib/ssl/config.mk4
-rw-r--r--nss/lib/ssl/dtlscon.c58
-rw-r--r--nss/lib/ssl/ssl.def13
-rw-r--r--nss/lib/ssl/ssl.gyp4
-rw-r--r--nss/lib/ssl/ssl.h43
-rw-r--r--nss/lib/ssl/ssl3con.c721
-rw-r--r--nss/lib/ssl/ssl3ecc.c45
-rw-r--r--nss/lib/ssl/ssl3ext.c34
-rw-r--r--nss/lib/ssl/ssl3ext.h17
-rw-r--r--nss/lib/ssl/ssl3exthandle.c1126
-rw-r--r--nss/lib/ssl/ssl3exthandle.h3
-rw-r--r--nss/lib/ssl/ssl3gthr.c31
-rw-r--r--nss/lib/ssl/ssl3prot.h13
-rw-r--r--nss/lib/ssl/sslcert.c785
-rw-r--r--nss/lib/ssl/sslcert.h41
-rw-r--r--nss/lib/ssl/ssldef.c2
-rw-r--r--nss/lib/ssl/sslerr.h2
-rw-r--r--nss/lib/ssl/sslimpl.h114
-rw-r--r--nss/lib/ssl/sslinfo.c27
-rw-r--r--nss/lib/ssl/sslmutex.c3
-rw-r--r--nss/lib/ssl/sslmutex.h3
-rw-r--r--nss/lib/ssl/sslnonce.c16
-rw-r--r--nss/lib/ssl/sslsecur.c77
-rw-r--r--nss/lib/ssl/sslsnce.c472
-rw-r--r--nss/lib/ssl/sslsock.c284
-rw-r--r--nss/lib/ssl/sslt.h24
-rw-r--r--nss/lib/ssl/tls13con.c278
-rw-r--r--nss/lib/ssl/tls13con.h1
-rw-r--r--nss/lib/ssl/tls13exthandle.c74
30 files changed, 2388 insertions, 1935 deletions
diff --git a/nss/lib/ssl/SSLerrs.h b/nss/lib/ssl/SSLerrs.h
index b0319b8..b73fb6b 100644
--- a/nss/lib/ssl/SSLerrs.h
+++ b/nss/lib/ssl/SSLerrs.h
@@ -504,4 +504,10 @@ ER3(SSL_ERROR_MALFORMED_PSK_KEY_EXCHANGE_MODES, (SSL_ERROR_BASE + 158),
"SSL received a malformed PSK key exchange modes extension.")
ER3(SSL_ERROR_MISSING_PSK_KEY_EXCHANGE_MODES, (SSL_ERROR_BASE + 159),
- "SSL expected a missing PSK key exchange modes extension.")
+ "SSL expected a PSK key exchange modes extension.")
+
+ER3(SSL_ERROR_DOWNGRADE_WITH_EARLY_DATA, (SSL_ERROR_BASE + 160),
+ "SSL got a pre-TLS 1.3 version even though we sent early data.")
+
+ER3(SSL_ERROR_TOO_MUCH_EARLY_DATA, (SSL_ERROR_BASE + 161),
+ "SSL received more early data than permitted.")
diff --git a/nss/lib/ssl/config.mk b/nss/lib/ssl/config.mk
index 339cc80..c8b053c 100644
--- a/nss/lib/ssl/config.mk
+++ b/nss/lib/ssl/config.mk
@@ -62,10 +62,6 @@ DEFINES += -DNSS_SSL_ENABLE_ZLIB
include $(CORE_DEPTH)/coreconf/zlib.mk
endif
-ifndef NSS_ENABLE_TLS_1_3
-NSS_DISABLE_TLS_1_3=1
-endif
-
ifdef NSS_DISABLE_TLS_1_3
DEFINES += -DNSS_DISABLE_TLS_1_3
endif
diff --git a/nss/lib/ssl/dtlscon.c b/nss/lib/ssl/dtlscon.c
index 09ceeac..b33dc2a 100644
--- a/nss/lib/ssl/dtlscon.c
+++ b/nss/lib/ssl/dtlscon.c
@@ -235,6 +235,26 @@ dtls_RetransmitDetected(sslSocket *ss)
return rv;
}
+static SECStatus
+dtls_HandleHandshakeMessage(sslSocket *ss, SSL3Opaque *data, PRBool last)
+{
+
+ /* At this point we are advancing our state machine, so we can free our last
+ * flight of messages. */
+ dtls_FreeHandshakeMessages(&ss->ssl3.hs.lastMessageFlight);
+ ss->ssl3.hs.recvdHighWater = -1;
+
+ /* Reset the timer to the initial value if the retry counter
+ * is 0, per Sec. 4.2.4.1 */
+ dtls_CancelTimer(ss);
+ if (ss->ssl3.hs.rtRetries == 0) {
+ ss->ssl3.hs.rtTimeoutMs = DTLS_RETRANSMIT_INITIAL_MS;
+ }
+
+ return ssl3_HandleHandshakeMessage(ss, data, ss->ssl3.hs.msg_len,
+ last);
+}
+
/* Called only from ssl3_HandleRecord, for each (deciphered) DTLS record.
* origBuf is the decrypted ssl record content and is expected to contain
* complete handshake records
@@ -329,23 +349,10 @@ dtls_HandleHandshake(sslSocket *ss, sslBuffer *origBuf)
ss->ssl3.hs.msg_type = (SSL3HandshakeType)type;
ss->ssl3.hs.msg_len = message_length;
- /* At this point we are advancing our state machine, so
- * we can free our last flight of messages */
- dtls_FreeHandshakeMessages(&ss->ssl3.hs.lastMessageFlight);
- ss->ssl3.hs.recvdHighWater = -1;
- dtls_CancelTimer(ss);
-
- /* Reset the timer to the initial value if the retry counter
- * is 0, per Sec. 4.2.4.1 */
- if (ss->ssl3.hs.rtRetries == 0) {
- ss->ssl3.hs.rtTimeoutMs = DTLS_RETRANSMIT_INITIAL_MS;
- }
-
- rv = ssl3_HandleHandshakeMessage(ss, buf.buf, ss->ssl3.hs.msg_len,
+ rv = dtls_HandleHandshakeMessage(ss, buf.buf,
buf.len == fragment_length);
if (rv == SECFailure) {
- /* Do not attempt to process rest of messages in this record */
- break;
+ break; /* Discard the remainder of the record. */
}
} else {
if (message_seq < ss->ssl3.hs.recvMessageSeq) {
@@ -446,24 +453,11 @@ dtls_HandleHandshake(sslSocket *ss, sslBuffer *origBuf)
/* If we have all the bytes, then we are good to go */
if (ss->ssl3.hs.recvdHighWater == ss->ssl3.hs.msg_len) {
- ss->ssl3.hs.recvdHighWater = -1;
+ rv = dtls_HandleHandshakeMessage(ss, ss->ssl3.hs.msg_body.buf,
+ buf.len == fragment_length);
- rv = ssl3_HandleHandshakeMessage(
- ss,
- ss->ssl3.hs.msg_body.buf, ss->ssl3.hs.msg_len,
- buf.len == fragment_length);
- if (rv == SECFailure)
- break; /* Skip rest of record */
-
- /* At this point we are advancing our state machine, so
- * we can free our last flight of messages */
- dtls_FreeHandshakeMessages(&ss->ssl3.hs.lastMessageFlight);
- dtls_CancelTimer(ss);
-
- /* If there have been no retries this time, reset the
- * timer value to the default per Section 4.2.4.1 */
- if (ss->ssl3.hs.rtRetries == 0) {
- ss->ssl3.hs.rtTimeoutMs = DTLS_RETRANSMIT_INITIAL_MS;
+ if (rv == SECFailure) {
+ break; /* Discard the rest of the record. */
}
}
}
diff --git a/nss/lib/ssl/ssl.def b/nss/lib/ssl/ssl.def
index 6aa8b64..94d3042 100644
--- a/nss/lib/ssl/ssl.def
+++ b/nss/lib/ssl/ssl.def
@@ -221,3 +221,16 @@ SSL_SignatureSchemePrefGet;
;+ local:
;+*;
;+};
+;+NSS_3.30 { # NSS 3.30 release
+;+ global:
+SSL_SetSessionTicketKeyPair;
+;+ local:
+;+*;
+;+};
+;+NSS_3.30.0.1 { # Additional symbols for NSS 3.30 release
+;+ global:
+SSL_AlertReceivedCallback;
+SSL_AlertSentCallback;
+;+ local:
+;+*;
+;+};
diff --git a/nss/lib/ssl/ssl.gyp b/nss/lib/ssl/ssl.gyp
index 0306ab6..175d1ce 100644
--- a/nss/lib/ssl/ssl.gyp
+++ b/nss/lib/ssl/ssl.gyp
@@ -63,7 +63,7 @@
'NSS_SSL_ENABLE_ZLIB',
],
}],
- [ 'fuzz==1', {
+ [ 'fuzz_tls==1', {
'defines': [
'UNSAFE_FUZZER_MODE',
],
@@ -71,7 +71,6 @@
],
'dependencies': [
'<(DEPTH)/exports.gyp:nss_exports',
- '<(DEPTH)/lib/freebl/freebl.gyp:freebl',
],
},
{
@@ -81,6 +80,7 @@
'ssl',
'<(DEPTH)/lib/nss/nss.gyp:nss3',
'<(DEPTH)/lib/util/util.gyp:nssutil3',
+ '<(DEPTH)/lib/freebl/freebl.gyp:freebl',
],
'variables': {
'mapfile': 'ssl.def'
diff --git a/nss/lib/ssl/ssl.h b/nss/lib/ssl/ssl.h
index b4af0e1..f19c2de 100644
--- a/nss/lib/ssl/ssl.h
+++ b/nss/lib/ssl/ssl.h
@@ -228,7 +228,7 @@ SSL_IMPORT PRFileDesc *DTLS_ImportFD(PRFileDesc *model, PRFileDesc *fd);
* on the server to read that data. Calls to
* SSL_GetPreliminaryChannelInfo() and SSL_GetNextProto()
* can be made used during this period to learn about the channel
- * parameters [TODO(ekr@rtfm.com): This hasn't landed yet].
+ * parameters.
*
* The transition between the 0-RTT and 1-RTT modes is marked by the
* handshake callback.
@@ -356,10 +356,11 @@ SSL_IMPORT SECStatus SSL_CipherPolicyGet(PRInt32 cipher, PRInt32 *policy);
** that is compatible with both its certificate and its peer's supported
** values.
**
-** NSS uses the strict signature schemes from TLS 1.3 in TLS 1.2. That means
-** that if a peer indicates support for SHA-384 and ECDSA, NSS will not
-** generate a signature if it has a P-256 key, even though that is permitted in
-** TLS 1.2.
+** This configuration affects TLS 1.2, but the combination of EC group and hash
+** algorithm is interpreted loosely to be compatible with other implementations.
+** For TLS 1.2, NSS will ignore the curve group when generating or verifying
+** ECDSA signatures. For example, a P-384 ECDSA certificate is used with
+** SHA-256 if ssl_sig_ecdsa_secp256r1_sha256 is enabled.
**
** Omitting SHA-256 schemes from this list might be foolish. Support is
** mandatory in TLS 1.2 and 1.3 and there might be interoperability issues.
@@ -819,6 +820,25 @@ SSL_IMPORT PRFileDesc *SSL_ReconfigFD(PRFileDesc *model, PRFileDesc *fd);
SSL_IMPORT SECStatus SSL_SetPKCS11PinArg(PRFileDesc *fd, void *a);
/*
+** These are callbacks for dealing with SSL alerts.
+ */
+
+typedef PRUint8 SSLAlertLevel;
+typedef PRUint8 SSLAlertDescription;
+
+typedef struct {
+ SSLAlertLevel level;
+ SSLAlertDescription description;
+} SSLAlert;
+
+typedef void(PR_CALLBACK *SSLAlertCallback)(const PRFileDesc *fd, void *arg,
+ const SSLAlert *alert);
+
+SSL_IMPORT SECStatus SSL_AlertReceivedCallback(PRFileDesc *fd, SSLAlertCallback cb,
+ void *arg);
+SSL_IMPORT SECStatus SSL_AlertSentCallback(PRFileDesc *fd, SSLAlertCallback cb,
+ void *arg);
+/*
** This is a callback for dealing with server certs that are not authenticated
** by the client. The client app can decide that it actually likes the
** cert by some external means and restart the connection.
@@ -914,6 +934,19 @@ SSL_ConfigSecureServerWithCertChain(PRFileDesc *fd, CERTCertificate *cert,
SECKEYPrivateKey *key, SSLKEAType kea);
/*
+** SSL_SetSessionTicketKeyPair configures an asymmetric key pair for use in
+** wrapping session ticket keys, used by the server. This function currently
+** only accepts an RSA public/private key pair.
+**
+** Prior to the existence of this function, NSS used an RSA private key
+** associated with a configured certificate to perform session ticket
+** encryption. If this function isn't used, the keys provided with a configured
+** RSA certificate are used for wrapping session ticket keys.
+*/
+SSL_IMPORT SECStatus
+SSL_SetSessionTicketKeyPair(SECKEYPublicKey *pubKey, SECKEYPrivateKey *privKey);
+
+/*
** Configure a secure server's session-id cache. Define the maximum number
** of entries in the cache, the longevity of the entires, and the directory
** where the cache files will be placed. These values can be zero, and
diff --git a/nss/lib/ssl/ssl3con.c b/nss/lib/ssl/ssl3con.c
index 154d22a..5d3bd07 100644
--- a/nss/lib/ssl/ssl3con.c
+++ b/nss/lib/ssl/ssl3con.c
@@ -38,13 +38,6 @@
#include "zlib.h"
#endif
-#ifndef PK11_SETATTRS
-#define PK11_SETATTRS(x, id, v, l) \
- (x)->type = (id); \
- (x)->pValue = (v); \
- (x)->ulValueLen = (l);
-#endif
-
static PK11SymKey *ssl3_GenerateRSAPMS(sslSocket *ss, ssl3CipherSpec *spec,
PK11SlotInfo *serverKeySlot);
static SECStatus ssl3_DeriveMasterSecret(sslSocket *ss, PK11SymKey *pms);
@@ -273,10 +266,6 @@ static const /*SSL3ClientCertificateType */ PRUint8 certificate_types[] = {
ct_DSS_sign,
};
-/* This global item is used only in servers. It is is initialized by
-** SSL_ConfigSecureServer(), and is used in ssl3_SendCertificateRequest().
-*/
-CERTDistNames *ssl3_server_ca_list = NULL;
static SSL3Statistics ssl3stats;
/* Record protection algorithms, indexed by SSL3BulkCipher.
@@ -863,12 +852,10 @@ ssl_HasCert(const sslSocket *ss, SSLAuthType authType)
cursor != &ss->serverCerts;
cursor = PR_NEXT_LINK(cursor)) {
sslServerCert *cert = (sslServerCert *)cursor;
- if (cert->certType.authType != authType) {
- continue;
- }
if (!cert->serverKeyPair ||
!cert->serverKeyPair->privKey ||
- !cert->serverCertChain) {
+ !cert->serverCertChain ||
+ !SSL_CERT_IS(cert, authType)) {
continue;
}
/* When called from ssl3_config_match_init(), all the EC curves will be
@@ -879,7 +866,7 @@ ssl_HasCert(const sslSocket *ss, SSLAuthType authType)
if ((authType == ssl_auth_ecdsa ||
authType == ssl_auth_ecdh_ecdsa ||
authType == ssl_auth_ecdh_rsa) &&
- !ssl_NamedGroupEnabled(ss, cert->certType.namedCurve)) {
+ !ssl_NamedGroupEnabled(ss, cert->namedCurve)) {
continue;
}
return PR_TRUE;
@@ -1044,8 +1031,9 @@ Null_Cipher(void *ctx, unsigned char *output, int *outputLen, int maxOutputLen,
return SECFailure;
}
*outputLen = inputLen;
- if (input != output)
+ if (inputLen > 0 && input != output) {
PORT_Memcpy(output, input, inputLen);
+ }
return SECSuccess;
}
@@ -1088,10 +1076,11 @@ ssl_ClientReadVersion(sslSocket *ss, SSL3Opaque **b, unsigned int *len,
SSL3ProtocolVersion *version)
{
SSL3ProtocolVersion v;
- PRInt32 temp;
+ PRUint32 temp;
+ SECStatus rv;
- temp = ssl3_ConsumeHandshakeNumber(ss, 2, b, len);
- if (temp < 0) {
+ rv = ssl3_ConsumeHandshakeNumber(ss, &temp, 2, b, len);
+ if (rv != SECSuccess) {
return SECFailure; /* alert has been sent */
}
@@ -1624,10 +1613,6 @@ ssl3_SetupPendingCipherSpec(sslSocket *ss)
pwSpec->compressContext = NULL;
pwSpec->decompressContext = NULL;
- if (ss->version >= SSL_LIBRARY_VERSION_TLS_1_3) {
- PORT_Assert(ss->ssl3.hs.kea_def->ephemeral);
- PORT_Assert(pwSpec->cipher_def->type == type_aead);
- }
ssl_ReleaseSpecWriteLock(ss); /*******************************/
return SECSuccess;
}
@@ -1777,29 +1762,6 @@ ssl3_InitCompressionContext(ssl3CipherSpec *pwSpec)
return SECSuccess;
}
-/* This function should probably be moved to pk11wrap and be named
- * PK11_ParamFromIVAndEffectiveKeyBits
- */
-static SECItem *
-ssl3_ParamFromIV(CK_MECHANISM_TYPE mtype, SECItem *iv, CK_ULONG ulEffectiveBits)
-{
- SECItem *param = PK11_ParamFromIV(mtype, iv);
- if (param && param->data && param->len >= sizeof(CK_RC2_PARAMS)) {
- switch (mtype) {
- case CKM_RC2_KEY_GEN:
- case CKM_RC2_ECB:
- case CKM_RC2_CBC:
- case CKM_RC2_MAC:
- case CKM_RC2_MAC_GENERAL:
- case CKM_RC2_CBC_PAD:
- *(CK_RC2_PARAMS *)param->data = ulEffectiveBits;
- default:
- break;
- }
- }
- return param;
-}
-
/* ssl3_BuildRecordPseudoHeader writes the SSL/TLS pseudo-header (the data
* which is included in the MAC or AEAD additional data) to |out| and returns
* its length. See https://tools.ietf.org/html/rfc5246#section-6.2.3.3 for the
@@ -1981,7 +1943,6 @@ ssl3_InitPendingContexts(sslSocket *ss)
CK_MECHANISM_TYPE mechanism;
CK_MECHANISM_TYPE mac_mech;
CK_ULONG macLength;
- CK_ULONG effKeyBits;
SECItem iv;
SECItem mac_param;
SSLCipherAlgorithm calg;
@@ -2051,14 +2012,13 @@ ssl3_InitPendingContexts(sslSocket *ss)
return SECSuccess;
}
mechanism = ssl3_Alg2Mech(calg);
- effKeyBits = cipher_def->key_size * BPB;
/*
* build the server context
*/
iv.data = pwSpec->server.write_iv;
iv.len = cipher_def->iv_size;
- param = ssl3_ParamFromIV(mechanism, &iv, effKeyBits);
+ param = PK11_ParamFromIV(mechanism, &iv);
if (param == NULL) {
ssl_MapLowLevelError(SSL_ERROR_IV_PARAM_FAILURE);
goto fail;
@@ -2082,7 +2042,7 @@ ssl3_InitPendingContexts(sslSocket *ss)
iv.data = pwSpec->client.write_iv;
iv.len = cipher_def->iv_size;
- param = ssl3_ParamFromIV(mechanism, &iv, effKeyBits);
+ param = PK11_ParamFromIV(mechanism, &iv);
if (param == NULL) {
ssl_MapLowLevelError(SSL_ERROR_IV_PARAM_FAILURE);
goto fail;
@@ -2702,6 +2662,7 @@ ssl3_SendRecord(sslSocket *ss,
SECStatus rv;
PRInt32 totalSent = 0;
PRBool capRecordVersion;
+ ssl3CipherSpec *spec;
SSL_TRC(3, ("%d: SSL3[%d] SendRecord type: %s nIn=%d",
SSL_GETPID(), ss->fd, ssl3_DecodeContentType(type),
@@ -2733,10 +2694,7 @@ ssl3_SendRecord(sslSocket *ss,
** trying to send an alert.
*/
PR_ASSERT(type == content_alert);
- rv = ssl3_InitState(ss);
- if (rv != SECSuccess) {
- return SECFailure; /* ssl3_InitState has set the error code. */
- }
+ ssl3_InitState(ss);
}
/* check for Token Presence */
@@ -2806,11 +2764,12 @@ ssl3_SendRecord(sslSocket *ss,
PORT_Assert(IS_DTLS(ss) &&
(type == content_handshake ||
type == content_change_cipher_spec));
+ spec = cwSpec;
} else {
- cwSpec = ss->ssl3.cwSpec;
+ spec = ss->ssl3.cwSpec;
}
- rv = ssl_ProtectRecord(ss, cwSpec, !IS_DTLS(ss) && capRecordVersion,
+ rv = ssl_ProtectRecord(ss, spec, !IS_DTLS(ss) && capRecordVersion,
type, pIn, contentLen, wrBuf);
if (rv == SECSuccess) {
PRINT_BUF(50, (ss, "send (encrypted) record data:",
@@ -2941,6 +2900,7 @@ ssl3_SendApplicationData(sslSocket *ss, const unsigned char *in,
ssl_GetXmitBufLock(ss);
}
toSend = PR_MIN(len - totalSent, MAX_FRAGMENT_LENGTH);
+
/*
* Note that the 0 epoch is OK because flags will never require
* its use, as guaranteed by the PORT_Assert above.
@@ -3077,7 +3037,9 @@ ssl3_HandleNoCertificate(sslSocket *ss)
(ss->opt.requireCertificate == SSL_REQUIRE_FIRST_HANDSHAKE))) {
PRFileDesc *lower;
- ss->sec.uncache(ss->sec.ci.sid);
+ if (!ss->opt.noCache) {
+ ss->sec.uncache(ss->sec.ci.sid);
+ }
SSL3_SendAlert(ss, alert_fatal, bad_certificate);
lower = ss->fd->lower;
@@ -3124,6 +3086,10 @@ SSL3_SendAlert(sslSocket *ss, SSL3AlertLevel level, SSL3AlertDescription desc)
{
PRUint8 bytes[2];
SECStatus rv;
+ PRBool needHsLock = !ssl_HaveSSL3HandshakeLock(ss);
+
+ /* Check that if I need the HS lock I also need the Xmit lock */
+ PORT_Assert(!needHsLock || !ssl_HaveXmitBufLock(ss));
SSL_TRC(3, ("%d: SSL3[%d]: send alert record, level=%d desc=%d",
SSL_GETPID(), ss->fd, level, desc));
@@ -3131,7 +3097,9 @@ SSL3_SendAlert(sslSocket *ss, SSL3AlertLevel level, SSL3AlertDescription desc)
bytes[0] = level;
bytes[1] = desc;
- ssl_GetSSL3HandshakeLock(ss);
+ if (needHsLock) {
+ ssl_GetSSL3HandshakeLock(ss);
+ }
if (level == alert_fatal) {
if (!ss->opt.noCache && ss->sec.ci.sid) {
ss->sec.uncache(ss->sec.ci.sid);
@@ -3149,7 +3117,13 @@ SSL3_SendAlert(sslSocket *ss, SSL3AlertLevel level, SSL3AlertDescription desc)
ss->ssl3.fatalAlertSent = PR_TRUE;
}
ssl_ReleaseXmitBufLock(ss);
- ssl_ReleaseSSL3HandshakeLock(ss);
+ if (needHsLock) {
+ ssl_ReleaseSSL3HandshakeLock(ss);
+ }
+ if (rv == SECSuccess && ss->alertSentCallback) {
+ SSLAlert alert = { level, desc };
+ ss->alertSentCallback(ss->fd, ss->alertSentCallbackArg, &alert);
+ }
return rv; /* error set by ssl3_FlushHandshake or ssl3_SendRecord */
}
@@ -3262,6 +3236,11 @@ ssl3_HandleAlert(sslSocket *ss, sslBuffer *buf)
SSL_TRC(5, ("%d: SSL3[%d] received alert, level = %d, description = %d",
SSL_GETPID(), ss->fd, level, desc));
+ if (ss->alertReceivedCallback) {
+ SSLAlert alert = { level, desc };
+ ss->alertReceivedCallback(ss->fd, ss->alertReceivedCallbackArg, &alert);
+ }
+
switch (desc) {
case close_notify:
ss->recvdCloseNotify = 1;
@@ -4088,11 +4067,9 @@ ssl3_InitHandshakeHashes(sslSocket *ss)
return SECSuccess;
}
-SECStatus
+void
ssl3_RestartHandshakeHashes(sslSocket *ss)
{
- SECStatus rv = SECSuccess;
-
SSL_TRC(30, ("%d: SSL3[%d]: reset handshake hashes",
SSL_GETPID(), ss->fd));
ss->ssl3.hs.hashType = handshake_hash_unknown;
@@ -4105,7 +4082,6 @@ ssl3_RestartHandshakeHashes(sslSocket *ss)
PK11_DestroyContext(ss->ssl3.hs.sha, PR_TRUE);
ss->ssl3.hs.sha = NULL;
}
- return rv;
}
/*
@@ -4330,7 +4306,7 @@ ssl3_AppendHandshakeHeader(sslSocket *ss, SSL3HandshakeType t, PRUint32 length)
* override the generic error code by setting another.
*/
SECStatus
-ssl3_ConsumeHandshake(sslSocket *ss, void *v, PRInt32 bytes, SSL3Opaque **b,
+ssl3_ConsumeHandshake(sslSocket *ss, void *v, PRUint32 bytes, SSL3Opaque **b,
PRUint32 *length)
{
PORT_Assert(ss->opt.noLocks || ssl_HaveRecvBufLock(ss));
@@ -4348,37 +4324,33 @@ ssl3_ConsumeHandshake(sslSocket *ss, void *v, PRInt32 bytes, SSL3Opaque **b,
/* Read up the next "bytes" number of bytes from the (decrypted) input
* stream "b" (which is *length bytes long), and interpret them as an
- * integer in network byte order. Returns the received value.
+ * integer in network byte order. Sets *num to the received value.
* Reduces *length by bytes. Advances *b by bytes.
*
- * Returns SECFailure (-1) on failure.
- * This value is indistinguishable from the equivalent received value.
- * Only positive numbers are to be received this way.
- * Thus, the largest value that may be sent this way is 0x7fffffff.
* On error, an alert has been sent, and a generic error code has been set.
*/
-PRInt32
-ssl3_ConsumeHandshakeNumber(sslSocket *ss, PRInt32 bytes, SSL3Opaque **b,
- PRUint32 *length)
+SECStatus
+ssl3_ConsumeHandshakeNumber(sslSocket *ss, PRUint32 *num, PRUint32 bytes,
+ SSL3Opaque **b, PRUint32 *length)
{
PRUint8 *buf = *b;
int i;
- PRInt32 num = 0;
PORT_Assert(ss->opt.noLocks || ssl_HaveRecvBufLock(ss));
PORT_Assert(ss->opt.noLocks || ssl_HaveSSL3HandshakeLock(ss));
- PORT_Assert(bytes <= sizeof num);
- if ((PRUint32)bytes > *length) {
+ *num = 0;
+ if (bytes > *length || bytes > sizeof(*num)) {
return ssl3_DecodeError(ss);
}
PRINT_BUF(60, (ss, "consume bytes:", *b, bytes));
- for (i = 0; i < bytes; i++)
- num = (num << 8) + buf[i];
+ for (i = 0; i < bytes; i++) {
+ *num = (*num << 8) + buf[i];
+ }
*b += bytes;
*length -= bytes;
- return num;
+ return SECSuccess;
}
/* Read in two values from the incoming decrypted byte stream "b", which is
@@ -4396,21 +4368,22 @@ ssl3_ConsumeHandshakeNumber(sslSocket *ss, PRInt32 bytes, SSL3Opaque **b,
* point to the values in the buffer **b.
*/
SECStatus
-ssl3_ConsumeHandshakeVariable(sslSocket *ss, SECItem *i, PRInt32 bytes,
+ssl3_ConsumeHandshakeVariable(sslSocket *ss, SECItem *i, PRUint32 bytes,
SSL3Opaque **b, PRUint32 *length)
{
- PRInt32 count;
+ PRUint32 count;
+ SECStatus rv;
PORT_Assert(bytes <= 3);
i->len = 0;
i->data = NULL;
i->type = siBuffer;
- count = ssl3_ConsumeHandshakeNumber(ss, bytes, b, length);
- if (count < 0) { /* Can't test for SECSuccess here. */
+ rv = ssl3_ConsumeHandshakeNumber(ss, &count, bytes, b, length);
+ if (rv != SECSuccess) {
return SECFailure;
}
if (count > 0) {
- if ((PRUint32)count > *length) {
+ if (count > *length) {
return ssl3_DecodeError(ss);
}
i->data = *b;
@@ -4681,10 +4654,11 @@ SECStatus
ssl_ConsumeSignatureScheme(sslSocket *ss, SSL3Opaque **b,
PRUint32 *length, SSLSignatureScheme *out)
{
- PRInt32 tmp;
+ PRUint32 tmp;
+ SECStatus rv;
- tmp = ssl3_ConsumeHandshakeNumber(ss, 2, b, length);
- if (tmp < 0) {
+ rv = ssl3_ConsumeHandshakeNumber(ss, &tmp, 2, b, length);
+ if (rv != SECSuccess) {
return SECFailure; /* Error code set already. */
}
if (!ssl_IsSupportedSignatureScheme((SSLSignatureScheme)tmp)) {
@@ -4990,7 +4964,6 @@ ssl3_SendClientHello(sslSocket *ss, sslClientHelloType type)
PRBool isTLS = PR_FALSE;
PRBool requestingResume = PR_FALSE, fallbackSCSV = PR_FALSE;
PRInt32 total_exten_len = 0;
- unsigned paddingExtensionLen;
unsigned numCompressionMethods;
PRUint16 version;
PRInt32 flags;
@@ -5013,15 +4986,8 @@ ssl3_SendClientHello(sslSocket *ss, sslClientHelloType type)
if (ss->ssl3.hs.helloRetry) {
PORT_Assert(type == client_hello_retry);
} else {
- rv = ssl3_InitState(ss);
- if (rv != SECSuccess) {
- return rv; /* ssl3_InitState has set the error code. */
- }
-
- rv = ssl3_RestartHandshakeHashes(ss);
- if (rv != SECSuccess) {
- return rv;
- }
+ ssl3_InitState(ss);
+ ssl3_RestartHandshakeHashes(ss);
}
/* These must be reset every handshake. */
@@ -5293,19 +5259,12 @@ ssl3_SendClientHello(sslSocket *ss, sslClientHelloType type)
length += 1 + ss->ssl3.hs.cookie.len;
}
- /* A padding extension may be included to ensure that the record containing
- * the ClientHello doesn't have a length between 256 and 511 bytes
- * (inclusive). Initial, ClientHello records with such lengths trigger bugs
- * in F5 devices.
- *
- * This is not done for DTLS, for renegotiation, or when there are no
- * extensions. */
- if (!IS_DTLS(ss) && isTLS && !ss->firstHsDone && total_exten_len) {
- paddingExtensionLen = ssl3_CalculatePaddingExtensionLength(length);
- total_exten_len += paddingExtensionLen;
- length += paddingExtensionLen;
- } else {
- paddingExtensionLen = 0;
+ if (total_exten_len > 0) {
+ ssl3_CalculatePaddingExtLen(ss, length);
+ if (ss->xtnData.paddingLen) {
+ total_exten_len += 4 + ss->xtnData.paddingLen;
+ length += 4 + ss->xtnData.paddingLen;
+ }
}
rv = ssl3_AppendHandshakeHeader(ss, client_hello, length);
@@ -5476,15 +5435,6 @@ ssl3_SendClientHello(sslSocket *ss, sslClientHelloType type)
return rv; /* err set by AppendHandshake. */
}
- extLen = ssl3_AppendPaddingExtension(ss, paddingExtensionLen, maxBytes);
- if (extLen < 0) {
- if (sid->u.ssl3.lock) {
- PR_RWLock_Unlock(sid->u.ssl3.lock);
- }
- return SECFailure;
- }
- maxBytes -= extLen;
-
extLen = ssl3_CallHelloExtensionSenders(ss, PR_TRUE, maxBytes, NULL);
if (extLen < 0) {
if (sid->u.ssl3.lock) {
@@ -5579,8 +5529,6 @@ ssl3_HandleHelloRequest(sslSocket *ss)
return rv;
}
-#define UNKNOWN_WRAP_MECHANISM 0x7fffffff
-
static const CK_MECHANISM_TYPE wrapMechanismList[SSL_NUM_WRAP_MECHS] = {
CKM_DES3_ECB,
CKM_CAST5_ECB,
@@ -5596,27 +5544,58 @@ static const CK_MECHANISM_TYPE wrapMechanismList[SSL_NUM_WRAP_MECHS] = {
CKM_SKIPJACK_CBC64,
CKM_AES_ECB,
CKM_CAMELLIA_ECB,
- CKM_SEED_ECB,
- UNKNOWN_WRAP_MECHANISM
+ CKM_SEED_ECB
};
-static int
-ssl_FindIndexByWrapMechanism(CK_MECHANISM_TYPE mech)
+static SECStatus
+ssl_FindIndexByWrapMechanism(CK_MECHANISM_TYPE mech, unsigned int *wrapMechIndex)
{
- const CK_MECHANISM_TYPE *pMech = wrapMechanismList;
+ unsigned int i;
+ for (i = 0; i < SSL_NUM_WRAP_MECHS; ++i) {
+ if (wrapMechanismList[i] == mech) {
+ *wrapMechIndex = i;
+ return SECSuccess;
+ }
+ }
+ PORT_Assert(0);
+ PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
+ return SECFailure;
+}
+
+/* Each process sharing the server session ID cache has its own array of SymKey
+ * pointers for the symmetric wrapping keys that are used to wrap the master
+ * secrets. There is one key for each authentication type. These Symkeys
+ * correspond to the wrapped SymKeys kept in the server session cache.
+ */
+const SSLAuthType ssl_wrap_key_auth_type[SSL_NUM_WRAP_KEYS] = {
+ ssl_auth_rsa_decrypt,
+ ssl_auth_rsa_sign,
+ ssl_auth_rsa_pss,
+ ssl_auth_ecdsa,
+ ssl_auth_ecdh_rsa,
+ ssl_auth_ecdh_ecdsa
+};
- while (mech != *pMech && *pMech != UNKNOWN_WRAP_MECHANISM) {
- ++pMech;
+static SECStatus
+ssl_FindIndexByWrapKey(const sslServerCert *serverCert, unsigned int *wrapKeyIndex)
+{
+ unsigned int i;
+ for (i = 0; i < SSL_NUM_WRAP_KEYS; ++i) {
+ if (SSL_CERT_IS(serverCert, ssl_wrap_key_auth_type[i])) {
+ *wrapKeyIndex = i;
+ return SECSuccess;
+ }
}
- return (*pMech == UNKNOWN_WRAP_MECHANISM) ? -1
- : (pMech - wrapMechanismList);
+ /* Can't assert here because we still get people using DSA certificates. */
+ PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
+ return SECFailure;
}
static PK11SymKey *
ssl_UnwrapSymWrappingKey(
SSLWrappedSymWrappingKey *pWswk,
SECKEYPrivateKey *svrPrivKey,
- SSLAuthType authType,
+ unsigned int wrapKeyIndex,
CK_MECHANISM_TYPE masterWrapMech,
void *pwArg)
{
@@ -5628,9 +5607,9 @@ ssl_UnwrapSymWrappingKey(
/* found the wrapping key on disk. */
PORT_Assert(pWswk->symWrapMechanism == masterWrapMech);
- PORT_Assert(pWswk->authType == authType);
+ PORT_Assert(pWswk->wrapKeyIndex == wrapKeyIndex);
if (pWswk->symWrapMechanism != masterWrapMech ||
- pWswk->authType != authType) {
+ pWswk->wrapKeyIndex != wrapKeyIndex) {
goto loser;
}
wrappedKey.type = siBuffer;
@@ -5638,7 +5617,7 @@ ssl_UnwrapSymWrappingKey(
wrappedKey.len = pWswk->wrappedSymKeyLen;
PORT_Assert(wrappedKey.len <= sizeof pWswk->wrappedSymmetricWrappingkey);
- switch (authType) {
+ switch (ssl_wrap_key_auth_type[wrapKeyIndex]) {
case ssl_auth_rsa_decrypt:
case ssl_auth_rsa_sign: /* bad: see Bug 1248320 */
@@ -5711,14 +5690,8 @@ loser:
return unwrappedWrappingKey;
}
-/* Each process sharing the server session ID cache has its own array of SymKey
- * pointers for the symmetric wrapping keys that are used to wrap the master
- * secrets. There is one key for each authentication type. These Symkeys
- * correspond to the wrapped SymKeys kept in the server session cache.
- */
-
typedef struct {
- PK11SymKey *symWrapKey[ssl_auth_size];
+ PK11SymKey *symWrapKey[SSL_NUM_WRAP_KEYS];
} ssl3SymWrapKey;
static PZLock *symWrapKeysLock = NULL;
@@ -5746,7 +5719,7 @@ SSL3_ShutdownServerCache(void)
PZ_Lock(symWrapKeysLock);
/* get rid of all symWrapKeys */
for (i = 0; i < SSL_NUM_WRAP_MECHS; ++i) {
- for (j = 0; j < ssl_auth_size; ++j) {
+ for (j = 0; j < SSL_NUM_WRAP_KEYS; ++j) {
PK11SymKey **pSymWrapKey;
pSymWrapKey = &symWrapKeys[i].symWrapKey[j];
if (*pSymWrapKey) {
@@ -5780,7 +5753,6 @@ ssl_InitSymWrapKeysLock(void)
PK11SymKey *
ssl3_GetWrappingKey(sslSocket *ss,
PK11SlotInfo *masterSecretSlot,
- const sslServerCert *serverCert,
CK_MECHANISM_TYPE masterWrapMech,
void *pwArg)
{
@@ -5791,7 +5763,8 @@ ssl3_GetWrappingKey(sslSocket *ss,
PK11SymKey **pSymWrapKey;
CK_MECHANISM_TYPE asymWrapMechanism = CKM_INVALID_MECHANISM;
int length;
- int symWrapMechIndex;
+ unsigned int wrapMechIndex;
+ unsigned int wrapKeyIndex;
SECStatus rv;
SECItem wrappedKey;
SSLWrappedSymWrappingKey wswk;
@@ -5799,6 +5772,7 @@ ssl3_GetWrappingKey(sslSocket *ss,
SECKEYPublicKey *pubWrapKey = NULL;
SECKEYPrivateKey *privWrapKey = NULL;
ECCWrappedKeyInfo *ecWrapped;
+ const sslServerCert *serverCert = ss->sec.serverCert;
PORT_Assert(serverCert);
PORT_Assert(serverCert->serverKeyPair);
@@ -5810,15 +5784,18 @@ ssl3_GetWrappingKey(sslSocket *ss,
PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
return NULL; /* hmm */
}
- authType = serverCert->certType.authType;
- svrPrivKey = serverCert->serverKeyPair->privKey;
- symWrapMechIndex = ssl_FindIndexByWrapMechanism(masterWrapMech);
- PORT_Assert(symWrapMechIndex >= 0);
- if (symWrapMechIndex < 0)
+ rv = ssl_FindIndexByWrapKey(serverCert, &wrapKeyIndex);
+ if (rv != SECSuccess)
+ return NULL; /* unusable wrapping key. */
+
+ rv = ssl_FindIndexByWrapMechanism(masterWrapMech, &wrapMechIndex);
+ if (rv != SECSuccess)
return NULL; /* invalid masterWrapMech. */
- pSymWrapKey = &symWrapKeys[symWrapMechIndex].symWrapKey[authType];
+ authType = ssl_wrap_key_auth_type[wrapKeyIndex];
+ svrPrivKey = serverCert->serverKeyPair->privKey;
+ pSymWrapKey = &symWrapKeys[wrapMechIndex].symWrapKey[wrapKeyIndex];
ssl_InitSessionCacheLocks(PR_TRUE);
@@ -5837,10 +5814,11 @@ ssl3_GetWrappingKey(sslSocket *ss,
/* Try to get wrapped SymWrapping key out of the (disk) cache. */
/* Following call fills in wswk on success. */
- if (ssl_GetWrappingKey(symWrapMechIndex, authType, &wswk)) {
+ rv = ssl_GetWrappingKey(wrapMechIndex, wrapKeyIndex, &wswk);
+ if (rv == SECSuccess) {
/* found the wrapped sym wrapping key on disk. */
unwrappedWrappingKey =
- ssl_UnwrapSymWrappingKey(&wswk, svrPrivKey, authType,
+ ssl_UnwrapSymWrappingKey(&wswk, svrPrivKey, wrapKeyIndex,
masterWrapMech, pwArg);
if (unwrappedWrappingKey) {
goto install;
@@ -5989,9 +5967,9 @@ ssl3_GetWrappingKey(sslSocket *ss,
PORT_Assert(asymWrapMechanism != CKM_INVALID_MECHANISM);
wswk.symWrapMechanism = masterWrapMech;
- wswk.symWrapMechIndex = symWrapMechIndex;
wswk.asymWrapMechanism = asymWrapMechanism;
- wswk.authType = authType;
+ wswk.wrapMechIndex = wrapMechIndex;
+ wswk.wrapKeyIndex = wrapKeyIndex;
wswk.wrappedSymKeyLen = wrappedKey.len;
/* put it on disk. */
@@ -5999,7 +5977,8 @@ ssl3_GetWrappingKey(sslSocket *ss,
* then abandon the value we just computed and
* use the one we got from the disk.
*/
- if (ssl_SetWrappingKey(&wswk)) {
+ rv = ssl_SetWrappingKey(&wswk);
+ if (rv == SECSuccess) {
/* somebody beat us to it. The original contents of our wswk
* has been replaced with the content on disk. Now, discard
* the key we just created and unwrap this new one.
@@ -6007,7 +5986,7 @@ ssl3_GetWrappingKey(sslSocket *ss,
PK11_FreeSymKey(unwrappedWrappingKey);
unwrappedWrappingKey =
- ssl_UnwrapSymWrappingKey(&wswk, svrPrivKey, authType,
+ ssl_UnwrapSymWrappingKey(&wswk, svrPrivKey, wrapKeyIndex,
masterWrapMech, pwArg);
}
@@ -6377,7 +6356,7 @@ ssl_PickSignatureScheme(sslSocket *ss,
PRUint32 policy;
if (!ssl_SignatureSchemeValidForKey(!isTLS13 /* allowSha1 */,
- PR_TRUE /* matchGroup */,
+ isTLS13 /* matchGroup */,
keyType, group, preferred)) {
continue;
}
@@ -6411,6 +6390,33 @@ ssl_PickSignatureScheme(sslSocket *ss,
return SECFailure;
}
+static SECStatus
+ssl_PickFallbackSignatureScheme(sslSocket *ss, SECKEYPublicKey *pubKey)
+{
+ PRBool isTLS12 = ss->version >= SSL_LIBRARY_VERSION_TLS_1_2;
+
+ switch (SECKEY_GetPublicKeyType(pubKey)) {
+ case rsaKey:
+ if (isTLS12) {
+ ss->ssl3.hs.signatureScheme = ssl_sig_rsa_pkcs1_sha1;
+ } else {
+ ss->ssl3.hs.signatureScheme = ssl_sig_rsa_pkcs1_sha1md5;
+ }
+ break;
+ case ecKey:
+ ss->ssl3.hs.signatureScheme = ssl_sig_ecdsa_sha1;
+ break;
+ case dsaKey:
+ ss->ssl3.hs.signatureScheme = ssl_sig_dsa_sha1;
+ break;
+ default:
+ PORT_Assert(0);
+ PORT_SetError(SEC_ERROR_INVALID_KEY);
+ return SECFailure;
+ }
+ return SECSuccess;
+}
+
/* ssl3_PickServerSignatureScheme selects a signature scheme for signing the
* handshake. Most of this is determined by the key pair we are using.
* Prior to TLS 1.2, the MD5/SHA1 combination is always used. With TLS 1.2, a
@@ -6424,26 +6430,7 @@ ssl3_PickServerSignatureScheme(sslSocket *ss)
if (!isTLS12 || !ssl3_ExtensionNegotiated(ss, ssl_signature_algorithms_xtn)) {
/* If the client didn't provide any signature_algorithms extension then
* we can assume that they support SHA-1: RFC5246, Section 7.4.1.4.1. */
- switch (SECKEY_GetPublicKeyType(keyPair->pubKey)) {
- case rsaKey:
- if (isTLS12) {
- ss->ssl3.hs.signatureScheme = ssl_sig_rsa_pkcs1_sha1;
- } else {
- ss->ssl3.hs.signatureScheme = ssl_sig_rsa_pkcs1_sha1md5;
- }
- break;
- case ecKey:
- ss->ssl3.hs.signatureScheme = ssl_sig_ecdsa_sha1;
- break;
- case dsaKey:
- ss->ssl3.hs.signatureScheme = ssl_sig_dsa_sha1;
- break;
- default:
- PORT_Assert(0);
- PORT_SetError(SEC_ERROR_INVALID_KEY);
- return SECFailure;
- }
- return SECSuccess;
+ return ssl_PickFallbackSignatureScheme(ss, keyPair->pubKey);
}
/* Sets error code, if needed. */
@@ -6461,9 +6448,21 @@ ssl_PickClientSignatureScheme(sslSocket *ss, const SSLSignatureScheme *schemes,
SECKEYPublicKey *pubKey;
SECStatus rv;
+ PRBool isTLS13 = (PRBool)ss->version >= SSL_LIBRARY_VERSION_TLS_1_3;
pubKey = CERT_ExtractPublicKey(ss->ssl3.clientCertificate);
PORT_Assert(pubKey);
- if (ss->version < SSL_LIBRARY_VERSION_TLS_1_3 &&
+
+ if (!isTLS13 && numSchemes == 0) {
+ /* If the server didn't provide any signature algorithms
+ * then let's assume they support SHA-1. */
+ rv = ssl_PickFallbackSignatureScheme(ss, pubKey);
+ SECKEY_DestroyPublicKey(pubKey);
+ return rv;
+ }
+
+ PORT_Assert(schemes && numSchemes > 0);
+
+ if (!isTLS13 &&
(SECKEY_GetPublicKeyType(pubKey) == rsaKey ||
SECKEY_GetPublicKeyType(pubKey) == dsaKey) &&
SECKEY_PublicKeyStrengthInBits(pubKey) <= 1024) {
@@ -6606,7 +6605,7 @@ ssl3_SetCipherSuite(sslSocket *ss, ssl3CipherSuite chosenSuite,
static SECStatus
ssl3_HandleServerHello(sslSocket *ss, SSL3Opaque *b, PRUint32 length)
{
- PRInt32 temp; /* allow for consume number failure */
+ PRUint32 temp;
PRBool suite_found = PR_FALSE;
int i;
int errCode = SSL_ERROR_RX_MALFORMED_SERVER_HELLO;
@@ -6649,11 +6648,21 @@ ssl3_HandleServerHello(sslSocket *ss, SSL3Opaque *b, PRUint32 length)
goto loser; /* alert has been sent */
}
- /* We got a HelloRetryRequest, but the server didn't pick 1.3. Scream. */
- if (ss->ssl3.hs.helloRetry && ss->version < SSL_LIBRARY_VERSION_TLS_1_3) {
- desc = illegal_parameter;
- errCode = SSL_ERROR_RX_MALFORMED_SERVER_HELLO;
- goto alert_loser;
+ /* The server didn't pick 1.3 although we either received a
+ * HelloRetryRequest, or we prepared to send early app data. */
+ if (ss->version < SSL_LIBRARY_VERSION_TLS_1_3) {
+ if (ss->ssl3.hs.helloRetry) {
+ /* SSL3_SendAlert() will uncache the SID. */
+ desc = illegal_parameter;
+ errCode = SSL_ERROR_RX_MALFORMED_SERVER_HELLO;
+ goto alert_loser;
+ }
+ if (ss->ssl3.hs.zeroRttState == ssl_0rtt_sent) {
+ /* SSL3_SendAlert() will uncache the SID. */
+ desc = illegal_parameter;
+ errCode = SSL_ERROR_DOWNGRADE_WITH_EARLY_DATA;
+ goto alert_loser;
+ }
}
/* Check that the server negotiated the same version as it did
@@ -6721,8 +6730,8 @@ ssl3_HandleServerHello(sslSocket *ss, SSL3Opaque *b, PRUint32 length)
}
/* find selected cipher suite in our list. */
- temp = ssl3_ConsumeHandshakeNumber(ss, 2, &b, &length);
- if (temp < 0) {
+ rv = ssl3_ConsumeHandshakeNumber(ss, &temp, 2, &b, &length);
+ if (rv != SECSuccess) {
goto loser; /* alert has been sent */
}
i = ssl3_config_match_init(ss);
@@ -6767,8 +6776,8 @@ ssl3_HandleServerHello(sslSocket *ss, SSL3Opaque *b, PRUint32 length)
if (ss->version < SSL_LIBRARY_VERSION_TLS_1_3) {
/* find selected compression method in our list. */
- temp = ssl3_ConsumeHandshakeNumber(ss, 1, &b, &length);
- if (temp < 0) {
+ rv = ssl3_ConsumeHandshakeNumber(ss, &temp, 1, &b, &length);
+ if (rv != SECSuccess) {
goto loser; /* alert has been sent */
}
suite_found = PR_FALSE;
@@ -7010,6 +7019,19 @@ ssl3_HandleServerHelloPart2(sslSocket *ss, const SECItem *sidBytes,
else
SSL_AtomicIncrementLong(&ssl3stats.hsh_sid_cache_misses);
+ /* We tried to resume a 1.3 session but the server negotiated 1.2. */
+ if (ss->statelessResume) {
+ PORT_Assert(sid->version == SSL_LIBRARY_VERSION_TLS_1_3);
+ PORT_Assert(ss->ssl3.hs.currentSecret);
+
+ /* Reset resumption state, only used by 1.3 code. */
+ ss->statelessResume = PR_FALSE;
+
+ /* Clear TLS 1.3 early data traffic key. */
+ PK11_FreeSymKey(ss->ssl3.hs.currentSecret);
+ ss->ssl3.hs.currentSecret = NULL;
+ }
+
/* throw the old one away */
sid->u.ssl3.keys.resumable = PR_FALSE;
ss->sec.uncache(sid);
@@ -7276,16 +7298,17 @@ SECStatus
ssl3_ParseCertificateRequestCAs(sslSocket *ss, SSL3Opaque **b, PRUint32 *length,
PLArenaPool *arena, CERTDistNames *ca_list)
{
- PRInt32 remaining;
+ PRUint32 remaining;
int nnames = 0;
dnameNode *node;
+ SECStatus rv;
int i;
- remaining = ssl3_ConsumeHandshakeNumber(ss, 2, b, length);
- if (remaining < 0)
+ rv = ssl3_ConsumeHandshakeNumber(ss, &remaining, 2, b, length);
+ if (rv != SECSuccess)
return SECFailure; /* malformed, alert has been sent */
- if ((PRUint32)remaining > *length)
+ if (remaining > *length)
goto alert_loser;
ca_list->head = node = PORT_ArenaZNew(arena, dnameNode);
@@ -7293,19 +7316,19 @@ ssl3_ParseCertificateRequestCAs(sslSocket *ss, SSL3Opaque **b, PRUint32 *length,
goto no_mem;
while (remaining > 0) {
- PRInt32 len;
+ PRUint32 len;
if (remaining < 2)
goto alert_loser; /* malformed */
- node->name.len = len = ssl3_ConsumeHandshakeNumber(ss, 2, b, length);
- if (len <= 0)
+ rv = ssl3_ConsumeHandshakeNumber(ss, &len, 2, b, length);
+ if (rv != SECSuccess)
return SECFailure; /* malformed, alert has been sent */
-
- remaining -= 2;
- if (remaining < len)
+ if (len == 0 || remaining < len + 2)
goto alert_loser; /* malformed */
+ remaining -= 2;
+ node->name.len = len;
node->name.data = *b;
*b += len;
*length -= len;
@@ -7353,7 +7376,7 @@ ssl_ParseSignatureSchemes(const sslSocket *ss, PLArenaPool *arena,
{
SECStatus rv;
SECItem buf;
- SSLSignatureScheme *schemes;
+ SSLSignatureScheme *schemes = NULL;
unsigned int numSchemes = 0;
unsigned int max;
@@ -7361,12 +7384,17 @@ ssl_ParseSignatureSchemes(const sslSocket *ss, PLArenaPool *arena,
if (rv != SECSuccess) {
return SECFailure;
}
- /* An empty or odd-length value is invalid. */
- if (buf.len == 0 || (buf.len & 1) != 0) {
+ /* An odd-length value is invalid. */
+ if ((buf.len & 1) != 0) {
ssl3_ExtSendAlert(ss, alert_fatal, decode_error);
return SECFailure;
}
+ /* Let the caller decide whether to alert here. */
+ if (buf.len == 0) {
+ goto done;
+ }
+
/* Limit the number of schemes we read. */
max = PR_MIN(buf.len / 2, MAX_SIGNATURE_SCHEMES);
@@ -7381,9 +7409,9 @@ ssl_ParseSignatureSchemes(const sslSocket *ss, PLArenaPool *arena,
}
for (; max; --max) {
- PRInt32 tmp;
- tmp = ssl3_ExtConsumeHandshakeNumber(ss, 2, &buf.data, &buf.len);
- if (tmp < 0) {
+ PRUint32 tmp;
+ rv = ssl3_ExtConsumeHandshakeNumber(ss, &tmp, 2, &buf.data, &buf.len);
+ if (rv != SECSuccess) {
PORT_Assert(0);
PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
return SECFailure;
@@ -7400,6 +7428,7 @@ ssl_ParseSignatureSchemes(const sslSocket *ss, PLArenaPool *arena,
schemes = NULL;
}
+done:
*schemesOut = schemes;
*numSchemesOut = numSchemes;
return SECSuccess;
@@ -8203,6 +8232,20 @@ ssl3_SelectServerCert(sslSocket *ss)
const ssl3KEADef *kea_def = ss->ssl3.hs.kea_def;
PRCList *cursor;
+ /* If the client didn't include the supported groups extension, assume just
+ * P-256 support and disable all the other ECDHE groups. This also affects
+ * ECDHE group selection, but this function is called first. */
+ if (!ssl3_ExtensionNegotiated(ss, ssl_supported_groups_xtn)) {
+ unsigned int i;
+ for (i = 0; i < SSL_NAMED_GROUP_COUNT; ++i) {
+ if (ss->namedGroupPreferences[i] &&
+ ss->namedGroupPreferences[i]->keaType == ssl_kea_ecdh &&
+ ss->namedGroupPreferences[i]->name != ssl_grp_ec_secp256r1) {
+ ss->namedGroupPreferences[i] = NULL;
+ }
+ }
+ }
+
/* This picks the first certificate that has:
* a) the right authentication method, and
* b) the right named curve (EC only)
@@ -8213,19 +8256,17 @@ ssl3_SelectServerCert(sslSocket *ss)
cursor != &ss->serverCerts;
cursor = PR_NEXT_LINK(cursor)) {
sslServerCert *cert = (sslServerCert *)cursor;
- if (cert->certType.authType != kea_def->authKeyType) {
+ if (!SSL_CERT_IS(cert, kea_def->authKeyType)) {
continue;
}
- if ((cert->certType.authType == ssl_auth_ecdsa ||
- cert->certType.authType == ssl_auth_ecdh_rsa ||
- cert->certType.authType == ssl_auth_ecdh_ecdsa) &&
- !ssl_NamedGroupEnabled(ss, cert->certType.namedCurve)) {
+ if (SSL_CERT_IS_EC(cert) &&
+ !ssl_NamedGroupEnabled(ss, cert->namedCurve)) {
continue;
}
/* Found one. */
ss->sec.serverCert = cert;
- ss->sec.authType = cert->certType.authType;
+ ss->sec.authType = kea_def->authKeyType;
ss->sec.authKeyBits = cert->serverKeyBits;
/* Don't pick a signature scheme if we aren't going to use it. */
@@ -8247,7 +8288,7 @@ static SECStatus
ssl3_HandleClientHello(sslSocket *ss, SSL3Opaque *b, PRUint32 length)
{
sslSessionID *sid = NULL;
- PRInt32 tmp;
+ PRUint32 tmp;
unsigned int i;
SECStatus rv;
int errCode = SSL_ERROR_RX_MALFORMED_CLIENT_HELLO;
@@ -8307,8 +8348,8 @@ ssl3_HandleClientHello(sslSocket *ss, SSL3Opaque *b, PRUint32 length)
dtls_RehandshakeCleanup(ss);
}
- tmp = ssl3_ConsumeHandshakeNumber(ss, 2, &b, &length);
- if (tmp < 0)
+ rv = ssl3_ConsumeHandshakeNumber(ss, &tmp, 2, &b, &length);
+ if (rv != SECSuccess)
goto loser; /* malformed, alert already sent */
/* Translate the version. */
@@ -8361,9 +8402,9 @@ ssl3_HandleClientHello(sslSocket *ss, SSL3Opaque *b, PRUint32 length)
if (length) {
/* Get length of hello extensions */
- PRInt32 extension_length;
- extension_length = ssl3_ConsumeHandshakeNumber(ss, 2, &b, &length);
- if (extension_length < 0) {
+ PRUint32 extension_length;
+ rv = ssl3_ConsumeHandshakeNumber(ss, &extension_length, 2, &b, &length);
+ if (rv != SECSuccess) {
goto loser; /* alert already sent */
}
if (extension_length != length) {
@@ -8465,7 +8506,7 @@ ssl3_HandleClientHello(sslSocket *ss, SSL3Opaque *b, PRUint32 length)
/* If the ClientHello version is less than our maximum version, check for a
* TLS_FALLBACK_SCSV and reject the connection if found. */
- if (ss->vrange.max > ss->clientHelloVersion) {
+ if (ss->vrange.max > ss->version) {
for (i = 0; i + 1 < suites.len; i += 2) {
PRUint16 suite_i = (suites.data[i] << 8) | suites.data[i + 1];
if (suite_i != TLS_FALLBACK_SCSV)
@@ -8749,7 +8790,6 @@ compression_found:
do {
ssl3CipherSpec *pwSpec;
SECItem wrappedMS; /* wrapped key */
- const sslServerCert *serverCert;
if (sid->version != ss->version ||
sid->u.ssl3.cipherSuite != ss->ssl3.hs.cipher_suite ||
@@ -8757,8 +8797,13 @@ compression_found:
break; /* not an error */
}
- serverCert = ssl_FindServerCert(ss, &sid->certType);
- if (!serverCert || !serverCert->serverCert) {
+ /* server sids don't remember the server cert we previously sent,
+ ** but they do remember the slot we originally used, so we
+ ** can locate it again, provided that the current ssl socket
+ ** has had its server certs configured the same as the previous one.
+ */
+ ss->sec.serverCert = ssl_FindServerCert(ss, sid->authType, sid->namedCurve);
+ if (!ss->sec.serverCert || !ss->sec.serverCert->serverCert) {
/* A compatible certificate must not have been configured. It
* might not be the same certificate, but we only find that out
* when the ticket fails to decrypt. */
@@ -8806,7 +8851,7 @@ compression_found:
PK11SymKey *wrapKey; /* wrapping key */
CK_FLAGS keyFlags = 0;
- wrapKey = ssl3_GetWrappingKey(ss, NULL, serverCert,
+ wrapKey = ssl3_GetWrappingKey(ss, NULL,
sid->u.ssl3.masterWrapMech,
ss->pkcs11PinArg);
if (!wrapKey) {
@@ -8865,13 +8910,8 @@ compression_found:
ss->sec.keaType = sid->keaType;
ss->sec.keaKeyBits = sid->keaKeyBits;
- /* server sids don't remember the server cert we previously sent,
- ** but they do remember the slot we originally used, so we
- ** can locate it again, provided that the current ssl socket
- ** has had its server certs configured the same as the previous one.
- */
- ss->sec.serverCert = serverCert;
- ss->sec.localCert = CERT_DupCertificate(serverCert->serverCert);
+ ss->sec.localCert =
+ CERT_DupCertificate(ss->sec.serverCert->serverCert);
/* Copy cached name in to pending spec */
if (sid != NULL &&
@@ -9063,16 +9103,8 @@ ssl3_HandleV2ClientHello(sslSocket *ss, unsigned char *buffer, int length,
goto loser;
}
- rv = ssl3_InitState(ss);
- if (rv != SECSuccess) {
- ssl_ReleaseSSL3HandshakeLock(ss);
- return rv; /* ssl3_InitState has set the error code. */
- }
- rv = ssl3_RestartHandshakeHashes(ss);
- if (rv != SECSuccess) {
- ssl_ReleaseSSL3HandshakeLock(ss);
- return rv;
- }
+ ssl3_InitState(ss);
+ ssl3_RestartHandshakeHashes(ss);
if (ss->ssl3.hs.ws != wait_client_hello) {
desc = unexpected_message;
@@ -9589,34 +9621,6 @@ ssl3_EncodeSigAlgs(const sslSocket *ss, PRUint8 *buf, unsigned maxLen, PRUint32
return SECSuccess;
}
-void
-ssl3_GetCertificateRequestCAs(sslSocket *ss, int *calen, SECItem **names,
- int *nnames)
-{
- SECItem *name;
- CERTDistNames *ca_list;
- int i;
-
- *calen = 0;
- *names = NULL;
- *nnames = 0;
-
- /* ssl3.ca_list is initialized to NULL, and never changed. */
- ca_list = ss->ssl3.ca_list;
- if (!ca_list) {
- ca_list = ssl3_server_ca_list;
- }
-
- if (ca_list != NULL) {
- *names = ca_list->names;
- *nnames = ca_list->nnames;
- }
-
- for (i = 0, name = *names; i < *nnames; i++, name++) {
- *calen += 2 + name->len;
- }
-}
-
static SECStatus
ssl3_SendCertificateRequest(sslSocket *ss)
{
@@ -9625,8 +9629,8 @@ ssl3_SendCertificateRequest(sslSocket *ss)
SECStatus rv;
int length;
SECItem *names;
- int calen;
- int nnames;
+ unsigned int calen;
+ unsigned int nnames;
SECItem *name;
int i;
int certTypesLength;
@@ -9641,7 +9645,10 @@ ssl3_SendCertificateRequest(sslSocket *ss)
isTLS12 = (PRBool)(ss->ssl3.pwSpec->version >= SSL_LIBRARY_VERSION_TLS_1_2);
- ssl3_GetCertificateRequestCAs(ss, &calen, &names, &nnames);
+ rv = ssl_GetCertificateRequestCAs(ss, &calen, &names, &nnames);
+ if (rv != SECSuccess) {
+ return rv;
+ }
certTypes = certificate_types;
certTypesLength = sizeof certificate_types;
@@ -9727,17 +9734,15 @@ ssl3_HandleCertificateVerify(sslSocket *ss, SSL3Opaque *b, PRUint32 length,
PORT_Assert(ss->opt.noLocks || ssl_HaveRecvBufLock(ss));
PORT_Assert(ss->opt.noLocks || ssl_HaveSSL3HandshakeLock(ss));
- /* TLS 1.3 is handled by tls13_HandleCertificateVerify */
- PORT_Assert(ss->ssl3.prSpec->version <= SSL_LIBRARY_VERSION_TLS_1_2);
-
- isTLS = (PRBool)(ss->ssl3.prSpec->version > SSL_LIBRARY_VERSION_3_0);
-
if (ss->ssl3.hs.ws != wait_cert_verify) {
desc = unexpected_message;
errCode = SSL_ERROR_RX_UNEXPECTED_CERT_VERIFY;
goto alert_loser;
}
+ /* TLS 1.3 is handled by tls13_HandleCertificateVerify */
+ PORT_Assert(ss->ssl3.prSpec->version <= SSL_LIBRARY_VERSION_TLS_1_2);
+
if (!hashes) {
PORT_Assert(0);
desc = internal_error;
@@ -9785,6 +9790,8 @@ ssl3_HandleCertificateVerify(sslSocket *ss, SSL3Opaque *b, PRUint32 length,
goto loser; /* malformed. */
}
+ isTLS = (PRBool)(ss->ssl3.prSpec->version > SSL_LIBRARY_VERSION_3_0);
+
/* XXX verify that the key & kea match */
rv = ssl3_VerifySignedHashes(ss, sigScheme, hashesForVerify, &signed_hash);
if (rv != SECSuccess) {
@@ -9915,9 +9922,9 @@ ssl3_HandleRSAClientKeyExchange(sslSocket *ss,
enc_pms.len = length;
if (ss->ssl3.prSpec->version > SSL_LIBRARY_VERSION_3_0) { /* isTLS */
- PRInt32 kLen;
- kLen = ssl3_ConsumeHandshakeNumber(ss, 2, &enc_pms.data, &enc_pms.len);
- if (kLen < 0) {
+ PRUint32 kLen;
+ rv = ssl3_ConsumeHandshakeNumber(ss, &kLen, 2, &enc_pms.data, &enc_pms.len);
+ if (rv != SECSuccess) {
PORT_SetError(SSL_ERROR_CLIENT_KEY_EXCHANGE_FAILURE);
return SECFailure;
}
@@ -10214,7 +10221,7 @@ ssl3_SendNewSessionTicket(sslSocket *ss)
goto loser;
/* This is a fixed value. */
- rv = ssl3_AppendHandshakeNumber(ss, TLS_EX_SESS_TICKET_LIFETIME_HINT, 4);
+ rv = ssl3_AppendHandshakeNumber(ss, ssl_ticket_lifetime, 4);
if (rv != SECSuccess)
goto loser;
@@ -10237,6 +10244,7 @@ ssl3_HandleNewSessionTicket(sslSocket *ss, SSL3Opaque *b, PRUint32 length)
{
SECStatus rv;
SECItem ticketData;
+ PRUint32 temp;
SSL_TRC(3, ("%d: SSL3[%d]: handle session_ticket handshake",
SSL_GETPID(), ss->fd));
@@ -10257,14 +10265,19 @@ ssl3_HandleNewSessionTicket(sslSocket *ss, SSL3Opaque *b, PRUint32 length)
* until it has verified the server's Finished message." See the comment in
* ssl3_FinishHandshake for more details.
*/
- ss->ssl3.hs.newSessionTicket.received_timestamp = ssl_Time();
+ ss->ssl3.hs.newSessionTicket.received_timestamp = PR_Now();
if (length < 4) {
(void)SSL3_SendAlert(ss, alert_fatal, decode_error);
PORT_SetError(SSL_ERROR_RX_MALFORMED_NEW_SESSION_TICKET);
return SECFailure;
}
- ss->ssl3.hs.newSessionTicket.ticket_lifetime_hint =
- (PRUint32)ssl3_ConsumeHandshakeNumber(ss, 4, &b, &length);
+
+ rv = ssl3_ConsumeHandshakeNumber(ss, &temp, 4, &b, &length);
+ if (rv != SECSuccess) {
+ PORT_SetError(SSL_ERROR_RX_MALFORMED_NEW_SESSION_TICKET);
+ return SECFailure;
+ }
+ ss->ssl3.hs.newSessionTicket.ticket_lifetime_hint = temp;
rv = ssl3_ConsumeHandshakeVariable(ss, &ticketData, 2, &b, &length);
if (rv != SECSuccess || length != 0) {
@@ -10559,21 +10572,20 @@ ssl3_HandleCertificateStatus(sslSocket *ss, SSL3Opaque *b, PRUint32 length)
SECStatus
ssl_ReadCertificateStatus(sslSocket *ss, SSL3Opaque *b, PRUint32 length)
{
- PRInt32 status, len;
+ PRUint32 status, len;
+ SECStatus rv;
PORT_Assert(!ss->sec.isServer);
/* Consume the CertificateStatusType enum */
- status = ssl3_ConsumeHandshakeNumber(ss, 1, &b, &length);
- if (status != 1 /* ocsp */) {
- ssl3_DecodeError(ss); /* sets error code */
- return SECFailure;
+ rv = ssl3_ConsumeHandshakeNumber(ss, &status, 1, &b, &length);
+ if (rv != SECSuccess || status != 1 /* ocsp */) {
+ return ssl3_DecodeError(ss);
}
- len = ssl3_ConsumeHandshakeNumber(ss, 3, &b, &length);
- if (len != length) {
- ssl3_DecodeError(ss); /* sets error code */
- return SECFailure;
+ rv = ssl3_ConsumeHandshakeNumber(ss, &len, 3, &b, &length);
+ if (rv != SECSuccess || len != length) {
+ return ssl3_DecodeError(ss);
}
#define MAX_CERTSTATUS_LEN 0x1ffff /* 128k - 1 */
@@ -10630,8 +10642,8 @@ ssl3_CompleteHandleCertificate(sslSocket *ss, SSL3Opaque *b, PRUint32 length)
{
ssl3CertNode *c;
ssl3CertNode *lastCert = NULL;
- PRInt32 remaining = 0;
- PRInt32 size;
+ PRUint32 remaining = 0;
+ PRUint32 size;
SECStatus rv;
PRBool isServer = ss->sec.isServer;
PRBool isTLS;
@@ -10647,10 +10659,10 @@ ssl3_CompleteHandleCertificate(sslSocket *ss, SSL3Opaque *b, PRUint32 length)
** normal no_certificates message to maximize interoperability.
*/
if (length) {
- remaining = ssl3_ConsumeHandshakeNumber(ss, 3, &b, &length);
- if (remaining < 0)
+ rv = ssl3_ConsumeHandshakeNumber(ss, &remaining, 3, &b, &length);
+ if (rv != SECSuccess)
goto loser; /* fatal alert already sent by ConsumeHandshake. */
- if ((PRUint32)remaining > length)
+ if (remaining > length)
goto decode_loser;
}
@@ -10681,15 +10693,14 @@ ssl3_CompleteHandleCertificate(sslSocket *ss, SSL3Opaque *b, PRUint32 length)
}
/* First get the peer cert. */
- remaining -= 3;
- if (remaining < 0)
+ if (remaining < 3)
goto decode_loser;
- size = ssl3_ConsumeHandshakeNumber(ss, 3, &b, &length);
- if (size <= 0)
+ remaining -= 3;
+ rv = ssl3_ConsumeHandshakeNumber(ss, &size, 3, &b, &length);
+ if (rv != SECSuccess)
goto loser; /* fatal alert already sent by ConsumeHandshake. */
-
- if (remaining < size)
+ if (size == 0 || remaining < size)
goto decode_loser;
certItem.data = b;
@@ -10709,15 +10720,14 @@ ssl3_CompleteHandleCertificate(sslSocket *ss, SSL3Opaque *b, PRUint32 length)
/* Now get all of the CA certs. */
while (remaining > 0) {
- remaining -= 3;
- if (remaining < 0)
+ if (remaining < 3)
goto decode_loser;
- size = ssl3_ConsumeHandshakeNumber(ss, 3, &b, &length);
- if (size <= 0)
+ remaining -= 3;
+ rv = ssl3_ConsumeHandshakeNumber(ss, &size, 3, &b, &length);
+ if (rv != SECSuccess)
goto loser; /* fatal alert already sent by ConsumeHandshake. */
-
- if (remaining < size)
+ if (size == 0 || remaining < size)
goto decode_loser;
certItem.data = b;
@@ -10746,9 +10756,6 @@ ssl3_CompleteHandleCertificate(sslSocket *ss, SSL3Opaque *b, PRUint32 length)
lastCert = c;
}
- if (remaining != 0)
- goto decode_loser;
-
SECKEY_UpdateCertPQG(ss->sec.peerCert);
if (!isServer &&
@@ -11036,13 +11043,10 @@ ssl3_ComputeTLSFinished(sslSocket *ss, ssl3CipherSpec *spec,
PK11Context *prf_context;
unsigned int retLen;
+ PORT_Assert(spec->master_secret);
if (!spec->master_secret) {
- const char *label = isServer ? "server finished" : "client finished";
- unsigned int len = 15;
- HASH_HashType hashType = ssl3_GetTls12HashType(ss);
- return ssl3_TLSPRFWithMasterSecret(spec, label, len, hashes->u.raw,
- hashes->len, tlsFinished->verify_data,
- sizeof tlsFinished->verify_data, hashType);
+ PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
+ return SECFailure;
}
if (spec->version < SSL_LIBRARY_VERSION_TLS_1_2) {
@@ -11075,9 +11079,10 @@ ssl3_ComputeTLSFinished(sslSocket *ss, ssl3CipherSpec *spec,
* ss->ssl3.crSpec).
*/
SECStatus
-ssl3_TLSPRFWithMasterSecret(ssl3CipherSpec *spec, const char *label,
- unsigned int labelLen, const unsigned char *val, unsigned int valLen,
- unsigned char *out, unsigned int outLen, HASH_HashType tls12HashType)
+ssl3_TLSPRFWithMasterSecret(sslSocket *ss, ssl3CipherSpec *spec,
+ const char *label, unsigned int labelLen,
+ const unsigned char *val, unsigned int valLen,
+ unsigned char *out, unsigned int outLen)
{
SECStatus rv = SECSuccess;
@@ -11088,6 +11093,12 @@ ssl3_TLSPRFWithMasterSecret(ssl3CipherSpec *spec, const char *label,
unsigned int retLen;
if (spec->version >= SSL_LIBRARY_VERSION_TLS_1_2) {
+ /* Bug 1312976 non-SHA256 exporters are broken. */
+ if (ssl3_GetPrfHashMechanism(ss) != CKM_SHA256) {
+ PORT_Assert(0);
+ PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
+ return SECFailure;
+ }
mech = CKM_NSS_TLS_PRF_GENERAL_SHA256;
}
prf_context = PK11_CreateContextBySymKey(mech, CKA_SIGN,
@@ -11130,9 +11141,7 @@ ssl3_SendNextProto(sslSocket *ss)
padding_len = 32 - ((ss->xtnData.nextProto.len + 2) % 32);
- rv = ssl3_AppendHandshakeHeader(ss, next_proto, ss->xtnData.nextProto.len +
- 2 +
- padding_len);
+ rv = ssl3_AppendHandshakeHeader(ss, next_proto, ss->xtnData.nextProto.len + 2 + padding_len);
if (rv != SECSuccess) {
return rv; /* error code set by AppendHandshakeHeader */
}
@@ -11285,7 +11294,7 @@ fail:
*/
SECStatus
ssl3_CacheWrappedMasterSecret(sslSocket *ss, sslSessionID *sid,
- ssl3CipherSpec *spec, SSLAuthType authType)
+ ssl3CipherSpec *spec)
{
PK11SymKey *wrappingKey = NULL;
PK11SlotInfo *symKeySlot;
@@ -11339,8 +11348,7 @@ ssl3_CacheWrappedMasterSecret(sslSocket *ss, sslSessionID *sid,
mechanism = PK11_GetBestWrapMechanism(symKeySlot);
if (mechanism != CKM_INVALID_MECHANISM) {
wrappingKey =
- ssl3_GetWrappingKey(ss, symKeySlot, ss->sec.serverCert,
- mechanism, pwArg);
+ ssl3_GetWrappingKey(ss, symKeySlot, mechanism, pwArg);
if (wrappingKey) {
mechanism = PK11_GetMechanism(wrappingKey); /* can't fail. */
}
@@ -11547,9 +11555,7 @@ ssl3_FillInCachedSID(sslSocket *ss, sslSessionID *sid)
sid->expirationTime = sid->creationTime + ssl3_sid_timeout;
sid->localCert = CERT_DupCertificate(ss->sec.localCert);
if (ss->sec.isServer) {
- memcpy(&sid->certType, &ss->sec.serverCert->certType, sizeof(sid->certType));
- } else {
- sid->certType.authType = ssl_auth_null;
+ sid->namedCurve = ss->sec.serverCert->namedCurve;
}
if (ss->xtnData.nextProtoState != SSL_NEXT_PROTO_NO_SUPPORT &&
@@ -11573,8 +11579,7 @@ ssl3_FillInCachedSID(sslSocket *ss, sslSessionID *sid)
rv = SECSuccess;
} else {
rv = ssl3_CacheWrappedMasterSecret(ss, ss->sec.ci.sid,
- ss->ssl3.crSpec,
- ss->ssl3.hs.kea_def->authKeyType);
+ ss->ssl3.crSpec);
sid->u.ssl3.keys.msIsWrapped = PR_TRUE;
}
ssl_ReleaseSpecReadLock(ss); /*************************************/
@@ -11719,10 +11724,7 @@ ssl3_HandleHandshakeMessage(sslSocket *ss, SSL3Opaque *b, PRUint32 length,
/* Start new handshake hashes when we start a new handshake. Unless this is
* TLS 1.3 and we sent a HelloRetryRequest. */
if (ss->ssl3.hs.msg_type == client_hello && !ss->ssl3.hs.helloRetry) {
- rv = ssl3_RestartHandshakeHashes(ss);
- if (rv != SECSuccess) {
- return rv;
- }
+ ssl3_RestartHandshakeHashes(ss);
}
/* We should not include hello_request and hello_verify_request messages
* in the handshake hashes */
@@ -12508,17 +12510,14 @@ ssl3_HandleRecord(sslSocket *ss, SSL3Ciphertext *cText, sslBuffer *databuf)
ssl3CipherSpec *crSpec;
SSL3ContentType rType;
sslBuffer *plaintext;
- sslBuffer temp_buf;
+ sslBuffer temp_buf = { NULL, 0, 0 };
SSL3AlertDescription alert = internal_error;
PORT_Assert(ss->opt.noLocks || ssl_HaveRecvBufLock(ss));
if (!ss->ssl3.initialized) {
ssl_GetSSL3HandshakeLock(ss);
- rv = ssl3_InitState(ss);
+ ssl3_InitState(ss);
ssl_ReleaseSSL3HandshakeLock(ss);
- if (rv != SECSuccess) {
- return rv; /* ssl3_InitState has set the error code. */
- }
}
/* check for Token Presence */
@@ -12565,25 +12564,11 @@ ssl3_HandleRecord(sslSocket *ss, SSL3Ciphertext *cText, sslBuffer *databuf)
/* If we will be decompressing the buffer we need to decrypt somewhere
* other than into databuf */
if (crSpec->decompressor) {
- temp_buf.buf = NULL;
- temp_buf.space = 0;
plaintext = &temp_buf;
} else {
plaintext = databuf;
}
-
plaintext->len = 0; /* filled in by Unprotect call below. */
- if (plaintext->space < MAX_FRAGMENT_LENGTH) {
- rv = sslBuffer_Grow(plaintext, MAX_FRAGMENT_LENGTH + 2048);
- if (rv != SECSuccess) {
- ssl_ReleaseSpecReadLock(ss); /*************************/
- SSL_DBG(("%d: SSL3[%d]: HandleRecord, tried to get %d bytes",
- SSL_GETPID(), ss->fd, MAX_FRAGMENT_LENGTH + 2048));
- /* sslBuffer_Grow has set a memory error code. */
- /* Perhaps we should send an alert. (but we have no memory!) */
- return SECFailure;
- }
- }
/* We're waiting for another ClientHello, which will appear unencrypted.
* Use the content type to tell whether this is should be discarded.
@@ -12598,6 +12583,18 @@ ssl3_HandleRecord(sslSocket *ss, SSL3Ciphertext *cText, sslBuffer *databuf)
return SECSuccess;
}
+ if (plaintext->space < MAX_FRAGMENT_LENGTH) {
+ rv = sslBuffer_Grow(plaintext, MAX_FRAGMENT_LENGTH + 2048);
+ if (rv != SECSuccess) {
+ ssl_ReleaseSpecReadLock(ss); /*************************/
+ SSL_DBG(("%d: SSL3[%d]: HandleRecord, tried to get %d bytes",
+ SSL_GETPID(), ss->fd, MAX_FRAGMENT_LENGTH + 2048));
+ /* sslBuffer_Grow has set a memory error code. */
+ /* Perhaps we should send an alert. (but we have no memory!) */
+ return SECFailure;
+ }
+ }
+
#ifdef UNSAFE_FUZZER_MODE
rv = Null_Cipher(NULL, plaintext->buf, (int *)&plaintext->len,
plaintext->space, cText->buf->buf, cText->buf->len);
@@ -12619,6 +12616,9 @@ ssl3_HandleRecord(sslSocket *ss, SSL3Ciphertext *cText, sslBuffer *databuf)
SSL_DBG(("%d: SSL3[%d]: decryption failed", SSL_GETPID(), ss->fd));
+ /* Clear the temp buffer used for decompression upon failure. */
+ sslBuffer_Clear(&temp_buf);
+
if (IS_DTLS(ss) ||
(ss->sec.isServer &&
ss->ssl3.hs.zeroRttIgnore == ssl_0rtt_ignore_trial)) {
@@ -12663,7 +12663,7 @@ ssl3_HandleRecord(sslSocket *ss, SSL3Ciphertext *cText, sslBuffer *databuf)
SSL3_COMPRESSION_MAX_EXPANSION));
/* sslBuffer_Grow has set a memory error code. */
/* Perhaps we should send an alert. (but we have no memory!) */
- PORT_Free(plaintext->buf);
+ sslBuffer_Clear(&temp_buf);
return SECFailure;
}
}
@@ -12701,12 +12701,12 @@ ssl3_HandleRecord(sslSocket *ss, SSL3Ciphertext *cText, sslBuffer *databuf)
}
}
- PORT_Free(plaintext->buf);
+ sslBuffer_Clear(&temp_buf);
PORT_SetError(err);
return SECFailure;
}
- PORT_Free(plaintext->buf);
+ sslBuffer_Clear(&temp_buf);
}
/*
@@ -12836,16 +12836,14 @@ ssl3_InitCipherSpec(ssl3CipherSpec *spec)
** ssl3_HandleRecord()
**
** This function should perhaps acquire and release the SpecWriteLock.
-**
-**
*/
-SECStatus
+void
ssl3_InitState(sslSocket *ss)
{
PORT_Assert(ss->opt.noLocks || ssl_HaveSSL3HandshakeLock(ss));
if (ss->ssl3.initialized)
- return SECSuccess; /* Function should be idempotent */
+ return; /* Function should be idempotent */
ss->ssl3.policy = SSL_ALLOWED;
@@ -12900,7 +12898,6 @@ ssl3_InitState(sslSocket *ss)
ssl_FilterSupportedGroups(ss);
ss->ssl3.initialized = PR_TRUE;
- return SECSuccess;
}
/* record the export policy for this cipher suite */
@@ -13280,8 +13277,6 @@ ssl3_DestroySSL3Info(sslSocket *ss)
tls13_DestroyEarlyData(&ss->ssl3.hs.bufferedEarlyData);
ss->ssl3.initialized = PR_FALSE;
-
- SECITEM_FreeItem(&ss->xtnData.nextProto, PR_FALSE);
}
#define MAP_NULL(x) (((x) != 0) ? (x) : SEC_OID_NULL_CIPHER)
diff --git a/nss/lib/ssl/ssl3ecc.c b/nss/lib/ssl/ssl3ecc.c
index 72c4ba5..2b2a611 100644
--- a/nss/lib/ssl/ssl3ecc.c
+++ b/nss/lib/ssl/ssl3ecc.c
@@ -31,13 +31,6 @@
#include <stdio.h>
-#ifndef PK11_SETATTRS
-#define PK11_SETATTRS(x, id, v, l) \
- (x)->type = (id); \
- (x)->pValue = (v); \
- (x)->ulValueLen = (l);
-#endif
-
SECStatus
ssl_NamedGroup2ECParams(PLArenaPool *arena, const sslNamedGroupDef *ecGroup,
SECKEYECParams *params)
@@ -257,16 +250,6 @@ loser:
return SECFailure;
}
-/* This function returns the size of the key_exchange field in
- * the KeyShareEntry structure, i.e.:
- * opaque point <1..2^8-1>; */
-unsigned int
-tls13_SizeOfECDHEKeyShareKEX(const SECKEYPublicKey *pubKey)
-{
- PORT_Assert(pubKey->keyType == ecKey);
- return pubKey->u.ec.publicValue.len;
-}
-
/* This function encodes the key_exchange field in
* the KeyShareEntry structure. */
SECStatus
@@ -303,7 +286,7 @@ ssl3_HandleECDHClientKeyExchange(sslSocket *ss, SSL3Opaque *b,
serverKeyPair->pubKey->u.ec.DEREncodedParams.len;
clntPubKey.u.ec.DEREncodedParams.data =
serverKeyPair->pubKey->u.ec.DEREncodedParams.data;
- clntPubKey.u.ec.encoding = serverKeyPair->pubKey->u.ec.encoding;
+ clntPubKey.u.ec.encoding = ECPoint_Undefined;
rv = ssl3_ConsumeHandshakeVariable(ss, &clntPubKey.u.ec.publicValue,
1, &b, &length);
@@ -387,11 +370,7 @@ ssl_ImportECDHKeyShare(sslSocket *ss, SECKEYPublicKey *peerKey,
ssl_MapLowLevelError(SSL_ERROR_RX_MALFORMED_ECDHE_KEY_SHARE);
return SECFailure;
}
- if (ecGroup->name == ssl_grp_ec_curve25519) {
- peerKey->u.ec.encoding = ECPoint_XOnly;
- } else {
- peerKey->u.ec.encoding = ECPoint_Uncompressed;
- }
+ peerKey->u.ec.encoding = ECPoint_Undefined;
/* copy publicValue in peerKey */
ecPoint.data = b;
@@ -440,23 +419,19 @@ ssl_GetECGroupForServerSocket(sslSocket *ss)
return NULL;
}
- if (cert->certType.authType == ssl_auth_rsa_sign) {
+ if (SSL_CERT_IS(cert, ssl_auth_rsa_sign) ||
+ SSL_CERT_IS(cert, ssl_auth_rsa_pss)) {
certKeySize = SECKEY_PublicKeyStrengthInBits(cert->serverKeyPair->pubKey);
- certKeySize =
- SSL_RSASTRENGTH_TO_ECSTRENGTH(certKeySize);
- } else if (cert->certType.authType == ssl_auth_ecdsa ||
- cert->certType.authType == ssl_auth_ecdh_rsa ||
- cert->certType.authType == ssl_auth_ecdh_ecdsa) {
- const sslNamedGroupDef *groupDef = cert->certType.namedCurve;
-
+ certKeySize = SSL_RSASTRENGTH_TO_ECSTRENGTH(certKeySize);
+ } else if (SSL_CERT_IS_EC(cert)) {
/* We won't select a certificate unless the named curve has been
* negotiated (or supported_curves was absent), double check that. */
- PORT_Assert(groupDef->keaType == ssl_kea_ecdh);
- PORT_Assert(ssl_NamedGroupEnabled(ss, groupDef));
- if (!ssl_NamedGroupEnabled(ss, groupDef)) {
+ PORT_Assert(cert->namedCurve->keaType == ssl_kea_ecdh);
+ PORT_Assert(ssl_NamedGroupEnabled(ss, cert->namedCurve));
+ if (!ssl_NamedGroupEnabled(ss, cert->namedCurve)) {
return NULL;
}
- certKeySize = groupDef->bits;
+ certKeySize = cert->namedCurve->bits;
} else {
PORT_Assert(0);
return NULL;
diff --git a/nss/lib/ssl/ssl3ext.c b/nss/lib/ssl/ssl3ext.c
index 0da41be..7700be2 100644
--- a/nss/lib/ssl/ssl3ext.c
+++ b/nss/lib/ssl/ssl3ext.c
@@ -87,6 +87,10 @@ static const ssl3ExtensionHandler serverCertificateHandlers[] = {
{ -1, NULL }
};
+static const ssl3ExtensionHandler certificateRequestHandlers[] = {
+ { -1, NULL }
+};
+
/* Tables of functions to format TLS hello extensions, one function per
* extension.
* These static tables are for the formatting of client hello extensions.
@@ -122,6 +126,7 @@ static const ssl3HelloExtensionSender clientHelloSendersTLS[SSL_MAX_EXTENSIONS]
{ ssl_tls13_cookie_xtn, &tls13_ClientSendHrrCookieXtn },
{ ssl_tls13_psk_key_exchange_modes_xtn,
&tls13_ClientSendPskKeyExchangeModesXtn },
+ { ssl_padding_xtn, &ssl3_ClientSendPaddingExtension },
/* The pre_shared_key extension MUST be last. */
{ ssl_tls13_pre_shared_key_xtn, &tls13_ClientSendPreSharedKeyXtn },
/* any extra entries will appear as { 0, NULL } */
@@ -174,15 +179,15 @@ ssl3_ParseExtensions(sslSocket *ss, SSL3Opaque **b, PRUint32 *length)
while (*length) {
SECStatus rv;
- PRInt32 extension_type;
+ PRUint32 extension_type;
SECItem extension_data = { siBuffer, NULL, 0 };
TLSExtension *extension;
PRCList *cursor;
/* Get the extension's type field */
- extension_type = ssl3_ConsumeHandshakeNumber(ss, 2, b, length);
- if (extension_type < 0) { /* failure to decode extension_type */
- return SECFailure; /* alert already sent */
+ rv = ssl3_ConsumeHandshakeNumber(ss, &extension_type, 2, b, length);
+ if (rv != SECSuccess) {
+ return SECFailure; /* alert already sent */
}
SSL_TRC(10, ("%d: SSL3[%d]: parsing extension %d",
@@ -249,7 +254,10 @@ ssl3_HandleParsedExtensions(sslSocket *ss,
SSL3HandshakeType handshakeMessage)
{
const ssl3ExtensionHandler *handlers;
- PRBool isTLS13 = ss->version >= SSL_LIBRARY_VERSION_TLS_1_3;
+ /* HelloRetryRequest doesn't set ss->version. It might be safe to
+ * do so, but we weren't entirely sure. TODO(ekr@rtfm.com). */
+ PRBool isTLS13 = (ss->version >= SSL_LIBRARY_VERSION_TLS_1_3) ||
+ (handshakeMessage == hello_retry_request);
PRCList *cursor;
switch (handshakeMessage) {
@@ -277,6 +285,10 @@ ssl3_HandleParsedExtensions(sslSocket *ss,
PORT_Assert(!ss->sec.isServer);
handlers = serverCertificateHandlers;
break;
+ case certificate_request:
+ PORT_Assert(!ss->sec.isServer);
+ handlers = certificateRequestHandlers;
+ break;
default:
PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
PORT_Assert(0);
@@ -508,22 +520,22 @@ ssl3_ExtDecodeError(const sslSocket *ss)
}
SECStatus
-ssl3_ExtConsumeHandshake(const sslSocket *ss, void *v, PRInt32 bytes,
+ssl3_ExtConsumeHandshake(const sslSocket *ss, void *v, PRUint32 bytes,
SSL3Opaque **b, PRUint32 *length)
{
return ssl3_ConsumeHandshake((sslSocket *)ss, v, bytes, b, length);
}
-PRInt32
-ssl3_ExtConsumeHandshakeNumber(const sslSocket *ss, PRInt32 bytes,
- SSL3Opaque **b, PRUint32 *length)
+SECStatus
+ssl3_ExtConsumeHandshakeNumber(const sslSocket *ss, PRUint32 *num,
+ PRUint32 bytes, SSL3Opaque **b, PRUint32 *length)
{
- return ssl3_ConsumeHandshakeNumber((sslSocket *)ss, bytes, b, length);
+ return ssl3_ConsumeHandshakeNumber((sslSocket *)ss, num, bytes, b, length);
}
SECStatus
ssl3_ExtConsumeHandshakeVariable(const sslSocket *ss, SECItem *i,
- PRInt32 bytes, SSL3Opaque **b,
+ PRUint32 bytes, SSL3Opaque **b,
PRUint32 *length)
{
return ssl3_ConsumeHandshakeVariable((sslSocket *)ss, i, bytes, b, length);
diff --git a/nss/lib/ssl/ssl3ext.h b/nss/lib/ssl/ssl3ext.h
index f93ad65..0aff523 100644
--- a/nss/lib/ssl/ssl3ext.h
+++ b/nss/lib/ssl/ssl3ext.h
@@ -54,6 +54,9 @@ struct TLSExtensionDataStr {
PRUint16 advertised[SSL_MAX_EXTENSIONS];
PRUint16 negotiated[SSL_MAX_EXTENSIONS];
+ /* Amount of padding we need to add. */
+ PRUint16 paddingLen;
+
/* SessionTicket Extension related data. */
PRBool ticketTimestampVerified;
PRBool emptySessionTicket;
@@ -130,9 +133,8 @@ SECStatus ssl3_RegisterExtensionSender(const sslSocket *ss,
PRInt32 ssl3_CallHelloExtensionSenders(sslSocket *ss, PRBool append, PRUint32 maxBytes,
const ssl3HelloExtensionSender *sender);
-unsigned int ssl3_CalculatePaddingExtensionLength(unsigned int clientHelloLength);
-PRInt32 ssl3_AppendPaddingExtension(sslSocket *ss, unsigned int extensionLen,
- PRUint32 maxBytes);
+void ssl3_CalculatePaddingExtLen(sslSocket *ss,
+ unsigned int clientHelloLength);
/* Thunks to let us operate on const sslSocket* objects. */
SECStatus ssl3_ExtAppendHandshake(const sslSocket *ss, const void *void_src,
@@ -145,12 +147,13 @@ SECStatus ssl3_ExtAppendHandshakeVariable(const sslSocket *ss,
void ssl3_ExtSendAlert(const sslSocket *ss, SSL3AlertLevel level,
SSL3AlertDescription desc);
void ssl3_ExtDecodeError(const sslSocket *ss);
-SECStatus ssl3_ExtConsumeHandshake(const sslSocket *ss, void *v, PRInt32 bytes,
+SECStatus ssl3_ExtConsumeHandshake(const sslSocket *ss, void *v, PRUint32 bytes,
SSL3Opaque **b, PRUint32 *length);
-PRInt32 ssl3_ExtConsumeHandshakeNumber(const sslSocket *ss, PRInt32 bytes,
- SSL3Opaque **b, PRUint32 *length);
+SECStatus ssl3_ExtConsumeHandshakeNumber(const sslSocket *ss, PRUint32 *num,
+ PRUint32 bytes, SSL3Opaque **b,
+ PRUint32 *length);
SECStatus ssl3_ExtConsumeHandshakeVariable(const sslSocket *ss, SECItem *i,
- PRInt32 bytes, SSL3Opaque **b,
+ PRUint32 bytes, SSL3Opaque **b,
PRUint32 *length);
#endif
diff --git a/nss/lib/ssl/ssl3exthandle.c b/nss/lib/ssl/ssl3exthandle.c
index 2a80e26..c9c99ab 100644
--- a/nss/lib/ssl/ssl3exthandle.c
+++ b/nss/lib/ssl/ssl3exthandle.c
@@ -16,22 +16,16 @@
#include "ssl3exthandle.h"
#include "tls13exthandle.h" /* For tls13_ServerSendStatusRequestXtn. */
-static unsigned char key_name[SESS_TICKET_KEY_NAME_LEN];
-static PK11SymKey *session_ticket_enc_key = NULL;
-static PK11SymKey *session_ticket_mac_key = NULL;
-
-static PRCallOnceType generate_session_keys_once;
-
-static SECStatus ssl3_ParseEncryptedSessionTicket(sslSocket *ss,
- SECItem *data, EncryptedSessionTicket *enc_session_ticket);
static SECStatus ssl3_AppendToItem(SECItem *item, const unsigned char *buf,
PRUint32 bytes);
-static SECStatus ssl3_ConsumeFromItem(SECItem *item, unsigned char **buf, PRUint32 bytes);
+static SECStatus ssl3_ConsumeFromItem(SECItem *item, unsigned char **buf,
+ PRUint32 bytes);
static SECStatus ssl3_AppendNumberToItem(SECItem *item, PRUint32 num,
PRInt32 lenSize);
-static SECStatus ssl3_GetSessionTicketKeys(sslSocket *ss,
- PK11SymKey **aes_key, PK11SymKey **mac_key);
-static SECStatus ssl3_ConsumeFromItem(SECItem *item, unsigned char **buf, PRUint32 bytes);
+
+PRUint32 ssl_ticket_lifetime = 2 * 24 * 60 * 60; /* 2 days in seconds */
+#define TLS_EX_SESS_TICKET_VERSION (0x0105)
+#define TLS_EX_SESS_TICKET_MAC_LENGTH 32
/*
* Write bytes. Using this function means the SECItem structure
@@ -76,83 +70,6 @@ ssl3_AppendNumberToItem(SECItem *item, PRUint32 num, PRInt32 lenSize)
return rv;
}
-SECStatus
-ssl3_SessionTicketShutdown(void *appData, void *nssData)
-{
- if (session_ticket_enc_key) {
- PK11_FreeSymKey(session_ticket_enc_key);
- session_ticket_enc_key = NULL;
- }
- if (session_ticket_mac_key) {
- PK11_FreeSymKey(session_ticket_mac_key);
- session_ticket_mac_key = NULL;
- }
- PORT_Memset(&generate_session_keys_once, 0,
- sizeof(generate_session_keys_once));
- return SECSuccess;
-}
-
-static PRStatus
-ssl3_GenerateSessionTicketKeys(void *data)
-{
- SECStatus rv;
- sslSocket *ss = (sslSocket *)data;
- sslServerCertType certType = { ssl_auth_rsa_decrypt, NULL };
- const sslServerCert *sc;
- SECKEYPrivateKey *svrPrivKey;
- SECKEYPublicKey *svrPubKey;
-
- sc = ssl_FindServerCert(ss, &certType);
- if (!sc || !sc->serverKeyPair) {
- SSL_DBG(("%d: SSL[%d]: No ssl_auth_rsa_decrypt cert and key pair",
- SSL_GETPID(), ss->fd));
- goto loser;
- }
- svrPrivKey = sc->serverKeyPair->privKey;
- svrPubKey = sc->serverKeyPair->pubKey;
- if (svrPrivKey == NULL || svrPubKey == NULL) {
- SSL_DBG(("%d: SSL[%d]: Pub or priv key(s) is NULL.",
- SSL_GETPID(), ss->fd));
- goto loser;
- }
-
- /* Get a copy of the session keys from shared memory. */
- PORT_Memcpy(key_name, SESS_TICKET_KEY_NAME_PREFIX,
- sizeof(SESS_TICKET_KEY_NAME_PREFIX));
- if (!ssl_GetSessionTicketKeys(svrPrivKey, svrPubKey, ss->pkcs11PinArg,
- &key_name[SESS_TICKET_KEY_NAME_PREFIX_LEN],
- &session_ticket_enc_key, &session_ticket_mac_key))
- return PR_FAILURE;
-
- rv = NSS_RegisterShutdown(ssl3_SessionTicketShutdown, NULL);
- if (rv != SECSuccess)
- goto loser;
-
- return PR_SUCCESS;
-
-loser:
- ssl3_SessionTicketShutdown(NULL, NULL);
- return PR_FAILURE;
-}
-
-static SECStatus
-ssl3_GetSessionTicketKeys(sslSocket *ss, PK11SymKey **aes_key,
- PK11SymKey **mac_key)
-{
- if (PR_CallOnceWithArg(&generate_session_keys_once,
- ssl3_GenerateSessionTicketKeys, ss) !=
- PR_SUCCESS)
- return SECFailure;
-
- if (session_ticket_enc_key == NULL ||
- session_ticket_mac_key == NULL)
- return SECFailure;
-
- *aes_key = session_ticket_enc_key;
- *mac_key = session_ticket_mac_key;
- return SECSuccess;
-}
-
/* Format an SNI extension, using the name from the socket's URL,
* unless that name is a dotted decimal string.
* Used by client and server.
@@ -223,7 +140,8 @@ SECStatus
ssl3_HandleServerNameXtn(const sslSocket *ss, TLSExtensionData *xtnData, PRUint16 ex_type, SECItem *data)
{
SECItem *names = NULL;
- PRInt32 listLenBytes = 0;
+ PRUint32 listLenBytes = 0;
+ SECStatus rv;
if (!ss->sec.isServer) {
return SECSuccess; /* ignore extension */
@@ -236,8 +154,8 @@ ssl3_HandleServerNameXtn(const sslSocket *ss, TLSExtensionData *xtnData, PRUint1
}
/* length of server_name_list */
- listLenBytes = ssl3_ExtConsumeHandshakeNumber(ss, 2, &data->data, &data->len);
- if (listLenBytes < 0) {
+ rv = ssl3_ExtConsumeHandshakeNumber(ss, &listLenBytes, 2, &data->data, &data->len);
+ if (rv != SECSuccess) {
goto loser; /* alert already sent */
}
if (listLenBytes == 0 || listLenBytes != data->len) {
@@ -247,12 +165,11 @@ ssl3_HandleServerNameXtn(const sslSocket *ss, TLSExtensionData *xtnData, PRUint1
/* Read ServerNameList. */
while (data->len > 0) {
SECItem tmp;
- SECStatus rv;
- PRInt32 type;
+ PRUint32 type;
/* Read Name Type. */
- type = ssl3_ExtConsumeHandshakeNumber(ss, 1, &data->data, &data->len);
- if (type < 0) { /* i.e., SECFailure cast to PRint32 */
+ rv = ssl3_ExtConsumeHandshakeNumber(ss, &type, 1, &data->data, &data->len);
+ if (rv != SECSuccess) {
/* alert sent in ConsumeHandshakeNumber */
goto loser;
}
@@ -372,11 +289,7 @@ ssl3_SendSessionTicketXtn(
if (session_ticket->ticket.data) {
if (xtnData->ticketTimestampVerified) {
extension_length += session_ticket->ticket.len;
- } else if (!append &&
- (session_ticket->ticket_lifetime_hint == 0 ||
- (session_ticket->ticket_lifetime_hint +
- session_ticket->received_timestamp >
- ssl_Time()))) {
+ } else if (!append && ssl_TicketTimeValid(session_ticket)) {
extension_length += session_ticket->ticket.len;
xtnData->ticketTimestampVerified = PR_TRUE;
}
@@ -418,31 +331,54 @@ loser:
}
static SECStatus
-ssl3_ParseEncryptedSessionTicket(sslSocket *ss, SECItem *data,
- EncryptedSessionTicket *enc_session_ticket)
+ssl3_ParseEncryptedSessionTicket(sslSocket *ss, const SECItem *data,
+ EncryptedSessionTicket *encryptedTicket)
{
- if (ssl3_ConsumeFromItem(data, &enc_session_ticket->key_name,
+ SECItem copy = *data;
+
+ if (ssl3_ConsumeFromItem(&copy, &encryptedTicket->key_name,
SESS_TICKET_KEY_NAME_LEN) !=
SECSuccess)
return SECFailure;
- if (ssl3_ConsumeFromItem(data, &enc_session_ticket->iv,
+ if (ssl3_ConsumeFromItem(&copy, &encryptedTicket->iv,
AES_BLOCK_SIZE) !=
SECSuccess)
return SECFailure;
- if (ssl3_ConsumeHandshakeVariable(ss, &enc_session_ticket->encrypted_state,
- 2, &data->data, &data->len) !=
+ if (ssl3_ConsumeHandshakeVariable(ss, &encryptedTicket->encrypted_state,
+ 2, &copy.data, &copy.len) !=
SECSuccess)
return SECFailure;
- if (ssl3_ConsumeFromItem(data, &enc_session_ticket->mac,
+ if (ssl3_ConsumeFromItem(&copy, &encryptedTicket->mac,
TLS_EX_SESS_TICKET_MAC_LENGTH) !=
SECSuccess)
return SECFailure;
- if (data->len != 0) /* Make sure that we have consumed all bytes. */
+ if (copy.len != 0) /* Make sure that we have consumed all bytes. */
return SECFailure;
return SECSuccess;
}
+PRBool
+ssl_AlpnTagAllowed(const sslSocket *ss, const SECItem *tag)
+{
+ const unsigned char *data = ss->opt.nextProtoNego.data;
+ unsigned int length = ss->opt.nextProtoNego.len;
+ unsigned int offset = 0;
+
+ if (!tag->len)
+ return PR_TRUE;
+
+ while (offset < length) {
+ unsigned int taglen = (unsigned int)data[offset];
+ if ((taglen == tag->len) &&
+ !PORT_Memcmp(data + offset + 1, tag->data, tag->len))
+ return PR_TRUE;
+ offset += 1 + taglen;
+ }
+
+ return PR_FALSE;
+}
+
/* handle an incoming Next Protocol Negotiation extension. */
SECStatus
ssl3_ServerHandleNextProtoNegoXtn(const sslSocket *ss, TLSExtensionData *xtnData, PRUint16 ex_type,
@@ -542,7 +478,7 @@ ssl3_SelectAppProtocol(const sslSocket *ss, TLSExtensionData *xtnData,
SECStatus
ssl3_ServerHandleAppProtoXtn(const sslSocket *ss, TLSExtensionData *xtnData, PRUint16 ex_type, SECItem *data)
{
- int count;
+ PRUint32 count;
SECStatus rv;
/* We expressly don't want to allow ALPN on renegotiation,
@@ -556,8 +492,8 @@ ssl3_ServerHandleAppProtoXtn(const sslSocket *ss, TLSExtensionData *xtnData, PRU
/* Unlike NPN, ALPN has extra redundant length information so that
* the extension is the same in both ClientHello and ServerHello. */
- count = ssl3_ExtConsumeHandshakeNumber(ss, 2, &data->data, &data->len);
- if (count != data->len) {
+ rv = ssl3_ExtConsumeHandshakeNumber(ss, &count, 2, &data->data, &data->len);
+ if (rv != SECSuccess || count != data->len) {
ssl3_ExtDecodeError(ss);
return SECFailure;
}
@@ -621,7 +557,7 @@ SECStatus
ssl3_ClientHandleAppProtoXtn(const sslSocket *ss, TLSExtensionData *xtnData, PRUint16 ex_type, SECItem *data)
{
SECStatus rv;
- PRInt32 list_len;
+ PRUint32 list_len;
SECItem protocol_name;
if (ssl3_ExtensionNegotiated(ss, ssl_next_proto_nego_xtn)) {
@@ -639,9 +575,10 @@ ssl3_ClientHandleAppProtoXtn(const sslSocket *ss, TLSExtensionData *xtnData, PRU
return SECFailure;
}
- list_len = ssl3_ExtConsumeHandshakeNumber(ss, 2, &data->data, &data->len);
+ rv = ssl3_ExtConsumeHandshakeNumber(ss, &list_len, 2, &data->data,
+ &data->len);
/* The list has to be the entire extension. */
- if (list_len != data->len) {
+ if (rv != SECSuccess || list_len != data->len) {
ssl3_ExtSendAlert(ss, alert_fatal, decode_error);
PORT_SetError(SSL_ERROR_NEXT_PROTOCOL_DATA_INVALID);
return SECFailure;
@@ -656,6 +593,12 @@ ssl3_ClientHandleAppProtoXtn(const sslSocket *ss, TLSExtensionData *xtnData, PRU
return SECFailure;
}
+ if (!ssl_AlpnTagAllowed(ss, &protocol_name)) {
+ ssl3_ExtSendAlert(ss, alert_fatal, illegal_parameter);
+ PORT_SetError(SSL_ERROR_NEXT_PROTOCOL_DATA_INVALID);
+ return SECFailure;
+ }
+
SECITEM_FreeItem(&xtnData->nextProto, PR_FALSE);
xtnData->nextProtoState = SSL_NEXT_PROTO_SELECTED;
xtnData->negotiated[xtnData->numNegotiated++] = ex_type;
@@ -963,23 +906,20 @@ ssl3_EncodeSessionTicket(sslSocket *ss,
PRUint32 cert_length = 0;
PRUint8 length_buf[4];
PRUint32 now;
+ unsigned char key_name[SESS_TICKET_KEY_NAME_LEN];
PK11SymKey *aes_key = NULL;
PK11SymKey *mac_key = NULL;
- CK_MECHANISM_TYPE cipherMech = CKM_AES_CBC;
PK11Context *aes_ctx;
- CK_MECHANISM_TYPE macMech = CKM_SHA256_HMAC;
PK11Context *hmac_ctx = NULL;
unsigned char computed_mac[TLS_EX_SESS_TICKET_MAC_LENGTH];
unsigned int computed_mac_length;
unsigned char iv[AES_BLOCK_SIZE];
SECItem ivItem;
SECItem *srvName = NULL;
- PRUint32 srvNameLen = 0;
CK_MECHANISM_TYPE msWrapMech = 0; /* dummy default value,
* must be >= 0 */
ssl3CipherSpec *spec;
- const sslServerCertType *certType;
- SECItem alpnSelection = { siBuffer, NULL, 0 };
+ SECItem *alpnSelection = NULL;
SSL_TRC(3, ("%d: SSL3[%d]: send session_ticket handshake",
SSL_GETPID(), ss->fd));
@@ -988,7 +928,7 @@ ssl3_EncodeSessionTicket(sslSocket *ss,
PORT_Assert(ss->opt.noLocks || ssl_HaveSSL3HandshakeLock(ss));
if (ss->opt.requestCertificate && ss->sec.ci.sid->peerCert) {
- cert_length = 3 + ss->sec.ci.sid->peerCert->derCert.len;
+ cert_length = 2 + ss->sec.ci.sid->peerCert->derCert.len;
}
/* Get IV and encryption keys */
@@ -998,7 +938,7 @@ ssl3_EncodeSessionTicket(sslSocket *ss,
if (rv != SECSuccess)
goto loser;
- rv = ssl3_GetSessionTicketKeys(ss, &aes_key, &mac_key);
+ rv = ssl_GetSessionTicketKeys(ss, key_name, &aes_key, &mac_key);
if (rv != SECSuccess)
goto loser;
@@ -1017,8 +957,7 @@ ssl3_EncodeSessionTicket(sslSocket *ss,
sslSessionID sid;
PORT_Memset(&sid, 0, sizeof(sslSessionID));
- rv = ssl3_CacheWrappedMasterSecret(ss, &sid, spec,
- ss->ssl3.hs.kea_def->authKeyType);
+ rv = ssl3_CacheWrappedMasterSecret(ss, &sid, spec);
if (rv == SECSuccess) {
if (sid.u.ssl3.keys.wrapped_master_secret_len > sizeof(wrapped_ms))
goto loser;
@@ -1035,17 +974,14 @@ ssl3_EncodeSessionTicket(sslSocket *ss,
}
/* Prep to send negotiated name */
srvName = &ss->sec.ci.sid->u.ssl3.srvName;
- if (srvName->data && srvName->len) {
- srvNameLen = 2 + srvName->len; /* len bytes + name len */
- }
- if (ss->xtnData.nextProtoState != SSL_NEXT_PROTO_NO_SUPPORT &&
- ss->xtnData.nextProto.data) {
- alpnSelection = ss->xtnData.nextProto;
- }
+ PORT_Assert(ss->xtnData.nextProtoState == SSL_NEXT_PROTO_SELECTED ||
+ ss->xtnData.nextProtoState == SSL_NEXT_PROTO_NEGOTIATED ||
+ ss->xtnData.nextProto.len == 0);
+ alpnSelection = &ss->xtnData.nextProto;
ciphertext_length =
- sizeof(PRUint16) /* ticket_version */
+ sizeof(PRUint16) /* ticket version */
+ sizeof(SSL3ProtocolVersion) /* ssl_version */
+ sizeof(ssl3CipherSuite) /* ciphersuite */
+ 1 /* compression */
@@ -1057,15 +993,19 @@ ssl3_EncodeSessionTicket(sslSocket *ss,
+ ms_item.len /* master_secret */
+ 1 /* client_auth_type */
+ cert_length /* cert */
- + 1 /* server name type */
- + srvNameLen /* name len + length field */
+ + 2 + srvName->len /* name len + length field */
+ 1 /* extendedMasterSecretUsed */
+ sizeof(ticket->ticket_lifetime_hint) /* ticket lifetime hint */
+ sizeof(ticket->flags) /* ticket flags */
- + 1 + alpnSelection.len; /* npn value + length field. */
+ + 1 + alpnSelection->len /* alpn value + length field */
+ + 4; /* maxEarlyData */
+#ifdef UNSAFE_FUZZER_MODE
+ padding_length = 0;
+#else
padding_length = AES_BLOCK_SIZE -
(ciphertext_length %
AES_BLOCK_SIZE);
+#endif
ciphertext_length += padding_length;
if (SECITEM_AllocItem(NULL, &plaintext_item, ciphertext_length) == NULL)
@@ -1073,7 +1013,7 @@ ssl3_EncodeSessionTicket(sslSocket *ss,
plaintext = plaintext_item;
- /* ticket_version */
+ /* ticket version */
rv = ssl3_AppendNumberToItem(&plaintext, TLS_EX_SESS_TICKET_VERSION,
sizeof(PRUint16));
if (rv != SECSuccess)
@@ -1111,22 +1051,15 @@ ssl3_EncodeSessionTicket(sslSocket *ss,
goto loser;
/* certificate type */
- certType = &ss->sec.serverCert->certType;
- PORT_Assert(certType->authType == ss->sec.authType);
- switch (ss->sec.authType) {
- case ssl_auth_ecdsa:
- case ssl_auth_ecdh_rsa:
- case ssl_auth_ecdh_ecdsa:
- PORT_Assert(certType->namedCurve);
- PORT_Assert(certType->namedCurve->keaType == ssl_kea_ecdh);
- /* EC curves only use the second of the two bytes. */
- PORT_Assert(certType->namedCurve->name < 256);
- rv = ssl3_AppendNumberToItem(&plaintext,
- certType->namedCurve->name, 1);
- break;
- default:
- rv = ssl3_AppendNumberToItem(&plaintext, 0, 1);
- break;
+ PORT_Assert(SSL_CERT_IS(ss->sec.serverCert, ss->sec.authType));
+ if (SSL_CERT_IS_EC(ss->sec.serverCert)) {
+ const sslServerCert *cert = ss->sec.serverCert;
+ PORT_Assert(cert->namedCurve);
+ /* EC curves only use the second of the two bytes. */
+ PORT_Assert(cert->namedCurve->name < 256);
+ rv = ssl3_AppendNumberToItem(&plaintext, cert->namedCurve->name, 1);
+ } else {
+ rv = ssl3_AppendNumberToItem(&plaintext, 0, 1);
}
if (rv != SECSuccess)
goto loser;
@@ -1145,13 +1078,13 @@ ssl3_EncodeSessionTicket(sslSocket *ss,
if (rv != SECSuccess)
goto loser;
- /* client_identity */
+ /* client identity */
if (ss->opt.requestCertificate && ss->sec.ci.sid->peerCert) {
rv = ssl3_AppendNumberToItem(&plaintext, CLIENT_AUTH_CERTIFICATE, 1);
if (rv != SECSuccess)
goto loser;
rv = ssl3_AppendNumberToItem(&plaintext,
- ss->sec.ci.sid->peerCert->derCert.len, 3);
+ ss->sec.ci.sid->peerCert->derCert.len, 2);
if (rv != SECSuccess)
goto loser;
rv = ssl3_AppendToItem(&plaintext,
@@ -1172,23 +1105,14 @@ ssl3_EncodeSessionTicket(sslSocket *ss,
if (rv != SECSuccess)
goto loser;
- if (srvNameLen) {
- /* Name Type (sni_host_name) */
- rv = ssl3_AppendNumberToItem(&plaintext, srvName->type, 1);
- if (rv != SECSuccess)
- goto loser;
- /* HostName (length and value) */
- rv = ssl3_AppendNumberToItem(&plaintext, srvName->len, 2);
- if (rv != SECSuccess)
- goto loser;
+ /* HostName (length and value) */
+ rv = ssl3_AppendNumberToItem(&plaintext, srvName->len, 2);
+ if (rv != SECSuccess)
+ goto loser;
+ if (srvName->len) {
rv = ssl3_AppendToItem(&plaintext, srvName->data, srvName->len);
if (rv != SECSuccess)
goto loser;
- } else {
- /* No Name */
- rv = ssl3_AppendNumberToItem(&plaintext, (char)TLS_STE_NO_SERVER_NAME, 1);
- if (rv != SECSuccess)
- goto loser;
}
/* extendedMasterSecretUsed */
@@ -1203,17 +1127,22 @@ ssl3_EncodeSessionTicket(sslSocket *ss,
if (rv != SECSuccess)
goto loser;
- /* NPN value. */
- PORT_Assert(alpnSelection.len < 256);
- rv = ssl3_AppendNumberToItem(&plaintext, alpnSelection.len, 1);
+ /* ALPN value. */
+ PORT_Assert(alpnSelection->len < 256);
+ rv = ssl3_AppendNumberToItem(&plaintext, alpnSelection->len, 1);
if (rv != SECSuccess)
goto loser;
- if (alpnSelection.len) {
- rv = ssl3_AppendToItem(&plaintext, alpnSelection.data, alpnSelection.len);
+ if (alpnSelection->len) {
+ rv = ssl3_AppendToItem(&plaintext, alpnSelection->data,
+ alpnSelection->len);
if (rv != SECSuccess)
goto loser;
}
+ rv = ssl3_AppendNumberToItem(&plaintext, ssl_max_early_data_size, 4);
+ if (rv != SECSuccess)
+ goto loser;
+
PORT_Assert(plaintext.len == padding_length);
for (i = 0; i < padding_length; i++)
plaintext.data[i] = (unsigned char)padding_length;
@@ -1225,7 +1154,11 @@ ssl3_EncodeSessionTicket(sslSocket *ss,
/* Generate encrypted portion of ticket. */
PORT_Assert(aes_key);
- aes_ctx = PK11_CreateContextBySymKey(cipherMech, CKA_ENCRYPT, aes_key, &ivItem);
+#ifdef UNSAFE_FUZZER_MODE
+ ciphertext.len = plaintext_item.len;
+ PORT_Memcpy(ciphertext.data, plaintext_item.data, plaintext_item.len);
+#else
+ aes_ctx = PK11_CreateContextBySymKey(CKM_AES_CBC, CKA_ENCRYPT, aes_key, &ivItem);
if (!aes_ctx)
goto loser;
@@ -1236,14 +1169,15 @@ ssl3_EncodeSessionTicket(sslSocket *ss,
PK11_DestroyContext(aes_ctx, PR_TRUE);
if (rv != SECSuccess)
goto loser;
+#endif
/* Convert ciphertext length to network order. */
- length_buf[0] = (ciphertext.len >> 8) & 0xff;
- length_buf[1] = (ciphertext.len) & 0xff;
+ (void)ssl_EncodeUintX(ciphertext.len, 2, length_buf);
/* Compute MAC. */
PORT_Assert(mac_key);
- hmac_ctx = PK11_CreateContextBySymKey(macMech, CKA_SIGN, mac_key, &macParam);
+ hmac_ctx = PK11_CreateContextBySymKey(CKM_SHA256_HMAC, CKA_SIGN, mac_key,
+ &macParam);
if (!hmac_ctx)
goto loser;
@@ -1338,434 +1272,525 @@ ssl3_ClientHandleSessionTicketXtn(const sslSocket *ss, TLSExtensionData *xtnData
return SECSuccess;
}
-/* Generic ticket processing code, common to TLS 1.0-1.2 and
- * TLS 1.3. */
-SECStatus
-ssl3_ProcessSessionTicketCommon(sslSocket *ss, SECItem *data)
+static SECStatus
+ssl_DecryptSessionTicket(sslSocket *ss, const SECItem *rawTicket,
+ const EncryptedSessionTicket *encryptedTicket,
+ SECItem *decryptedTicket)
{
SECStatus rv;
- SECItem *decrypted_state = NULL;
- SessionTicket *parsed_session_ticket = NULL;
- sslSessionID *sid = NULL;
- SSL3Statistics *ssl3stats;
- PRUint32 i;
- SECItem extension_data;
- EncryptedSessionTicket enc_session_ticket;
- unsigned char computed_mac[TLS_EX_SESS_TICKET_MAC_LENGTH];
- unsigned int computed_mac_length;
- PK11SymKey *aes_key = NULL;
- PK11SymKey *mac_key = NULL;
- PK11Context *hmac_ctx;
- CK_MECHANISM_TYPE macMech = CKM_SHA256_HMAC;
- PK11Context *aes_ctx;
- CK_MECHANISM_TYPE cipherMech = CKM_AES_CBC;
- unsigned char *padding;
- PRUint32 padding_length;
- unsigned char *buffer;
- unsigned int buffer_len;
- PRInt32 temp;
- SECItem cert_item;
- PRInt8 nameType = TLS_STE_NO_SERVER_NAME;
+ unsigned char keyName[SESS_TICKET_KEY_NAME_LEN];
+
+ PK11SymKey *macKey = NULL;
+ PK11Context *hmacCtx;
+ unsigned char computedMac[TLS_EX_SESS_TICKET_MAC_LENGTH];
+ unsigned int computedMacLength;
SECItem macParam = { siBuffer, NULL, 0 };
- SECItem alpn_item;
- SECItem ivItem;
- /* Turn off stateless session resumption if the client sends a
- * SessionTicket extension, even if the extension turns out to be
- * malformed (ss->sec.ci.sid is non-NULL when doing session
- * renegotiation.)
- */
- if (ss->sec.ci.sid != NULL) {
- ss->sec.uncache(ss->sec.ci.sid);
- ssl_FreeSID(ss->sec.ci.sid);
- ss->sec.ci.sid = NULL;
- }
+ PK11SymKey *aesKey = NULL;
+#ifndef UNSAFE_FUZZER_MODE
+ PK11Context *aesCtx;
+ SECItem ivItem;
- extension_data.data = data->data; /* Keep a copy for future use. */
- extension_data.len = data->len;
+ unsigned int i;
+ SSL3Opaque *padding;
+ SSL3Opaque paddingLength;
+#endif
- if (ssl3_ParseEncryptedSessionTicket(ss, data, &enc_session_ticket) !=
- SECSuccess) {
- return SECSuccess; /* Pretend it isn't there */
+ PORT_Assert(!decryptedTicket->data);
+ PORT_Assert(!decryptedTicket->len);
+ if (rawTicket->len < TLS_EX_SESS_TICKET_MAC_LENGTH) {
+ PORT_SetError(SSL_ERROR_RX_MALFORMED_CLIENT_HELLO);
+ return SECFailure;
}
/* Get session ticket keys. */
- rv = ssl3_GetSessionTicketKeys(ss, &aes_key, &mac_key);
+ rv = ssl_GetSessionTicketKeys(ss, keyName, &aesKey, &macKey);
if (rv != SECSuccess) {
SSL_DBG(("%d: SSL[%d]: Unable to get/generate session ticket keys.",
SSL_GETPID(), ss->fd));
- goto loser;
+ return SECFailure; /* code already set */
}
- /* If the ticket sent by the client was generated under a key different
- * from the one we have, bypass ticket processing.
+ /* If the ticket sent by the client was generated under a key different from
+ * the one we have, bypass ticket processing. This reports success, meaning
+ * that the handshake completes, but doesn't resume.
*/
- if (PORT_Memcmp(enc_session_ticket.key_name, key_name,
+ if (PORT_Memcmp(encryptedTicket->key_name, keyName,
SESS_TICKET_KEY_NAME_LEN) != 0) {
+#ifndef UNSAFE_FUZZER_MODE
SSL_DBG(("%d: SSL[%d]: Session ticket key_name sent mismatch.",
SSL_GETPID(), ss->fd));
- goto no_ticket;
+ return SECSuccess;
+#endif
}
- /* Verify the MAC on the ticket. MAC verification may also
- * fail if the MAC key has been recently refreshed.
- */
- PORT_Assert(mac_key);
- hmac_ctx = PK11_CreateContextBySymKey(macMech, CKA_SIGN, mac_key, &macParam);
- if (!hmac_ctx) {
+ /* Verify the MAC on the ticket. */
+ PORT_Assert(macKey);
+ hmacCtx = PK11_CreateContextBySymKey(CKM_SHA256_HMAC, CKA_SIGN, macKey,
+ &macParam);
+ if (!hmacCtx) {
SSL_DBG(("%d: SSL[%d]: Unable to create HMAC context: %d.",
SSL_GETPID(), ss->fd, PORT_GetError()));
- goto no_ticket;
- } else {
- SSL_DBG(("%d: SSL[%d]: Successfully created HMAC context.",
- SSL_GETPID(), ss->fd));
- }
- rv = PK11_DigestBegin(hmac_ctx);
- if (rv != SECSuccess) {
- PK11_DestroyContext(hmac_ctx, PR_TRUE);
- goto no_ticket;
+ PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
+ return SECFailure;
}
- rv = PK11_DigestOp(hmac_ctx, extension_data.data,
- extension_data.len -
- TLS_EX_SESS_TICKET_MAC_LENGTH);
+
+ SSL_DBG(("%d: SSL[%d]: Successfully created HMAC context.",
+ SSL_GETPID(), ss->fd));
+ do {
+ rv = PK11_DigestBegin(hmacCtx);
+ if (rv != SECSuccess) {
+ break;
+ }
+ rv = PK11_DigestOp(hmacCtx, rawTicket->data,
+ rawTicket->len - TLS_EX_SESS_TICKET_MAC_LENGTH);
+ if (rv != SECSuccess) {
+ break;
+ }
+ rv = PK11_DigestFinal(hmacCtx, computedMac, &computedMacLength,
+ sizeof(computedMac));
+ } while (0);
+ PK11_DestroyContext(hmacCtx, PR_TRUE);
if (rv != SECSuccess) {
- PK11_DestroyContext(hmac_ctx, PR_TRUE);
- goto no_ticket;
+ PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
+ return SECFailure;
}
- rv = PK11_DigestFinal(hmac_ctx, computed_mac,
- &computed_mac_length, sizeof(computed_mac));
- PK11_DestroyContext(hmac_ctx, PR_TRUE);
- if (rv != SECSuccess)
- goto no_ticket;
- if (NSS_SecureMemcmp(computed_mac, enc_session_ticket.mac,
- computed_mac_length) !=
- 0) {
+ if (NSS_SecureMemcmp(computedMac, encryptedTicket->mac,
+ computedMacLength) != 0) {
+#ifndef UNSAFE_FUZZER_MODE
SSL_DBG(("%d: SSL[%d]: Session ticket MAC mismatch.",
SSL_GETPID(), ss->fd));
- goto no_ticket;
+ PORT_SetError(SSL_ERROR_RX_MALFORMED_CLIENT_HELLO);
+ return SECFailure;
+#endif
}
- /* We ignore key_name for now.
- * This is ok as MAC verification succeeded.
- */
-
/* Decrypt the ticket. */
/* Plaintext is shorter than the ciphertext due to padding. */
- decrypted_state = SECITEM_AllocItem(NULL, NULL,
- enc_session_ticket.encrypted_state.len);
-
- PORT_Assert(aes_key);
- ivItem.data = enc_session_ticket.iv;
+ if (!SECITEM_AllocItem(NULL, decryptedTicket,
+ encryptedTicket->encrypted_state.len)) {
+ return SECFailure; /* code already set */
+ }
+
+ PORT_Assert(aesKey);
+#ifdef UNSAFE_FUZZER_MODE
+ decryptedTicket->len = encryptedTicket->encrypted_state.len;
+ PORT_Memcpy(decryptedTicket->data,
+ encryptedTicket->encrypted_state.data,
+ encryptedTicket->encrypted_state.len);
+#else
+ ivItem.data = encryptedTicket->iv;
ivItem.len = AES_BLOCK_SIZE;
- aes_ctx = PK11_CreateContextBySymKey(cipherMech, CKA_DECRYPT,
- aes_key, &ivItem);
- if (!aes_ctx) {
+ aesCtx = PK11_CreateContextBySymKey(CKM_AES_CBC, CKA_DECRYPT, aesKey,
+ &ivItem);
+ if (!aesCtx) {
SSL_DBG(("%d: SSL[%d]: Unable to create AES context.",
SSL_GETPID(), ss->fd));
- goto no_ticket;
+ PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
+ return SECFailure;
}
- rv = PK11_CipherOp(aes_ctx, decrypted_state->data,
- (int *)&decrypted_state->len, decrypted_state->len,
- enc_session_ticket.encrypted_state.data,
- enc_session_ticket.encrypted_state.len);
- PK11_Finalize(aes_ctx);
- PK11_DestroyContext(aes_ctx, PR_TRUE);
- if (rv != SECSuccess)
- goto no_ticket;
+ do {
+ rv = PK11_CipherOp(aesCtx, decryptedTicket->data,
+ (int *)&decryptedTicket->len, decryptedTicket->len,
+ encryptedTicket->encrypted_state.data,
+ encryptedTicket->encrypted_state.len);
+ if (rv != SECSuccess) {
+ break;
+ }
+ rv = PK11_Finalize(aesCtx);
+ if (rv != SECSuccess) {
+ break;
+ }
+ } while (0);
+ PK11_DestroyContext(aesCtx, PR_TRUE);
+ if (rv != SECSuccess) {
+ PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
+ return SECFailure;
+ }
/* Check padding. */
- padding_length =
- (PRUint32)decrypted_state->data[decrypted_state->len - 1];
- if (padding_length == 0 || padding_length > AES_BLOCK_SIZE)
- goto no_ticket;
+ paddingLength = decryptedTicket->data[decryptedTicket->len - 1];
+ if (paddingLength == 0 || paddingLength > AES_BLOCK_SIZE) {
+ PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
+ return SECFailure;
+ }
- padding = &decrypted_state->data[decrypted_state->len - padding_length];
- for (i = 0; i < padding_length; i++, padding++) {
- if (padding_length != (PRUint32)*padding)
- goto no_ticket;
+ padding = &decryptedTicket->data[decryptedTicket->len - paddingLength];
+ for (i = 0; i < paddingLength; i++, padding++) {
+ if (paddingLength != *padding) {
+ PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
+ return SECFailure;
+ }
}
+ decryptedTicket->len -= paddingLength;
+#endif /* UNSAFE_FUZZER_MODE */
- /* Deserialize session state. */
- buffer = decrypted_state->data;
- buffer_len = decrypted_state->len;
+ return SECSuccess;
+}
- parsed_session_ticket = PORT_ZAlloc(sizeof(SessionTicket));
- if (parsed_session_ticket == NULL) {
- rv = SECFailure;
- goto loser;
+static SECStatus
+ssl_ParseSessionTicket(sslSocket *ss, const SECItem *decryptedTicket,
+ SessionTicket *parsedTicket)
+{
+ PRUint32 temp;
+ SECStatus rv;
+
+ SSL3Opaque *buffer = decryptedTicket->data;
+ unsigned int len = decryptedTicket->len;
+
+ PORT_Memset(parsedTicket, 0, sizeof(*parsedTicket));
+ parsedTicket->valid = PR_FALSE;
+
+ /* If the decrypted ticket is empty, then report success, but leave the
+ * ticket marked as invalid. */
+ if (decryptedTicket->len == 0) {
+ return SECSuccess;
}
- /* Read ticket_version and reject if the version is wrong */
- temp = ssl3_ExtConsumeHandshakeNumber(ss, 2, &buffer, &buffer_len);
- if (temp != TLS_EX_SESS_TICKET_VERSION)
- goto no_ticket;
+ /* Read ticket version. */
+ rv = ssl3_ExtConsumeHandshakeNumber(ss, &temp, 2, &buffer, &len);
+ if (rv != SECSuccess) {
+ PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
+ return SECFailure;
+ }
- parsed_session_ticket->ticket_version = (SSL3ProtocolVersion)temp;
+ /* Skip the ticket if the version is wrong. This won't result in a
+ * handshake failure, just a failure to resume. */
+ if (temp != TLS_EX_SESS_TICKET_VERSION) {
+ return SECSuccess;
+ }
/* Read SSLVersion. */
- temp = ssl3_ExtConsumeHandshakeNumber(ss, 2, &buffer, &buffer_len);
- if (temp < 0)
- goto no_ticket;
- parsed_session_ticket->ssl_version = (SSL3ProtocolVersion)temp;
+ rv = ssl3_ExtConsumeHandshakeNumber(ss, &temp, 2, &buffer, &len);
+ if (rv != SECSuccess) {
+ PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
+ return SECFailure;
+ }
+ parsedTicket->ssl_version = (SSL3ProtocolVersion)temp;
+ if (!ssl3_VersionIsSupported(ss->protocolVariant,
+ parsedTicket->ssl_version)) {
+ /* This socket doesn't support the version from the ticket. */
+ return SECSuccess;
+ }
/* Read cipher_suite. */
- temp = ssl3_ExtConsumeHandshakeNumber(ss, 2, &buffer, &buffer_len);
- if (temp < 0)
- goto no_ticket;
- parsed_session_ticket->cipher_suite = (ssl3CipherSuite)temp;
+ rv = ssl3_ExtConsumeHandshakeNumber(ss, &temp, 2, &buffer, &len);
+ if (rv != SECSuccess) {
+ PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
+ return SECFailure;
+ }
+ parsedTicket->cipher_suite = (ssl3CipherSuite)temp;
/* Read compression_method. */
- temp = ssl3_ExtConsumeHandshakeNumber(ss, 1, &buffer, &buffer_len);
- if (temp < 0)
- goto no_ticket;
- parsed_session_ticket->compression_method = (SSLCompressionMethod)temp;
+ rv = ssl3_ExtConsumeHandshakeNumber(ss, &temp, 1, &buffer, &len);
+ if (rv != SECSuccess) {
+ PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
+ return SECFailure;
+ }
+ parsedTicket->compression_method = (SSLCompressionMethod)temp;
/* Read cipher spec parameters. */
- temp = ssl3_ExtConsumeHandshakeNumber(ss, 1, &buffer, &buffer_len);
- if (temp < 0)
- goto no_ticket;
- parsed_session_ticket->authType = (SSLAuthType)temp;
- temp = ssl3_ExtConsumeHandshakeNumber(ss, 4, &buffer, &buffer_len);
- if (temp < 0)
- goto no_ticket;
- parsed_session_ticket->authKeyBits = (PRUint32)temp;
- temp = ssl3_ExtConsumeHandshakeNumber(ss, 1, &buffer, &buffer_len);
- if (temp < 0)
- goto no_ticket;
- parsed_session_ticket->keaType = (SSLKEAType)temp;
- temp = ssl3_ExtConsumeHandshakeNumber(ss, 4, &buffer, &buffer_len);
- if (temp < 0)
- goto no_ticket;
- parsed_session_ticket->keaKeyBits = (PRUint32)temp;
-
- /* Read certificate slot */
- parsed_session_ticket->certType.authType = parsed_session_ticket->authType;
- temp = ssl3_ExtConsumeHandshakeNumber(ss, 1, &buffer, &buffer_len);
- if (temp < 0)
- goto no_ticket;
- switch (parsed_session_ticket->authType) {
- case ssl_auth_ecdsa:
- case ssl_auth_ecdh_rsa:
- case ssl_auth_ecdh_ecdsa: {
- const sslNamedGroupDef *group =
- ssl_LookupNamedGroup((SSLNamedGroup)temp);
- if (!group || group->keaType != ssl_kea_ecdh) {
- goto no_ticket;
- }
- parsed_session_ticket->certType.namedCurve = group;
- } break;
- default:
- break;
+ rv = ssl3_ExtConsumeHandshakeNumber(ss, &temp, 1, &buffer, &len);
+ if (rv != SECSuccess) {
+ PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
+ return SECFailure;
+ }
+ parsedTicket->authType = (SSLAuthType)temp;
+ rv = ssl3_ExtConsumeHandshakeNumber(ss, &temp, 4, &buffer, &len);
+ if (rv != SECSuccess) {
+ PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
+ return SECFailure;
}
+ parsedTicket->authKeyBits = temp;
+ rv = ssl3_ExtConsumeHandshakeNumber(ss, &temp, 1, &buffer, &len);
+ if (rv != SECSuccess) {
+ PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
+ return SECFailure;
+ }
+ parsedTicket->keaType = (SSLKEAType)temp;
+ rv = ssl3_ExtConsumeHandshakeNumber(ss, &temp, 4, &buffer, &len);
+ if (rv != SECSuccess) {
+ PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
+ return SECFailure;
+ }
+ parsedTicket->keaKeyBits = temp;
- /* Read wrapped master_secret. */
- temp = ssl3_ExtConsumeHandshakeNumber(ss, 1, &buffer, &buffer_len);
- if (temp < 0)
- goto no_ticket;
- parsed_session_ticket->ms_is_wrapped = (PRBool)temp;
-
- temp = ssl3_ExtConsumeHandshakeNumber(ss, 4, &buffer, &buffer_len);
- if (temp < 0)
- goto no_ticket;
- parsed_session_ticket->msWrapMech = (CK_MECHANISM_TYPE)temp;
-
- temp = ssl3_ExtConsumeHandshakeNumber(ss, 2, &buffer, &buffer_len);
- if (temp < 0)
- goto no_ticket;
- parsed_session_ticket->ms_length = (PRUint16)temp;
- if (parsed_session_ticket->ms_length == 0 || /* sanity check MS. */
- parsed_session_ticket->ms_length >
- sizeof(parsed_session_ticket->master_secret))
- goto no_ticket;
-
- /* Allow for the wrapped master secret to be longer. */
- if (buffer_len < parsed_session_ticket->ms_length)
- goto no_ticket;
- PORT_Memcpy(parsed_session_ticket->master_secret, buffer,
- parsed_session_ticket->ms_length);
- buffer += parsed_session_ticket->ms_length;
- buffer_len -= parsed_session_ticket->ms_length;
-
- /* Read client_identity */
- temp = ssl3_ExtConsumeHandshakeNumber(ss, 1, &buffer, &buffer_len);
- if (temp < 0)
- goto no_ticket;
- parsed_session_ticket->client_identity.client_auth_type =
- (ClientAuthenticationType)temp;
- switch (parsed_session_ticket->client_identity.client_auth_type) {
+ /* Read the optional named curve. */
+ rv = ssl3_ExtConsumeHandshakeNumber(ss, &temp, 1, &buffer, &len);
+ if (rv != SECSuccess) {
+ PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
+ return SECFailure;
+ }
+ if (parsedTicket->authType == ssl_auth_ecdsa ||
+ parsedTicket->authType == ssl_auth_ecdh_rsa ||
+ parsedTicket->authType == ssl_auth_ecdh_ecdsa) {
+ const sslNamedGroupDef *group =
+ ssl_LookupNamedGroup((SSLNamedGroup)temp);
+ if (!group || group->keaType != ssl_kea_ecdh) {
+ PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
+ return SECFailure;
+ }
+ parsedTicket->namedCurve = group;
+ }
+
+ /* Read the master secret (and how it is wrapped). */
+ rv = ssl3_ExtConsumeHandshakeNumber(ss, &temp, 1, &buffer, &len);
+ if (rv != SECSuccess) {
+ PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
+ return SECFailure;
+ }
+ PORT_Assert(temp == PR_TRUE || temp == PR_FALSE);
+ parsedTicket->ms_is_wrapped = (PRBool)temp;
+
+ rv = ssl3_ExtConsumeHandshakeNumber(ss, &temp, 4, &buffer, &len);
+ if (rv != SECSuccess) {
+ PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
+ return SECFailure;
+ }
+ parsedTicket->msWrapMech = (CK_MECHANISM_TYPE)temp;
+
+ rv = ssl3_ExtConsumeHandshakeNumber(ss, &temp, 2, &buffer, &len);
+ if (rv != SECSuccess) {
+ PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
+ return SECFailure;
+ }
+ if (temp == 0 || temp > sizeof(parsedTicket->master_secret)) {
+ PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
+ return SECFailure;
+ }
+ parsedTicket->ms_length = (PRUint16)temp;
+
+ /* Read the master secret. */
+ rv = ssl3_ExtConsumeHandshake(ss, parsedTicket->master_secret,
+ parsedTicket->ms_length, &buffer, &len);
+ if (rv != SECSuccess) {
+ PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
+ return SECFailure;
+ }
+ /* Read client identity */
+ rv = ssl3_ExtConsumeHandshakeNumber(ss, &temp, 1, &buffer, &len);
+ if (rv != SECSuccess) {
+ PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
+ return SECFailure;
+ }
+ parsedTicket->client_auth_type = (ClientAuthenticationType)temp;
+ switch (parsedTicket->client_auth_type) {
case CLIENT_AUTH_ANONYMOUS:
break;
case CLIENT_AUTH_CERTIFICATE:
- rv = ssl3_ExtConsumeHandshakeVariable(ss, &cert_item, 3,
- &buffer, &buffer_len);
- if (rv != SECSuccess)
- goto no_ticket;
- rv = SECITEM_CopyItem(NULL, &parsed_session_ticket->peer_cert,
- &cert_item);
- if (rv != SECSuccess)
- goto no_ticket;
+ rv = ssl3_ExtConsumeHandshakeVariable(ss, &parsedTicket->peer_cert, 2,
+ &buffer, &len);
+ if (rv != SECSuccess) {
+ PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
+ return SECFailure;
+ }
break;
default:
- goto no_ticket;
+ PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
+ return SECFailure;
}
/* Read timestamp. */
- temp = ssl3_ExtConsumeHandshakeNumber(ss, 4, &buffer, &buffer_len);
- if (temp < 0)
- goto no_ticket;
- parsed_session_ticket->timestamp = (PRUint32)temp;
+ rv = ssl3_ExtConsumeHandshakeNumber(ss, &temp, 4, &buffer, &len);
+ if (rv != SECSuccess) {
+ PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
+ return SECFailure;
+ }
+ parsedTicket->timestamp = temp;
/* Read server name */
- nameType =
- ssl3_ExtConsumeHandshakeNumber(ss, 1, &buffer, &buffer_len);
- if (nameType != TLS_STE_NO_SERVER_NAME) {
- SECItem name_item;
- rv = ssl3_ExtConsumeHandshakeVariable(ss, &name_item, 2, &buffer,
- &buffer_len);
- if (rv != SECSuccess)
- goto no_ticket;
- rv = SECITEM_CopyItem(NULL, &parsed_session_ticket->srvName,
- &name_item);
- if (rv != SECSuccess)
- goto no_ticket;
- parsed_session_ticket->srvName.type = nameType;
+ rv = ssl3_ExtConsumeHandshakeVariable(ss, &parsedTicket->srvName, 2,
+ &buffer, &len);
+ if (rv != SECSuccess) {
+ PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
+ return SECFailure;
}
/* Read extendedMasterSecretUsed */
- temp = ssl3_ExtConsumeHandshakeNumber(ss, 1, &buffer, &buffer_len);
- if (temp < 0)
- goto no_ticket;
+ rv = ssl3_ExtConsumeHandshakeNumber(ss, &temp, 1, &buffer, &len);
+ if (rv != SECSuccess) {
+ PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
+ return SECFailure;
+ }
PORT_Assert(temp == PR_TRUE || temp == PR_FALSE);
- parsed_session_ticket->extendedMasterSecretUsed = (PRBool)temp;
+ parsedTicket->extendedMasterSecretUsed = (PRBool)temp;
- rv = ssl3_ExtConsumeHandshake(ss, &parsed_session_ticket->flags, 4,
- &buffer, &buffer_len);
- if (rv != SECSuccess)
- goto no_ticket;
- parsed_session_ticket->flags = PR_ntohl(parsed_session_ticket->flags);
+ rv = ssl3_ExtConsumeHandshake(ss, &temp, 4, &buffer, &len);
+ if (rv != SECSuccess) {
+ PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
+ return SECFailure;
+ }
+ parsedTicket->flags = PR_ntohl(temp);
- rv = ssl3_ExtConsumeHandshakeVariable(ss, &alpn_item, 1, &buffer, &buffer_len);
- if (rv != SECSuccess)
- goto no_ticket;
- if (alpn_item.len != 0) {
- rv = SECITEM_CopyItem(NULL, &parsed_session_ticket->alpnSelection,
- &alpn_item);
- if (rv != SECSuccess)
- goto no_ticket;
- if (alpn_item.len >= 256)
- goto no_ticket;
+ rv = ssl3_ExtConsumeHandshakeVariable(ss, &parsedTicket->alpnSelection, 1,
+ &buffer, &len);
+ PORT_Assert(parsedTicket->alpnSelection.len < 256);
+ if (rv != SECSuccess) {
+ PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
+ return SECFailure;
}
+ rv = ssl3_ExtConsumeHandshakeNumber(ss, &temp, 4, &buffer, &len);
+ if (rv != SECSuccess) {
+ PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
+ return SECFailure;
+ }
+ parsedTicket->maxEarlyData = temp;
+
+#ifndef UNSAFE_FUZZER_MODE
/* Done parsing. Check that all bytes have been consumed. */
- if (buffer_len != padding_length)
- goto no_ticket;
+ if (len != 0) {
+ PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
+ return SECFailure;
+ }
+#endif
- /* Use the ticket if it has not expired, otherwise free the allocated
- * memory since the ticket is of no use.
- */
- if (parsed_session_ticket->timestamp != 0 &&
- parsed_session_ticket->timestamp +
- TLS_EX_SESS_TICKET_LIFETIME_HINT >
- ssl_Time()) {
-
- sid = ssl3_NewSessionID(ss, PR_TRUE);
- if (sid == NULL) {
- rv = SECFailure;
+ parsedTicket->valid = PR_TRUE;
+ return SECSuccess;
+}
+
+static SECStatus
+ssl_CreateSIDFromTicket(sslSocket *ss, const SECItem *rawTicket,
+ SessionTicket *parsedTicket, sslSessionID **out)
+{
+ sslSessionID *sid;
+ SECStatus rv;
+
+ sid = ssl3_NewSessionID(ss, PR_TRUE);
+ if (sid == NULL) {
+ return SECFailure;
+ }
+
+ /* Copy over parameters. */
+ sid->version = parsedTicket->ssl_version;
+ sid->u.ssl3.cipherSuite = parsedTicket->cipher_suite;
+ sid->u.ssl3.compression = parsedTicket->compression_method;
+ sid->authType = parsedTicket->authType;
+ sid->authKeyBits = parsedTicket->authKeyBits;
+ sid->keaType = parsedTicket->keaType;
+ sid->keaKeyBits = parsedTicket->keaKeyBits;
+ sid->namedCurve = parsedTicket->namedCurve;
+
+ rv = SECITEM_CopyItem(NULL, &sid->u.ssl3.locked.sessionTicket.ticket,
+ rawTicket);
+ if (rv != SECSuccess) {
+ goto loser;
+ }
+ sid->u.ssl3.locked.sessionTicket.flags = parsedTicket->flags;
+ sid->u.ssl3.locked.sessionTicket.max_early_data_size =
+ parsedTicket->maxEarlyData;
+
+ if (parsedTicket->ms_length >
+ sizeof(sid->u.ssl3.keys.wrapped_master_secret)) {
+ goto loser;
+ }
+ PORT_Memcpy(sid->u.ssl3.keys.wrapped_master_secret,
+ parsedTicket->master_secret, parsedTicket->ms_length);
+ sid->u.ssl3.keys.wrapped_master_secret_len = parsedTicket->ms_length;
+ sid->u.ssl3.masterWrapMech = parsedTicket->msWrapMech;
+ sid->u.ssl3.keys.msIsWrapped = parsedTicket->ms_is_wrapped;
+ sid->u.ssl3.masterValid = PR_TRUE;
+ sid->u.ssl3.keys.resumable = PR_TRUE;
+ sid->u.ssl3.keys.extendedMasterSecretUsed = parsedTicket->extendedMasterSecretUsed;
+
+ /* Copy over client cert from session ticket if there is one. */
+ if (parsedTicket->peer_cert.data != NULL) {
+ PORT_Assert(!sid->peerCert);
+ sid->peerCert = CERT_NewTempCertificate(ss->dbHandle,
+ &parsedTicket->peer_cert,
+ NULL, PR_FALSE, PR_TRUE);
+ if (!sid->peerCert) {
goto loser;
}
+ }
- /* Copy over parameters. */
- sid->version = parsed_session_ticket->ssl_version;
- sid->u.ssl3.cipherSuite = parsed_session_ticket->cipher_suite;
- sid->u.ssl3.compression = parsed_session_ticket->compression_method;
- sid->authType = parsed_session_ticket->authType;
- sid->authKeyBits = parsed_session_ticket->authKeyBits;
- sid->keaType = parsed_session_ticket->keaType;
- sid->keaKeyBits = parsed_session_ticket->keaKeyBits;
- memcpy(&sid->certType, &parsed_session_ticket->certType,
- sizeof(sslServerCertType));
-
- if (SECITEM_CopyItem(NULL, &sid->u.ssl3.locked.sessionTicket.ticket,
- &extension_data) != SECSuccess)
- goto no_ticket;
- sid->u.ssl3.locked.sessionTicket.flags = parsed_session_ticket->flags;
-
- if (parsed_session_ticket->ms_length >
- sizeof(sid->u.ssl3.keys.wrapped_master_secret))
- goto no_ticket;
- PORT_Memcpy(sid->u.ssl3.keys.wrapped_master_secret,
- parsed_session_ticket->master_secret,
- parsed_session_ticket->ms_length);
- sid->u.ssl3.keys.wrapped_master_secret_len =
- parsed_session_ticket->ms_length;
- sid->u.ssl3.masterWrapMech = parsed_session_ticket->msWrapMech;
- sid->u.ssl3.keys.msIsWrapped =
- parsed_session_ticket->ms_is_wrapped;
- sid->u.ssl3.masterValid = PR_TRUE;
- sid->u.ssl3.keys.resumable = PR_TRUE;
- sid->u.ssl3.keys.extendedMasterSecretUsed = parsed_session_ticket->extendedMasterSecretUsed;
-
- /* Copy over client cert from session ticket if there is one. */
- if (parsed_session_ticket->peer_cert.data != NULL) {
- if (sid->peerCert != NULL)
- CERT_DestroyCertificate(sid->peerCert);
- sid->peerCert = CERT_NewTempCertificate(ss->dbHandle,
- &parsed_session_ticket->peer_cert, NULL, PR_FALSE, PR_TRUE);
- if (sid->peerCert == NULL) {
- rv = SECFailure;
- goto loser;
- }
- }
- if (parsed_session_ticket->srvName.data != NULL) {
- if (sid->u.ssl3.srvName.data) {
- SECITEM_FreeItem(&sid->u.ssl3.srvName, PR_FALSE);
- }
- sid->u.ssl3.srvName = parsed_session_ticket->srvName;
+ /* Transfer ownership of the remaining items. */
+ if (parsedTicket->srvName.data != NULL) {
+ SECITEM_FreeItem(&sid->u.ssl3.srvName, PR_FALSE);
+ rv = SECITEM_CopyItem(NULL, &sid->u.ssl3.srvName,
+ &parsedTicket->srvName);
+ if (rv != SECSuccess) {
+ goto loser;
}
- if (parsed_session_ticket->alpnSelection.data != NULL) {
- sid->u.ssl3.alpnSelection = parsed_session_ticket->alpnSelection;
- /* So we don't free below. */
- parsed_session_ticket->alpnSelection.data = NULL;
+ }
+ if (parsedTicket->alpnSelection.data != NULL) {
+ rv = SECITEM_CopyItem(NULL, &sid->u.ssl3.alpnSelection,
+ &parsedTicket->alpnSelection);
+ if (rv != SECSuccess) {
+ goto loser;
}
- ss->statelessResume = PR_TRUE;
- ss->sec.ci.sid = sid;
}
- if (0) {
- no_ticket:
+ *out = sid;
+ return SECSuccess;
+
+loser:
+ ssl_FreeSID(sid);
+ return SECFailure;
+}
+
+/* Generic ticket processing code, common to all TLS versions. */
+SECStatus
+ssl3_ProcessSessionTicketCommon(sslSocket *ss, SECItem *data)
+{
+ EncryptedSessionTicket encryptedTicket;
+ SECItem decryptedTicket = { siBuffer, NULL, 0 };
+ SessionTicket parsedTicket;
+ SECStatus rv;
+
+ if (ss->sec.ci.sid != NULL) {
+ ss->sec.uncache(ss->sec.ci.sid);
+ ssl_FreeSID(ss->sec.ci.sid);
+ ss->sec.ci.sid = NULL;
+ }
+
+ rv = ssl3_ParseEncryptedSessionTicket(ss, data, &encryptedTicket);
+ if (rv != SECSuccess) {
+ PORT_SetError(SSL_ERROR_RX_MALFORMED_CLIENT_HELLO);
+ return SECFailure;
+ }
+
+ rv = ssl_DecryptSessionTicket(ss, data, &encryptedTicket,
+ &decryptedTicket);
+ if (rv != SECSuccess) {
+ PORT_SetError(SSL_ERROR_RX_MALFORMED_CLIENT_HELLO);
+ return SECFailure;
+ }
+
+ rv = ssl_ParseSessionTicket(ss, &decryptedTicket, &parsedTicket);
+ if (rv != SECSuccess) {
+ SSL3Statistics *ssl3stats;
+
SSL_DBG(("%d: SSL[%d]: Session ticket parsing failed.",
SSL_GETPID(), ss->fd));
ssl3stats = SSL_GetStatistics();
SSL_AtomicIncrementLong(&ssl3stats->hch_sid_ticket_parse_failures);
+ goto loser; /* code already set */
}
- rv = SECSuccess;
-loser:
- /* ss->sec.ci.sid == sid if it did NOT come here via goto statement
- * in that case do not free sid
- */
- if (sid && (ss->sec.ci.sid != sid)) {
- ssl_FreeSID(sid);
- sid = NULL;
- }
- if (decrypted_state != NULL) {
- SECITEM_FreeItem(decrypted_state, PR_TRUE);
- decrypted_state = NULL;
- }
+ /* Use the ticket if it is valid and unexpired. */
+ if (parsedTicket.valid &&
+ parsedTicket.timestamp + ssl_ticket_lifetime > ssl_Time()) {
+ sslSessionID *sid;
- if (parsed_session_ticket != NULL) {
- if (parsed_session_ticket->peer_cert.data) {
- SECITEM_FreeItem(&parsed_session_ticket->peer_cert, PR_FALSE);
- }
- if (parsed_session_ticket->alpnSelection.data) {
- SECITEM_FreeItem(&parsed_session_ticket->alpnSelection, PR_FALSE);
+ rv = ssl_CreateSIDFromTicket(ss, data, &parsedTicket, &sid);
+ if (rv != SECSuccess) {
+ goto loser; /* code already set */
}
- PORT_ZFree(parsed_session_ticket, sizeof(SessionTicket));
+ ss->statelessResume = PR_TRUE;
+ ss->sec.ci.sid = sid;
}
- return rv;
+ SECITEM_ZfreeItem(&decryptedTicket, PR_FALSE);
+ PORT_Memset(&parsedTicket, 0, sizeof(parsedTicket));
+ return SECSuccess;
+
+loser:
+ SECITEM_ZfreeItem(&decryptedTicket, PR_FALSE);
+ PORT_Memset(&parsedTicket, 0, sizeof(parsedTicket));
+ return SECFailure;
}
SECStatus
@@ -2145,7 +2170,8 @@ ssl3_ServerHandleSigAlgsXtn(const sslSocket *ss, TLSExtensionData *xtnData, PRUi
&xtnData->clientSigSchemes,
&xtnData->numClientSigScheme,
&data->data, &data->len);
- if (rv != SECSuccess) {
+ if (rv != SECSuccess || xtnData->numClientSigScheme == 0) {
+ ssl3_ExtSendAlert(ss, alert_fatal, decode_error);
PORT_SetError(SSL_ERROR_RX_MALFORMED_CLIENT_HELLO);
return SECFailure;
}
@@ -2216,55 +2242,73 @@ ssl3_ClientSendSigAlgsXtn(const sslSocket *ss, TLSExtensionData *xtnData, PRBool
/* Takes the size of the ClientHello, less the record header, and determines how
* much padding is required. */
-unsigned int
-ssl3_CalculatePaddingExtensionLength(unsigned int clientHelloLength)
+void
+ssl3_CalculatePaddingExtLen(sslSocket *ss,
+ unsigned int clientHelloLength)
{
unsigned int recordLength = 1 /* handshake message type */ +
3 /* handshake message length */ +
clientHelloLength;
- unsigned int extensionLength;
+ unsigned int extensionLen;
+
+ /* Don't pad for DTLS, for SSLv3, or for renegotiation. */
+ if (IS_DTLS(ss) ||
+ ss->vrange.max < SSL_LIBRARY_VERSION_TLS_1_0 ||
+ ss->firstHsDone) {
+ return;
+ }
+ /* A padding extension may be included to ensure that the record containing
+ * the ClientHello doesn't have a length between 256 and 511 bytes
+ * (inclusive). Initial ClientHello records with such lengths trigger bugs
+ * in F5 devices. */
if (recordLength < 256 || recordLength >= 512) {
- return 0;
+ return;
}
- extensionLength = 512 - recordLength;
+ extensionLen = 512 - recordLength;
/* Extensions take at least four bytes to encode. Always include at least
- * one byte of data if including the extension. Some servers (e.g.
- * WebSphere Application Server 7.0 and Tomcat) will time out or terminate
- * the connection if the last extension in the client hello is empty. */
- if (extensionLength < 4 + 1) {
- extensionLength = 4 + 1;
+ * one byte of data if we are padding. Some servers will time out or
+ * terminate the connection if the last ClientHello extension is empty. */
+ if (extensionLen < 4 + 1) {
+ extensionLen = 4 + 1;
}
- return extensionLength;
+ ss->xtnData.paddingLen = extensionLen - 4;
}
-/* ssl3_AppendPaddingExtension possibly adds an extension which ensures that a
+/* ssl3_SendPaddingExtension possibly adds an extension which ensures that a
* ClientHello record is either < 256 bytes or is >= 512 bytes. This ensures
* that we don't trigger bugs in F5 products. */
PRInt32
-ssl3_AppendPaddingExtension(sslSocket *ss, unsigned int extensionLen,
- PRUint32 maxBytes)
+ssl3_ClientSendPaddingExtension(const sslSocket *ss, TLSExtensionData *xtnData,
+ PRBool append, PRUint32 maxBytes)
{
- unsigned int paddingLen = extensionLen - 4;
- static unsigned char padding[252];
+ static unsigned char padding[252] = { 0 };
+ unsigned int extensionLen;
+ SECStatus rv;
- if (extensionLen == 0) {
+ /* On the length-calculation pass, report zero total length. The record
+ * will be larger on the second pass if needed. */
+ if (!append || !xtnData->paddingLen) {
return 0;
}
+ extensionLen = xtnData->paddingLen + 4;
if (extensionLen > maxBytes ||
- !paddingLen ||
- paddingLen > sizeof(padding)) {
+ xtnData->paddingLen > sizeof(padding)) {
PORT_Assert(0);
return -1;
}
- if (SECSuccess != ssl3_ExtAppendHandshakeNumber(ss, ssl_padding_xtn, 2))
+ rv = ssl3_ExtAppendHandshakeNumber(ss, ssl_padding_xtn, 2);
+ if (rv != SECSuccess) {
return -1;
- if (SECSuccess != ssl3_ExtAppendHandshakeVariable(ss, padding, paddingLen, 2))
+ }
+ rv = ssl3_ExtAppendHandshakeVariable(ss, padding, xtnData->paddingLen, 2);
+ if (rv != SECSuccess) {
return -1;
+ }
return extensionLen;
}
@@ -2484,7 +2528,8 @@ ssl3_HandleSupportedPointFormatsXtn(const sslSocket *ss, TLSExtensionData *xtnDa
static SECStatus
ssl_UpdateSupportedGroups(sslSocket *ss, SECItem *data)
{
- PRInt32 list_len;
+ SECStatus rv;
+ PRUint32 list_len;
unsigned int i;
const sslNamedGroupDef *enabled[SSL_NAMED_GROUP_COUNT] = { 0 };
PORT_Assert(SSL_NAMED_GROUP_COUNT == PR_ARRAY_SIZE(enabled));
@@ -2495,8 +2540,8 @@ ssl_UpdateSupportedGroups(sslSocket *ss, SECItem *data)
}
/* get the length of elliptic_curve_list */
- list_len = ssl3_ConsumeHandshakeNumber(ss, 2, &data->data, &data->len);
- if (list_len < 0 || data->len != list_len || (data->len % 2) != 0) {
+ rv = ssl3_ConsumeHandshakeNumber(ss, &list_len, 2, &data->data, &data->len);
+ if (rv != SECSuccess || data->len != list_len || (data->len % 2) != 0) {
(void)ssl3_DecodeError(ss);
return SECFailure;
}
@@ -2510,9 +2555,10 @@ ssl_UpdateSupportedGroups(sslSocket *ss, SECItem *data)
/* Read groups from data and enable if in |enabled| */
while (data->len) {
const sslNamedGroupDef *group;
- PRInt32 curve_name =
- ssl3_ConsumeHandshakeNumber(ss, 2, &data->data, &data->len);
- if (curve_name < 0) {
+ PRUint32 curve_name;
+ rv = ssl3_ConsumeHandshakeNumber(ss, &curve_name, 2, &data->data,
+ &data->len);
+ if (rv != SECSuccess) {
return SECFailure; /* fatal alert already sent */
}
group = ssl_LookupNamedGroup(curve_name);
diff --git a/nss/lib/ssl/ssl3exthandle.h b/nss/lib/ssl/ssl3exthandle.h
index 65223d6..5fdbe90 100644
--- a/nss/lib/ssl/ssl3exthandle.h
+++ b/nss/lib/ssl/ssl3exthandle.h
@@ -49,6 +49,9 @@ PRInt32 ssl3_ClientSendSigAlgsXtn(const sslSocket *ss, TLSExtensionData *xtnData
SECStatus ssl3_ServerHandleSigAlgsXtn(const sslSocket *ss, TLSExtensionData *xtnData, PRUint16 ex_type,
SECItem *data);
+PRInt32 ssl3_ClientSendPaddingExtension(const sslSocket *ss, TLSExtensionData *xtnData,
+ PRBool append, PRUint32 maxBytes);
+
PRInt32 ssl3_ClientSendSignedCertTimestampXtn(const sslSocket *ss, TLSExtensionData *xtnData,
PRBool append,
PRUint32 maxBytes);
diff --git a/nss/lib/ssl/ssl3gthr.c b/nss/lib/ssl/ssl3gthr.c
index 2bcc1d0..cf6f4cb 100644
--- a/nss/lib/ssl/ssl3gthr.c
+++ b/nss/lib/ssl/ssl3gthr.c
@@ -32,6 +32,7 @@ ssl3_InitGather(sslGather *gs)
gs->readOffset = 0;
gs->dtlsPacketOffset = 0;
gs->dtlsPacket.len = 0;
+ gs->rejectV2Records = PR_FALSE;
status = sslBuffer_Grow(&gs->buf, 4096);
return status;
}
@@ -147,8 +148,11 @@ ssl3_GatherData(sslSocket *ss, sslGather *gs, int flags, ssl2Gather *ssl2gs)
switch (gs->state) {
case GS_HEADER:
/* Check for SSLv2 handshakes. Always assume SSLv3 on clients,
- * support SSLv2 handshakes only when ssl2gs != NULL. */
- if (!ssl2gs || ssl3_isLikelyV3Hello(gs->hdr)) {
+ * support SSLv2 handshakes only when ssl2gs != NULL.
+ * Always assume v3 after we received the first record. */
+ if (!ssl2gs ||
+ ss->gs.rejectV2Records ||
+ ssl3_isLikelyV3Hello(gs->hdr)) {
/* Should have a non-SSLv2 record header in gs->hdr. Extract
* the length of the following encrypted data, and then
* read in the rest of the record into gs->inbuf. */
@@ -183,7 +187,7 @@ ssl3_GatherData(sslSocket *ss, sslGather *gs, int flags, ssl2Gather *ssl2gs)
/* This is the max length for an encrypted SSLv3+ fragment. */
if (!v2HdrLength &&
gs->remainder > (MAX_FRAGMENT_LENGTH + 2048)) {
- SSL3_SendAlert(ss, alert_fatal, unexpected_message);
+ SSL3_SendAlert(ss, alert_fatal, record_overflow);
gs->state = GS_INIT;
PORT_SetError(SSL_ERROR_RX_RECORD_TOO_LONG);
return SECFailure;
@@ -205,13 +209,28 @@ ssl3_GatherData(sslSocket *ss, sslGather *gs, int flags, ssl2Gather *ssl2gs)
* many into the gs->hdr[] buffer. Copy them over into inbuf so
* that we can properly process the hello record later. */
if (v2HdrLength) {
+ /* Reject v2 records that don't even carry enough data to
+ * resemble a valid ClientHello header. */
+ if (gs->remainder < SSL_HL_CLIENT_HELLO_HBYTES) {
+ SSL3_SendAlert(ss, alert_fatal, illegal_parameter);
+ PORT_SetError(SSL_ERROR_RX_MALFORMED_CLIENT_HELLO);
+ return SECFailure;
+ }
+
+ PORT_Assert(lbp);
gs->inbuf.len = 5 - v2HdrLength;
PORT_Memcpy(lbp, gs->hdr + v2HdrLength, gs->inbuf.len);
gs->remainder -= gs->inbuf.len;
lbp += gs->inbuf.len;
}
- break; /* End this case. Continue around the loop. */
+ if (gs->remainder > 0) {
+ break; /* End this case. Continue around the loop. */
+ }
+
+ /* FALL THROUGH if (gs->remainder == 0) as we just received
+ * an empty record and there's really no point in calling
+ * ssl_DefRecv() with buf=NULL and len=0. */
case GS_DATA:
/*
@@ -219,6 +238,10 @@ ssl3_GatherData(sslSocket *ss, sslGather *gs, int flags, ssl2Gather *ssl2gs)
*/
SSL_TRC(10, ("%d: SSL[%d]: got record of %d bytes",
SSL_GETPID(), ss->fd, gs->inbuf.len));
+
+ /* reject any v2 records from now on */
+ ss->gs.rejectV2Records = PR_TRUE;
+
gs->state = GS_INIT;
return 1;
}
diff --git a/nss/lib/ssl/ssl3prot.h b/nss/lib/ssl/ssl3prot.h
index 146cba4..60a978b 100644
--- a/nss/lib/ssl/ssl3prot.h
+++ b/nss/lib/ssl/ssl3prot.h
@@ -287,7 +287,7 @@ typedef struct {
/* NewSessionTicket handshake message. */
typedef struct {
- PRUint32 received_timestamp;
+ PRTime received_timestamp;
PRUint32 ticket_lifetime_hint;
PRUint32 flags;
PRUint32 ticket_age_add;
@@ -305,13 +305,6 @@ typedef enum {
CLIENT_AUTH_CERTIFICATE = 1
} ClientAuthenticationType;
-typedef struct {
- ClientAuthenticationType client_auth_type;
- union {
- SSL3Opaque *certificate_list;
- } identity;
-} ClientIdentity;
-
#define SESS_TICKET_KEY_NAME_LEN 16
#define SESS_TICKET_KEY_NAME_PREFIX "NSS!"
#define SESS_TICKET_KEY_NAME_PREFIX_LEN 4
@@ -324,8 +317,4 @@ typedef struct {
unsigned char *mac;
} EncryptedSessionTicket;
-#define TLS_EX_SESS_TICKET_MAC_LENGTH 32
-
-#define TLS_STE_NO_SERVER_NAME -1
-
#endif /* __ssl3proto_h_ */
diff --git a/nss/lib/ssl/sslcert.c b/nss/lib/ssl/sslcert.c
index ea52455..388fc09 100644
--- a/nss/lib/ssl/sslcert.c
+++ b/nss/lib/ssl/sslcert.c
@@ -13,42 +13,91 @@
#include "nss.h" /* for NSS_RegisterShutdown */
#include "prinit.h" /* for PR_CallOnceWithArg */
-static const PRCallOnceType pristineCallOnce;
-static PRCallOnceType setupServerCAListOnce;
+/* This global item is used only in servers. It is is initialized by
+ * SSL_ConfigSecureServer(), and is used in ssl3_SendCertificateRequest().
+ */
+static struct {
+ PRCallOnceType setup;
+ CERTDistNames *names;
+} ssl_server_ca_list;
static SECStatus
-serverCAListShutdown(void *appData, void *nssData)
+ssl_ServerCAListShutdown(void *appData, void *nssData)
{
- PORT_Assert(ssl3_server_ca_list);
- if (ssl3_server_ca_list) {
- CERT_FreeDistNames(ssl3_server_ca_list);
- ssl3_server_ca_list = NULL;
+ PORT_Assert(ssl_server_ca_list.names);
+ if (ssl_server_ca_list.names) {
+ CERT_FreeDistNames(ssl_server_ca_list.names);
}
- setupServerCAListOnce = pristineCallOnce;
+ PORT_Memset(&ssl_server_ca_list, 0, sizeof(ssl_server_ca_list));
return SECSuccess;
}
static PRStatus
-serverCAListSetup(void *arg)
+ssl_SetupCAListOnce(void *arg)
{
CERTCertDBHandle *dbHandle = (CERTCertDBHandle *)arg;
- SECStatus rv = NSS_RegisterShutdown(serverCAListShutdown, NULL);
+ SECStatus rv = NSS_RegisterShutdown(ssl_ServerCAListShutdown, NULL);
PORT_Assert(SECSuccess == rv);
if (SECSuccess == rv) {
- ssl3_server_ca_list = CERT_GetSSLCACerts(dbHandle);
+ ssl_server_ca_list.names = CERT_GetSSLCACerts(dbHandle);
return PR_SUCCESS;
}
return PR_FAILURE;
}
+SECStatus
+ssl_SetupCAList(sslSocket *ss)
+{
+ if (PR_SUCCESS != PR_CallOnceWithArg(&ssl_server_ca_list.setup,
+ &ssl_SetupCAListOnce,
+ (void *)(ss->dbHandle))) {
+ PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
+ return SECFailure;
+ }
+ return SECSuccess;
+}
+
+SECStatus
+ssl_GetCertificateRequestCAs(sslSocket *ss, unsigned int *calen,
+ SECItem **names, unsigned int *nnames)
+{
+ SECItem *name;
+ CERTDistNames *ca_list;
+ unsigned int i;
+
+ *calen = 0;
+ *names = NULL;
+ *nnames = 0;
+
+ /* ssl3.ca_list is initialized to NULL, and never changed. */
+ ca_list = ss->ssl3.ca_list;
+ if (!ca_list) {
+ if (ssl_SetupCAList(ss) != SECSuccess) {
+ return SECFailure;
+ }
+ ca_list = ssl_server_ca_list.names;
+ }
+
+ if (ca_list != NULL) {
+ *names = ca_list->names;
+ *nnames = ca_list->nnames;
+ }
+
+ for (i = 0, name = *names; i < *nnames; i++, name++) {
+ *calen += 2 + name->len;
+ }
+ return SECSuccess;
+}
+
sslServerCert *
-ssl_NewServerCert(const sslServerCertType *certType)
+ssl_NewServerCert()
{
sslServerCert *sc = PORT_ZNew(sslServerCert);
if (!sc) {
return NULL;
}
- memcpy(&sc->certType, certType, sizeof(sc->certType));
+ sc->authTypes = 0;
+ sc->namedCurve = NULL;
sc->serverCert = NULL;
sc->serverCertChain = NULL;
sc->certStatusArray = NULL;
@@ -61,11 +110,14 @@ ssl_CopyServerCert(const sslServerCert *oc)
{
sslServerCert *sc;
- sc = ssl_NewServerCert(&oc->certType);
+ sc = ssl_NewServerCert();
if (!sc) {
return NULL;
}
+ sc->authTypes = oc->authTypes;
+ sc->namedCurve = oc->namedCurve;
+
if (oc->serverCert && oc->serverCertChain) {
sc->serverCert = CERT_DupCertificate(oc->serverCert);
if (!sc->serverCert)
@@ -129,9 +181,9 @@ ssl_FreeServerCert(sslServerCert *sc)
PORT_ZFree(sc, sizeof(*sc));
}
-sslServerCert *
-ssl_FindServerCert(const sslSocket *ss,
- const sslServerCertType *certType)
+const sslServerCert *
+ssl_FindServerCert(const sslSocket *ss, SSLAuthType authType,
+ const sslNamedGroupDef *namedCurve)
{
PRCList *cursor;
@@ -139,68 +191,21 @@ ssl_FindServerCert(const sslSocket *ss,
cursor != &ss->serverCerts;
cursor = PR_NEXT_LINK(cursor)) {
sslServerCert *cert = (sslServerCert *)cursor;
- if (cert->certType.authType != certType->authType) {
+ if (!SSL_CERT_IS(cert, authType)) {
continue;
}
- switch (cert->certType.authType) {
- case ssl_auth_ecdsa:
- case ssl_auth_ecdh_rsa:
- case ssl_auth_ecdh_ecdsa:
- /* Note: For deprecated APIs, we need to be able to find and
- match a slot with any named curve. */
- if (certType->namedCurve &&
- cert->certType.namedCurve != certType->namedCurve) {
- continue;
- }
- break;
- default:
- break;
+ if (SSL_CERT_IS_EC(cert)) {
+ /* Note: For deprecated APIs, we need to be able to find and
+ match a slot with any named curve. */
+ if (namedCurve && cert->namedCurve != namedCurve) {
+ continue;
+ }
}
return cert;
}
return NULL;
}
-sslServerCert *
-ssl_FindServerCertByAuthType(const sslSocket *ss, SSLAuthType authType)
-{
- sslServerCertType certType;
- certType.authType = authType;
- /* Setting the named curve to NULL ensures that all EC certificates
- * are matched when searching for this slot. */
- certType.namedCurve = NULL;
- return ssl_FindServerCert(ss, &certType);
-}
-
-SECStatus
-ssl_OneTimeCertSetup(sslSocket *ss, const sslServerCert *sc)
-{
- if (PR_SUCCESS != PR_CallOnceWithArg(&setupServerCAListOnce,
- &serverCAListSetup,
- (void *)(ss->dbHandle))) {
- return SECFailure;
- }
- return SECSuccess;
-}
-
-/* Determine which slot a certificate fits into. SSLAuthType is known, but
- * extra information needs to be worked out from the cert and key. */
-static void
-ssl_PopulateCertType(sslServerCertType *certType, SSLAuthType authType,
- CERTCertificate *cert, sslKeyPair *keyPair)
-{
- certType->authType = authType;
- switch (authType) {
- case ssl_auth_ecdsa:
- case ssl_auth_ecdh_rsa:
- case ssl_auth_ecdh_ecdsa:
- certType->namedCurve = ssl_ECPubKey2NamedGroup(keyPair->pubKey);
- break;
- default:
- break;
- }
-}
-
static SECStatus
ssl_PopulateServerCert(sslServerCert *sc, CERTCertificate *cert,
const CERTCertificateList *certChain)
@@ -232,21 +237,43 @@ ssl_PopulateServerCert(sslServerCert *sc, CERTCertificate *cert,
static SECStatus
ssl_PopulateKeyPair(sslServerCert *sc, sslKeyPair *keyPair)
{
- /* Copy over the key pair. */
if (sc->serverKeyPair) {
ssl_FreeKeyPair(sc->serverKeyPair);
+ sc->serverKeyPair = NULL;
}
if (keyPair) {
+ KeyType keyType = SECKEY_GetPublicKeyType(keyPair->pubKey);
+ PORT_Assert(keyType == SECKEY_GetPrivateKeyType(keyPair->privKey));
+
+ if (keyType == ecKey) {
+ sc->namedCurve = ssl_ECPubKey2NamedGroup(keyPair->pubKey);
+ if (!sc->namedCurve) {
+ /* Unsupported curve. */
+ PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
+ return SECFailure;
+ }
+ }
+
/* Get the size of the cert's public key, and remember it. */
sc->serverKeyBits = SECKEY_PublicKeyStrengthInBits(keyPair->pubKey);
if (sc->serverKeyBits == 0) {
+ PORT_SetError(SEC_ERROR_INVALID_ARGS);
return SECFailure;
}
SECKEY_CacheStaticFlags(keyPair->privKey);
sc->serverKeyPair = ssl_GetKeyPairRef(keyPair);
+
+ if (SSL_CERT_IS(sc, ssl_auth_rsa_decrypt)) {
+ /* This will update the global session ticket key pair with this
+ * key, if a value hasn't been set already. */
+ if (ssl_MaybeSetSessionTicketKeyPair(keyPair) != SECSuccess) {
+ return SECFailure;
+ }
+ }
} else {
sc->serverKeyPair = NULL;
+ sc->namedCurve = NULL;
}
return SECSuccess;
}
@@ -281,12 +308,39 @@ ssl_PopulateSignedCertTimestamps(sslServerCert *sc,
return SECSuccess;
}
+/* Find any existing certificates that overlap with the new certificate and
+ * either remove any supported authentication types that overlap with the new
+ * certificate or - if they have no types left - remove them entirely. */
+static void
+ssl_ClearMatchingCerts(sslSocket *ss, sslAuthTypeMask authTypes,
+ const sslNamedGroupDef *namedCurve)
+{
+ PRCList *cursor = PR_NEXT_LINK(&ss->serverCerts);
+
+ while (cursor != &ss->serverCerts) {
+ sslServerCert *sc = (sslServerCert *)cursor;
+ cursor = PR_NEXT_LINK(cursor);
+ if ((sc->authTypes & authTypes) == 0) {
+ continue;
+ }
+ /* namedCurve will be NULL only for legacy functions. */
+ if (namedCurve != NULL && sc->namedCurve != namedCurve) {
+ continue;
+ }
+
+ sc->authTypes &= ~authTypes;
+ if (sc->authTypes == 0) {
+ PR_REMOVE_LINK(&sc->link);
+ ssl_FreeServerCert(sc);
+ }
+ }
+}
+
static SECStatus
-ssl_ConfigCert(sslSocket *ss, CERTCertificate *cert,
- sslKeyPair *keyPair, const SSLExtraServerCertData *data)
+ssl_ConfigCert(sslSocket *ss, sslAuthTypeMask authTypes,
+ CERTCertificate *cert, sslKeyPair *keyPair,
+ const SSLExtraServerCertData *data)
{
- sslServerCert *oldsc;
- sslServerCertType certType;
SECStatus rv;
sslServerCert *sc = NULL;
int error_code = SEC_ERROR_NO_MEMORY;
@@ -294,34 +348,26 @@ ssl_ConfigCert(sslSocket *ss, CERTCertificate *cert,
PORT_Assert(cert);
PORT_Assert(keyPair);
PORT_Assert(data);
- PORT_Assert(data->authType != ssl_auth_null);
+ PORT_Assert(authTypes);
- if (!cert || !keyPair || !data || data->authType == ssl_auth_null) {
+ if (!cert || !keyPair || !data || !authTypes) {
error_code = SEC_ERROR_INVALID_ARGS;
goto loser;
}
- ssl_PopulateCertType(&certType, data->authType, cert, keyPair);
-
- /* Delete any existing certificate that matches this one, since we can only
- * use one certificate of a given type. */
- oldsc = ssl_FindServerCert(ss, &certType);
- if (oldsc) {
- PR_REMOVE_LINK(&oldsc->link);
- ssl_FreeServerCert(oldsc);
- }
- sc = ssl_NewServerCert(&certType);
+ sc = ssl_NewServerCert();
if (!sc) {
goto loser;
}
+ sc->authTypes = authTypes;
rv = ssl_PopulateServerCert(sc, cert, data->certChain);
if (rv != SECSuccess) {
goto loser;
}
rv = ssl_PopulateKeyPair(sc, keyPair);
if (rv != SECSuccess) {
- error_code = SEC_ERROR_INVALID_ARGS;
+ error_code = PORT_GetError();
goto loser;
}
rv = ssl_PopulateOCSPResponses(sc, data->stapledOCSPResponses);
@@ -332,23 +378,12 @@ ssl_ConfigCert(sslSocket *ss, CERTCertificate *cert,
if (rv != SECSuccess) {
goto loser;
}
+ ssl_ClearMatchingCerts(ss, sc->authTypes, sc->namedCurve);
PR_APPEND_LINK(&sc->link, &ss->serverCerts);
-
- /* This one-time setup depends on having the certificate in place. */
- rv = ssl_OneTimeCertSetup(ss, sc);
- if (rv != SECSuccess) {
- PR_REMOVE_LINK(&sc->link);
- error_code = PORT_GetError();
- goto loser;
- }
return SECSuccess;
loser:
- if (sc) {
- ssl_FreeServerCert(sc);
- }
- /* This is the only way any of the calls above can fail, except the one time
- * setup, which doesn't land here. */
+ ssl_FreeServerCert(sc);
PORT_SetError(error_code);
return SECFailure;
}
@@ -382,114 +417,55 @@ ssl_GetEcdhAuthType(CERTCertificate *cert)
}
}
-/* This function examines the key usages of the given RSA-PKCS1 certificate
- * and configures one or multiple server certificates based on that data.
- *
- * If the data argument contains an authType value other than ssl_auth_null,
- * then only that slot will be used. If that choice is invalid,
- * then this will fail. */
-static SECStatus
-ssl_ConfigRsaPkcs1CertByUsage(sslSocket *ss, CERTCertificate *cert,
- sslKeyPair *keyPair,
- SSLExtraServerCertData *data)
-{
- SECStatus rv = SECFailure;
-
- PRBool ku_sig = (PRBool)(cert->keyUsage & KU_DIGITAL_SIGNATURE);
- PRBool ku_enc = (PRBool)(cert->keyUsage & KU_KEY_ENCIPHERMENT);
-
- if ((data->authType == ssl_auth_rsa_sign && ku_sig) ||
- (data->authType == ssl_auth_rsa_pss && ku_sig) ||
- (data->authType == ssl_auth_rsa_decrypt && ku_enc)) {
- return ssl_ConfigCert(ss, cert, keyPair, data);
- }
-
- if (data->authType != ssl_auth_null || !(ku_sig || ku_enc)) {
- PORT_SetError(SEC_ERROR_INVALID_ARGS);
- return SECFailure;
- }
-
- if (ku_sig) {
- data->authType = ssl_auth_rsa_sign;
- rv = ssl_ConfigCert(ss, cert, keyPair, data);
- if (rv != SECSuccess) {
- return rv;
- }
-
- /* This certificate is RSA, assume that it's also PSS. */
- data->authType = ssl_auth_rsa_pss;
- rv = ssl_ConfigCert(ss, cert, keyPair, data);
- if (rv != SECSuccess) {
- return rv;
- }
- }
-
- if (ku_enc) {
- /* If ku_sig=true we configure signature and encryption slots with the
- * same cert. This is bad form, but there are enough dual-usage RSA
- * certs that we can't really break by limiting this to one type. */
- data->authType = ssl_auth_rsa_decrypt;
- rv = ssl_ConfigCert(ss, cert, keyPair, data);
- if (rv != SECSuccess) {
- return rv;
- }
- }
-
- return rv;
-}
-
/* This function examines the type of certificate and its key usage and
- * configures a certificate based on that information. For some certificates
- * this can mean that multiple server certificates are configured.
+ * chooses which authTypes apply. For some certificates
+ * this can mean that multiple authTypes.
*
- * If the data argument contains an authType value other than ssl_auth_null,
- * then only that slot will be used. If that choice is invalid,
- * then this will fail. */
-static SECStatus
-ssl_ConfigCertByUsage(sslSocket *ss, CERTCertificate *cert,
- sslKeyPair *keyPair, const SSLExtraServerCertData *data)
+ * If the targetAuthType is not ssl_auth_null, then only that type will be used.
+ * If that choice is invalid, then this function will fail. */
+static sslAuthTypeMask
+ssl_GetCertificateAuthTypes(CERTCertificate *cert, SSLAuthType targetAuthType)
{
- SECStatus rv = SECFailure;
- SSLExtraServerCertData arg;
+ sslAuthTypeMask authTypes = 0;
SECOidTag tag;
- PORT_Assert(data);
- /* Take a (shallow) copy so that we can play with it */
- memcpy(&arg, data, sizeof(arg));
-
tag = SECOID_GetAlgorithmTag(&cert->subjectPublicKeyInfo.algorithm);
switch (tag) {
case SEC_OID_X500_RSA_ENCRYPTION:
case SEC_OID_PKCS1_RSA_ENCRYPTION:
- return ssl_ConfigRsaPkcs1CertByUsage(ss, cert, keyPair, &arg);
+ if (cert->keyUsage & KU_DIGITAL_SIGNATURE) {
+ authTypes |= 1 << ssl_auth_rsa_sign;
+ /* This certificate is RSA, assume that it's also PSS. */
+ authTypes |= 1 << ssl_auth_rsa_pss;
+ }
+
+ if (cert->keyUsage & KU_KEY_ENCIPHERMENT) {
+ /* If ku_sig=true we configure signature and encryption slots with the
+ * same cert. This is bad form, but there are enough dual-usage RSA
+ * certs that we can't really break by limiting this to one type. */
+ authTypes |= 1 << ssl_auth_rsa_decrypt;
+ }
+ break;
case SEC_OID_PKCS1_RSA_PSS_SIGNATURE:
if (cert->keyUsage & KU_DIGITAL_SIGNATURE) {
- arg.authType = ssl_auth_rsa_pss;
+ authTypes |= 1 << ssl_auth_rsa_pss;
}
break;
case SEC_OID_ANSIX9_DSA_SIGNATURE:
if (cert->keyUsage & KU_DIGITAL_SIGNATURE) {
- arg.authType = ssl_auth_dsa;
+ authTypes |= 1 << ssl_auth_dsa;
}
break;
case SEC_OID_ANSIX962_EC_PUBLIC_KEY:
+ if (cert->keyUsage & KU_DIGITAL_SIGNATURE) {
+ authTypes |= 1 << ssl_auth_ecdsa;
+ }
+ /* Again, bad form to have dual usage and we don't prevent it. */
if (cert->keyUsage & KU_KEY_ENCIPHERMENT) {
- if ((cert->keyUsage & KU_DIGITAL_SIGNATURE) &&
- arg.authType == ssl_auth_null) {
- /* See above regarding bad practice. */
- arg.authType = ssl_auth_ecdsa;
- rv = ssl_ConfigCert(ss, cert, keyPair, &arg);
- if (rv != SECSuccess) {
- return rv;
- }
- }
-
- arg.authType = ssl_GetEcdhAuthType(cert);
- } else if (cert->keyUsage & KU_DIGITAL_SIGNATURE) {
- arg.authType = ssl_auth_ecdsa;
+ authTypes |= 1 << ssl_GetEcdhAuthType(cert);
}
break;
@@ -498,27 +474,33 @@ ssl_ConfigCertByUsage(sslSocket *ss, CERTCertificate *cert,
}
/* Check that we successfully picked an authType */
- if (arg.authType == ssl_auth_null) {
- PORT_SetError(SEC_ERROR_INVALID_ARGS);
- return SECFailure;
- }
- /* |data->authType| has to either agree or be ssl_auth_null. */
- if (data && data->authType != ssl_auth_null &&
- data->authType != arg.authType) {
- PORT_SetError(SEC_ERROR_INVALID_ARGS);
- return SECFailure;
+ if (targetAuthType != ssl_auth_null) {
+ authTypes &= 1 << targetAuthType;
}
- return ssl_ConfigCert(ss, cert, keyPair, &arg);
+ return authTypes;
}
/* This function adopts pubKey and destroys it if things go wrong. */
static sslKeyPair *
-ssl_MakeKeyPairForCert(SECKEYPrivateKey *key, SECKEYPublicKey *pubKey)
+ssl_MakeKeyPairForCert(SECKEYPrivateKey *key, CERTCertificate *cert)
{
sslKeyPair *keyPair = NULL;
+ SECKEYPublicKey *pubKey = NULL;
SECKEYPrivateKey *privKeyCopy = NULL;
PK11SlotInfo *bestSlot;
+ pubKey = CERT_ExtractPublicKey(cert);
+ if (!pubKey) {
+ PORT_SetError(SEC_ERROR_NO_MEMORY);
+ return NULL;
+ }
+
+ if (SECKEY_GetPublicKeyType(pubKey) != SECKEY_GetPrivateKeyType(key)) {
+ SECKEY_DestroyPublicKey(pubKey);
+ PORT_SetError(SEC_ERROR_INVALID_ARGS);
+ return NULL;
+ }
+
if (key->pkcs11Slot) {
bestSlot = PK11_ReferenceSlot(key->pkcs11Slot);
if (bestSlot) {
@@ -545,20 +527,18 @@ ssl_MakeKeyPairForCert(SECKEYPrivateKey *key, SECKEYPublicKey *pubKey)
if (privKeyCopy) {
SECKEY_DestroyPrivateKey(privKeyCopy);
}
- /* We adopted the public key, so we're responsible. */
- if (pubKey) {
- SECKEY_DestroyPublicKey(pubKey);
- }
+ SECKEY_DestroyPublicKey(pubKey);
+ PORT_SetError(SEC_ERROR_NO_MEMORY);
}
return keyPair;
}
/* Configure a certificate and private key.
*
- * This function examines the certificate and key to determine which slot (or
- * slots) to place the information in. As long as certificates are different
- * (based on having different values of sslServerCertType), then this function
- * can be called multiple times and the certificates will all be remembered.
+ * This function examines the certificate and key to determine the type (or
+ * types) of authentication the certificate supports. As long as certificates
+ * are different (different authTypes and maybe keys in different ec groups),
+ * then this function can be called multiple times.
*/
SECStatus
SSL_ConfigServerCert(PRFileDesc *fd, CERTCertificate *cert,
@@ -566,12 +546,12 @@ SSL_ConfigServerCert(PRFileDesc *fd, CERTCertificate *cert,
const SSLExtraServerCertData *data, unsigned int data_len)
{
sslSocket *ss;
- SECKEYPublicKey *pubKey;
sslKeyPair *keyPair;
SECStatus rv;
SSLExtraServerCertData dataCopy = {
ssl_auth_null, NULL, NULL, NULL
};
+ sslAuthTypeMask authTypes;
ss = ssl_FindSocket(fd);
if (!ss) {
@@ -591,21 +571,23 @@ SSL_ConfigServerCert(PRFileDesc *fd, CERTCertificate *cert,
PORT_Memcpy(&dataCopy, data, data_len);
}
- pubKey = CERT_ExtractPublicKey(cert);
- if (!pubKey) {
+ authTypes = ssl_GetCertificateAuthTypes(cert, dataCopy.authType);
+ if (!authTypes) {
+ PORT_SetError(SEC_ERROR_INVALID_ARGS);
return SECFailure;
}
- keyPair = ssl_MakeKeyPairForCert(key, pubKey);
+ keyPair = ssl_MakeKeyPairForCert(key, cert);
if (!keyPair) {
- /* pubKey is adopted by ssl_MakeKeyPairForCert() */
- PORT_SetError(SEC_ERROR_NO_MEMORY);
return SECFailure;
}
- rv = ssl_ConfigCertByUsage(ss, cert, keyPair, &dataCopy);
+ rv = ssl_ConfigCert(ss, authTypes, cert, keyPair, &dataCopy);
ssl_FreeKeyPair(keyPair);
- return rv;
+ if (rv != SECSuccess) {
+ return SECFailure;
+ }
+ return SECSuccess;
}
/*******************************************************************/
@@ -630,164 +612,148 @@ SSL_ConfigSecureServer(PRFileDesc *fd, CERTCertificate *cert,
* ssl_ConfigCertByUsage(), only checking against the type of key and ignoring
* things like usage. */
static PRBool
-ssl_CertSuitableForAuthType(CERTCertificate *cert, SSLAuthType authType)
+ssl_CertSuitableForAuthType(CERTCertificate *cert, sslAuthTypeMask authTypes)
{
SECOidTag tag = SECOID_GetAlgorithmTag(&cert->subjectPublicKeyInfo.algorithm);
- switch (authType) {
- case ssl_auth_rsa_decrypt:
- case ssl_auth_rsa_sign:
- return tag == SEC_OID_X500_RSA_ENCRYPTION ||
- tag == SEC_OID_PKCS1_RSA_ENCRYPTION;
- case ssl_auth_dsa:
- return tag == SEC_OID_ANSIX9_DSA_SIGNATURE;
- case ssl_auth_ecdsa:
- case ssl_auth_ecdh_rsa:
- case ssl_auth_ecdh_ecdsa:
- return tag == SEC_OID_ANSIX962_EC_PUBLIC_KEY;
- case ssl_auth_null:
- case ssl_auth_kea:
- case ssl_auth_rsa_pss: /* not supported with deprecated APIs */
- return PR_FALSE;
+ sslAuthTypeMask mask = 0;
+ switch (tag) {
+ case SEC_OID_X500_RSA_ENCRYPTION:
+ case SEC_OID_PKCS1_RSA_ENCRYPTION:
+ mask |= 1 << ssl_auth_rsa_decrypt;
+ mask |= 1 << ssl_auth_rsa_sign;
+ break;
+ case SEC_OID_ANSIX9_DSA_SIGNATURE:
+ mask |= 1 << ssl_auth_dsa;
+ break;
+ case SEC_OID_ANSIX962_EC_PUBLIC_KEY:
+ mask |= 1 << ssl_auth_ecdsa;
+ mask |= 1 << ssl_auth_ecdh_rsa;
+ mask |= 1 << ssl_auth_ecdh_ecdsa;
+ break;
default:
- PORT_Assert(0);
- return PR_FALSE;
+ break;
+ }
+ PORT_Assert(authTypes);
+ /* Simply test that no inappropriate auth types are set. */
+ return (authTypes & ~mask) == 0;
+}
+
+/* Lookup a cert for the legacy configuration functions. An exact match on
+ * authTypes and ignoring namedCurve will ensure that values configured using
+ * legacy functions are overwritten by other legacy functions. */
+static sslServerCert *
+ssl_FindCertWithMask(sslSocket *ss, sslAuthTypeMask authTypes)
+{
+ PRCList *cursor;
+
+ for (cursor = PR_NEXT_LINK(&ss->serverCerts);
+ cursor != &ss->serverCerts;
+ cursor = PR_NEXT_LINK(cursor)) {
+ sslServerCert *cert = (sslServerCert *)cursor;
+ if (cert->authTypes == authTypes) {
+ return cert;
+ }
}
+ return NULL;
}
-/* This finds an existing server cert slot and unlinks it, or it makes a new
+/* This finds an existing server cert in a matching slot that can be reused.
+ * Failing that, it removes any other certs that might conflict and makes a new
* server cert slot of the right type. */
static sslServerCert *
-ssl_FindOrMakeCertType(sslSocket *ss, SSLAuthType authType)
+ssl_FindOrMakeCert(sslSocket *ss, sslAuthTypeMask authTypes)
{
sslServerCert *sc;
- sslServerCertType certType;
- certType.authType = authType;
- /* Setting the named curve to NULL ensures that all EC certificates
- * are matched when searching for this slot. */
- certType.namedCurve = NULL;
- sc = ssl_FindServerCert(ss, &certType);
+ /* Reuse a perfect match. Note that there is a problem here with use of
+ * multiple EC certificates that have keys on different curves: these
+ * deprecated functions will match the first found and overwrite that
+ * certificate, potentially leaving the other values with a duplicate curve.
+ * Configuring multiple EC certificates are only possible with the new
+ * functions, so this is not something that is worth fixing. */
+ sc = ssl_FindCertWithMask(ss, authTypes);
if (sc) {
PR_REMOVE_LINK(&sc->link);
return sc;
}
- return ssl_NewServerCert(&certType);
+ /* Ignore the namedCurve parameter. Like above, this means that legacy
+ * functions will clobber values set with the new functions blindly. */
+ ssl_ClearMatchingCerts(ss, authTypes, NULL);
+
+ sc = ssl_NewServerCert();
+ if (sc) {
+ sc->authTypes = authTypes;
+ }
+ return sc;
}
-static void
-ssl_RemoveCertAndKeyByAuthType(sslSocket *ss, SSLAuthType authType)
+static sslAuthTypeMask
+ssl_KeaTypeToAuthTypeMask(SSLKEAType keaType)
{
- sslServerCert *sc;
+ switch (keaType) {
+ case ssl_kea_rsa:
+ return (1 << ssl_auth_rsa_decrypt) |
+ (1 << ssl_auth_rsa_sign);
- sc = ssl_FindServerCertByAuthType(ss, authType);
- if (sc) {
- (void)ssl_PopulateServerCert(sc, NULL, NULL);
- (void)ssl_PopulateKeyPair(sc, NULL);
- /* Leave the entry linked here because the old API expects that. There
- * might be OCSP stapling values or signed certificate timestamps still
- * present that will subsequently be used. */
- /* For ECC certificates, also leave the namedCurve parameter on the slot
- * unchanged; the value will be updated when a key is added. */
+ case ssl_kea_dh:
+ return 1 << ssl_auth_dsa;
+
+ case ssl_kea_ecdh:
+ return (1 << ssl_auth_ecdsa) |
+ (1 << ssl_auth_ecdh_rsa) |
+ (1 << ssl_auth_ecdh_ecdsa);
+
+ default:
+ PORT_SetError(SEC_ERROR_INVALID_ARGS);
}
+ return 0;
}
static SECStatus
-ssl_AddCertAndKeyByAuthType(sslSocket *ss, SSLAuthType authType,
- CERTCertificate *cert,
- const CERTCertificateList *certChainOpt,
- sslKeyPair *keyPair)
+ssl_AddCertChain(sslSocket *ss, CERTCertificate *cert,
+ const CERTCertificateList *certChainOpt,
+ SECKEYPrivateKey *key, sslAuthTypeMask authTypes)
{
sslServerCert *sc;
+ sslKeyPair *keyPair;
SECStatus rv;
+ PRErrorCode err = SEC_ERROR_NO_MEMORY;
- if (!ssl_CertSuitableForAuthType(cert, authType)) {
+ if (!ssl_CertSuitableForAuthType(cert, authTypes)) {
PORT_SetError(SEC_ERROR_INVALID_ARGS);
return SECFailure;
}
- sc = ssl_FindOrMakeCertType(ss, authType);
+ sc = ssl_FindOrMakeCert(ss, authTypes);
if (!sc) {
- PORT_SetError(SEC_ERROR_NO_MEMORY);
- return SECFailure;
- }
- rv = ssl_PopulateKeyPair(sc, keyPair);
- if (rv != SECSuccess) {
- PORT_SetError(SEC_ERROR_INVALID_ARGS);
goto loser;
}
- /* Now that we have a key pair, update the details of the slot. Many of the
- * legacy functions create a slot with a namedCurve of NULL, which
- * makes the slot unusable; this corrects that. */
- ssl_PopulateCertType(&sc->certType, authType, cert, keyPair);
+
rv = ssl_PopulateServerCert(sc, cert, certChainOpt);
if (rv != SECSuccess) {
- PORT_SetError(SEC_ERROR_NO_MEMORY);
goto loser;
}
- PR_APPEND_LINK(&sc->link, &ss->serverCerts);
- return ssl_OneTimeCertSetup(ss, sc);
-loser:
- ssl_FreeServerCert(sc);
- return SECFailure;
-}
-
-static SECStatus
-ssl_AddCertsByKEA(sslSocket *ss, CERTCertificate *cert,
- const CERTCertificateList *certChainOpt,
- SECKEYPrivateKey *key, SSLKEAType certType)
-{
- SECKEYPublicKey *pubKey;
- sslKeyPair *keyPair;
- SECStatus rv;
- pubKey = CERT_ExtractPublicKey(cert);
- if (!pubKey) {
- return SECFailure;
- }
-
- keyPair = ssl_MakeKeyPairForCert(key, pubKey);
+ keyPair = ssl_MakeKeyPairForCert(key, cert);
if (!keyPair) {
- /* Note: pubKey is adopted or freed by ssl_MakeKeyPairForCert()
- * depending on whether it succeeds or not. */
- PORT_SetError(SEC_ERROR_NO_MEMORY);
- return SECFailure;
+ /* Error code is set by ssl_MakeKeyPairForCert */
+ goto loser;
}
-
- switch (certType) {
- case ssl_kea_rsa:
- rv = ssl_AddCertAndKeyByAuthType(ss, ssl_auth_rsa_decrypt,
- cert, certChainOpt, keyPair);
- if (rv != SECSuccess) {
- return SECFailure;
- }
- rv = ssl_AddCertAndKeyByAuthType(ss, ssl_auth_rsa_sign,
- cert, certChainOpt, keyPair);
- break;
-
- case ssl_kea_dh:
- rv = ssl_AddCertAndKeyByAuthType(ss, ssl_auth_dsa,
- cert, certChainOpt, keyPair);
- break;
-
- case ssl_kea_ecdh:
- rv = ssl_AddCertAndKeyByAuthType(ss, ssl_auth_ecdsa,
- cert, certChainOpt, keyPair);
- if (rv != SECSuccess) {
- return SECFailure;
- }
- rv = ssl_AddCertAndKeyByAuthType(ss, ssl_GetEcdhAuthType(cert),
- cert, certChainOpt, keyPair);
- break;
-
- default:
- PORT_SetError(SEC_ERROR_INVALID_ARGS);
- rv = SECFailure;
- break;
+ rv = ssl_PopulateKeyPair(sc, keyPair);
+ ssl_FreeKeyPair(keyPair);
+ if (rv != SECSuccess) {
+ err = PORT_GetError();
+ goto loser;
}
- ssl_FreeKeyPair(keyPair);
- return rv;
+ PR_APPEND_LINK(&sc->link, &ss->serverCerts);
+ return SECSuccess;
+
+loser:
+ ssl_FreeServerCert(sc);
+ PORT_SetError(err);
+ return SECFailure;
}
/* Public deprecated function */
@@ -797,6 +763,7 @@ SSL_ConfigSecureServerWithCertChain(PRFileDesc *fd, CERTCertificate *cert,
SECKEYPrivateKey *key, SSLKEAType certType)
{
sslSocket *ss;
+ sslAuthTypeMask authTypes;
ss = ssl_FindSocket(fd);
if (!ss) {
@@ -808,52 +775,25 @@ SSL_ConfigSecureServerWithCertChain(PRFileDesc *fd, CERTCertificate *cert,
return SECFailure;
}
+ authTypes = ssl_KeaTypeToAuthTypeMask(certType);
+ if (!authTypes) {
+ PORT_SetError(SEC_ERROR_INVALID_ARGS);
+ return SECFailure;
+ }
+
if (!cert) {
- switch (certType) {
- case ssl_kea_rsa:
- ssl_RemoveCertAndKeyByAuthType(ss, ssl_auth_rsa_decrypt);
- ssl_RemoveCertAndKeyByAuthType(ss, ssl_auth_rsa_sign);
- break;
-
- case ssl_kea_dh:
- ssl_RemoveCertAndKeyByAuthType(ss, ssl_auth_dsa);
- break;
-
- case ssl_kea_ecdh:
- ssl_RemoveCertAndKeyByAuthType(ss, ssl_auth_ecdsa);
- ssl_RemoveCertAndKeyByAuthType(ss, ssl_auth_ecdh_rsa);
- ssl_RemoveCertAndKeyByAuthType(ss, ssl_auth_ecdh_ecdsa);
- break;
-
- default:
- PORT_SetError(SEC_ERROR_INVALID_ARGS);
- return SECFailure;
+ sslServerCert *sc = ssl_FindCertWithMask(ss, authTypes);
+ if (sc) {
+ (void)ssl_PopulateServerCert(sc, NULL, NULL);
+ (void)ssl_PopulateKeyPair(sc, NULL);
+ /* Leave the entry linked here because the old API expects that.
+ * There might be OCSP stapling values or signed certificate
+ * timestamps still present that will subsequently be used. */
}
return SECSuccess;
}
- return ssl_AddCertsByKEA(ss, cert, certChainOpt, key, certType);
-}
-
-static SECStatus
-ssl_SetOCSPResponsesInSlot(sslSocket *ss, SSLAuthType authType,
- const SECItemArray *responses)
-{
- sslServerCert *sc;
- SECStatus rv;
-
- sc = ssl_FindOrMakeCertType(ss, authType);
- if (!sc) {
- PORT_SetError(SEC_ERROR_NO_MEMORY);
- return SECFailure;
- }
- rv = ssl_PopulateOCSPResponses(sc, responses);
- if (rv == SECSuccess) {
- PR_APPEND_LINK(&sc->link, &ss->serverCerts);
- } else {
- ssl_FreeServerCert(sc);
- }
- return rv;
+ return ssl_AddCertChain(ss, cert, certChainOpt, key, authTypes);
}
/* Public deprecated function */
@@ -862,6 +802,8 @@ SSL_SetStapledOCSPResponses(PRFileDesc *fd, const SECItemArray *responses,
SSLKEAType certType)
{
sslSocket *ss;
+ sslServerCert *sc;
+ sslAuthTypeMask authTypes;
SECStatus rv;
ss = ssl_FindSocket(fd);
@@ -871,49 +813,28 @@ SSL_SetStapledOCSPResponses(PRFileDesc *fd, const SECItemArray *responses,
return SECFailure;
}
- switch (certType) {
- case ssl_kea_rsa:
- rv = ssl_SetOCSPResponsesInSlot(ss, ssl_auth_rsa_decrypt, responses);
- if (rv != SECSuccess) {
- return SECFailure;
- }
- return ssl_SetOCSPResponsesInSlot(ss, ssl_auth_rsa_sign, responses);
-
- case ssl_kea_dh:
- return ssl_SetOCSPResponsesInSlot(ss, ssl_auth_dsa, responses);
-
- case ssl_kea_ecdh:
- rv = ssl_SetOCSPResponsesInSlot(ss, ssl_auth_ecdsa, responses);
- if (rv != SECSuccess) {
- return SECFailure;
- }
- rv = ssl_SetOCSPResponsesInSlot(ss, ssl_auth_ecdh_rsa, responses);
- if (rv != SECSuccess) {
- return SECFailure;
- }
- return ssl_SetOCSPResponsesInSlot(ss, ssl_auth_ecdh_ecdsa, responses);
-
- default:
- SSL_DBG(("%d: SSL[%d]: invalid cert type in SSL_SetStapledOCSPResponses",
- SSL_GETPID(), fd));
- PORT_SetError(SEC_ERROR_INVALID_ARGS);
- return SECFailure;
+ authTypes = ssl_KeaTypeToAuthTypeMask(certType);
+ if (!authTypes) {
+ SSL_DBG(("%d: SSL[%d]: invalid cert type in SSL_SetStapledOCSPResponses",
+ SSL_GETPID(), fd));
+ PORT_SetError(SEC_ERROR_INVALID_ARGS);
+ return SECFailure;
}
-}
-static SECStatus
-ssl_SetSignedTimestampsInSlot(sslSocket *ss, SSLAuthType authType,
- const SECItem *scts)
-{
- sslServerCert *sc;
- SECStatus rv;
+ if (!responses) {
+ sc = ssl_FindCertWithMask(ss, authTypes);
+ if (sc) {
+ (void)ssl_PopulateOCSPResponses(sc, NULL);
+ }
+ return SECSuccess;
+ }
- sc = ssl_FindOrMakeCertType(ss, authType);
+ sc = ssl_FindOrMakeCert(ss, authTypes);
if (!sc) {
- PORT_SetError(SEC_ERROR_NO_MEMORY);
return SECFailure;
}
- rv = ssl_PopulateSignedCertTimestamps(sc, scts);
+
+ rv = ssl_PopulateOCSPResponses(sc, responses);
if (rv == SECSuccess) {
PR_APPEND_LINK(&sc->link, &ss->serverCerts);
} else {
@@ -928,6 +849,8 @@ SSL_SetSignedCertTimestamps(PRFileDesc *fd, const SECItem *scts,
SSLKEAType certType)
{
sslSocket *ss;
+ sslServerCert *sc;
+ sslAuthTypeMask authTypes;
SECStatus rv;
ss = ssl_FindSocket(fd);
@@ -937,34 +860,34 @@ SSL_SetSignedCertTimestamps(PRFileDesc *fd, const SECItem *scts,
return SECFailure;
}
- switch (certType) {
- case ssl_kea_rsa:
- rv = ssl_SetSignedTimestampsInSlot(ss, ssl_auth_rsa_decrypt, scts);
- if (rv != SECSuccess) {
- return SECFailure;
- }
- return ssl_SetSignedTimestampsInSlot(ss, ssl_auth_rsa_sign, scts);
+ authTypes = ssl_KeaTypeToAuthTypeMask(certType);
+ if (!authTypes) {
+ SSL_DBG(("%d: SSL[%d]: invalid cert type in SSL_SetSignedCertTimestamps",
+ SSL_GETPID(), fd));
+ PORT_SetError(SEC_ERROR_INVALID_ARGS);
+ return SECFailure;
+ }
- case ssl_kea_dh:
- return ssl_SetSignedTimestampsInSlot(ss, ssl_auth_dsa, scts);
+ if (!scts) {
+ sc = ssl_FindCertWithMask(ss, authTypes);
+ if (sc) {
+ (void)ssl_PopulateSignedCertTimestamps(sc, NULL);
+ }
+ return SECSuccess;
+ }
- case ssl_kea_ecdh:
- rv = ssl_SetSignedTimestampsInSlot(ss, ssl_auth_ecdsa, scts);
- if (rv != SECSuccess) {
- return SECFailure;
- }
- rv = ssl_SetSignedTimestampsInSlot(ss, ssl_auth_ecdh_rsa, scts);
- if (rv != SECSuccess) {
- return SECFailure;
- }
- return ssl_SetSignedTimestampsInSlot(ss, ssl_auth_ecdh_ecdsa, scts);
+ sc = ssl_FindOrMakeCert(ss, authTypes);
+ if (!sc) {
+ return SECFailure;
+ }
- default:
- SSL_DBG(("%d: SSL[%d]: invalid cert type in SSL_SetSignedCertTimestamps",
- SSL_GETPID(), fd));
- PORT_SetError(SEC_ERROR_INVALID_ARGS);
- return SECFailure;
+ rv = ssl_PopulateSignedCertTimestamps(sc, scts);
+ if (rv == SECSuccess) {
+ PR_APPEND_LINK(&sc->link, &ss->serverCerts);
+ } else {
+ ssl_FreeServerCert(sc);
}
+ return rv;
}
/* Public deprecated function. */
diff --git a/nss/lib/ssl/sslcert.h b/nss/lib/ssl/sslcert.h
index 052c7d6..fb31d13 100644
--- a/nss/lib/ssl/sslcert.h
+++ b/nss/lib/ssl/sslcert.h
@@ -13,26 +13,21 @@
#include "secitem.h"
#include "keyhi.h"
-/* The following struct identifies a single slot into which a certificate can be
-** loaded. The authType field determines the basic slot, then additional
-** parameters further narrow the slot.
-**
-** An EC key (ssl_auth_ecdsa or ssl_auth_ecdh_*) is assigned to a slot based on
-** the named curve of the key.
-*/
-typedef struct sslServerCertTypeStr {
- SSLAuthType authType;
+/* This type is a bitvector that is indexed by SSLAuthType values. Note that
+ * the bit for ssl_auth_null(0) - the least significant bit - isn't used. */
+typedef PRUint16 sslAuthTypeMask;
+PR_STATIC_ASSERT(sizeof(sslAuthTypeMask) * 8 >= ssl_auth_size);
+
+typedef struct sslServerCertStr {
+ PRCList link; /* The linked list link */
+
+ /* The auth types that this certificate provides. */
+ sslAuthTypeMask authTypes;
/* For ssl_auth_ecdsa and ssl_auth_ecdh_*. This is only the named curve
* of the end-entity certificate key. The keys in other certificates in
* the chain aren't directly relevant to the operation of TLS (though it
* might make certificate validation difficult, libssl doesn't care). */
const sslNamedGroupDef *namedCurve;
-} sslServerCertType;
-
-typedef struct sslServerCertStr {
- PRCList link; /* The linked list link */
-
- sslServerCertType certType; /* The certificate slot this occupies */
/* Configuration state for server sockets */
CERTCertificate *serverCert;
@@ -48,12 +43,18 @@ typedef struct sslServerCertStr {
SECItem signedCertTimestamps;
} sslServerCert;
-extern sslServerCert *ssl_NewServerCert(const sslServerCertType *slot);
+#define SSL_CERT_IS(c, t) ((c)->authTypes & (1 << (t)))
+#define SSL_CERT_IS_ONLY(c, t) ((c)->authTypes == (1 << (t)))
+#define SSL_CERT_IS_EC(c) \
+ ((c)->authTypes & ((1 << ssl_auth_ecdsa) | \
+ (1 << ssl_auth_ecdh_rsa) | \
+ (1 << ssl_auth_ecdh_ecdsa)))
+
+extern sslServerCert *ssl_NewServerCert();
extern sslServerCert *ssl_CopyServerCert(const sslServerCert *oc);
-extern sslServerCert *ssl_FindServerCert(const sslSocket *ss,
- const sslServerCertType *slot);
-extern sslServerCert *ssl_FindServerCertByAuthType(const sslSocket *ss,
- SSLAuthType authType);
+extern const sslServerCert *ssl_FindServerCert(
+ const sslSocket *ss, SSLAuthType authType,
+ const sslNamedGroupDef *namedCurve);
extern void ssl_FreeServerCert(sslServerCert *sc);
#endif /* __sslcert_h_ */
diff --git a/nss/lib/ssl/ssldef.c b/nss/lib/ssl/ssldef.c
index 77a744c..be5bcb2 100644
--- a/nss/lib/ssl/ssldef.c
+++ b/nss/lib/ssl/ssldef.c
@@ -66,6 +66,8 @@ ssl_DefRecv(sslSocket *ss, unsigned char *buf, int len, int flags)
PRFileDesc *lower = ss->fd->lower;
int rv;
+ PORT_Assert(buf && len > 0);
+
rv = lower->methods->recv(lower, (void *)buf, len, flags, ss->rTimeout);
if (rv < 0) {
DEFINE_ERROR
diff --git a/nss/lib/ssl/sslerr.h b/nss/lib/ssl/sslerr.h
index 751c335..865077c 100644
--- a/nss/lib/ssl/sslerr.h
+++ b/nss/lib/ssl/sslerr.h
@@ -244,6 +244,8 @@ typedef enum {
SSL_ERROR_MISSING_SIGNATURE_ALGORITHMS_EXTENSION = (SSL_ERROR_BASE + 157),
SSL_ERROR_MALFORMED_PSK_KEY_EXCHANGE_MODES = (SSL_ERROR_BASE + 158),
SSL_ERROR_MISSING_PSK_KEY_EXCHANGE_MODES = (SSL_ERROR_BASE + 159),
+ SSL_ERROR_DOWNGRADE_WITH_EARLY_DATA = (SSL_ERROR_BASE + 160),
+ SSL_ERROR_TOO_MUCH_EARLY_DATA = (SSL_ERROR_BASE + 161),
SSL_ERROR_END_OF_LIST /* let the c compiler determine the value of this. */
} SSLErrorCodes;
#endif /* NO_SECURITY_ERROR_ENUM */
diff --git a/nss/lib/ssl/sslimpl.h b/nss/lib/ssl/sslimpl.h
index 09c3783..55fb8cb 100644
--- a/nss/lib/ssl/sslimpl.h
+++ b/nss/lib/ssl/sslimpl.h
@@ -34,7 +34,7 @@
#include "sslt.h" /* for some formerly private types, now public */
typedef struct sslSocketStr sslSocket;
-
+typedef struct ssl3CipherSpecStr ssl3CipherSpec;
#include "ssl3ext.h"
/* to make some of these old enums public without namespace pollution,
@@ -125,7 +125,8 @@ typedef enum { SSLAppOpRead = 0,
#define SSL3_MASTER_SECRET_LENGTH 48
/* number of wrap mechanisms potentially used to wrap master secrets. */
-#define SSL_NUM_WRAP_MECHS 16
+#define SSL_NUM_WRAP_MECHS 15
+#define SSL_NUM_WRAP_KEYS 6
/* This makes the cert cache entry exactly 4k. */
#define SSL_MAX_CACHED_CERT_LEN 4060
@@ -200,6 +201,9 @@ typedef sslSessionID *(*sslSessionIDLookupFunc)(const PRIPv6Addr *addr,
unsigned char *sid,
unsigned int sidLen,
CERTCertDBHandle *dbHandle);
+typedef void (*sslCipherSpecChangedFunc)(void *arg,
+ PRBool sending,
+ ssl3CipherSpec *newSpec);
/* Socket ops */
struct sslSocketOpsStr {
@@ -367,6 +371,10 @@ struct sslGatherStr {
/* the start of the buffered DTLS record in dtlsPacket */
unsigned int dtlsPacketOffset;
+
+ /* tracks whether we've seen a v3-type record before and must reject
+ * any further v2-type records. */
+ PRBool rejectV2Records;
};
/* sslGather.state */
@@ -469,7 +477,7 @@ typedef struct DTLSRecvdRecordsStr {
** Access to the pointers to these specs, and all the specs' contents
** (direct and indirect) is protected by the reader/writer lock ss->specLock.
*/
-typedef struct {
+struct ssl3CipherSpecStr {
PRCList link;
const ssl3BulkCipherDef *cipher_def;
const ssl3MACDef *mac_def;
@@ -496,10 +504,13 @@ typedef struct {
SECItem msItem;
DTLSEpoch epoch;
DTLSRecvdRecords recvdRecords;
+ /* The number of 0-RTT bytes that can be sent or received in TLS 1.3. This
+ * will be zero for everything but 0-RTT. */
+ PRUint32 earlyDataRemaining;
PRUint8 refCt;
const char *phase;
-} ssl3CipherSpec;
+};
typedef enum { never_cached,
in_client_cache,
@@ -523,10 +534,10 @@ struct sslSessionIDStr {
*/
CERTCertificate *peerCert;
- SECItemArray peerCertStatus; /* client only */
- const char *peerID; /* client only */
- const char *urlSvrName; /* client only */
- sslServerCertType certType;
+ SECItemArray peerCertStatus; /* client only */
+ const char *peerID; /* client only */
+ const char *urlSvrName; /* client only */
+ const sslNamedGroupDef *namedCurve; /* (server) for certificate lookup */
CERTCertificate *localCert;
PRIPv6Addr addr;
@@ -862,7 +873,6 @@ typedef struct SSL3HandshakeStateStr {
TLS13CertificateRequest *certificateRequest;
PRCList cipherSpecs; /* The cipher specs in the sequence they
* will be applied. */
- ssl3CipherSpec *nullSpec; /* In case 0-RTT is rejected. */
sslZeroRttState zeroRttState; /* Are we doing a 0-RTT handshake? */
sslZeroRttIgnore zeroRttIgnore; /* Are we ignoring 0-RTT? */
ssl3CipherSuite zeroRttSuite; /* The cipher suite we used for 0-RTT. */
@@ -894,6 +904,11 @@ struct ssl3StateStr {
ssl3CipherSpec *cwSpec; /* current write spec. */
ssl3CipherSpec *pwSpec; /* pending write spec. */
+ /* Internal callback for when we do a cipher suite change. Used for
+ * debugging in TLS 1.3. This can only be set by non-public functions. */
+ sslCipherSpecChangedFunc changedCipherSpecFunc;
+ void *changedCipherSpecArg;
+
CERTCertificate *clientCertificate; /* used by client */
SECKEYPrivateKey *clientPrivateKey; /* used by client */
CERTCertificateList *clientCertChain; /* used by client */
@@ -971,13 +986,13 @@ typedef struct SSLWrappedSymWrappingKeyStr {
CK_MECHANISM_TYPE asymWrapMechanism;
/* mechanism used to wrap the SymmetricWrappingKey using
* server's public and/or private keys. */
- SSLAuthType authType; /* type of keys used to wrap SymWrapKey*/
- PRInt32 symWrapMechIndex;
+ PRInt16 wrapMechIndex;
+ PRUint16 wrapKeyIndex;
PRUint16 wrappedSymKeyLen;
} SSLWrappedSymWrappingKey;
typedef struct SessionTicketStr {
- PRUint16 ticket_version;
+ PRBool valid;
SSL3ProtocolVersion ssl_version;
ssl3CipherSuite cipher_suite;
SSLCompressionMethod compression_method;
@@ -985,7 +1000,8 @@ typedef struct SessionTicketStr {
PRUint32 authKeyBits;
SSLKEAType keaType;
PRUint32 keaKeyBits;
- sslServerCertType certType;
+ const sslNamedGroupDef *namedCurve; /* For certificate lookup. */
+
/*
* msWrapMech contains a meaningful value only if ms_is_wrapped is true.
*/
@@ -994,12 +1010,13 @@ typedef struct SessionTicketStr {
PRUint16 ms_length;
SSL3Opaque master_secret[48];
PRBool extendedMasterSecretUsed;
- ClientIdentity client_identity;
+ ClientAuthenticationType client_auth_type;
SECItem peer_cert;
PRUint32 timestamp;
PRUint32 flags;
SECItem srvName; /* negotiated server name */
SECItem alpnSelection;
+ PRUint32 maxEarlyData;
} SessionTicket;
/*
@@ -1121,6 +1138,10 @@ struct sslSocketStr {
void *getClientAuthDataArg;
SSLSNISocketConfig sniSocketConfig;
void *sniSocketConfigArg;
+ SSLAlertCallback alertReceivedCallback;
+ void *alertReceivedCallbackArg;
+ SSLAlertCallback alertSentCallback;
+ void *alertSentCallbackArg;
SSLBadCertHandler handleBadCert;
void *badCertArg;
SSLHandshakeCallback handshakeCallback;
@@ -1208,17 +1229,13 @@ struct sslSocketStr {
SSLProtocolVariant protocolVariant;
};
-/* All the global data items declared here should be protected using the
-** ssl_global_data_lock, which is a reader/writer lock.
-*/
-extern NSSRWLock *ssl_global_data_lock;
extern char ssl_debug;
extern char ssl_trace;
extern FILE *ssl_trace_iob;
extern FILE *ssl_keylog_iob;
-extern CERTDistNames *ssl3_server_ca_list;
-extern PRUint32 ssl_sid_timeout;
extern PRUint32 ssl3_sid_timeout;
+extern PRUint32 ssl_ticket_lifetime;
+extern PRUint32 ssl_max_early_data_size;
extern const char *const ssl3_cipherName[];
@@ -1338,8 +1355,8 @@ extern SECStatus ssl_CipherPrefSetDefault(PRInt32 which, PRBool enabled);
extern SECStatus ssl3_ConstrainRangeByPolicy(void);
-extern SECStatus ssl3_InitState(sslSocket *ss);
-extern SECStatus ssl3_RestartHandshakeHashes(sslSocket *ss);
+extern void ssl3_InitState(sslSocket *ss);
+extern void ssl3_RestartHandshakeHashes(sslSocket *ss);
extern SECStatus ssl3_UpdateHandshakeHashes(sslSocket *ss,
const unsigned char *b,
unsigned int l);
@@ -1479,6 +1496,14 @@ extern PRInt32 ssl3_SendRecord(sslSocket *ss, ssl3CipherSpec *cwSpec,
*/
#define SSL_LIBRARY_VERSION_NONE 0
+/* SSL_LIBRARY_VERSION_MIN_SUPPORTED is the minimum version that this version
+ * of libssl supports. Applications should use SSL_VersionRangeGetSupported at
+ * runtime to determine which versions are supported by the version of libssl
+ * in use.
+ */
+#define SSL_LIBRARY_VERSION_MIN_SUPPORTED_DATAGRAM SSL_LIBRARY_VERSION_TLS_1_1
+#define SSL_LIBRARY_VERSION_MIN_SUPPORTED_STREAM SSL_LIBRARY_VERSION_3_0
+
/* SSL_LIBRARY_VERSION_MAX_SUPPORTED is the maximum version that this version
* of libssl supports. Applications should use SSL_VersionRangeGetSupported at
* runtime to determine which versions are supported by the version of libssl
@@ -1627,7 +1652,6 @@ extern SECStatus ssl3_SendECDHServerKeyExchange(sslSocket *ss);
extern SECStatus ssl_ImportECDHKeyShare(
sslSocket *ss, SECKEYPublicKey *peerKey,
SSL3Opaque *b, PRUint32 length, const sslNamedGroupDef *curve);
-unsigned int tls13_SizeOfECDHEKeyShareKEX(const SECKEYPublicKey *pubKey);
SECStatus tls13_EncodeECDHEKeyShareKEX(const sslSocket *ss,
const SECKEYPublicKey *pubKey);
@@ -1647,12 +1671,13 @@ extern SECStatus ssl3_AppendHandshakeVariable(sslSocket *ss,
const SSL3Opaque *src, PRInt32 bytes, PRInt32 lenSize);
extern SECStatus ssl3_AppendSignatureAndHashAlgorithm(
sslSocket *ss, const SSLSignatureAndHashAlg *sigAndHash);
-extern SECStatus ssl3_ConsumeHandshake(sslSocket *ss, void *v, PRInt32 bytes,
+extern SECStatus ssl3_ConsumeHandshake(sslSocket *ss, void *v, PRUint32 bytes,
SSL3Opaque **b, PRUint32 *length);
-extern PRInt32 ssl3_ConsumeHandshakeNumber(sslSocket *ss, PRInt32 bytes,
- SSL3Opaque **b, PRUint32 *length);
+extern SECStatus ssl3_ConsumeHandshakeNumber(sslSocket *ss, PRUint32 *num,
+ PRUint32 bytes, SSL3Opaque **b,
+ PRUint32 *length);
extern SECStatus ssl3_ConsumeHandshakeVariable(sslSocket *ss, SECItem *i,
- PRInt32 bytes, SSL3Opaque **b,
+ PRUint32 bytes, SSL3Opaque **b,
PRUint32 *length);
extern PRUint8 *ssl_EncodeUintX(PRUint64 value, unsigned int bytes,
PRUint8 *to);
@@ -1671,8 +1696,7 @@ extern SECStatus ssl3_SignHashes(sslSocket *ss, SSL3Hashes *hash,
extern SECStatus ssl3_VerifySignedHashes(sslSocket *ss, SSLSignatureScheme scheme,
SSL3Hashes *hash, SECItem *buf);
extern SECStatus ssl3_CacheWrappedMasterSecret(
- sslSocket *ss, sslSessionID *sid,
- ssl3CipherSpec *spec, SSLAuthType authType);
+ sslSocket *ss, sslSessionID *sid, ssl3CipherSpec *spec);
extern void ssl3_FreeSniNameArray(TLSExtensionData *xtnData);
/* Hello Extension related routines. */
@@ -1681,15 +1705,10 @@ extern void ssl3_SetSIDSessionTicket(sslSessionID *sid,
SECStatus ssl3_EncodeSessionTicket(sslSocket *ss,
const NewSessionTicket *ticket_input,
SECItem *ticket_data);
-extern PRBool ssl_GetSessionTicketKeys(SECKEYPrivateKey *svrPrivKey,
- SECKEYPublicKey *svrPubKey, void *pwArg,
- unsigned char *keyName, PK11SymKey **aesKey,
- PK11SymKey **macKey);
-extern SECStatus ssl3_SessionTicketShutdown(void *appData, void *nssData);
-
-/* Tell clients to consider tickets valid for this long. */
-#define TLS_EX_SESS_TICKET_LIFETIME_HINT (2 * 24 * 60 * 60) /* 2 days */
-#define TLS_EX_SESS_TICKET_VERSION (0x0103)
+SECStatus ssl_MaybeSetSessionTicketKeyPair(const sslKeyPair *keyPair);
+SECStatus ssl_GetSessionTicketKeys(sslSocket *ss, unsigned char *keyName,
+ PK11SymKey **encKey, PK11SymKey **macKey);
+void ssl_ResetSessionTicketKeys();
extern SECStatus ssl3_ValidateNextProtoNego(const unsigned char *data,
unsigned int length);
@@ -1703,8 +1722,8 @@ extern void ssl_FreePRSocket(PRFileDesc *fd);
extern int ssl3_config_match_init(sslSocket *);
/* calls for accessing wrapping keys across processes. */
-extern PRBool
-ssl_GetWrappingKey(PRInt32 symWrapMechIndex, SSLAuthType authType,
+extern SECStatus
+ssl_GetWrappingKey(unsigned int symWrapMechIndex, unsigned int wrapKeyIndex,
SSLWrappedSymWrappingKey *wswk);
/* The caller passes in the new value it wants
@@ -1716,7 +1735,7 @@ ssl_GetWrappingKey(PRInt32 symWrapMechIndex, SSLAuthType authType,
* This is all done while holding the locks/semaphores necessary to make
* the operation atomic.
*/
-extern PRBool
+extern SECStatus
ssl_SetWrappingKey(SSLWrappedSymWrappingKey *wswk);
/* get rid of the symmetric wrapping key references. */
@@ -1781,8 +1800,8 @@ SECStatus ssl_ReadCertificateStatus(sslSocket *ss, SSL3Opaque *b,
PRUint32 length);
SECStatus ssl3_EncodeSigAlgs(const sslSocket *ss, PRUint8 *buf,
unsigned maxLen, PRUint32 *len);
-void ssl3_GetCertificateRequestCAs(sslSocket *ss, int *calenp, SECItem **namesp,
- int *nnamesp);
+SECStatus ssl_GetCertificateRequestCAs(sslSocket *ss, unsigned int *calenp,
+ SECItem **namesp, unsigned int *nnamesp);
SECStatus ssl3_ParseCertificateRequestCAs(sslSocket *ss, SSL3Opaque **b,
PRUint32 *length, PLArenaPool *arena,
CERTDistNames *ca_list);
@@ -1802,7 +1821,6 @@ SECStatus ssl_CreateStaticECDHEKey(sslSocket *ss,
SECStatus ssl3_FlushHandshake(sslSocket *ss, PRInt32 flags);
PK11SymKey *ssl3_GetWrappingKey(sslSocket *ss,
PK11SlotInfo *masterSecretSlot,
- const sslServerCert *serverCert,
CK_MECHANISM_TYPE masterWrapMech,
void *pwArg);
SECStatus ssl3_FillInCachedSID(sslSocket *ss, sslSessionID *sid);
@@ -1835,6 +1853,7 @@ extern void ssl3_CheckCipherSuiteOrderConsistency();
extern int ssl_MapLowLevelError(int hiLevelError);
extern PRUint32 ssl_Time(void);
+extern PRBool ssl_TicketTimeValid(const NewSessionTicket *ticket);
extern void SSL_AtomicIncrementLong(long *x);
@@ -1844,11 +1863,12 @@ extern HASH_HashType
ssl3_GetTls12HashType(sslSocket *ss);
extern SECStatus
-ssl3_TLSPRFWithMasterSecret(ssl3CipherSpec *spec,
+ssl3_TLSPRFWithMasterSecret(sslSocket *ss, ssl3CipherSpec *spec,
const char *label, unsigned int labelLen,
const unsigned char *val, unsigned int valLen,
- unsigned char *out, unsigned int outLen,
- HASH_HashType tls12HashType);
+ unsigned char *out, unsigned int outLen);
+
+PRBool ssl_AlpnTagAllowed(const sslSocket *ss, const SECItem *tag);
#ifdef TRACE
#define SSL_TRACE(msg) ssl_Trace msg
diff --git a/nss/lib/ssl/sslinfo.c b/nss/lib/ssl/sslinfo.c
index 665109d..88162d8 100644
--- a/nss/lib/ssl/sslinfo.c
+++ b/nss/lib/ssl/sslinfo.c
@@ -140,6 +140,20 @@ SSL_GetPreliminaryChannelInfo(PRFileDesc *fd,
inf.valuesSet = ss->ssl3.hs.preliminaryInfo;
inf.protocolVersion = ss->version;
inf.cipherSuite = ss->ssl3.hs.cipher_suite;
+ inf.canSendEarlyData = !ss->sec.isServer &&
+ (ss->ssl3.hs.zeroRttState == ssl_0rtt_sent ||
+ ss->ssl3.hs.zeroRttState == ssl_0rtt_accepted);
+ /* We shouldn't be able to send early data if the handshake is done. */
+ PORT_Assert(!ss->firstHsDone || !inf.canSendEarlyData);
+
+ if (ss->sec.ci.sid &&
+ (ss->ssl3.hs.zeroRttState == ssl_0rtt_sent ||
+ ss->ssl3.hs.zeroRttState == ssl_0rtt_accepted)) {
+ inf.maxEarlyDataSize =
+ ss->sec.ci.sid->u.ssl3.locked.sessionTicket.max_early_data_size;
+ } else {
+ inf.maxEarlyDataSize = 0;
+ }
memcpy(info, &inf, inf.length);
return SECSuccess;
@@ -219,6 +233,9 @@ SSL_GetPreliminaryChannelInfo(PRFileDesc *fd,
#define F_NFIPS_NSTD 0, 0, 1, 0 /* i.e., trash */
#define F_EXPORT 0, 1, 0, 0 /* i.e., trash */
+// RFC 5705
+#define MAX_CONTEXT_LEN PR_UINT16_MAX - 1
+
static const SSLCipherSuiteInfo suiteInfo[] = {
/* <------ Cipher suite --------------------> <auth> <KEA> <bulk cipher> <MAC> <FIPS> */
{ 0, CS_(TLS_AES_128_GCM_SHA256), S_ANY, K_ANY, C_AESGCM, B_128, M_AEAD_128, F_FIPS_STD, A_ANY },
@@ -425,6 +442,11 @@ SSL_ExportKeyingMaterial(PRFileDesc *fd,
out, outLen);
}
+ if (hasContext && contextLen > MAX_CONTEXT_LEN) {
+ PORT_SetError(SEC_ERROR_INVALID_ARGS);
+ return SECFailure;
+ }
+
/* construct PRF arguments */
valLen = SSL3_RANDOM_LENGTH * 2;
if (hasContext) {
@@ -455,9 +477,8 @@ SSL_ExportKeyingMaterial(PRFileDesc *fd,
PORT_SetError(SSL_ERROR_HANDSHAKE_NOT_COMPLETED);
rv = SECFailure;
} else {
- HASH_HashType ht = ssl3_GetTls12HashType(ss);
- rv = ssl3_TLSPRFWithMasterSecret(ss->ssl3.cwSpec, label, labelLen, val,
- valLen, out, outLen, ht);
+ rv = ssl3_TLSPRFWithMasterSecret(ss, ss->ssl3.cwSpec, label, labelLen,
+ val, valLen, out, outLen);
}
ssl_ReleaseSpecReadLock(ss);
diff --git a/nss/lib/ssl/sslmutex.c b/nss/lib/ssl/sslmutex.c
index 560a9e8..10b6cf5 100644
--- a/nss/lib/ssl/sslmutex.c
+++ b/nss/lib/ssl/sslmutex.c
@@ -60,7 +60,8 @@ single_process_sslMutex_Lock(sslMutex* pMutex)
return SECSuccess;
}
-#if defined(LINUX) || defined(AIX) || defined(BEOS) || defined(BSDI) || (defined(NETBSD) && __NetBSD_Version__ < 500000000) || defined(OPENBSD)
+#if defined(LINUX) || defined(AIX) || defined(BEOS) || defined(BSDI) || \
+ (defined(NETBSD) && __NetBSD_Version__ < 500000000) || defined(OPENBSD) || defined(__GLIBC__)
#include <unistd.h>
#include <fcntl.h>
diff --git a/nss/lib/ssl/sslmutex.h b/nss/lib/ssl/sslmutex.h
index 7611148..3f63ed8 100644
--- a/nss/lib/ssl/sslmutex.h
+++ b/nss/lib/ssl/sslmutex.h
@@ -49,7 +49,8 @@ typedef struct {
typedef int sslPID;
-#elif defined(LINUX) || defined(AIX) || defined(BEOS) || defined(BSDI) || (defined(NETBSD) && __NetBSD_Version__ < 500000000) || defined(OPENBSD)
+#elif defined(LINUX) || defined(AIX) || defined(BEOS) || defined(BSDI) || \
+ (defined(NETBSD) && __NetBSD_Version__ < 500000000) || defined(OPENBSD) || defined(__GLIBC__)
#include <sys/types.h>
#include "prtypes.h"
diff --git a/nss/lib/ssl/sslnonce.c b/nss/lib/ssl/sslnonce.c
index 91cc870..7ad1c6b 100644
--- a/nss/lib/ssl/sslnonce.c
+++ b/nss/lib/ssl/sslnonce.c
@@ -1,3 +1,4 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
/*
* This file implements the CLIENT Session ID cache.
*
@@ -18,7 +19,6 @@
#include <time.h>
#endif
-PRUint32 ssl_sid_timeout = 100;
PRUint32 ssl3_sid_timeout = 86400L; /* 24 hours */
static sslSessionID *cache = NULL;
@@ -460,6 +460,20 @@ ssl_Time(void)
return myTime;
}
+PRBool
+ssl_TicketTimeValid(const NewSessionTicket *ticket)
+{
+ PRTime endTime;
+
+ if (ticket->ticket_lifetime_hint == 0) {
+ return PR_TRUE;
+ }
+
+ endTime = ticket->received_timestamp +
+ (PRTime)(ticket->ticket_lifetime_hint * PR_USEC_PER_SEC);
+ return endTime > PR_Now();
+}
+
void
ssl3_SetSIDSessionTicket(sslSessionID *sid,
/*in/out*/ NewSessionTicket *newSessionTicket)
diff --git a/nss/lib/ssl/sslsecur.c b/nss/lib/ssl/sslsecur.c
index eecf443..8bec3d3 100644
--- a/nss/lib/ssl/sslsecur.c
+++ b/nss/lib/ssl/sslsecur.c
@@ -478,7 +478,7 @@ sslBuffer_Append(sslBuffer *b, const void *data, unsigned int len)
void
sslBuffer_Clear(sslBuffer *b)
{
- if (b->len > 0) {
+ if (b->buf) {
PORT_Free(b->buf);
b->buf = NULL;
b->len = 0;
@@ -884,6 +884,7 @@ int
ssl_SecureSend(sslSocket *ss, const unsigned char *buf, int len, int flags)
{
int rv = 0;
+ PRBool zeroRtt = PR_FALSE;
SSL_TRC(2, ("%d: SSL[%d]: SecureSend: sending %d bytes",
SSL_GETPID(), ss->fd, len));
@@ -923,19 +924,20 @@ ssl_SecureSend(sslSocket *ss, const unsigned char *buf, int len, int flags)
* Case 2: TLS 1.3 0-RTT
*/
if (!ss->firstHsDone) {
- PRBool falseStart = PR_FALSE;
+ PRBool allowEarlySend = PR_FALSE;
+
ssl_Get1stHandshakeLock(ss);
if (ss->opt.enableFalseStart ||
(ss->opt.enable0RttData && !ss->sec.isServer)) {
ssl_GetSSL3HandshakeLock(ss);
/* The client can sometimes send before the handshake is fully
* complete. In TLS 1.2: false start; in TLS 1.3: 0-RTT. */
- falseStart = ss->ssl3.hs.canFalseStart ||
- ss->ssl3.hs.zeroRttState == ssl_0rtt_sent ||
- ss->ssl3.hs.zeroRttState == ssl_0rtt_accepted;
+ zeroRtt = ss->ssl3.hs.zeroRttState == ssl_0rtt_sent ||
+ ss->ssl3.hs.zeroRttState == ssl_0rtt_accepted;
+ allowEarlySend = ss->ssl3.hs.canFalseStart || zeroRtt;
ssl_ReleaseSSL3HandshakeLock(ss);
}
- if (!falseStart && ss->handshake) {
+ if (!allowEarlySend && ss->handshake) {
rv = ssl_Do1stHandshake(ss);
}
ssl_Release1stHandshakeLock(ss);
@@ -945,6 +947,20 @@ ssl_SecureSend(sslSocket *ss, const unsigned char *buf, int len, int flags)
goto done;
}
+ if (zeroRtt) {
+ /* There's a limit to the number of early data octets we can send.
+ *
+ * Note that taking this lock doesn't prevent the cipher specs from
+ * being changed out between here and when records are ultimately
+ * encrypted. The only effect of that is to occasionally do an
+ * unnecessary short write when data is identified as 0-RTT here but
+ * 1-RTT later.
+ */
+ ssl_GetSpecReadLock(ss);
+ len = tls13_LimitEarlyData(ss, content_application_data, len);
+ ssl_ReleaseSpecReadLock(ss);
+ }
+
/* Check for zero length writes after we do housekeeping so we make forward
* progress.
*/
@@ -959,19 +975,6 @@ ssl_SecureSend(sslSocket *ss, const unsigned char *buf, int len, int flags)
goto done;
}
- if (!ss->firstHsDone) {
-#ifdef DEBUG
- ssl_GetSSL3HandshakeLock(ss);
- PORT_Assert(!ss->sec.isServer &&
- (ss->ssl3.hs.canFalseStart ||
- ss->ssl3.hs.zeroRttState == ssl_0rtt_sent ||
- ss->ssl3.hs.zeroRttState == ssl_0rtt_accepted));
- ssl_ReleaseSSL3HandshakeLock(ss);
-#endif
- SSL_TRC(3, ("%d: SSL[%d]: SecureSend: sending data due to false start",
- SSL_GETPID(), ss->fd));
- }
-
ssl_GetXmitBufLock(ss);
rv = ssl3_SendApplicationData(ss, buf, len, flags);
ssl_ReleaseXmitBufLock(ss);
@@ -994,6 +997,42 @@ ssl_SecureWrite(sslSocket *ss, const unsigned char *buf, int len)
}
SECStatus
+SSL_AlertReceivedCallback(PRFileDesc *fd, SSLAlertCallback cb, void *arg)
+{
+ sslSocket *ss;
+
+ ss = ssl_FindSocket(fd);
+ if (!ss) {
+ SSL_DBG(("%d: SSL[%d]: unable to find socket in SSL_AlertReceivedCallback",
+ SSL_GETPID(), fd));
+ return SECFailure;
+ }
+
+ ss->alertReceivedCallback = cb;
+ ss->alertReceivedCallbackArg = arg;
+
+ return SECSuccess;
+}
+
+SECStatus
+SSL_AlertSentCallback(PRFileDesc *fd, SSLAlertCallback cb, void *arg)
+{
+ sslSocket *ss;
+
+ ss = ssl_FindSocket(fd);
+ if (!ss) {
+ SSL_DBG(("%d: SSL[%d]: unable to find socket in SSL_AlertSentCallback",
+ SSL_GETPID(), fd));
+ return SECFailure;
+ }
+
+ ss->alertSentCallback = cb;
+ ss->alertSentCallbackArg = arg;
+
+ return SECSuccess;
+}
+
+SECStatus
SSL_BadCertHook(PRFileDesc *fd, SSLBadCertHandler f, void *arg)
{
sslSocket *ss;
diff --git a/nss/lib/ssl/sslsnce.c b/nss/lib/ssl/sslsnce.c
index 4a4005c..cf86edc 100644
--- a/nss/lib/ssl/sslsnce.c
+++ b/nss/lib/ssl/sslsnce.c
@@ -1,3 +1,4 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
/* This file implements the SERVER Session ID cache.
* NOTE: The contents of this file are NOT used by the client.
*
@@ -33,7 +34,7 @@
* sidCacheSet sidCacheSets[ numSIDCacheSets ];
* sidCacheEntry sidCacheData[ numSIDCacheEntries];
* certCacheEntry certCacheData[numCertCacheEntries];
- * SSLWrappedSymWrappingKey keyCacheData[ssl_auth_size][SSL_NUM_WRAP_MECHS];
+ * SSLWrappedSymWrappingKey keyCacheData[SSL_NUM_WRAP_KEYS][SSL_NUM_WRAP_MECHS];
* PRUint8 keyNameSuffix[SESS_TICKET_KEY_VAR_NAME_LEN]
* encKeyCacheEntry ticketEncKey; // Wrapped
* encKeyCacheEntry ticketMacKey; // Wrapped
@@ -54,6 +55,7 @@
#include "base64.h"
#include "keyhi.h"
#include "blapit.h"
+#include "nss.h" /* for NSS_RegisterShutdown */
#include "sechash.h"
#include <stdio.h>
@@ -109,7 +111,7 @@ struct sidCacheEntryStr {
/* 4 */ PRInt32 certIndex;
/* 4 */ PRInt32 srvNameIndex;
/* 32 */ PRUint8 srvNameHash[SHA256_LENGTH]; /* SHA256 name hash */
- /* 2 */ PRUint16 certTypeArgs;
+ /* 2 */ PRUint16 namedCurve;
/*104 */} ssl3;
/* force sizeof(sidCacheEntry) to be a multiple of cache line size */
@@ -440,17 +442,12 @@ ConvertFromSID(sidCacheEntry *to, sslSessionID *from)
to->u.ssl3.srvNameIndex = -1;
PORT_Memcpy(to->sessionID, from->u.ssl3.sessionID,
to->sessionIDLength);
- to->u.ssl3.certTypeArgs = 0U;
- switch (from->authType) {
- case ssl_auth_ecdsa:
- case ssl_auth_ecdh_rsa:
- case ssl_auth_ecdh_ecdsa:
- PORT_Assert(from->certType.namedCurve);
- to->u.ssl3.certTypeArgs =
- (PRUint16)from->certType.namedCurve->name;
- break;
- default:
- break;
+ to->u.ssl3.namedCurve = 0U;
+ if (from->authType == ssl_auth_ecdsa ||
+ from->authType == ssl_auth_ecdh_rsa ||
+ from->authType == ssl_auth_ecdh_ecdsa) {
+ PORT_Assert(from->namedCurve);
+ to->u.ssl3.namedCurve = (PRUint16)from->namedCurve->name;
}
SSL_TRC(8, ("%d: SSL3: ConvertSID: time=%d addr=0x%08x%08x%08x%08x "
@@ -526,16 +523,11 @@ ConvertToSID(sidCacheEntry *from,
if (to->peerCert == NULL)
goto loser;
}
- to->certType.authType = from->authType;
- switch (from->authType) {
- case ssl_auth_ecdsa:
- case ssl_auth_ecdh_rsa:
- case ssl_auth_ecdh_ecdsa:
- to->certType.namedCurve =
- ssl_LookupNamedGroup((SSLNamedGroup)from->u.ssl3.certTypeArgs);
- break;
- default:
- break;
+ if (from->authType == ssl_auth_ecdsa ||
+ from->authType == ssl_auth_ecdh_rsa ||
+ from->authType == ssl_auth_ecdh_ecdsa) {
+ to->namedCurve =
+ ssl_LookupNamedGroup((SSLNamedGroup)from->u.ssl3.namedCurve);
}
to->version = from->version;
@@ -983,7 +975,7 @@ InitCache(cacheDesc *cache, int maxCacheEntries, int maxCertCacheEntries,
cache->certCacheSize =
(char *)cache->keyCacheData - (char *)cache->certCacheData;
- cache->numKeyCacheEntries = ssl_auth_size * SSL_NUM_WRAP_MECHS;
+ cache->numKeyCacheEntries = SSL_NUM_WRAP_KEYS * SSL_NUM_WRAP_MECHS;
ptr = (ptrdiff_t)(cache->keyCacheData + cache->numKeyCacheEntries);
ptr = SID_ROUNDUP(ptr, SID_ALIGNMENT);
@@ -1608,36 +1600,255 @@ StopLockPoller(cacheDesc *cache)
* Code dealing with shared wrapped symmetric wrapping keys below *
************************************************************************/
-/* If now is zero, it implies that the lock is not held, and must be
-** aquired here.
-*/
+/* The asymmetric key we use for wrapping the symmetric ticket keys. This is a
+ * global structure that can be initialized without a socket. Access is
+ * synchronized on the reader-writer lock. This is setup either by calling
+ * SSL_SetSessionTicketKeyPair() or by configuring a certificate of the
+ * ssl_auth_rsa_decrypt type. */
+static struct {
+ PRCallOnceType setup;
+ PRRWLock *lock;
+ SECKEYPublicKey *pubKey;
+ SECKEYPrivateKey *privKey;
+ PRBool configured;
+} ssl_session_ticket_key_pair;
+
+/* The symmetric ticket keys. This requires a socket to construct and requires
+ * that the global structure be initialized before use. */
+static struct {
+ PRCallOnceType setup;
+ unsigned char keyName[SESS_TICKET_KEY_NAME_LEN];
+ PK11SymKey *encKey;
+ PK11SymKey *macKey;
+} ssl_session_ticket_keys;
+
+static void
+ssl_CleanupSessionTicketKeyPair()
+{
+ if (ssl_session_ticket_key_pair.pubKey) {
+ PORT_Assert(ssl_session_ticket_key_pair.privKey);
+ SECKEY_DestroyPublicKey(ssl_session_ticket_key_pair.pubKey);
+ SECKEY_DestroyPrivateKey(ssl_session_ticket_key_pair.privKey);
+ }
+}
+
+void
+ssl_ResetSessionTicketKeys()
+{
+ if (ssl_session_ticket_keys.encKey) {
+ PORT_Assert(ssl_session_ticket_keys.macKey);
+ PK11_FreeSymKey(ssl_session_ticket_keys.encKey);
+ PK11_FreeSymKey(ssl_session_ticket_keys.macKey);
+ }
+ PORT_Memset(&ssl_session_ticket_keys, 0,
+ sizeof(ssl_session_ticket_keys));
+}
+
+static SECStatus
+ssl_SessionTicketShutdown(void *appData, void *nssData)
+{
+ ssl_CleanupSessionTicketKeyPair();
+ PR_DestroyRWLock(ssl_session_ticket_key_pair.lock);
+ PORT_Memset(&ssl_session_ticket_key_pair, 0,
+ sizeof(ssl_session_ticket_key_pair));
+
+ ssl_ResetSessionTicketKeys();
+ return SECSuccess;
+}
+
+static PRStatus
+ssl_SessionTicketSetup(void)
+{
+ SECStatus rv = NSS_RegisterShutdown(ssl_SessionTicketShutdown, NULL);
+ if (rv != SECSuccess) {
+ return PR_FAILURE;
+ }
+ ssl_session_ticket_key_pair.lock = PR_NewRWLock(PR_RWLOCK_RANK_NONE, NULL);
+ if (!ssl_session_ticket_key_pair.lock) {
+ return PR_FAILURE;
+ }
+ return PR_SUCCESS;
+}
+
+/* Configure a session ticket key pair. |explicitConfig| is set to true for
+ * calls to SSL_SetSessionTicketKeyPair(), false for implicit configuration.
+ * This assumes that the setup has been run. */
+static SECStatus
+ssl_SetSessionTicketKeyPair(SECKEYPublicKey *pubKey,
+ SECKEYPrivateKey *privKey,
+ PRBool explicitConfig)
+{
+ SECKEYPublicKey *pubKeyCopy;
+ SECKEYPrivateKey *privKeyCopy;
+
+ PORT_Assert(ssl_session_ticket_key_pair.lock);
+
+ pubKeyCopy = SECKEY_CopyPublicKey(pubKey);
+ if (!pubKeyCopy) {
+ PORT_SetError(SEC_ERROR_NO_MEMORY);
+ return SECFailure;
+ }
+
+ privKeyCopy = SECKEY_CopyPrivateKey(privKey);
+ if (!privKeyCopy) {
+ SECKEY_DestroyPublicKey(pubKeyCopy);
+ PORT_SetError(SEC_ERROR_NO_MEMORY);
+ return SECFailure;
+ }
+
+ PR_RWLock_Wlock(ssl_session_ticket_key_pair.lock);
+ ssl_CleanupSessionTicketKeyPair();
+ ssl_session_ticket_key_pair.pubKey = pubKeyCopy;
+ ssl_session_ticket_key_pair.privKey = privKeyCopy;
+ ssl_session_ticket_key_pair.configured = explicitConfig;
+ PR_RWLock_Unlock(ssl_session_ticket_key_pair.lock);
+ return SECSuccess;
+}
+
+SECStatus
+SSL_SetSessionTicketKeyPair(SECKEYPublicKey *pubKey,
+ SECKEYPrivateKey *privKey)
+{
+ if (SECKEY_GetPublicKeyType(pubKey) != rsaKey ||
+ SECKEY_GetPrivateKeyType(privKey) != rsaKey) {
+ PORT_SetError(SEC_ERROR_INVALID_ARGS);
+ return SECFailure;
+ }
+
+ if (PR_SUCCESS != PR_CallOnce(&ssl_session_ticket_key_pair.setup,
+ &ssl_SessionTicketSetup)) {
+ PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
+ return SECFailure;
+ }
+
+ return ssl_SetSessionTicketKeyPair(pubKey, privKey, PR_TRUE);
+}
+
+/* When configuring a server cert, we should save the RSA key in case it is
+ * needed for ticket encryption. This saves the latest copy, unless there has
+ * been an explicit call to SSL_SetSessionTicketKeyPair(). */
+SECStatus
+ssl_MaybeSetSessionTicketKeyPair(const sslKeyPair *keyPair)
+{
+ PRBool configured;
+
+ if (PR_SUCCESS != PR_CallOnce(&ssl_session_ticket_key_pair.setup,
+ &ssl_SessionTicketSetup)) {
+ PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
+ return SECFailure;
+ }
+
+ PR_RWLock_Rlock(ssl_session_ticket_key_pair.lock);
+ configured = ssl_session_ticket_key_pair.configured;
+ PR_RWLock_Unlock(ssl_session_ticket_key_pair.lock);
+ if (configured) {
+ return SECSuccess;
+ }
+ return ssl_SetSessionTicketKeyPair(keyPair->pubKey,
+ keyPair->privKey, PR_FALSE);
+}
+
+static SECStatus
+ssl_GetSessionTicketKeyPair(SECKEYPublicKey **pubKey,
+ SECKEYPrivateKey **privKey)
+{
+ if (PR_SUCCESS != PR_CallOnce(&ssl_session_ticket_key_pair.setup,
+ &ssl_SessionTicketSetup)) {
+ PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
+ return SECFailure;
+ }
+
+ PR_RWLock_Rlock(ssl_session_ticket_key_pair.lock);
+ *pubKey = ssl_session_ticket_key_pair.pubKey;
+ *privKey = ssl_session_ticket_key_pair.privKey;
+ PR_RWLock_Unlock(ssl_session_ticket_key_pair.lock);
+ if (!*pubKey) {
+ PORT_Assert(!*privKey);
+ PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
+ return SECFailure;
+ }
+ PORT_Assert(*privKey);
+ return SECSuccess;
+}
+
static PRBool
-getSvrWrappingKey(PRInt32 symWrapMechIndex,
- SSLAuthType authType,
+ssl_GenerateSessionTicketKeys(void *pwArg, unsigned char *keyName,
+ PK11SymKey **aesKey, PK11SymKey **macKey);
+
+static PRStatus
+ssl_GenerateSessionTicketKeysOnce(void *arg)
+{
+ SECStatus rv;
+
+ /* Get a copy of the session keys from shared memory. */
+ PORT_Memcpy(ssl_session_ticket_keys.keyName,
+ SESS_TICKET_KEY_NAME_PREFIX,
+ sizeof(SESS_TICKET_KEY_NAME_PREFIX));
+ /* This function calls ssl_GetSessionTicketKeyPair(), which initializes the
+ * key pair stuff. That allows this to use the same shutdown function. */
+ rv = ssl_GenerateSessionTicketKeys(arg, ssl_session_ticket_keys.keyName,
+ &ssl_session_ticket_keys.encKey,
+ &ssl_session_ticket_keys.macKey);
+ if (rv != SECSuccess) {
+ return PR_FAILURE;
+ }
+
+ return PR_SUCCESS;
+}
+
+SECStatus
+ssl_GetSessionTicketKeys(sslSocket *ss, unsigned char *keyName,
+ PK11SymKey **encKey, PK11SymKey **macKey)
+{
+ if (PR_SUCCESS != PR_CallOnceWithArg(&ssl_session_ticket_keys.setup,
+ &ssl_GenerateSessionTicketKeysOnce,
+ ss->pkcs11PinArg)) {
+ PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
+ return SECFailure;
+ }
+
+ if (!ssl_session_ticket_keys.encKey || !ssl_session_ticket_keys.macKey) {
+ PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
+ return SECFailure;
+ }
+
+ PORT_Memcpy(keyName, ssl_session_ticket_keys.keyName,
+ sizeof(ssl_session_ticket_keys.keyName));
+ *encKey = ssl_session_ticket_keys.encKey;
+ *macKey = ssl_session_ticket_keys.macKey;
+ return SECSuccess;
+}
+
+/* If lockTime is zero, it implies that the lock is not held, and must be
+ * aquired here.
+ */
+static SECStatus
+getSvrWrappingKey(unsigned int symWrapMechIndex,
+ unsigned int wrapKeyIndex,
SSLWrappedSymWrappingKey *wswk,
cacheDesc *cache,
PRUint32 lockTime)
{
- PRUint32 ndx = (authType * SSL_NUM_WRAP_MECHS) + symWrapMechIndex;
+ PRUint32 ndx = (wrapKeyIndex * SSL_NUM_WRAP_MECHS) + symWrapMechIndex;
SSLWrappedSymWrappingKey *pwswk = cache->keyCacheData + ndx;
PRUint32 now = 0;
- PRBool rv = PR_FALSE;
+ PRBool rv = SECFailure;
if (!cache->cacheMem) { /* cache is uninitialized */
PORT_SetError(SSL_ERROR_SERVER_CACHE_NOT_CONFIGURED);
- return rv;
+ return SECFailure;
}
if (!lockTime) {
- lockTime = now = LockSidCacheLock(cache->keyCacheLock, now);
- if (!lockTime) {
- return rv;
+ now = LockSidCacheLock(cache->keyCacheLock, 0);
+ if (!now) {
+ return SECFailure;
}
}
- if (pwswk->authType == authType &&
- pwswk->symWrapMechIndex == symWrapMechIndex &&
+ if (pwswk->wrapKeyIndex == wrapKeyIndex &&
+ pwswk->wrapMechIndex == symWrapMechIndex &&
pwswk->wrappedSymKeyLen != 0) {
*wswk = *pwswk;
- rv = PR_TRUE;
+ rv = SECSuccess;
}
if (now) {
UnlockSidCacheLock(cache->keyCacheLock);
@@ -1645,28 +1856,25 @@ getSvrWrappingKey(PRInt32 symWrapMechIndex,
return rv;
}
-PRBool
-ssl_GetWrappingKey(PRInt32 symWrapMechIndex,
- SSLAuthType authType,
+SECStatus
+ssl_GetWrappingKey(unsigned int wrapMechIndex,
+ unsigned int wrapKeyIndex,
SSLWrappedSymWrappingKey *wswk)
{
- PRBool rv;
-
- PORT_Assert((unsigned)authType < ssl_auth_size);
- PORT_Assert((unsigned)symWrapMechIndex < SSL_NUM_WRAP_MECHS);
- if ((unsigned)authType < ssl_auth_size &&
- (unsigned)symWrapMechIndex < SSL_NUM_WRAP_MECHS) {
- rv = getSvrWrappingKey(symWrapMechIndex, authType, wswk,
- &globalCache, 0);
- } else {
- rv = PR_FALSE;
+ PORT_Assert(wrapMechIndex < SSL_NUM_WRAP_MECHS);
+ PORT_Assert(wrapKeyIndex < SSL_NUM_WRAP_KEYS);
+ if (wrapMechIndex >= SSL_NUM_WRAP_MECHS ||
+ wrapKeyIndex >= SSL_NUM_WRAP_KEYS) {
+ PORT_SetError(SEC_ERROR_INVALID_ARGS);
+ return SECFailure;
}
- return rv;
+ return getSvrWrappingKey(wrapMechIndex, wrapKeyIndex, wswk,
+ &globalCache, 0);
}
/* Wrap and cache a session ticket key. */
-static PRBool
+static SECStatus
WrapTicketKey(SECKEYPublicKey *svrPubKey, PK11SymKey *symKey,
const char *keyName, encKeyCacheEntry *cacheEntry)
{
@@ -1682,13 +1890,13 @@ WrapTicketKey(SECKEYPublicKey *svrPubKey, PK11SymKey *symKey,
SECSuccess) {
SSL_DBG(("%d: SSL[%s]: Unable to wrap session ticket %s.",
SSL_GETPID(), "unknown", keyName));
- return PR_FALSE;
+ return SECFailure;
}
cacheEntry->length = wrappedKey.len;
- return PR_TRUE;
+ return SECSuccess;
}
-static PRBool
+static SECStatus
GenerateTicketKeys(void *pwArg, unsigned char *keyName, PK11SymKey **aesKey,
PK11SymKey **macKey)
{
@@ -1712,7 +1920,7 @@ GenerateTicketKeys(void *pwArg, unsigned char *keyName, PK11SymKey **aesKey,
SECSuccess) {
SSL_DBG(("%d: SSL[%s]: Unable to generate random key name bytes.",
SSL_GETPID(), "unknown"));
- goto loser;
+ return SECFailure;
}
mechanismArray[0] = CKM_AES_CBC;
@@ -1735,17 +1943,17 @@ GenerateTicketKeys(void *pwArg, unsigned char *keyName, PK11SymKey **aesKey,
PORT_Memcpy(keyName, ticketKeyNameSuffix, SESS_TICKET_KEY_VAR_NAME_LEN);
*aesKey = aesKeyTmp;
*macKey = macKeyTmp;
- return PR_TRUE;
+ return SECSuccess;
loser:
if (aesKeyTmp)
PK11_FreeSymKey(aesKeyTmp);
if (macKeyTmp)
PK11_FreeSymKey(macKeyTmp);
- return PR_FALSE;
+ return SECFailure;
}
-static PRBool
+static SECStatus
GenerateAndWrapTicketKeys(SECKEYPublicKey *svrPubKey, void *pwArg,
unsigned char *keyName, PK11SymKey **aesKey,
PK11SymKey **macKey)
@@ -1753,31 +1961,35 @@ GenerateAndWrapTicketKeys(SECKEYPublicKey *svrPubKey, void *pwArg,
PK11SymKey *aesKeyTmp = NULL;
PK11SymKey *macKeyTmp = NULL;
cacheDesc *cache = &globalCache;
+ SECStatus rv;
- if (!GenerateTicketKeys(pwArg, keyName, &aesKeyTmp, &macKeyTmp)) {
- goto loser;
+ rv = GenerateTicketKeys(pwArg, keyName, &aesKeyTmp, &macKeyTmp);
+ if (rv != SECSuccess) {
+ return SECFailure;
}
if (cache->cacheMem) {
/* Export the keys to the shared cache in wrapped form. */
- if (!WrapTicketKey(svrPubKey, aesKeyTmp, "enc key", cache->ticketEncKey))
+ rv = WrapTicketKey(svrPubKey, aesKeyTmp, "enc key", cache->ticketEncKey);
+ if (rv != SECSuccess) {
goto loser;
- if (!WrapTicketKey(svrPubKey, macKeyTmp, "mac key", cache->ticketMacKey))
+ }
+ rv = WrapTicketKey(svrPubKey, macKeyTmp, "mac key", cache->ticketMacKey);
+ if (rv != SECSuccess) {
goto loser;
+ }
}
*aesKey = aesKeyTmp;
*macKey = macKeyTmp;
- return PR_TRUE;
+ return SECSuccess;
loser:
- if (aesKeyTmp)
- PK11_FreeSymKey(aesKeyTmp);
- if (macKeyTmp)
- PK11_FreeSymKey(macKeyTmp);
- return PR_FALSE;
+ PK11_FreeSymKey(aesKeyTmp);
+ PK11_FreeSymKey(macKeyTmp);
+ return SECFailure;
}
-static PRBool
+static SECStatus
UnwrapCachedTicketKeys(SECKEYPrivateKey *svrPrivKey, unsigned char *keyName,
PK11SymKey **aesKey, PK11SymKey **macKey)
{
@@ -1810,52 +2022,48 @@ UnwrapCachedTicketKeys(SECKEYPrivateKey *svrPrivKey, unsigned char *keyName,
SESS_TICKET_KEY_VAR_NAME_LEN);
*aesKey = aesKeyTmp;
*macKey = macKeyTmp;
- return PR_TRUE;
+ return SECSuccess;
loser:
if (aesKeyTmp)
PK11_FreeSymKey(aesKeyTmp);
if (macKeyTmp)
PK11_FreeSymKey(macKeyTmp);
- return PR_FALSE;
+ return SECFailure;
}
-PRBool
-ssl_GetSessionTicketKeys(SECKEYPrivateKey *svrPrivKey,
- SECKEYPublicKey *svrPubKey, void *pwArg,
- unsigned char *keyName, PK11SymKey **aesKey,
- PK11SymKey **macKey)
+static SECStatus
+ssl_GenerateSessionTicketKeys(void *pwArg, unsigned char *keyName,
+ PK11SymKey **encKey, PK11SymKey **macKey)
{
- PRUint32 now = 0;
- PRBool rv = PR_FALSE;
- PRBool keysGenerated = PR_FALSE;
+ SECKEYPrivateKey *svrPrivKey;
+ SECKEYPublicKey *svrPubKey;
+ PRUint32 now;
+ SECStatus rv;
cacheDesc *cache = &globalCache;
- if (!cache->cacheMem) {
- /* cache is uninitialized. Generate keys and return them
- * without caching. */
- return GenerateTicketKeys(pwArg, keyName, aesKey, macKey);
+ rv = ssl_GetSessionTicketKeyPair(&svrPubKey, &svrPrivKey);
+ if (rv != SECSuccess || !cache->cacheMem) {
+ /* No key pair for wrapping, or the cache is uninitialized. Generate
+ * keys and return them without caching. */
+ return GenerateTicketKeys(pwArg, keyName, encKey, macKey);
}
- now = LockSidCacheLock(cache->keyCacheLock, now);
+ now = LockSidCacheLock(cache->keyCacheLock, 0);
if (!now)
- return rv;
+ return SECFailure;
- if (!*(cache->ticketKeysValid)) {
+ if (*(cache->ticketKeysValid)) {
+ rv = UnwrapCachedTicketKeys(svrPrivKey, keyName, encKey, macKey);
+ } else {
/* Keys do not exist, create them. */
- if (!GenerateAndWrapTicketKeys(svrPubKey, pwArg, keyName,
- aesKey, macKey))
- goto loser;
- keysGenerated = PR_TRUE;
- *(cache->ticketKeysValid) = 1;
+ rv = GenerateAndWrapTicketKeys(svrPubKey, pwArg, keyName,
+ encKey, macKey);
+ if (rv == SECSuccess) {
+ *(cache->ticketKeysValid) = 1;
+ }
}
-
- rv = PR_TRUE;
-
-loser:
UnlockSidCacheLock(cache->keyCacheLock);
- if (rv && !keysGenerated)
- rv = UnwrapCachedTicketKeys(svrPrivKey, keyName, aesKey, macKey);
return rv;
}
@@ -1868,47 +2076,45 @@ loser:
* This is all done while holding the locks/mutexes necessary to make
* the operation atomic.
*/
-PRBool
+SECStatus
ssl_SetWrappingKey(SSLWrappedSymWrappingKey *wswk)
{
cacheDesc *cache = &globalCache;
- PRBool rv = PR_FALSE;
- SSLAuthType authType = wswk->authType;
- /* type of keys used to wrap SymWrapKey*/
- PRInt32 symWrapMechIndex = wswk->symWrapMechIndex;
+ PRBool rv = SECFailure;
PRUint32 ndx;
- PRUint32 now = 0;
+ PRUint32 now;
SSLWrappedSymWrappingKey myWswk;
if (!cache->cacheMem) { /* cache is uninitialized */
PORT_SetError(SSL_ERROR_SERVER_CACHE_NOT_CONFIGURED);
- return 0;
+ return SECFailure;
}
- PORT_Assert((unsigned)authType < ssl_auth_size);
- if ((unsigned)authType >= ssl_auth_size)
- return 0;
-
- PORT_Assert((unsigned)symWrapMechIndex < SSL_NUM_WRAP_MECHS);
- if ((unsigned)symWrapMechIndex >= SSL_NUM_WRAP_MECHS)
- return 0;
+ PORT_Assert(wswk->wrapMechIndex < SSL_NUM_WRAP_MECHS);
+ PORT_Assert(wswk->wrapKeyIndex < SSL_NUM_WRAP_KEYS);
+ if (wswk->wrapMechIndex >= SSL_NUM_WRAP_MECHS ||
+ wswk->wrapKeyIndex >= SSL_NUM_WRAP_KEYS) {
+ PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
+ return SECFailure;
+ }
- ndx = (authType * SSL_NUM_WRAP_MECHS) + symWrapMechIndex;
+ ndx = (wswk->wrapKeyIndex * SSL_NUM_WRAP_MECHS) + wswk->wrapMechIndex;
PORT_Memset(&myWswk, 0, sizeof myWswk); /* eliminate UMRs. */
- now = LockSidCacheLock(cache->keyCacheLock, now);
- if (now) {
- rv = getSvrWrappingKey(wswk->symWrapMechIndex, wswk->authType,
- &myWswk, cache, now);
- if (rv) {
- /* we found it on disk, copy it out to the caller. */
- PORT_Memcpy(wswk, &myWswk, sizeof *wswk);
- } else {
- /* Wasn't on disk, and we're still holding the lock, so write it. */
- cache->keyCacheData[ndx] = *wswk;
- }
- UnlockSidCacheLock(cache->keyCacheLock);
+ now = LockSidCacheLock(cache->keyCacheLock, 0);
+ if (!now) {
+ return SECFailure;
+ }
+ rv = getSvrWrappingKey(wswk->wrapMechIndex, wswk->wrapKeyIndex,
+ &myWswk, cache, now);
+ if (rv == SECSuccess) {
+ /* we found it on disk, copy it out to the caller. */
+ PORT_Memcpy(wswk, &myWswk, sizeof *wswk);
+ } else {
+ /* Wasn't on disk, and we're still holding the lock, so write it. */
+ cache->keyCacheData[ndx] = *wswk;
}
+ UnlockSidCacheLock(cache->keyCacheLock);
return rv;
}
@@ -1946,14 +2152,13 @@ SSL_InheritMPServerSIDCache(const char *envString)
return SECFailure;
}
-PRBool
-ssl_GetWrappingKey(PRInt32 symWrapMechIndex,
- SSLAuthType authType,
+SECStatus
+ssl_GetWrappingKey(unsigned int wrapMechIndex,
+ unsigned int wrapKeyIndex,
SSLWrappedSymWrappingKey *wswk)
{
- PRBool rv = PR_FALSE;
PR_ASSERT(!"SSL servers are not supported on this platform. (ssl_GetWrappingKey)");
- return rv;
+ return SECFailure;
}
/* This is a kind of test-and-set. The caller passes in the new value it wants
@@ -1965,12 +2170,11 @@ ssl_GetWrappingKey(PRInt32 symWrapMechIndex,
* This is all done while holding the locks/mutexes necessary to make
* the operation atomic.
*/
-PRBool
+SECStatus
ssl_SetWrappingKey(SSLWrappedSymWrappingKey *wswk)
{
- PRBool rv = PR_FALSE;
PR_ASSERT(!"SSL servers are not supported on this platform. (ssl_SetWrappingKey)");
- return rv;
+ return SECFailure;
}
PRUint32
diff --git a/nss/lib/ssl/sslsock.c b/nss/lib/ssl/sslsock.c
index 626f4a9..99828c8 100644
--- a/nss/lib/ssl/sslsock.c
+++ b/nss/lib/ssl/sslsock.c
@@ -330,6 +330,10 @@ ssl_DupSocket(sslSocket *os)
ss->getClientAuthDataArg = os->getClientAuthDataArg;
ss->sniSocketConfig = os->sniSocketConfig;
ss->sniSocketConfigArg = os->sniSocketConfigArg;
+ ss->alertReceivedCallback = os->alertReceivedCallback;
+ ss->alertReceivedCallbackArg = os->alertReceivedCallbackArg;
+ ss->alertSentCallback = os->alertSentCallback;
+ ss->alertSentCallbackArg = os->alertSentCallbackArg;
ss->handleBadCert = os->handleBadCert;
ss->badCertArg = os->badCertArg;
ss->handshakeCallback = os->handshakeCallback;
@@ -2148,6 +2152,14 @@ SSL_ReconfigFD(PRFileDesc *model, PRFileDesc *fd)
ss->sniSocketConfig = sm->sniSocketConfig;
if (sm->sniSocketConfigArg)
ss->sniSocketConfigArg = sm->sniSocketConfigArg;
+ if (sm->alertReceivedCallback) {
+ ss->alertReceivedCallback = sm->alertReceivedCallback;
+ ss->alertReceivedCallbackArg = sm->alertReceivedCallbackArg;
+ }
+ if (sm->alertSentCallback) {
+ ss->alertSentCallback = sm->alertSentCallback;
+ ss->alertSentCallbackArg = sm->alertSentCallbackArg;
+ }
if (sm->handleBadCert)
ss->handleBadCert = sm->handleBadCert;
if (sm->badCertArg)
@@ -2161,61 +2173,82 @@ SSL_ReconfigFD(PRFileDesc *model, PRFileDesc *fd)
return fd;
}
-/*
- * Get the user supplied range
- */
-static SECStatus
-ssl3_GetRangePolicy(SSLProtocolVariant protocolVariant, SSLVersionRange *prange)
+SECStatus
+ssl3_GetEffectiveVersionPolicy(SSLProtocolVariant variant,
+ SSLVersionRange *effectivePolicy)
{
SECStatus rv;
- PRUint32 policy;
- PRInt32 option;
+ PRUint32 policyFlag;
+ PRInt32 minPolicy, maxPolicy;
- /* only use policy constraints if we've set the apply ssl policy bit */
- rv = NSS_GetAlgorithmPolicy(SEC_OID_APPLY_SSL_POLICY, &policy);
- if ((rv != SECSuccess) || !(policy & NSS_USE_POLICY_IN_SSL)) {
- return SECFailure;
+ if (variant == ssl_variant_stream) {
+ effectivePolicy->min = SSL_LIBRARY_VERSION_MIN_SUPPORTED_STREAM;
+ effectivePolicy->max = SSL_LIBRARY_VERSION_MAX_SUPPORTED;
+ } else {
+ effectivePolicy->min = SSL_LIBRARY_VERSION_MIN_SUPPORTED_DATAGRAM;
+ effectivePolicy->max = SSL_LIBRARY_VERSION_MAX_SUPPORTED;
}
- rv = NSS_OptionGet(VERSIONS_POLICY_MIN(protocolVariant), &option);
+
+ rv = NSS_GetAlgorithmPolicy(SEC_OID_APPLY_SSL_POLICY, &policyFlag);
+ if ((rv != SECSuccess) || !(policyFlag & NSS_USE_POLICY_IN_SSL)) {
+ /* Policy is not active, report library extents. */
+ return SECSuccess;
+ }
+
+ rv = NSS_OptionGet(VERSIONS_POLICY_MIN(variant), &minPolicy);
if (rv != SECSuccess) {
- return rv;
+ return SECFailure;
}
- prange->min = (PRUint16)option;
- rv = NSS_OptionGet(VERSIONS_POLICY_MAX(protocolVariant), &option);
+ rv = NSS_OptionGet(VERSIONS_POLICY_MAX(variant), &maxPolicy);
if (rv != SECSuccess) {
- return rv;
+ return SECFailure;
}
- prange->max = (PRUint16)option;
- if (prange->max < prange->min) {
- return SECFailure; /* don't accept an invalid policy */
+
+ if (minPolicy > effectivePolicy->max ||
+ maxPolicy < effectivePolicy->min ||
+ minPolicy > maxPolicy) {
+ return SECFailure;
}
+ effectivePolicy->min = PR_MAX(effectivePolicy->min, minPolicy);
+ effectivePolicy->max = PR_MIN(effectivePolicy->max, maxPolicy);
return SECSuccess;
}
-/*
- * Constrain a single protocol variant's range based on the user policy
+/*
+ * Assumes that rangeParam values are within the supported boundaries,
+ * but should contain all potentially allowed versions, even if they contain
+ * conflicting versions.
+ * Will return the overlap, or a NONE range if system policy is invalid.
*/
static SECStatus
-ssl3_ConstrainVariantRangeByPolicy(SSLProtocolVariant protocolVariant)
+ssl3_CreateOverlapWithPolicy(SSLProtocolVariant protocolVariant,
+ SSLVersionRange *input,
+ SSLVersionRange *overlap)
{
- SSLVersionRange vrange;
- SSLVersionRange pvrange;
SECStatus rv;
+ SSLVersionRange effectivePolicyBoundary;
+ SSLVersionRange vrange;
- vrange = *VERSIONS_DEFAULTS(protocolVariant);
- rv = ssl3_GetRangePolicy(protocolVariant, &pvrange);
- if (rv != SECSuccess) {
- return SECSuccess; /* we don't have any policy */
+ PORT_Assert(input != NULL);
+
+ rv = ssl3_GetEffectiveVersionPolicy(protocolVariant,
+ &effectivePolicyBoundary);
+ if (rv == SECFailure) {
+ /* SECFailure means internal failure or invalid configuration. */
+ overlap->min = overlap->max = SSL_LIBRARY_VERSION_NONE;
+ return SECFailure;
}
- vrange.min = PR_MAX(vrange.min, pvrange.min);
- vrange.max = PR_MIN(vrange.max, pvrange.max);
- if (vrange.max >= vrange.min) {
- *VERSIONS_DEFAULTS(protocolVariant) = vrange;
- } else {
+
+ vrange.min = PR_MAX(input->min, effectivePolicyBoundary.min);
+ vrange.max = PR_MIN(input->max, effectivePolicyBoundary.max);
+
+ if (vrange.max < vrange.min) {
/* there was no overlap, turn off range altogether */
- pvrange.min = pvrange.max = SSL_LIBRARY_VERSION_NONE;
- *VERSIONS_DEFAULTS(protocolVariant) = pvrange;
+ overlap->min = overlap->max = SSL_LIBRARY_VERSION_NONE;
+ return SECFailure;
}
+
+ *overlap = vrange;
return SECSuccess;
}
@@ -2223,16 +2256,17 @@ static PRBool
ssl_VersionIsSupportedByPolicy(SSLProtocolVariant protocolVariant,
SSL3ProtocolVersion version)
{
- SSLVersionRange pvrange;
SECStatus rv;
+ SSLVersionRange effectivePolicyBoundary;
- rv = ssl3_GetRangePolicy(protocolVariant, &pvrange);
- if (rv == SECSuccess) {
- if ((version > pvrange.max) || (version < pvrange.min)) {
- return PR_FALSE; /* disallowed by policy */
- }
+ rv = ssl3_GetEffectiveVersionPolicy(protocolVariant,
+ &effectivePolicyBoundary);
+ if (rv == SECFailure) {
+ /* SECFailure means internal failure or invalid configuration. */
+ return PR_FALSE;
}
- return PR_TRUE;
+ return version >= effectivePolicyBoundary.min &&
+ version <= effectivePolicyBoundary.max;
}
/*
@@ -2242,52 +2276,44 @@ ssl_VersionIsSupportedByPolicy(SSLProtocolVariant protocolVariant,
SECStatus
ssl3_ConstrainRangeByPolicy(void)
{
- SECStatus rv;
- rv = ssl3_ConstrainVariantRangeByPolicy(ssl_variant_stream);
- if (rv != SECSuccess) {
- return rv;
- }
- rv = ssl3_ConstrainVariantRangeByPolicy(ssl_variant_datagram);
- if (rv != SECSuccess) {
- return rv;
- }
+ /* We ignore failures in ssl3_CreateOverlapWithPolicy. Although an empty
+ * overlap disables all connectivity, it's an allowed state.
+ */
+ ssl3_CreateOverlapWithPolicy(ssl_variant_stream,
+ VERSIONS_DEFAULTS(ssl_variant_stream),
+ VERSIONS_DEFAULTS(ssl_variant_stream));
+ ssl3_CreateOverlapWithPolicy(ssl_variant_datagram,
+ VERSIONS_DEFAULTS(ssl_variant_datagram),
+ VERSIONS_DEFAULTS(ssl_variant_datagram));
return SECSuccess;
}
PRBool
-ssl3_VersionIsSupported(SSLProtocolVariant protocolVariant,
- SSL3ProtocolVersion version)
+ssl3_VersionIsSupportedByCode(SSLProtocolVariant protocolVariant,
+ SSL3ProtocolVersion version)
{
- if (!ssl_VersionIsSupportedByPolicy(protocolVariant, version)) {
- return PR_FALSE;
- }
switch (protocolVariant) {
case ssl_variant_stream:
- return (version >= SSL_LIBRARY_VERSION_3_0 &&
+ return (version >= SSL_LIBRARY_VERSION_MIN_SUPPORTED_STREAM &&
version <= SSL_LIBRARY_VERSION_MAX_SUPPORTED);
case ssl_variant_datagram:
- return (version >= SSL_LIBRARY_VERSION_TLS_1_1 &&
+ return (version >= SSL_LIBRARY_VERSION_MIN_SUPPORTED_DATAGRAM &&
version <= SSL_LIBRARY_VERSION_MAX_SUPPORTED);
- default:
- /* Can't get here */
- PORT_Assert(PR_FALSE);
- return PR_FALSE;
}
+
+ /* Can't get here */
+ PORT_Assert(PR_FALSE);
+ return PR_FALSE;
}
-/* Returns PR_TRUE if the given version range is valid and
-** fully supported; otherwise, returns PR_FALSE.
-*/
-static PRBool
-ssl3_VersionRangeIsValid(SSLProtocolVariant protocolVariant,
- const SSLVersionRange *vrange)
+PRBool
+ssl3_VersionIsSupported(SSLProtocolVariant protocolVariant,
+ SSL3ProtocolVersion version)
{
- return vrange &&
- vrange->min <= vrange->max &&
- ssl3_VersionIsSupported(protocolVariant, vrange->min) &&
- ssl3_VersionIsSupported(protocolVariant, vrange->max) &&
- (vrange->min > SSL_LIBRARY_VERSION_3_0 ||
- vrange->max < SSL_LIBRARY_VERSION_TLS_1_3);
+ if (!ssl_VersionIsSupportedByPolicy(protocolVariant, version)) {
+ return PR_FALSE;
+ }
+ return ssl3_VersionIsSupportedByCode(protocolVariant, version);
}
const SECItem *
@@ -2313,6 +2339,8 @@ SECStatus
SSL_VersionRangeGetSupported(SSLProtocolVariant protocolVariant,
SSLVersionRange *vrange)
{
+ SECStatus rv;
+
if (!vrange) {
PORT_SetError(SEC_ERROR_INVALID_ARGS);
return SECFailure;
@@ -2320,15 +2348,15 @@ SSL_VersionRangeGetSupported(SSLProtocolVariant protocolVariant,
switch (protocolVariant) {
case ssl_variant_stream:
- vrange->min = SSL_LIBRARY_VERSION_3_0;
+ vrange->min = SSL_LIBRARY_VERSION_MIN_SUPPORTED_STREAM;
vrange->max = SSL_LIBRARY_VERSION_MAX_SUPPORTED;
- // We don't allow SSLv3 and TLSv1.3 together.
- if (vrange->max == SSL_LIBRARY_VERSION_TLS_1_3) {
- vrange->min = SSL_LIBRARY_VERSION_TLS_1_0;
- }
+ /* We don't allow SSLv3 and TLSv1.3 together.
+ * However, don't check yet, apply the policy first.
+ * Because if the effective supported range doesn't use TLS 1.3,
+ * then we don't need to increase the minimum. */
break;
case ssl_variant_datagram:
- vrange->min = SSL_LIBRARY_VERSION_TLS_1_1;
+ vrange->min = SSL_LIBRARY_VERSION_MIN_SUPPORTED_DATAGRAM;
vrange->max = SSL_LIBRARY_VERSION_MAX_SUPPORTED;
break;
default:
@@ -2336,6 +2364,17 @@ SSL_VersionRangeGetSupported(SSLProtocolVariant protocolVariant,
return SECFailure;
}
+ rv = ssl3_CreateOverlapWithPolicy(protocolVariant, vrange, vrange);
+ if (rv != SECSuccess) {
+ /* Library default and policy don't overlap. */
+ return rv;
+ }
+
+ /* We don't allow SSLv3 and TLSv1.3 together */
+ if (vrange->max >= SSL_LIBRARY_VERSION_TLS_1_3) {
+ vrange->min = PR_MAX(vrange->min, SSL_LIBRARY_VERSION_TLS_1_0);
+ }
+
return SECSuccess;
}
@@ -2351,6 +2390,43 @@ SSL_VersionRangeGetDefault(SSLProtocolVariant protocolVariant,
}
*vrange = *VERSIONS_DEFAULTS(protocolVariant);
+ return ssl3_CreateOverlapWithPolicy(protocolVariant, vrange, vrange);
+}
+
+static PRBool
+ssl3_HasConflictingSSLVersions(const SSLVersionRange *vrange)
+{
+ return (vrange->min <= SSL_LIBRARY_VERSION_3_0 &&
+ vrange->max >= SSL_LIBRARY_VERSION_TLS_1_3);
+}
+
+static SECStatus
+ssl3_CheckRangeValidAndConstrainByPolicy(SSLProtocolVariant protocolVariant,
+ SSLVersionRange *vrange)
+{
+ SECStatus rv;
+
+ if (vrange->min > vrange->max ||
+ !ssl3_VersionIsSupportedByCode(protocolVariant, vrange->min) ||
+ !ssl3_VersionIsSupportedByCode(protocolVariant, vrange->max) ||
+ ssl3_HasConflictingSSLVersions(vrange)) {
+ PORT_SetError(SSL_ERROR_INVALID_VERSION_RANGE);
+ return SECFailure;
+ }
+
+ /* Try to adjust the received range using our policy.
+ * If there's overlap, we'll use the (possibly reduced) range.
+ * If there isn't overlap, it's failure. */
+
+ rv = ssl3_CreateOverlapWithPolicy(protocolVariant, vrange, vrange);
+ if (rv != SECSuccess) {
+ return rv;
+ }
+
+ /* We don't allow SSLv3 and TLSv1.3 together */
+ if (vrange->max >= SSL_LIBRARY_VERSION_TLS_1_3) {
+ vrange->min = PR_MAX(vrange->min, SSL_LIBRARY_VERSION_TLS_1_0);
+ }
return SECSuccess;
}
@@ -2359,13 +2435,21 @@ SECStatus
SSL_VersionRangeSetDefault(SSLProtocolVariant protocolVariant,
const SSLVersionRange *vrange)
{
- if (!ssl3_VersionRangeIsValid(protocolVariant, vrange)) {
- PORT_SetError(SSL_ERROR_INVALID_VERSION_RANGE);
+ SSLVersionRange constrainedRange;
+ SECStatus rv;
+
+ if (!vrange) {
+ PORT_SetError(SEC_ERROR_INVALID_ARGS);
return SECFailure;
}
- *VERSIONS_DEFAULTS(protocolVariant) = *vrange;
+ constrainedRange = *vrange;
+ rv = ssl3_CheckRangeValidAndConstrainByPolicy(protocolVariant,
+ &constrainedRange);
+ if (rv != SECSuccess)
+ return rv;
+ *VERSIONS_DEFAULTS(protocolVariant) = constrainedRange;
return SECSuccess;
}
@@ -2393,24 +2477,33 @@ SSL_VersionRangeGet(PRFileDesc *fd, SSLVersionRange *vrange)
ssl_ReleaseSSL3HandshakeLock(ss);
ssl_Release1stHandshakeLock(ss);
- return SECSuccess;
+ return ssl3_CreateOverlapWithPolicy(ss->protocolVariant, vrange, vrange);
}
SECStatus
SSL_VersionRangeSet(PRFileDesc *fd, const SSLVersionRange *vrange)
{
- sslSocket *ss = ssl_FindSocket(fd);
+ SSLVersionRange constrainedRange;
+ sslSocket *ss;
+ SECStatus rv;
+ if (!vrange) {
+ PORT_SetError(SEC_ERROR_INVALID_ARGS);
+ return SECFailure;
+ }
+
+ ss = ssl_FindSocket(fd);
if (!ss) {
SSL_DBG(("%d: SSL[%d]: bad socket in SSL_VersionRangeSet",
SSL_GETPID(), fd));
return SECFailure;
}
- if (!ssl3_VersionRangeIsValid(ss->protocolVariant, vrange)) {
- PORT_SetError(SSL_ERROR_INVALID_VERSION_RANGE);
- return SECFailure;
- }
+ constrainedRange = *vrange;
+ rv = ssl3_CheckRangeValidAndConstrainByPolicy(ss->protocolVariant,
+ &constrainedRange);
+ if (rv != SECSuccess)
+ return rv;
ssl_Get1stHandshakeLock(ss);
ssl_GetSSL3HandshakeLock(ss);
@@ -2423,7 +2516,7 @@ SSL_VersionRangeSet(PRFileDesc *fd, const SSLVersionRange *vrange)
return SECFailure;
}
- ss->vrange = *vrange;
+ ss->vrange = constrainedRange;
ssl_ReleaseSSL3HandshakeLock(ss);
ssl_Release1stHandshakeLock(ss);
@@ -3672,7 +3765,10 @@ ssl_NewSocket(PRBool makeLocks, SSLProtocolVariant protocolVariant)
ss->opt.noLocks = !makeLocks;
ss->vrange = *VERSIONS_DEFAULTS(protocolVariant);
ss->protocolVariant = protocolVariant;
-
+ /* Ignore overlap failures, because returning NULL would trigger assertion
+ * failures elsewhere. We don't want this scenario to be fatal, it's just
+ * a state where no SSL connectivity is possible. */
+ ssl3_CreateOverlapWithPolicy(ss->protocolVariant, &ss->vrange, &ss->vrange);
ss->peerID = NULL;
ss->rTimeout = PR_INTERVAL_NO_TIMEOUT;
ss->wTimeout = PR_INTERVAL_NO_TIMEOUT;
@@ -3690,6 +3786,10 @@ ssl_NewSocket(PRBool makeLocks, SSLProtocolVariant protocolVariant)
ss->sniSocketConfig = NULL;
ss->sniSocketConfigArg = NULL;
ss->getClientAuthData = NULL;
+ ss->alertReceivedCallback = NULL;
+ ss->alertReceivedCallbackArg = NULL;
+ ss->alertSentCallback = NULL;
+ ss->alertSentCallbackArg = NULL;
ss->handleBadCert = NULL;
ss->badCertArg = NULL;
ss->pkcs11PinArg = NULL;
@@ -3704,6 +3804,7 @@ ssl_NewSocket(PRBool makeLocks, SSLProtocolVariant protocolVariant)
PR_INIT_CLIST(&ss->ssl3.hs.lastMessageFlight);
PR_INIT_CLIST(&ss->ssl3.hs.cipherSpecs);
PR_INIT_CLIST(&ss->ssl3.hs.bufferedEarlyData);
+ ssl3_InitExtensionData(&ss->xtnData);
if (makeLocks) {
rv = ssl_MakeLocks(ss);
if (rv != SECSuccess)
@@ -3715,7 +3816,6 @@ ssl_NewSocket(PRBool makeLocks, SSLProtocolVariant protocolVariant)
rv = ssl3_InitGather(&ss->gs);
if (rv != SECSuccess)
goto loser;
- ssl3_InitExtensionData(&ss->xtnData);
return ss;
loser:
diff --git a/nss/lib/ssl/sslt.h b/nss/lib/ssl/sslt.h
index 506b78d..bd9a2ae 100644
--- a/nss/lib/ssl/sslt.h
+++ b/nss/lib/ssl/sslt.h
@@ -298,6 +298,21 @@ typedef struct SSLPreliminaryChannelInfoStr {
/* Cipher suite: test (valuesSet & ssl_preinfo_cipher_suite) */
PRUint16 cipherSuite;
+ /* The following fields were added in NSS 3.29. */
+ /* |canSendEarlyData| is true when a 0-RTT is enabled. This can only be
+ * true after sending the ClientHello and before the handshake completes.
+ */
+ PRBool canSendEarlyData;
+
+ /* The following fields were added in NSS 3.31. */
+ /* The number of early data octets that a client is permitted to send on
+ * this connection. The value will be zero if the connection was not
+ * resumed or early data is not permitted. For a client, this value only
+ * has meaning if |canSendEarlyData| is true. For a server, this indicates
+ * the value that was advertised in the session ticket that was used to
+ * resume this session. */
+ PRUint32 maxEarlyDataSize;
+
/* When adding new fields to this structure, please document the
* NSS version in which they were added. */
} SSLPreliminaryChannelInfo;
@@ -395,11 +410,10 @@ typedef enum {
/* This is the old name for the supported_groups extensions. */
#define ssl_elliptic_curves_xtn ssl_supported_groups_xtn
-/* SSL_MAX_EXTENSIONS doesn't include ssl_padding_xtn. It includes the maximum
- * number of extensions that are supported for any single message type. That
- * is, a ClientHello; ServerHello and TLS 1.3 NewSessionTicket and
- * HelloRetryRequest extensions are smaller. */
-#define SSL_MAX_EXTENSIONS 19
+/* SSL_MAX_EXTENSIONS includes the maximum number of extensions that are
+ * supported for any single message type. That is, a ClientHello; ServerHello
+ * and TLS 1.3 NewSessionTicket and HelloRetryRequest extensions have fewer. */
+#define SSL_MAX_EXTENSIONS 20
/* Deprecated */
typedef enum {
diff --git a/nss/lib/ssl/tls13con.c b/nss/lib/ssl/tls13con.c
index 68a2a2c..37b7e81 100644
--- a/nss/lib/ssl/tls13con.c
+++ b/nss/lib/ssl/tls13con.c
@@ -22,9 +22,10 @@
#include "tls13exthandle.h"
typedef enum {
- TrafficKeyEarlyApplicationData,
- TrafficKeyHandshake,
- TrafficKeyApplicationData
+ TrafficKeyClearText = 0,
+ TrafficKeyEarlyApplicationData = 1,
+ TrafficKeyHandshake = 2,
+ TrafficKeyApplicationData = 3
} TrafficKeyType;
typedef enum {
@@ -76,7 +77,6 @@ tls13_DeriveSecret(sslSocket *ss, PK11SymKey *key,
const char *suffix,
const SSL3Hashes *hashes,
PK11SymKey **dest);
-static void tls13_SetNullCipherSpec(sslSocket *ss, ssl3CipherSpec **specp);
static SECStatus tls13_SendEndOfEarlyData(sslSocket *ss);
static SECStatus tls13_SendFinished(sslSocket *ss, PK11SymKey *baseKey);
static SECStatus tls13_ComputePskBinderHash(sslSocket *ss,
@@ -132,7 +132,7 @@ const SSL3ProtocolVersion kDtlsRecordVersion = SSL_LIBRARY_VERSION_TLS_1_1;
PR_STATIC_ASSERT(SSL_LIBRARY_VERSION_MAX_SUPPORTED <=
SSL_LIBRARY_VERSION_TLS_1_3);
-/* Use this instead of FATAL_ERROR when an alert isn't possible. */
+/* Use this instead of FATAL_ERROR when no alert shall be sent. */
#define LOG_ERROR(ss, prError) \
do { \
SSL_TRC(3, ("%d: TLS13[%d]: fatal error %d in %s (%s:%d)", \
@@ -163,15 +163,21 @@ static char *
tls13_HandshakeState(SSL3WaitState st)
{
switch (st) {
+ STATE_CASE(idle_handshake);
STATE_CASE(wait_client_hello);
STATE_CASE(wait_client_cert);
+ STATE_CASE(wait_client_key);
STATE_CASE(wait_cert_verify);
+ STATE_CASE(wait_change_cipher);
STATE_CASE(wait_finished);
STATE_CASE(wait_server_hello);
+ STATE_CASE(wait_certificate_status);
STATE_CASE(wait_server_cert);
+ STATE_CASE(wait_server_key);
STATE_CASE(wait_cert_request);
+ STATE_CASE(wait_hello_done);
+ STATE_CASE(wait_new_session_ticket);
STATE_CASE(wait_encrypted_extensions);
- STATE_CASE(idle_handshake);
default:
break;
}
@@ -426,10 +432,7 @@ tls13_SetupClientHello(sslSocket *ss)
session_ticket = &sid->u.ssl3.locked.sessionTicket;
PORT_Assert(session_ticket && session_ticket->ticket.data);
- if (session_ticket->ticket_lifetime_hint == 0 ||
- (session_ticket->ticket_lifetime_hint +
- session_ticket->received_timestamp >
- ssl_Time())) {
+ if (ssl_TicketTimeValid(session_ticket)) {
ss->statelessResume = PR_TRUE;
}
@@ -625,13 +628,9 @@ tls13_RecoverWrappedSharedSecret(sslSocket *ss, sslSessionID *sid)
hashType = tls13_GetHashForCipherSuite(sid->u.ssl3.cipherSuite);
/* If we are the server, we compute the wrapping key, but if we
- * are the client, it's coordinates are stored with the ticket. */
+ * are the client, its coordinates are stored with the ticket. */
if (ss->sec.isServer) {
- const sslServerCert *serverCert;
-
- serverCert = ssl_FindServerCert(ss, &sid->certType);
- PORT_Assert(serverCert);
- wrapKey = ssl3_GetWrappingKey(ss, NULL, serverCert,
+ wrapKey = ssl3_GetWrappingKey(ss, NULL,
sid->u.ssl3.masterWrapMech,
ss->pkcs11PinArg);
} else {
@@ -934,7 +933,7 @@ tls13_CanResume(sslSocket *ss, const sslSessionID *sid)
* do remember the type of certificate we originally used, so we can locate
* it again, provided that the current ssl socket has had its server certs
* configured the same as the previous one. */
- sc = ssl_FindServerCert(ss, &sid->certType);
+ sc = ssl_FindServerCert(ss, sid->authType, sid->namedCurve);
if (!sc || !sc->serverCert) {
return PR_FALSE;
}
@@ -943,27 +942,6 @@ tls13_CanResume(sslSocket *ss, const sslSessionID *sid)
}
static PRBool
-tls13_AlpnTagAllowed(const sslSocket *ss, const SECItem *tag)
-{
- const unsigned char *data = ss->opt.nextProtoNego.data;
- unsigned int length = ss->opt.nextProtoNego.len;
- unsigned int offset = 0;
-
- if (!tag->len)
- return PR_TRUE;
-
- while (offset < length) {
- unsigned int taglen = (unsigned int)data[offset];
- if ((taglen == tag->len) &&
- !PORT_Memcmp(data + offset + 1, tag->data, tag->len))
- return PR_TRUE;
- offset += 1 + taglen;
- }
-
- return PR_FALSE;
-}
-
-static PRBool
tls13_CanNegotiateZeroRtt(sslSocket *ss, const sslSessionID *sid)
{
PORT_Assert(ss->ssl3.hs.zeroRttState == ssl_0rtt_sent);
@@ -1158,6 +1136,30 @@ tls13_NegotiateKeyExchange(sslSocket *ss, TLS13KeyShareEntry **clientShare)
return SECSuccess;
}
+SSLAuthType
+ssl_SignatureSchemeToAuthType(SSLSignatureScheme scheme)
+{
+ switch (scheme) {
+ case ssl_sig_rsa_pkcs1_sha1:
+ case ssl_sig_rsa_pkcs1_sha256:
+ 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:
+ return ssl_auth_rsa_sign;
+ case ssl_sig_ecdsa_secp256r1_sha256:
+ case ssl_sig_ecdsa_secp384r1_sha384:
+ case ssl_sig_ecdsa_secp521r1_sha512:
+ case ssl_sig_ecdsa_sha1:
+ return ssl_auth_ecdsa;
+ default:
+ PORT_Assert(0);
+ }
+ return ssl_auth_null;
+}
+
SECStatus
tls13_SelectServerCert(sslSocket *ss)
{
@@ -1181,8 +1183,7 @@ tls13_SelectServerCert(sslSocket *ss)
cursor = PR_NEXT_LINK(cursor)) {
sslServerCert *cert = (sslServerCert *)cursor;
- if (cert->certType.authType == ssl_auth_rsa_pss ||
- cert->certType.authType == ssl_auth_rsa_decrypt) {
+ if (SSL_CERT_IS_ONLY(cert, ssl_auth_rsa_decrypt)) {
continue;
}
@@ -1195,8 +1196,8 @@ tls13_SelectServerCert(sslSocket *ss)
if (rv == SECSuccess) {
/* Found one. */
ss->sec.serverCert = cert;
- ss->sec.authType = cert->certType.authType;
- ss->ssl3.hs.kea_def_mutable.authKeyType = cert->certType.authType;
+ ss->sec.authType = ss->ssl3.hs.kea_def_mutable.authKeyType =
+ ssl_SignatureSchemeToAuthType(ss->ssl3.hs.signatureScheme);
ss->sec.authKeyBits = cert->serverKeyBits;
return SECSuccess;
}
@@ -1227,8 +1228,6 @@ tls13_NegotiateAuthentication(sslSocket *ss)
if (rv != SECSuccess) {
return SECFailure;
}
- ss->ssl3.hs.kea_def_mutable.authKeyType =
- ss->sec.serverCert->certType.authType;
return SECSuccess;
}
@@ -1248,16 +1247,6 @@ tls13_HandleClientHelloPart2(sslSocket *ss,
if (ssl3_ExtensionNegotiated(ss, ssl_tls13_early_data_xtn)) {
ss->ssl3.hs.zeroRttState = ssl_0rtt_sent;
-
- if (IS_DTLS(ss)) {
- /* Save the null spec, which we should be currently reading. We will
- * use this when 0-RTT sending is over. */
- ssl_GetSpecReadLock(ss);
- ss->ssl3.hs.nullSpec = ss->ssl3.crSpec;
- tls13_CipherSpecAddRef(ss->ssl3.hs.nullSpec);
- PORT_Assert(ss->ssl3.hs.nullSpec->cipher_def->cipher == cipher_null);
- ssl_ReleaseSpecReadLock(ss);
- }
}
#ifndef PARANOID
@@ -1340,6 +1329,10 @@ tls13_HandleClientHelloPart2(sslSocket *ss,
goto loser;
}
+ ss->sec.serverCert = ssl_FindServerCert(ss, sid->authType,
+ sid->namedCurve);
+ PORT_Assert(ss->sec.serverCert);
+
rv = tls13_RecoverWrappedSharedSecret(ss, sid);
if (rv != SECSuccess) {
SSL_AtomicIncrementLong(&ssl3stats->hch_sid_cache_not_ok);
@@ -1348,12 +1341,11 @@ tls13_HandleClientHelloPart2(sslSocket *ss,
}
tls13_RestoreCipherInfo(ss, sid);
- ss->sec.serverCert = ssl_FindServerCert(ss, &sid->certType);
- PORT_Assert(ss->sec.serverCert);
ss->sec.localCert = CERT_DupCertificate(ss->sec.serverCert->serverCert);
if (sid->peerCert != NULL) {
ss->sec.peerCert = CERT_DupCertificate(sid->peerCert);
}
+
ssl3_RegisterExtensionSender(
ss, &ss->xtnData,
ssl_tls13_pre_shared_key_xtn, tls13_ServerSendPreSharedKeyXtn);
@@ -1614,9 +1606,9 @@ static SECStatus
tls13_SendCertificateRequest(sslSocket *ss)
{
SECStatus rv;
- int calen;
+ unsigned int calen;
SECItem *names;
- int nnames;
+ unsigned int nnames;
SECItem *name;
int i;
PRUint8 sigSchemes[MAX_SIGNATURE_SCHEMES * 2];
@@ -1632,7 +1624,10 @@ tls13_SendCertificateRequest(sslSocket *ss)
return rv;
}
- ssl3_GetCertificateRequestCAs(ss, &calen, &names, &nnames);
+ rv = ssl_GetCertificateRequestCAs(ss, &calen, &names, &nnames);
+ if (rv != SECSuccess) {
+ return rv;
+ }
length = 1 + 0 /* length byte for empty request context */ +
2 + sigSchemesLength + 2 + calen + 2;
@@ -1670,7 +1665,7 @@ SECStatus
tls13_HandleHelloRetryRequest(sslSocket *ss, SSL3Opaque *b, PRUint32 length)
{
SECStatus rv;
- PRInt32 tmp;
+ PRUint32 tmp;
SSL3ProtocolVersion version;
SSL_TRC(3, ("%d: TLS13[%d]: handle hello retry request",
@@ -1700,9 +1695,13 @@ tls13_HandleHelloRetryRequest(sslSocket *ss, SSL3Opaque *b, PRUint32 length)
}
if (ss->ssl3.hs.zeroRttState == ssl_0rtt_sent) {
- /* Oh well, back to the start. */
- tls13_SetNullCipherSpec(ss, &ss->ssl3.cwSpec);
ss->ssl3.hs.zeroRttState = ssl_0rtt_ignored;
+ /* Restore the null cipher spec for writing. */
+ ssl_GetSpecWriteLock(ss);
+ tls13_CipherSpecRelease(ss->ssl3.cwSpec);
+ ss->ssl3.cwSpec = ss->ssl3.crSpec;
+ PORT_Assert(ss->ssl3.cwSpec->cipher_def->cipher == cipher_null);
+ ssl_ReleaseSpecWriteLock(ss);
} else {
PORT_Assert(ss->ssl3.hs.zeroRttState == ssl_0rtt_none);
}
@@ -1719,8 +1718,8 @@ tls13_HandleHelloRetryRequest(sslSocket *ss, SSL3Opaque *b, PRUint32 length)
}
/* Extensions. */
- tmp = ssl3_ConsumeHandshakeNumber(ss, 2, &b, &length);
- if (tmp < 0) {
+ rv = ssl3_ConsumeHandshakeNumber(ss, &tmp, 2, &b, &length);
+ if (rv != SECSuccess) {
return SECFailure; /* error code already set */
}
/* Extensions must be non-empty and use the remainder of the message.
@@ -1758,7 +1757,7 @@ tls13_HandleCertificateRequest(sslSocket *ss, SSL3Opaque *b, PRUint32 length)
TLS13CertificateRequest *certRequest = NULL;
SECItem context = { siBuffer, NULL, 0 };
PLArenaPool *arena;
- PRInt32 extensionsLength;
+ SECItem extensionsData = { siBuffer, NULL, 0 };
SSL_TRC(3, ("%d: TLS13[%d]: handle certificate_request sequence",
SSL_GETPID(), ss->fd));
@@ -1805,7 +1804,7 @@ tls13_HandleCertificateRequest(sslSocket *ss, SSL3Opaque *b, PRUint32 length)
&certRequest->signatureSchemes,
&certRequest->signatureSchemeCount,
&b, &length);
- if (rv != SECSuccess) {
+ if (rv != SECSuccess || certRequest->signatureSchemeCount == 0) {
FATAL_ERROR(ss, SSL_ERROR_RX_MALFORMED_CERT_REQUEST,
decode_error);
goto loser;
@@ -1816,14 +1815,16 @@ tls13_HandleCertificateRequest(sslSocket *ss, SSL3Opaque *b, PRUint32 length)
if (rv != SECSuccess)
goto loser; /* alert already sent */
- /* Verify that the extensions length is correct. */
- extensionsLength = ssl3_ConsumeHandshakeNumber(ss, 2, &b, &length);
- if (extensionsLength < 0) {
- goto loser; /* alert already sent */
+ /* Verify that the extensions are sane. */
+ rv = ssl3_ConsumeHandshakeVariable(ss, &extensionsData, 2, &b, &length);
+ if (rv != SECSuccess) {
+ goto loser;
}
- if (extensionsLength != length) {
- FATAL_ERROR(ss, SSL_ERROR_RX_MALFORMED_CERT_REQUEST,
- illegal_parameter);
+
+ /* Process all the extensions (note: currently a no-op). */
+ rv = ssl3_HandleExtensions(ss, &extensionsData.data, &extensionsData.len,
+ certificate_request);
+ if (rv != SECSuccess) {
goto loser;
}
@@ -2758,7 +2759,7 @@ tls13_SetCipherSpec(sslSocket *ss, TrafficKeyType type,
if ((*specp)->epoch == PR_UINT16_MAX) {
return SECFailure;
}
- spec->epoch = (*specp)->epoch + 1;
+ spec->epoch = (PRUint16)type;
if (!IS_DTLS(ss)) {
spec->read_seq_num = spec->write_seq_num = 0;
@@ -2770,6 +2771,11 @@ tls13_SetCipherSpec(sslSocket *ss, TrafficKeyType type,
dtls_InitRecvdRecords(&spec->recvdRecords);
}
+ if (type == TrafficKeyEarlyApplicationData) {
+ spec->earlyDataRemaining =
+ ss->sec.ci.sid->u.ssl3.locked.sessionTicket.max_early_data_size;
+ }
+
/* Now that we've set almost everything up, finally cut over. */
ssl_GetSpecWriteLock(ss);
tls13_CipherSpecRelease(*specp); /* May delete old cipher. */
@@ -2781,6 +2787,10 @@ tls13_SetCipherSpec(sslSocket *ss, TrafficKeyType type,
spec->phase, spec->epoch,
direction == CipherSpecRead ? "read" : "write"));
+ if (ss->ssl3.changedCipherSpecFunc) {
+ ss->ssl3.changedCipherSpecFunc(ss->ssl3.changedCipherSpecArg,
+ direction == CipherSpecWrite, spec);
+ }
return SECSuccess;
}
@@ -2853,6 +2863,9 @@ tls13_DestroyKeyShares(PRCList *list)
{
PRCList *cur_p;
+ /* The list must be initialized. */
+ PORT_Assert(PR_LIST_HEAD(list));
+
while (!PR_CLIST_IS_EMPTY(list)) {
cur_p = PR_LIST_TAIL(list);
PR_REMOVE_LINK(cur_p);
@@ -2926,6 +2939,7 @@ tls13_WriteNonce(ssl3KeyMaterial *keys,
for (i = 0; i < 8; ++i) {
nonce[4 + i] ^= seqNumBuf[i];
}
+ PRINT_BUF(50, (NULL, "Nonce", nonce, nonceLen));
}
/* Implement the SSLAEADCipher interface defined in sslimpl.h.
@@ -3015,7 +3029,7 @@ static SECStatus
tls13_HandleEncryptedExtensions(sslSocket *ss, SSL3Opaque *b, PRUint32 length)
{
SECStatus rv;
- PRInt32 innerLength;
+ PRUint32 innerLength;
SECItem oldNpn = { siBuffer, NULL, 0 };
PORT_Assert(ss->opt.noLocks || ssl_HaveRecvBufLock(ss));
@@ -3030,8 +3044,8 @@ tls13_HandleEncryptedExtensions(sslSocket *ss, SSL3Opaque *b, PRUint32 length)
return SECFailure;
}
- innerLength = ssl3_ConsumeHandshakeNumber(ss, 2, &b, &length);
- if (innerLength < 0) {
+ rv = ssl3_ConsumeHandshakeNumber(ss, &innerLength, 2, &b, &length);
+ if (rv != SECSuccess) {
return SECFailure; /* Alert already sent. */
}
if (innerLength != length) {
@@ -3283,16 +3297,7 @@ tls13_HandleCertificateVerify(sslSocket *ss, SSL3Opaque *b, PRUint32 length,
/* Set the auth type. */
if (!ss->sec.isServer) {
- switch (ssl_SignatureSchemeToKeyType(sigScheme)) {
- case rsaKey:
- ss->sec.authType = ssl_auth_rsa_sign;
- break;
- case ecKey:
- ss->sec.authType = ssl_auth_ecdsa;
- break;
- default:
- PORT_Assert(PR_FALSE);
- }
+ ss->sec.authType = ssl_SignatureSchemeToAuthType(sigScheme);
}
/* Request a client certificate now if one was requested. */
@@ -3712,17 +3717,10 @@ tls13_SendClientSecondRound(sslSocket *ss)
return SECWouldBlock;
}
- if (ss->ssl3.hs.zeroRttState != ssl_0rtt_none) {
- if (ss->ssl3.hs.zeroRttState == ssl_0rtt_accepted) {
- rv = tls13_SendEndOfEarlyData(ss);
- if (rv != SECSuccess) {
- return SECFailure; /* Error code already set. */
- }
- }
- if (IS_DTLS(ss) && !ss->ssl3.hs.helloRetry) {
- /* Reset the counters so that the next epoch isn't set
- * incorrectly. */
- tls13_SetNullCipherSpec(ss, &ss->ssl3.cwSpec);
+ if (ss->ssl3.hs.zeroRttState == ssl_0rtt_accepted) {
+ rv = tls13_SendEndOfEarlyData(ss);
+ if (rv != SECSuccess) {
+ return SECFailure; /* Error code already set. */
}
}
@@ -3784,7 +3782,7 @@ tls13_SendClientSecondRound(sslSocket *ss)
* } NewSessionTicket;
*/
-#define MAX_EARLY_DATA_SIZE (2 << 16) /* Arbitrary limit. */
+PRUint32 ssl_max_early_data_size = (2 << 16); /* Arbitrary limit. */
SECStatus
tls13_SendNewSessionTicket(sslSocket *ss)
@@ -3799,7 +3797,7 @@ tls13_SendNewSessionTicket(sslSocket *ss)
ticket.flags |= ticket_allow_early_data;
max_early_data_size_len = 8; /* type + len + value. */
}
- ticket.ticket_lifetime_hint = TLS_EX_SESS_TICKET_LIFETIME_HINT;
+ ticket.ticket_lifetime_hint = ssl_ticket_lifetime;
rv = ssl3_EncodeSessionTicket(ss, &ticket, &ticket_data);
if (rv != SECSuccess)
@@ -3818,7 +3816,7 @@ tls13_SendNewSessionTicket(sslSocket *ss)
goto loser;
/* This is a fixed value. */
- rv = ssl3_AppendHandshakeNumber(ss, TLS_EX_SESS_TICKET_LIFETIME_HINT, 4);
+ rv = ssl3_AppendHandshakeNumber(ss, ssl_ticket_lifetime, 4);
if (rv != SECSuccess)
goto loser;
@@ -3854,7 +3852,7 @@ tls13_SendNewSessionTicket(sslSocket *ss)
if (rv != SECSuccess)
goto loser;
- rv = ssl3_AppendHandshakeNumber(ss, MAX_EARLY_DATA_SIZE, 4);
+ rv = ssl3_AppendHandshakeNumber(ss, ssl_max_early_data_size, 4);
if (rv != SECSuccess)
goto loser;
}
@@ -3873,7 +3871,6 @@ static SECStatus
tls13_HandleNewSessionTicket(sslSocket *ss, SSL3Opaque *b, PRUint32 length)
{
SECStatus rv;
- PRInt32 tmp;
PRUint32 utmp;
NewSessionTicket ticket = { 0 };
SECItem data;
@@ -3893,14 +3890,14 @@ tls13_HandleNewSessionTicket(sslSocket *ss, SSL3Opaque *b, PRUint32 length)
return SECFailure;
}
- ticket.received_timestamp = ssl_Time();
- tmp = ssl3_ConsumeHandshakeNumber(ss, 4, &b, &length);
- if (tmp < 0) {
+ ticket.received_timestamp = PR_Now();
+ rv = ssl3_ConsumeHandshakeNumber(ss, &ticket.ticket_lifetime_hint, 4, &b,
+ &length);
+ if (rv != SECSuccess) {
FATAL_ERROR(ss, SSL_ERROR_RX_MALFORMED_NEW_SESSION_TICKET,
decode_error);
return SECFailure;
}
- ticket.ticket_lifetime_hint = (PRUint32)tmp;
ticket.ticket.type = siBuffer;
rv = ssl3_ConsumeHandshake(ss, &utmp, sizeof(utmp),
@@ -4039,7 +4036,8 @@ tls13_ExtensionAllowed(PRUint16 extension, SSL3HandshakeType message)
(message == hello_retry_request) ||
(message == encrypted_extensions) ||
(message == new_session_ticket) ||
- (message == certificate));
+ (message == certificate) ||
+ (message == certificate_request));
for (i = 0; i < PR_ARRAY_SIZE(KnownExtensions); i++) {
if (KnownExtensions[i].ex_value == extension)
@@ -4099,6 +4097,28 @@ tls13_FormatAdditionalData(PRUint8 *aad, unsigned int length,
PORT_Assert((ptr - aad) == length);
}
+PRInt32
+tls13_LimitEarlyData(sslSocket *ss, SSL3ContentType type, PRInt32 toSend)
+{
+ PRInt32 reduced;
+
+ PORT_Assert(type == content_application_data);
+ PORT_Assert(ss->vrange.max >= SSL_LIBRARY_VERSION_TLS_1_3);
+ PORT_Assert(!ss->firstHsDone);
+ if (ss->ssl3.cwSpec->epoch != TrafficKeyEarlyApplicationData) {
+ return toSend;
+ }
+
+ if (IS_DTLS(ss) && toSend > ss->ssl3.cwSpec->earlyDataRemaining) {
+ /* Don't split application data records in DTLS. */
+ return 0;
+ }
+
+ reduced = PR_MIN(toSend, ss->ssl3.cwSpec->earlyDataRemaining);
+ ss->ssl3.cwSpec->earlyDataRemaining -= reduced;
+ return reduced;
+}
+
SECStatus
tls13_ProtectRecord(sslSocket *ss,
ssl3CipherSpec *cwSpec,
@@ -4250,6 +4270,17 @@ tls13_UnprotectRecord(sslSocket *ss, SSL3Ciphertext *cText, sslBuffer *plaintext
cText->type = plaintext->buf[plaintext->len - 1];
--plaintext->len;
+ /* Check that we haven't received too much 0-RTT data. */
+ if (crSpec->epoch == TrafficKeyEarlyApplicationData &&
+ cText->type == content_application_data) {
+ if (plaintext->len > crSpec->earlyDataRemaining) {
+ *alert = unexpected_message;
+ PORT_SetError(SSL_ERROR_TOO_MUCH_EARLY_DATA);
+ return SECFailure;
+ }
+ crSpec->earlyDataRemaining -= plaintext->len;
+ }
+
SSL_TRC(10,
("%d: TLS13[%d]: %s received record of length=%d type=%d",
SSL_GETPID(), ss->fd, SSL_ROLE(ss),
@@ -4285,7 +4316,7 @@ tls13_ClientAllow0Rtt(const sslSocket *ss, const sslSessionID *sid)
return PR_FALSE;
if ((sid->u.ssl3.locked.sessionTicket.flags & ticket_allow_early_data) == 0)
return PR_FALSE;
- return tls13_AlpnTagAllowed(ss, &sid->u.ssl3.alpnSelection);
+ return ssl_AlpnTagAllowed(ss, &sid->u.ssl3.alpnSelection);
}
SECStatus
@@ -4314,15 +4345,8 @@ tls13_MaybeDo0RTTHandshake(sslSocket *ss)
return rv;
}
- /* Null spec... */
- ssl_GetSpecReadLock(ss);
- ss->ssl3.hs.nullSpec = ss->ssl3.cwSpec;
- tls13_CipherSpecAddRef(ss->ssl3.hs.nullSpec);
- ssl_ReleaseSpecReadLock(ss);
-
/* Cipher suite already set in tls13_SetupClientHello. */
- ss->ssl3.hs.preliminaryInfo = 0; /* TODO(ekr@rtfm.com) Fill this in.
- * bug 1281255. */
+ ss->ssl3.hs.preliminaryInfo = 0;
rv = tls13_DeriveSecret(ss, ss->ssl3.hs.currentSecret,
kHkdfLabelClient,
@@ -4363,21 +4387,6 @@ tls13_Read0RttData(sslSocket *ss, void *buf, PRInt32 len)
return len;
}
-/* 0-RTT data will be followed by a different cipher spec; this resets the
- * current spec to the null spec so that the following state can be set as
- * though 0-RTT didn't happen. TODO: work out if this is the best plan. */
-static void
-tls13_SetNullCipherSpec(sslSocket *ss, ssl3CipherSpec **specp)
-{
- PORT_Assert(ss->ssl3.hs.nullSpec);
-
- ssl_GetSpecWriteLock(ss);
- tls13_CipherSpecRelease(*specp);
- *specp = ss->ssl3.hs.nullSpec;
- ssl_ReleaseSpecWriteLock(ss);
- ss->ssl3.hs.nullSpec = NULL;
-}
-
static SECStatus
tls13_SendEndOfEarlyData(sslSocket *ss)
{
@@ -4410,11 +4419,6 @@ tls13_HandleEndOfEarlyData(sslSocket *ss)
PORT_Assert(TLS13_IN_HS_STATE(ss, ss->opt.requestCertificate ? wait_client_cert : wait_finished));
- if (IS_DTLS(ss)) {
- /* Reset the cipher spec so that the epoch counter is properly reset. */
- tls13_SetNullCipherSpec(ss, &ss->ssl3.crSpec);
- }
-
rv = tls13_SetCipherSpec(ss, TrafficKeyHandshake,
CipherSpecRead, PR_FALSE);
if (rv != SECSuccess) {
diff --git a/nss/lib/ssl/tls13con.h b/nss/lib/ssl/tls13con.h
index c39c62a..189da0a 100644
--- a/nss/lib/ssl/tls13con.h
+++ b/nss/lib/ssl/tls13con.h
@@ -45,6 +45,7 @@ void tls13_FatalError(sslSocket *ss, PRErrorCode prError,
SSL3AlertDescription desc);
SECStatus tls13_SetupClientHello(sslSocket *ss);
SECStatus tls13_MaybeDo0RTTHandshake(sslSocket *ss);
+PRInt32 tls13_LimitEarlyData(sslSocket *ss, SSL3ContentType type, PRInt32 toSend);
PRBool tls13_AllowPskCipher(const sslSocket *ss,
const ssl3CipherSuiteDef *cipher_def);
PRBool tls13_PskSuiteEnabled(sslSocket *ss);
diff --git a/nss/lib/ssl/tls13exthandle.c b/nss/lib/ssl/tls13exthandle.c
index be93b97..c2ce390 100644
--- a/nss/lib/ssl/tls13exthandle.c
+++ b/nss/lib/ssl/tls13exthandle.c
@@ -208,13 +208,13 @@ static SECStatus
tls13_HandleKeyShareEntry(const sslSocket *ss, TLSExtensionData *xtnData, SECItem *data)
{
SECStatus rv;
- PRInt32 group;
+ PRUint32 group;
const sslNamedGroupDef *groupDef;
TLS13KeyShareEntry *ks = NULL;
SECItem share = { siBuffer, NULL, 0 };
- group = ssl3_ExtConsumeHandshakeNumber(ss, 2, &data->data, &data->len);
- if (group < 0) {
+ rv = ssl3_ExtConsumeHandshakeNumber(ss, &group, 2, &data->data, &data->len);
+ if (rv != SECSuccess) {
PORT_SetError(SSL_ERROR_RX_MALFORMED_KEY_SHARE);
goto loser;
}
@@ -256,11 +256,10 @@ tls13_ClientHandleKeyShareXtn(const sslSocket *ss, TLSExtensionData *xtnData, PR
PORT_Assert(PR_CLIST_IS_EMPTY(&xtnData->remoteKeyShares));
PORT_Assert(!ss->sec.isServer);
+
+ /* The server must not send this extension when negotiating < TLS 1.3. */
if (ss->version < SSL_LIBRARY_VERSION_TLS_1_3) {
- /* This can't happen because the extension processing
- * code filters out TLS 1.3 extensions when not in
- * TLS 1.3 mode. */
- PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
+ PORT_SetError(SSL_ERROR_EXTENSION_DISALLOWED_FOR_VERSION);
return SECFailure;
}
@@ -285,7 +284,7 @@ SECStatus
tls13_ClientHandleKeyShareXtnHrr(const sslSocket *ss, TLSExtensionData *xtnData, PRUint16 ex_type, SECItem *data)
{
SECStatus rv;
- PRInt32 tmp;
+ PRUint32 tmp;
const sslNamedGroupDef *group;
PORT_Assert(!ss->sec.isServer);
@@ -294,8 +293,8 @@ tls13_ClientHandleKeyShareXtnHrr(const sslSocket *ss, TLSExtensionData *xtnData,
SSL_TRC(3, ("%d: SSL3[%d]: handle key_share extension in HRR",
SSL_GETPID(), ss->fd));
- tmp = ssl3_ExtConsumeHandshakeNumber(ss, 2, &data->data, &data->len);
- if (tmp < 0) {
+ rv = ssl3_ExtConsumeHandshakeNumber(ss, &tmp, 2, &data->data, &data->len);
+ if (rv != SECSuccess) {
return SECFailure; /* error code already set */
}
if (data->len) {
@@ -335,7 +334,7 @@ SECStatus
tls13_ServerHandleKeyShareXtn(const sslSocket *ss, TLSExtensionData *xtnData, PRUint16 ex_type, SECItem *data)
{
SECStatus rv;
- PRInt32 length;
+ PRUint32 length;
PORT_Assert(ss->sec.isServer);
PORT_Assert(PR_CLIST_IS_EMPTY(&xtnData->remoteKeyShares));
@@ -349,9 +348,9 @@ tls13_ServerHandleKeyShareXtn(const sslSocket *ss, TLSExtensionData *xtnData, PR
/* Redundant length because of TLS encoding (this vector consumes
* the entire extension.) */
- length = ssl3_ExtConsumeHandshakeNumber(ss, 2, &data->data,
- &data->len);
- if (length < 0)
+ rv = ssl3_ExtConsumeHandshakeNumber(ss, &length, 2, &data->data,
+ &data->len);
+ if (rv != SECSuccess)
goto loser;
if (length != data->len) {
/* Check for consistency */
@@ -487,7 +486,7 @@ tls13_ClientSendPreSharedKeyXtn(const sslSocket *ss, TLSExtensionData *xtnData,
if (append) {
SECStatus rv;
- PRUint32 age;
+ PRTime age;
unsigned int prefixLength;
PRUint8 binder[TLS13_MAX_FINISHED_SIZE];
unsigned int binderLen;
@@ -508,7 +507,8 @@ tls13_ClientSendPreSharedKeyXtn(const sslSocket *ss, TLSExtensionData *xtnData,
goto loser;
/* Obfuscated age. */
- age = ssl_Time() - session_ticket->received_timestamp;
+ age = PR_Now() - session_ticket->received_timestamp;
+ age /= PR_USEC_PER_MSEC;
age += session_ticket->ticket_age_add;
rv = ssl3_ExtAppendHandshakeNumber(ss, age, 4);
if (rv != SECSuccess)
@@ -684,18 +684,20 @@ SECStatus
tls13_ClientHandlePreSharedKeyXtn(const sslSocket *ss, TLSExtensionData *xtnData, PRUint16 ex_type,
SECItem *data)
{
- PRInt32 index;
+ PRUint32 index;
+ SECStatus rv;
SSL_TRC(3, ("%d: SSL3[%d]: handle pre_shared_key extension",
SSL_GETPID(), ss->fd));
- /* If we are doing < TLS 1.3, then ignore this. */
+ /* The server must not send this extension when negotiating < TLS 1.3. */
if (ss->version < SSL_LIBRARY_VERSION_TLS_1_3) {
- return SECSuccess;
+ PORT_SetError(SSL_ERROR_EXTENSION_DISALLOWED_FOR_VERSION);
+ return SECFailure;
}
- index = ssl3_ExtConsumeHandshakeNumber(ss, 2, &data->data, &data->len);
- if (index < 0)
+ rv = ssl3_ExtConsumeHandshakeNumber(ss, &index, 2, &data->data, &data->len);
+ if (rv != SECSuccess)
return SECFailure;
/* This should be the end of the extension. */
@@ -746,10 +748,10 @@ tls13_ClientSendEarlyDataXtn(const sslSocket *ss, TLSExtensionData *xtnData,
rv = ssl3_ExtAppendHandshakeNumber(ss, 0, 2);
if (rv != SECSuccess)
return -1;
- }
- xtnData->advertised[xtnData->numAdvertised++] =
- ssl_tls13_early_data_xtn;
+ xtnData->advertised[xtnData->numAdvertised++] =
+ ssl_tls13_early_data_xtn;
+ }
return extension_length;
}
@@ -766,6 +768,12 @@ tls13_ServerHandleEarlyDataXtn(const sslSocket *ss, TLSExtensionData *xtnData, P
return SECSuccess;
}
+ if (ss->ssl3.hs.helloRetry) {
+ ssl3_ExtSendAlert(ss, alert_fatal, unsupported_extension);
+ PORT_SetError(SSL_ERROR_RX_UNEXPECTED_EXTENSION);
+ return SECFailure;
+ }
+
if (data->len) {
PORT_SetError(SSL_ERROR_MALFORMED_EARLY_DATA);
return SECFailure;
@@ -814,7 +822,7 @@ tls13_ClientHandleEarlyDataXtn(const sslSocket *ss, TLSExtensionData *xtnData, P
SSL_TRC(3, ("%d: TLS13[%d]: handle early_data extension",
SSL_GETPID(), ss->fd));
- /* If we are doing < TLS 1.3, then ignore this. */
+ /* The server must not send this extension when negotiating < TLS 1.3. */
if (ss->version < SSL_LIBRARY_VERSION_TLS_1_3) {
PORT_SetError(SSL_ERROR_EXTENSION_DISALLOWED_FOR_VERSION);
return SECFailure;
@@ -841,7 +849,7 @@ tls13_ClientHandleTicketEarlyDataInfoXtn(const sslSocket *ss, TLSExtensionData *
SSL_TRC(3, ("%d: TLS13[%d]: handle early_data_info extension",
SSL_GETPID(), ss->fd));
- /* If we are doing < TLS 1.3, then ignore this. */
+ /* The server must not send this extension when negotiating < TLS 1.3. */
if (ss->version < SSL_LIBRARY_VERSION_TLS_1_3) {
PORT_SetError(SSL_ERROR_EXTENSION_DISALLOWED_FOR_VERSION);
return SECFailure;
@@ -912,6 +920,9 @@ tls13_ClientSendSupportedVersionsXtn(const sslSocket *ss, TLSExtensionData *xtnD
if (rv != SECSuccess)
return -1;
}
+
+ xtnData->advertised[xtnData->numAdvertised++] =
+ ssl_tls13_supported_versions_xtn;
}
return extensions_len;
@@ -1091,6 +1102,13 @@ tls13_SendShortHeaderXtn(const sslSocket *ss,
return 0;
}
+ /* Don't send this if TLS 1.3 isn't at least possible. */
+ if (ss->vrange.max < SSL_LIBRARY_VERSION_TLS_1_3) {
+ /* This should only happen on the client. */
+ PORT_Assert(!ss->sec.isServer);
+ return 0;
+ }
+
SSL_TRC(3, ("%d: TLS13[%d]: send short_header extension",
SSL_GETPID(), ss->fd));
@@ -1122,10 +1140,10 @@ tls13_HandleShortHeaderXtn(
const sslSocket *ss, TLSExtensionData *xtnData, PRUint16 ex_type,
SECItem *data)
{
- SSL_TRC(3, ("%d: TLS13[%d]: handle early_data extension",
+ SSL_TRC(3, ("%d: TLS13[%d]: handle short_header extension",
SSL_GETPID(), ss->fd));
- /* If we are doing < TLS 1.3, then ignore this. */
+ /* The client might have asked for this, but we didn't negotiate TLS 1.3. */
if (ss->version < SSL_LIBRARY_VERSION_TLS_1_3) {
return SECSuccess;
}