summaryrefslogtreecommitdiff
path: root/lib/ssl
diff options
context:
space:
mode:
Diffstat (limited to 'lib/ssl')
-rw-r--r--lib/ssl/SSLerrs.h6
-rw-r--r--lib/ssl/derive.c2
-rw-r--r--lib/ssl/ssl.h8
-rw-r--r--lib/ssl/ssl3con.c535
-rw-r--r--lib/ssl/ssl3ecc.c16
-rw-r--r--lib/ssl/ssl3ext.c116
-rw-r--r--lib/ssl/sslerr.h3
-rw-r--r--lib/ssl/sslimpl.h7
-rw-r--r--lib/ssl/sslinfo.c2
-rw-r--r--lib/ssl/sslsnce.c7
-rw-r--r--lib/ssl/sslsock.c14
-rw-r--r--lib/ssl/sslt.h9
12 files changed, 550 insertions, 175 deletions
diff --git a/lib/ssl/SSLerrs.h b/lib/ssl/SSLerrs.h
index da5616441..602839680 100644
--- a/lib/ssl/SSLerrs.h
+++ b/lib/ssl/SSLerrs.h
@@ -434,3 +434,9 @@ ER3(SSL_ERROR_NO_SUPPORTED_SIGNATURE_ALGORITHM, (SSL_ERROR_BASE + 134),
ER3(SSL_ERROR_UNSUPPORTED_SIGNATURE_ALGORITHM, (SSL_ERROR_BASE + 135),
"The peer used an unsupported combination of signature and hash algorithm.")
+
+ER3(SSL_ERROR_MISSING_EXTENDED_MASTER_SECRET, (SSL_ERROR_BASE + 136),
+"The peer tried to resume without a correct extended_master_secret extension")
+
+ER3(SSL_ERROR_UNEXPECTED_EXTENDED_MASTER_SECRET, (SSL_ERROR_BASE + 137),
+"The peer tried to resume with an unexpected extended_master_secret extension")
diff --git a/lib/ssl/derive.c b/lib/ssl/derive.c
index b7c38c30b..8b58b800d 100644
--- a/lib/ssl/derive.c
+++ b/lib/ssl/derive.c
@@ -431,7 +431,7 @@ key_and_mac_derive_fail:
* so isRSA is always true.
*/
SECStatus
-ssl3_MasterKeyDeriveBypass(
+ssl3_MasterSecretDeriveBypass(
ssl3CipherSpec * pwSpec,
const unsigned char * cr,
const unsigned char * sr,
diff --git a/lib/ssl/ssl.h b/lib/ssl/ssl.h
index 40f8476d5..2a527693b 100644
--- a/lib/ssl/ssl.h
+++ b/lib/ssl/ssl.h
@@ -196,6 +196,14 @@ SSL_IMPORT PRFileDesc *DTLS_ImportFD(PRFileDesc *model, PRFileDesc *fd);
*/
#define SSL_ENABLE_SERVER_DHE 29
+/* Use draft-ietf-tls-session-hash. Controls whether we offer the
+ * extended_master_secret extension which, when accepted, hashes
+ * the handshake transcript into the master secret. This option is
+ * disabled by default.
+ */
+#define SSL_ENABLE_EXTENDED_MASTER_SECRET 30
+
+
#ifdef SSL_DEPRECATED_FUNCTION
/* Old deprecated function names */
SSL_IMPORT SECStatus SSL_Enable(PRFileDesc *fd, int option, PRBool on);
diff --git a/lib/ssl/ssl3con.c b/lib/ssl/ssl3con.c
index 717ece17a..877f1fcb0 100644
--- a/lib/ssl/ssl3con.c
+++ b/lib/ssl/ssl3con.c
@@ -62,6 +62,10 @@ static SECStatus ssl3_UpdateHandshakeHashes( sslSocket *ss,
const unsigned char *b,
unsigned int l);
static SECOidTag ssl3_TLSHashAlgorithmToOID(SSLHashType hashFunc);
+static SECStatus ssl3_ComputeHandshakeHashes(sslSocket *ss,
+ ssl3CipherSpec *spec,
+ SSL3Hashes *hashes,
+ PRUint32 sender);
static SECStatus ssl3_FlushHandshakeMessages(sslSocket *ss, PRInt32 flags);
static SECStatus Null_Cipher(void *ctx, unsigned char *output, int *outputLen,
@@ -2177,7 +2181,11 @@ fail:
* Sets error code, but caller probably should override to disambiguate.
* NULL pms means re-use old master_secret.
*
- * This code is common to the bypass and PKCS11 execution paths.
+ * This code is common to the bypass and PKCS11 execution paths. For
+ * the bypass case, pms is NULL. If the old master secret is reused,
+ * pms is NULL and the master secret is already in either
+ * pwSpec->msItem.len (the bypass case) or pwSpec->master_secret.
+ *
* For the bypass case, pms is NULL.
*/
SECStatus
@@ -3583,13 +3591,70 @@ ssl3_HandleChangeCipherSpecs(sslSocket *ss, sslBuffer *buf)
return SECSuccess;
}
-/* This method uses PKCS11 to derive the MS from the PMS, where PMS
-** is a PKCS11 symkey. This is used in all cases except the
-** "triple bypass" with RSA key exchange.
-** Called from ssl3_InitPendingCipherSpec. prSpec is pwSpec.
+/* This method completes the derivation of the MS from the PMS.
+**
+** 1. Derive the MS, if possible, else return an error.
+**
+** 2. Check the version if |pms_version| is non-zero and if wrong,
+** return an error.
+**
+** 3. If |msp| is nonzero, return MS in |*msp|.
+
+** Called from:
+** ssl3_ComputeMasterSecretInt
+** tls_ComputeExtendedMasterSecretInt
*/
static SECStatus
-ssl3_DeriveMasterSecret(sslSocket *ss, PK11SymKey *pms)
+ssl3_ComputeMasterSecretFinish(sslSocket *ss,
+ CK_MECHANISM_TYPE master_derive,
+ CK_MECHANISM_TYPE key_derive,
+ CK_VERSION *pms_version,
+ SECItem *params, CK_FLAGS keyFlags,
+ PK11SymKey *pms, PK11SymKey **msp)
+{
+ PK11SymKey *ms = NULL;
+
+ ms = PK11_DeriveWithFlags(pms, master_derive,
+ params, key_derive,
+ CKA_DERIVE, 0, keyFlags);
+ if (!ms) {
+ ssl_MapLowLevelError(SSL_ERROR_SESSION_KEY_GEN_FAILURE);
+ return SECFailure;
+ }
+
+ if (pms_version && ss->opt.detectRollBack) {
+ SSL3ProtocolVersion client_version;
+ client_version = pms_version->major << 8 | pms_version->minor;
+
+ if (IS_DTLS(ss)) {
+ client_version = dtls_DTLSVersionToTLSVersion(client_version);
+ }
+
+ if (client_version != ss->clientHelloVersion) {
+ /* Destroy MS. Version roll-back detected. */
+ PK11_FreeSymKey(ms);
+ ssl_MapLowLevelError(SSL_ERROR_SESSION_KEY_GEN_FAILURE);
+ return SECFailure;
+ }
+ }
+
+ if (msp) {
+ *msp = ms;
+ } else {
+ PK11_FreeSymKey(ms);
+ }
+
+ return SECSuccess;
+}
+
+/* Compute the ordinary (pre draft-ietf-tls-session-hash) master
+ ** secret and return it in |*msp|.
+ **
+ ** Called from: ssl3_ComputeMasterSecret
+ */
+static SECStatus
+ssl3_ComputeMasterSecretInt(sslSocket *ss, PK11SymKey *pms,
+ PK11SymKey **msp)
{
ssl3CipherSpec * pwSpec = ss->ssl3.pwSpec;
const ssl3KEADef *kea_def= ss->ssl3.hs.kea_def;
@@ -3599,26 +3664,23 @@ ssl3_DeriveMasterSecret(sslSocket *ss, PK11SymKey *pms)
(pwSpec->version > SSL_LIBRARY_VERSION_3_0));
PRBool isTLS12=
(PRBool)(isTLS && pwSpec->version >= SSL_LIBRARY_VERSION_TLS_1_2);
- /*
+ /*
* Whenever isDH is true, we need to use CKM_TLS_MASTER_KEY_DERIVE_DH
* which, unlike CKM_TLS_MASTER_KEY_DERIVE, converts arbitrary size
- * data into a 48-byte value.
+ * data into a 48-byte value, and does not expect to return the version.
*/
PRBool isDH = (PRBool) ((ss->ssl3.hs.kea_def->exchKeyType == kt_dh) ||
(ss->ssl3.hs.kea_def->exchKeyType == kt_ecdh));
- SECStatus rv = SECFailure;
CK_MECHANISM_TYPE master_derive;
CK_MECHANISM_TYPE key_derive;
SECItem params;
CK_FLAGS keyFlags;
CK_VERSION pms_version;
+ CK_VERSION *pms_version_ptr = NULL;
/* master_params may be used as a CK_SSL3_MASTER_KEY_DERIVE_PARAMS */
CK_TLS12_MASTER_KEY_DERIVE_PARAMS master_params;
unsigned int master_params_len;
- PORT_Assert( ss->opt.noLocks || ssl_HaveSSL3HandshakeLock(ss));
- PORT_Assert( ss->opt.noLocks || ssl_HaveSpecWriteLock(ss));
- PORT_Assert(ss->ssl3.prSpec == ss->ssl3.pwSpec);
if (isTLS12) {
if(isDH) master_derive = CKM_TLS12_MASTER_KEY_DERIVE_DH;
else master_derive = CKM_TLS12_MASTER_KEY_DERIVE;
@@ -3636,93 +3698,142 @@ ssl3_DeriveMasterSecret(sslSocket *ss, PK11SymKey *pms)
keyFlags = 0;
}
- if (pms || !pwSpec->master_secret) {
- if (isDH) {
- master_params.pVersion = NULL;
- } else {
- master_params.pVersion = &pms_version;
- }
- master_params.RandomInfo.pClientRandom = cr;
- master_params.RandomInfo.ulClientRandomLen = SSL3_RANDOM_LENGTH;
- master_params.RandomInfo.pServerRandom = sr;
- master_params.RandomInfo.ulServerRandomLen = SSL3_RANDOM_LENGTH;
- if (isTLS12) {
- master_params.prfHashMechanism = CKM_SHA256;
- master_params_len = sizeof(CK_TLS12_MASTER_KEY_DERIVE_PARAMS);
- } else {
- master_params_len = sizeof(CK_SSL3_MASTER_KEY_DERIVE_PARAMS);
- }
+ if (!isDH) {
+ pms_version_ptr = &pms_version;
+ }
- params.data = (unsigned char *) &master_params;
- params.len = master_params_len;
+ master_params.pVersion = pms_version_ptr;
+ master_params.RandomInfo.pClientRandom = cr;
+ master_params.RandomInfo.ulClientRandomLen = SSL3_RANDOM_LENGTH;
+ master_params.RandomInfo.pServerRandom = sr;
+ master_params.RandomInfo.ulServerRandomLen = SSL3_RANDOM_LENGTH;
+ if (isTLS12) {
+ master_params.prfHashMechanism = CKM_SHA256;
+ master_params_len = sizeof(CK_TLS12_MASTER_KEY_DERIVE_PARAMS);
+ } else {
+ /* prfHashMechanism is not relevant with this PRF */
+ master_params_len = sizeof(CK_SSL3_MASTER_KEY_DERIVE_PARAMS);
}
- if (pms != NULL) {
-#if defined(TRACE)
- if (ssl_trace >= 100) {
- SECStatus extractRV = PK11_ExtractKeyValue(pms);
- if (extractRV == SECSuccess) {
- SECItem * keyData = PK11_GetKeyData(pms);
- if (keyData && keyData->data && keyData->len) {
- ssl_PrintBuf(ss, "Pre-Master Secret",
- keyData->data, keyData->len);
- }
- }
- }
-#endif
- pwSpec->master_secret = PK11_DeriveWithFlags(pms, master_derive,
- &params, key_derive, CKA_DERIVE, 0, keyFlags);
- if (!isDH && pwSpec->master_secret && ss->opt.detectRollBack) {
- SSL3ProtocolVersion client_version;
- client_version = pms_version.major << 8 | pms_version.minor;
+ params.data = (unsigned char *) &master_params;
+ params.len = master_params_len;
- if (IS_DTLS(ss)) {
- client_version = dtls_DTLSVersionToTLSVersion(client_version);
- }
+ return ssl3_ComputeMasterSecretFinish(ss, master_derive, key_derive,
+ pms_version_ptr, &params,
+ keyFlags, pms, msp);
+}
- if (client_version != ss->clientHelloVersion) {
- /* Destroy it. Version roll-back detected. */
- PK11_FreeSymKey(pwSpec->master_secret);
- pwSpec->master_secret = NULL;
- }
- }
- if (pwSpec->master_secret == NULL) {
- /* Generate a faux master secret in the same slot as the old one. */
- PK11SlotInfo * slot = PK11_GetSlotFromKey((PK11SymKey *)pms);
- PK11SymKey * fpms = ssl3_GenerateRSAPMS(ss, pwSpec, slot);
+/* Compute the draft-ietf-tls-session-hash master
+** secret and return it in |*msp|.
+**
+** Called from: ssl3_ComputeMasterSecret
+*/
+static SECStatus
+tls_ComputeExtendedMasterSecretInt(sslSocket *ss, PK11SymKey *pms,
+ PK11SymKey **msp)
+{
+ ssl3CipherSpec *pwSpec = ss->ssl3.pwSpec;
+ CK_NSS_TLS_EXTENDED_MASTER_KEY_DERIVE_PARAMS extended_master_params;
+ SSL3Hashes hashes;
+ /*
+ * Determine whether to use the DH/ECDH or RSA derivation modes.
+ */
+ /*
+ * TODO(ekr@rtfm.com): Verify that the slot can handle this key expansion
+ * mode. Bug 1198298 */
+ PRBool isDH = (PRBool) ((ss->ssl3.hs.kea_def->exchKeyType == kt_dh) ||
+ (ss->ssl3.hs.kea_def->exchKeyType == kt_ecdh));
+ CK_MECHANISM_TYPE master_derive;
+ CK_MECHANISM_TYPE key_derive;
+ SECItem params;
+ const CK_FLAGS keyFlags = CKF_SIGN | CKF_VERIFY;
+ CK_VERSION pms_version;
+ CK_VERSION *pms_version_ptr = NULL;
+ SECStatus rv;
- PK11_FreeSlot(slot);
- if (fpms != NULL) {
- pwSpec->master_secret = PK11_DeriveWithFlags(fpms,
- master_derive, &params, key_derive,
- CKA_DERIVE, 0, keyFlags);
- PK11_FreeSymKey(fpms);
- }
- }
+ rv = ssl3_ComputeHandshakeHashes(ss, pwSpec, &hashes, 0);
+ if (rv != SECSuccess) {
+ PORT_Assert(0); /* Should never fail */
+ ssl_MapLowLevelError(SSL_ERROR_SESSION_KEY_GEN_FAILURE);
+ return SECFailure;
}
- if (pwSpec->master_secret == NULL) {
- /* Generate a faux master secret from the internal slot. */
- PK11SlotInfo * slot = PK11_GetInternalSlot();
- PK11SymKey * fpms = ssl3_GenerateRSAPMS(ss, pwSpec, slot);
- PK11_FreeSlot(slot);
- if (fpms != NULL) {
- pwSpec->master_secret = PK11_DeriveWithFlags(fpms,
- master_derive, &params, key_derive,
- CKA_DERIVE, 0, keyFlags);
- if (pwSpec->master_secret == NULL) {
- pwSpec->master_secret = fpms; /* use the fpms as the master. */
- fpms = NULL;
- }
- }
- if (fpms) {
- PK11_FreeSymKey(fpms);
- }
+ if (isDH) {
+ master_derive = CKM_NSS_TLS_EXTENDED_MASTER_KEY_DERIVE_DH;
+ } else {
+ master_derive = CKM_NSS_TLS_EXTENDED_MASTER_KEY_DERIVE;
+ pms_version_ptr = &pms_version;
}
- if (pwSpec->master_secret == NULL) {
- ssl_MapLowLevelError(SSL_ERROR_SESSION_KEY_GEN_FAILURE);
- return rv;
+
+ if (pwSpec->version >= SSL_LIBRARY_VERSION_TLS_1_2) {
+ /* TLS 1.2 */
+ extended_master_params.prfHashMechanism = CKM_SHA256;
+ key_derive = CKM_TLS12_KEY_AND_MAC_DERIVE;
+ } else {
+ /* TLS < 1.2 */
+ extended_master_params.prfHashMechanism = CKM_TLS_PRF;
+ key_derive = CKM_TLS_KEY_AND_MAC_DERIVE;
+ }
+
+ extended_master_params.pVersion = pms_version_ptr;
+ extended_master_params.pSessionHash = hashes.u.raw;
+ extended_master_params.ulSessionHashLen = hashes.len;
+
+ params.data = (unsigned char *) &extended_master_params;
+ params.len = sizeof extended_master_params;
+
+ return ssl3_ComputeMasterSecretFinish(ss, master_derive, key_derive,
+ pms_version_ptr, &params,
+ keyFlags, pms, msp);
+}
+
+
+/* Wrapper method to compute the master secret and return it in |*msp|.
+**
+** Called from ssl3_ComputeMasterSecret
+*/
+static SECStatus
+ssl3_ComputeMasterSecret(sslSocket *ss, PK11SymKey *pms,
+ PK11SymKey **msp)
+{
+ PORT_Assert(pms != NULL);
+ PORT_Assert(ss->opt.noLocks || ssl_HaveSSL3HandshakeLock(ss));
+ PORT_Assert(ss->ssl3.prSpec == ss->ssl3.pwSpec);
+
+ if (ssl3_ExtensionNegotiated(ss, ssl_extended_master_secret_xtn)) {
+ return tls_ComputeExtendedMasterSecretInt(ss, pms, msp);
+ } else {
+ return ssl3_ComputeMasterSecretInt(ss, pms, msp);
+ }
+}
+
+/* This method uses PKCS11 to derive the MS from the PMS, where PMS
+** is a PKCS11 symkey. We call ssl3_ComputeMasterSecret to do the
+** computations and then modify the pwSpec->state as a side effect.
+**
+** This is used in all cases except the "triple bypass" with RSA key
+** exchange.
+**
+** Called from ssl3_InitPendingCipherSpec. prSpec is pwSpec.
+*/
+static SECStatus
+ssl3_DeriveMasterSecret(sslSocket *ss, PK11SymKey *pms)
+{
+ SECStatus rv;
+ PK11SymKey* ms = NULL;
+ ssl3CipherSpec *pwSpec = ss->ssl3.pwSpec;
+
+ PORT_Assert( ss->opt.noLocks || ssl_HaveSSL3HandshakeLock(ss));
+ PORT_Assert( ss->opt.noLocks || ssl_HaveSpecWriteLock(ss));
+ PORT_Assert(ss->ssl3.prSpec == ss->ssl3.pwSpec);
+
+ if (pms) {
+ rv = ssl3_ComputeMasterSecret(ss, pms, &ms);
+ pwSpec->master_secret = ms;
+ if (rv != SECSuccess)
+ return rv;
}
+
#ifndef NO_PKCS11_BYPASS
if (ss->opt.bypassPKCS11) {
SECItem * keydata;
@@ -3733,7 +3844,7 @@ ssl3_DeriveMasterSecret(sslSocket *ss, PK11SymKey *pms)
rv = PK11_ExtractKeyValue(pwSpec->master_secret);
if (rv != SECSuccess) {
return rv;
- }
+ }
/* This returns the address of the secItem inside the key struct,
* not a copy or a reference. So, there's no need to free it.
*/
@@ -3748,10 +3859,10 @@ ssl3_DeriveMasterSecret(sslSocket *ss, PK11SymKey *pms)
}
}
#endif
+
return SECSuccess;
}
-
/*
* Derive encryption and MAC Keys (and IVs) from master secret
* Sets a useful error code when returning SECFailure.
@@ -4584,11 +4695,6 @@ ssl3_ComputeHandshakeHashes(sslSocket * ss,
/* compute them without PKCS11 */
PRUint64 sha_cx[MAX_MAC_CONTEXT_LLONGS];
- if (!spec->msItem.data) {
- PORT_SetError(SSL_ERROR_RX_UNEXPECTED_HANDSHAKE);
- return SECFailure;
- }
-
ss->ssl3.hs.sha_clone(sha_cx, ss->ssl3.hs.sha_cx);
ss->ssl3.hs.sha_obj->end(sha_cx, hashes->u.raw, &hashes->len,
sizeof(hashes->u.raw));
@@ -4607,15 +4713,15 @@ ssl3_ComputeHandshakeHashes(sslSocket * ss,
#define md5cx ((MD5Context *)md5_cx)
#define shacx ((SHA1Context *)sha_cx)
- if (!spec->msItem.data) {
- PORT_SetError(SSL_ERROR_RX_UNEXPECTED_HANDSHAKE);
- return SECFailure;
- }
-
MD5_Clone (md5cx, (MD5Context *)ss->ssl3.hs.md5_cx);
SHA1_Clone(shacx, (SHA1Context *)ss->ssl3.hs.sha_cx);
if (!isTLS) {
+ if (!spec->msItem.data) {
+ PORT_SetError(SSL_ERROR_RX_UNEXPECTED_HANDSHAKE);
+ return SECFailure;
+ }
+
/* compute hashes for SSL3. */
unsigned char s[4];
@@ -4691,11 +4797,6 @@ ssl3_ComputeHandshakeHashes(sslSocket * ss,
unsigned char stackBuf[1024];
unsigned char *stateBuf = NULL;
- if (!spec->master_secret) {
- PORT_SetError(SSL_ERROR_RX_UNEXPECTED_HANDSHAKE);
- return SECFailure;
- }
-
h = ss->ssl3.hs.sha;
stateBuf = PK11_SaveContextAlloc(h, stackBuf,
sizeof(stackBuf), &stateLen);
@@ -4735,11 +4836,6 @@ tls12_loser:
unsigned char md5StackBuf[256];
unsigned char shaStackBuf[512];
- if (!spec->master_secret) {
- PORT_SetError(SSL_ERROR_RX_UNEXPECTED_HANDSHAKE);
- return SECFailure;
- }
-
md5StateBuf = PK11_SaveContextAlloc(ss->ssl3.hs.md5, md5StackBuf,
sizeof md5StackBuf, &md5StateLen);
if (md5StateBuf == NULL) {
@@ -4757,6 +4853,11 @@ tls12_loser:
sha = ss->ssl3.hs.sha;
if (!isTLS) {
+ if (!spec->master_secret) {
+ PORT_SetError(SSL_ERROR_RX_UNEXPECTED_HANDSHAKE);
+ return SECFailure;
+ }
+
/* compute hashes for SSL3. */
unsigned char s[4];
@@ -6005,14 +6106,6 @@ sendRSAClientKeyExchange(sslSocket * ss, SECKEYPublicKey * svrPubKey)
}
}
- rv = ssl3_InitPendingCipherSpec(ss, pms);
- PK11_FreeSymKey(pms); pms = NULL;
-
- if (rv != SECSuccess) {
- ssl_MapLowLevelError(SSL_ERROR_CLIENT_KEY_EXCHANGE_FAILURE);
- goto loser;
- }
-
rv = ssl3_AppendHandshakeHeader(ss, client_key_exchange,
isTLS ? enc_pms.len + 2 : enc_pms.len);
if (rv != SECSuccess) {
@@ -6027,6 +6120,15 @@ sendRSAClientKeyExchange(sslSocket * ss, SECKEYPublicKey * svrPubKey)
goto loser; /* err set by ssl3_AppendHandshake* */
}
+ rv = ssl3_InitPendingCipherSpec(ss, pms);
+ PK11_FreeSymKey(pms);
+ pms = NULL;
+
+ if (rv != SECSuccess) {
+ ssl_MapLowLevelError(SSL_ERROR_CLIENT_KEY_EXCHANGE_FAILURE);
+ goto loser;
+ }
+
rv = SECSuccess;
loser:
@@ -6096,14 +6198,6 @@ sendDHClientKeyExchange(sslSocket * ss, SECKEYPublicKey * svrPubKey)
SECKEY_DestroyPrivateKey(privKey);
privKey = NULL;
- rv = ssl3_InitPendingCipherSpec(ss, pms);
- PK11_FreeSymKey(pms); pms = NULL;
-
- if (rv != SECSuccess) {
- ssl_MapLowLevelError(SSL_ERROR_CLIENT_KEY_EXCHANGE_FAILURE);
- goto loser;
- }
-
rv = ssl3_AppendHandshakeHeader(ss, client_key_exchange,
pubKey->u.dh.publicValue.len + 2);
if (rv != SECSuccess) {
@@ -6119,8 +6213,16 @@ sendDHClientKeyExchange(sslSocket * ss, SECKEYPublicKey * svrPubKey)
goto loser; /* err set by ssl3_AppendHandshake* */
}
- rv = SECSuccess;
+ rv = ssl3_InitPendingCipherSpec(ss, pms);
+ PK11_FreeSymKey(pms);
+ pms = NULL;
+ if (rv != SECSuccess) {
+ ssl_MapLowLevelError(SSL_ERROR_CLIENT_KEY_EXCHANGE_FAILURE);
+ goto loser;
+ }
+
+ rv = SECSuccess;
loser:
@@ -6517,6 +6619,32 @@ ssl3_HandleServerHello(sslSocket *ss, SSL3Opaque *b, PRUint32 length)
SECItem wrappedMS; /* wrapped master secret. */
+ /* [draft-ietf-tls-session-hash-06; Section 5.3]
+ *
+ * o If the original session did not use the "extended_master_secret"
+ * extension but the new ServerHello contains the extension, the
+ * client MUST abort the handshake.
+ */
+ if (!sid->u.ssl3.keys.extendedMasterSecretUsed &&
+ ssl3_ExtensionNegotiated(ss, ssl_extended_master_secret_xtn)) {
+ errCode = SSL_ERROR_UNEXPECTED_EXTENDED_MASTER_SECRET;
+ goto alert_loser;
+ }
+
+ /*
+ * o If the original session used an extended master secret but the new
+ * ServerHello does not contain the "extended_master_secret"
+ * extension, the client SHOULD abort the handshake.
+ *
+ * TODO(ekr@rtfm.com): Add option to refuse to resume when EMS is not
+ * used at all (bug 1176526).
+ */
+ if (sid->u.ssl3.keys.extendedMasterSecretUsed &&
+ !ssl3_ExtensionNegotiated(ss, ssl_extended_master_secret_xtn)) {
+ errCode = SSL_ERROR_MISSING_EXTENDED_MASTER_SECRET;
+ goto alert_loser;
+ }
+
ss->sec.authAlgorithm = sid->authAlgorithm;
ss->sec.authKeyBits = sid->authKeyBits;
ss->sec.keaType = sid->keaType;
@@ -6618,7 +6746,7 @@ ssl3_HandleServerHello(sslSocket *ss, SSL3Opaque *b, PRUint32 length)
ss->sec.peerCert = CERT_DupCertificate(sid->peerCert);
}
- /* NULL value for PMS signifies re-use of the old MS */
+ /* NULL value for PMS because we are reusing the old MS */
rv = ssl3_InitPendingCipherSpec(ss, NULL);
if (rv != SECSuccess) {
goto alert_loser; /* err code was set */
@@ -6647,6 +6775,9 @@ ssl3_HandleServerHello(sslSocket *ss, SSL3Opaque *b, PRUint32 length)
sid->u.ssl3.sessionIDLength = sidBytes.len;
PORT_Memcpy(sid->u.ssl3.sessionID, sidBytes.data, sidBytes.len);
+ sid->u.ssl3.keys.extendedMasterSecretUsed =
+ ssl3_ExtensionNegotiated(ss, ssl_extended_master_secret_xtn);
+
ss->ssl3.hs.isResuming = PR_FALSE;
if (ss->ssl3.hs.kea_def->signKeyType != sign_null) {
/* All current cipher suites other than those with sign_null (i.e.,
@@ -7584,6 +7715,7 @@ ssl3_NewSessionID(sslSocket *ss, PRBool is_server)
sid->u.ssl3.policy = SSL_ALLOWED;
sid->u.ssl3.clientWriteKey = NULL;
sid->u.ssl3.serverWriteKey = NULL;
+ sid->u.ssl3.keys.extendedMasterSecretUsed = PR_FALSE;
if (is_server) {
SECStatus rv;
@@ -8144,6 +8276,8 @@ compression_found:
/* If there are any failures while processing the old sid,
* we don't consider them to be errors. Instead, We just behave
* as if the client had sent us no sid to begin with, and make a new one.
+ * The exception here is attempts to resume extended_master_secret
+ * sessions without the extension, which causes an alert.
*/
if (sid != NULL) do {
ssl3CipherSpec *pwSpec;
@@ -8155,6 +8289,30 @@ compression_found:
break; /* not an error */
}
+ /* [draft-ietf-tls-session-hash-06; Section 5.3]
+ * o If the original session did not use the "extended_master_secret"
+ * extension but the new ClientHello contains the extension, then the
+ * server MUST NOT perform the abbreviated handshake. Instead, it
+ * SHOULD continue with a full handshake (as described in
+ * Section 5.2) to negotiate a new session.
+ *
+ * o If the original session used the "extended_master_secret"
+ * extension but the new ClientHello does not contain the extension,
+ * the server MUST abort the abbreviated handshake.
+ */
+ if (ssl3_ExtensionNegotiated(ss, ssl_extended_master_secret_xtn)) {
+ if (!sid->u.ssl3.keys.extendedMasterSecretUsed) {
+ break; /* not an error */
+ }
+ } else {
+ if (sid->u.ssl3.keys.extendedMasterSecretUsed) {
+ /* Note: we do not destroy the session */
+ desc = handshake_failure;
+ errCode = SSL_ERROR_MISSING_EXTENDED_MASTER_SECRET;
+ goto alert_loser;
+ }
+ }
+
if (ss->sec.ci.sid) {
if (ss->sec.uncache)
ss->sec.uncache(ss->sec.ci.sid);
@@ -8295,7 +8453,7 @@ compression_found:
haveSpecWriteLock = PR_FALSE;
}
- /* NULL value for PMS signifies re-use of the old MS */
+ /* NULL value for PMS because we are re-using the old MS */
rv = ssl3_InitPendingCipherSpec(ss, NULL);
if (rv != SECSuccess) {
errCode = PORT_GetError();
@@ -8486,6 +8644,8 @@ compression_found:
}
ss->sec.ci.sid = sid;
+ sid->u.ssl3.keys.extendedMasterSecretUsed =
+ ssl3_ExtensionNegotiated(ss, ssl_extended_master_secret_xtn);
ss->ssl3.hs.isResuming = PR_FALSE;
ssl_GetXmitBufLock(ss);
rv = ssl3_SendServerHelloSequence(ss);
@@ -9496,7 +9656,6 @@ ssl3_HandleRSAClientKeyExchange(sslSocket *ss,
PRUint32 length,
SECKEYPrivateKey *serverKey)
{
- PK11SymKey * pms;
#ifndef NO_PKCS11_BYPASS
unsigned char * cr = (unsigned char *)&ss->ssl3.hs.client_random;
unsigned char * sr = (unsigned char *)&ss->ssl3.hs.server_random;
@@ -9541,6 +9700,13 @@ ssl3_HandleRSAClientKeyExchange(sslSocket *ss,
#ifndef NO_PKCS11_BYPASS
if (ss->opt.bypassPKCS11) {
+ /* We have not implemented a tls_ExtendedMasterKeyDeriveBypass
+ * and will not negotiate this extension in bypass mode. This
+ * assert just double-checks that.
+ */
+ PORT_Assert(
+ !ssl3_ExtensionNegotiated(ss, ssl_extended_master_secret_xtn));
+
/* TRIPLE BYPASS, get PMS directly from RSA decryption.
* Use PK11_PrivDecryptPKCS1 to decrypt the PMS to a buffer,
* then, check for version rollback attack, then
@@ -9568,8 +9734,8 @@ ssl3_HandleRSAClientKeyExchange(sslSocket *ss,
}
}
/* have PMS, build MS without PKCS11 */
- rv = ssl3_MasterKeyDeriveBypass(pwSpec, cr, sr, &pmsItem, isTLS,
- PR_TRUE);
+ rv = ssl3_MasterSecretDeriveBypass(pwSpec, cr, sr, &pmsItem, isTLS,
+ PR_TRUE);
if (rv != SECSuccess) {
pwSpec->msItem.data = pwSpec->raw_master_secret;
pwSpec->msItem.len = SSL3_MASTER_SECRET_LENGTH;
@@ -9579,46 +9745,101 @@ ssl3_HandleRSAClientKeyExchange(sslSocket *ss,
} else
#endif
{
+ PK11SymKey *tmpPms[2] = {NULL, NULL};
+ PK11SlotInfo *slot;
+ int useFauxPms = 0;
+#define currentPms tmpPms[!useFauxPms]
+#define unusedPms tmpPms[useFauxPms]
+#define realPms tmpPms[1]
+#define fauxPms tmpPms[0]
+
#ifndef NO_PKCS11_BYPASS
double_bypass:
#endif
- /*
- * unwrap pms out of the incoming buffer
- * Note: CKM_SSL3_MASTER_KEY_DERIVE is NOT the mechanism used to do
- * the unwrap. Rather, it is the mechanism with which the
- * unwrapped pms will be used.
- */
- pms = PK11_PubUnwrapSymKey(serverKey, &enc_pms,
- CKM_SSL3_MASTER_KEY_DERIVE, CKA_DERIVE, 0);
- if (pms != NULL) {
- PRINT_BUF(60, (ss, "decrypted premaster secret:",
- PK11_GetKeyData(pms)->data,
- PK11_GetKeyData(pms)->len));
- } else {
- /* unwrap failed. Generate a bogus PMS and carry on. */
- PK11SlotInfo * slot = PK11_GetSlotFromPrivateKey(serverKey);
- ssl_GetSpecWriteLock(ss);
- pms = ssl3_GenerateRSAPMS(ss, ss->ssl3.prSpec, slot);
- ssl_ReleaseSpecWriteLock(ss);
- PK11_FreeSlot(slot);
- }
+ /*
+ * Get as close to algorithm 2 from RFC 5246; Section 7.4.7.1
+ * as we can within the constraints of the PKCS#11 interface.
+ *
+ * 1. Unconditionally generate a bogus PMS (what RFC 5246
+ * calls R).
+ * 2. Attempt the RSA decryption to recover the PMS (what
+ * RFC 5246 calls M).
+ * 3. Set PMS = (M == NULL) ? R : M
+ * 4. Use ssl3_ComputeMasterSecret(PMS) to attempt to derive
+ * the MS from PMS. This includes performing the version
+ * check and length check.
+ * 5. If either the initial RSA decryption failed or
+ * ssl3_ComputeMasterSecret(PMS) failed, then discard
+ * M and set PMS = R. Else, discard R and set PMS = M.
+ *
+ * We do two derivations here because we can't rely on having
+ * a function that only performs the PMS version and length
+ * check. The only redundant cost is that this runs the PRF,
+ * which isn't necessary here.
+ */
- if (pms == NULL) {
- /* last gasp. */
+ /* Generate the bogus PMS (R) */
+ slot = PK11_GetSlotFromPrivateKey(serverKey);
+ if (!PK11_DoesMechanism(slot, CKM_SSL3_MASTER_KEY_DERIVE)) {
+ slot = PK11_GetBestSlot(CKM_SSL3_MASTER_KEY_DERIVE, NULL);
+ if (!slot) {
+ PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
+ return SECFailure;
+ }
+ }
+
+ ssl_GetSpecWriteLock(ss);
+ fauxPms = ssl3_GenerateRSAPMS(ss, ss->ssl3.prSpec, slot);
+ ssl_ReleaseSpecWriteLock(ss);
+ PK11_FreeSlot(slot);
+
+ if (fauxPms == NULL) {
ssl_MapLowLevelError(SSL_ERROR_CLIENT_KEY_EXCHANGE_FAILURE);
return SECFailure;
}
+ /*
+ * unwrap pms out of the incoming buffer
+ * Note: CKM_SSL3_MASTER_KEY_DERIVE is NOT the mechanism used to do
+ * the unwrap. Rather, it is the mechanism with which the
+ * unwrapped pms will be used.
+ */
+ realPms = PK11_PubUnwrapSymKey(serverKey, &enc_pms,
+ CKM_SSL3_MASTER_KEY_DERIVE, CKA_DERIVE, 0);
+ /* Temporarily use the PMS if unwrapping the real PMS fails. */
+ useFauxPms |= (realPms == NULL);
+
+ /* Attempt to derive the MS from the PMS. This is the only way to
+ * check the version field in the RSA PMS. If this fails, we
+ * then use the faux PMS in place of the PMS. Note that this
+ * operation should never fail if we are using the faux PMS
+ * since it is correctly formatted. */
+ rv = ssl3_ComputeMasterSecret(ss, currentPms, NULL);
+
+ /* If we succeeded, then select the true PMS and discard the
+ * FPMS. Else, select the FPMS and select the true PMS */
+ useFauxPms |= (rv != SECSuccess);
+
+ if (unusedPms) {
+ PK11_FreeSymKey(unusedPms);
+ }
+
/* This step will derive the MS from the PMS, among other things. */
- rv = ssl3_InitPendingCipherSpec(ss, pms);
- PK11_FreeSymKey(pms);
+ rv = ssl3_InitPendingCipherSpec(ss, currentPms);
+ PK11_FreeSymKey(currentPms);
}
if (rv != SECSuccess) {
SEND_ALERT
return SECFailure; /* error code set by ssl3_InitPendingCipherSpec */
}
+
+#undef currentPms
+#undef unusedPms
+#undef realPms
+#undef fauxPms
+
return SECSuccess;
}
diff --git a/lib/ssl/ssl3ecc.c b/lib/ssl/ssl3ecc.c
index 5dbca1658..539ddbbab 100644
--- a/lib/ssl/ssl3ecc.c
+++ b/lib/ssl/ssl3ecc.c
@@ -319,14 +319,6 @@ ssl3_SendECDHClientKeyExchange(sslSocket * ss, SECKEYPublicKey * svrPubKey)
SECKEY_DestroyPrivateKey(privKey);
privKey = NULL;
- rv = ssl3_InitPendingCipherSpec(ss, pms);
- PK11_FreeSymKey(pms); pms = NULL;
-
- if (rv != SECSuccess) {
- ssl_MapLowLevelError(SSL_ERROR_CLIENT_KEY_EXCHANGE_FAILURE);
- goto loser;
- }
-
rv = ssl3_AppendHandshakeHeader(ss, client_key_exchange,
pubKey->u.ec.publicValue.len + 1);
if (rv != SECSuccess) {
@@ -343,6 +335,14 @@ ssl3_SendECDHClientKeyExchange(sslSocket * ss, SECKEYPublicKey * svrPubKey)
goto loser; /* err set by ssl3_AppendHandshake* */
}
+ rv = ssl3_InitPendingCipherSpec(ss, pms);
+ PK11_FreeSymKey(pms); pms = NULL;
+
+ if (rv != SECSuccess) {
+ ssl_MapLowLevelError(SSL_ERROR_CLIENT_KEY_EXCHANGE_FAILURE);
+ goto loser;
+ }
+
rv = SECSuccess;
loser:
diff --git a/lib/ssl/ssl3ext.c b/lib/ssl/ssl3ext.c
index c45f29542..07d792944 100644
--- a/lib/ssl/ssl3ext.c
+++ b/lib/ssl/ssl3ext.c
@@ -91,6 +91,12 @@ static PRInt32 ssl3_ClientSendDraftVersionXtn(sslSocket *ss, PRBool append,
PRUint32 maxBytes);
static SECStatus ssl3_ServerHandleDraftVersionXtn(sslSocket *ss, PRUint16 ex_type,
SECItem *data);
+static PRInt32 ssl3_SendExtendedMasterSecretXtn(sslSocket *ss, PRBool append,
+ PRUint32 maxBytes);
+static SECStatus ssl3_HandleExtendedMasterSecretXtn(sslSocket *ss,
+ PRUint16 ex_type,
+ SECItem *data);
+
/*
* Write bytes. Using this function means the SECItem structure
@@ -256,6 +262,7 @@ static const ssl3HelloExtensionHandler clientHelloHandlers[] = {
{ ssl_cert_status_xtn, &ssl3_ServerHandleStatusRequestXtn },
{ ssl_signature_algorithms_xtn, &ssl3_ServerHandleSigAlgsXtn },
{ ssl_tls13_draft_version_xtn, &ssl3_ServerHandleDraftVersionXtn },
+ { ssl_extended_master_secret_xtn, &ssl3_HandleExtendedMasterSecretXtn },
{ -1, NULL }
};
@@ -270,6 +277,7 @@ static const ssl3HelloExtensionHandler serverHelloHandlersTLS[] = {
{ ssl_app_layer_protocol_xtn, &ssl3_ClientHandleAppProtoXtn },
{ ssl_use_srtp_xtn, &ssl3_ClientHandleUseSRTPXtn },
{ ssl_cert_status_xtn, &ssl3_ClientHandleStatusRequestXtn },
+ { ssl_extended_master_secret_xtn, &ssl3_HandleExtendedMasterSecretXtn },
{ -1, NULL }
};
@@ -299,6 +307,7 @@ ssl3HelloExtensionSender clientHelloSendersTLS[SSL_MAX_EXTENSIONS] = {
{ ssl_cert_status_xtn, &ssl3_ClientSendStatusRequestXtn },
{ ssl_signature_algorithms_xtn, &ssl3_ClientSendSigAlgsXtn },
{ ssl_tls13_draft_version_xtn, &ssl3_ClientSendDraftVersionXtn },
+ { ssl_extended_master_secret_xtn, &ssl3_SendExtendedMasterSecretXtn},
/* any extra entries will appear as { 0, NULL } */
};
@@ -1182,6 +1191,7 @@ ssl3_SendNewSessionTicket(sslSocket *ss)
+ cert_length /* cert */
+ 1 /* server name type */
+ srvNameLen /* name len + length field */
+ + 1 /* extendedMasterSecretUsed */
+ sizeof(ticket.ticket_lifetime_hint);
padding_length = AES_BLOCK_SIZE -
(ciphertext_length % AES_BLOCK_SIZE);
@@ -1280,6 +1290,11 @@ ssl3_SendNewSessionTicket(sslSocket *ss)
if (rv != SECSuccess) goto loser;
}
+ /* extendedMasterSecretUsed */
+ rv = ssl3_AppendNumberToItem(
+ &plaintext, ss->sec.ci.sid->u.ssl3.keys.extendedMasterSecretUsed, 1);
+ 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;
@@ -1637,9 +1652,10 @@ ssl3_ServerHandleSessionTicketXtn(sslSocket *ss, PRUint16 ex_type,
goto loser;
}
- /* Read ticket_version (which is ignored for now.) */
+ /* Read ticket_version and reject if the version is wrong */
temp = ssl3_ConsumeHandshakeNumber(ss, 2, &buffer, &buffer_len);
- if (temp < 0) goto no_ticket;
+ if (temp != TLS_EX_SESS_TICKET_VERSION) goto no_ticket;
+
parsed_session_ticket->ticket_version = (SSL3ProtocolVersion)temp;
/* Read SSLVersion. */
@@ -1740,6 +1756,13 @@ ssl3_ServerHandleSessionTicketXtn(sslSocket *ss, PRUint16 ex_type,
parsed_session_ticket->srvName.type = nameType;
}
+ /* Read extendedMasterSecretUsed */
+ temp = ssl3_ConsumeHandshakeNumber(ss, 1, &buffer, &buffer_len);
+ if (temp < 0)
+ goto no_ticket;
+ PORT_Assert(temp == PR_TRUE || temp == PR_FALSE);
+ parsed_session_ticket->extendedMasterSecretUsed = (PRBool)temp;
+
/* Done parsing. Check that all bytes have been consumed. */
if (buffer_len != padding_length)
goto no_ticket;
@@ -1786,6 +1809,8 @@ ssl3_ServerHandleSessionTicketXtn(sslSocket *ss, PRUint16 ex_type,
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) {
@@ -2559,3 +2584,90 @@ ssl3_ServerHandleDraftVersionXtn(sslSocket * ss, PRUint16 ex_type,
return SECSuccess;
}
+
+static PRInt32
+ssl3_SendExtendedMasterSecretXtn(sslSocket * ss, PRBool append,
+ PRUint32 maxBytes)
+{
+ PRInt32 extension_length;
+
+ if (!ss->opt.enableExtendedMS) {
+ return 0;
+ }
+
+#ifndef NO_PKCS11_BYPASS
+ /* Extended MS can only be used w/o bypass mode */
+ if (ss->opt.bypassPKCS11) {
+ PORT_Assert(0);
+ PORT_SetError(PR_NOT_IMPLEMENTED_ERROR);
+ return -1;
+ }
+#endif
+
+ /* Always send the extension in this function, since the
+ * client always sends it and this function is only called on
+ * the server if we negotiated the extension. */
+ extension_length = 4; /* Type + length (0) */
+ if (maxBytes < extension_length) {
+ PORT_Assert(0);
+ return 0;
+ }
+
+ if (append) {
+ SECStatus rv;
+ rv = ssl3_AppendHandshakeNumber(ss, ssl_extended_master_secret_xtn, 2);
+ if (rv != SECSuccess)
+ goto loser;
+ rv = ssl3_AppendHandshakeNumber(ss, 0, 2);
+ if (rv != SECSuccess)
+ goto loser;
+ ss->xtnData.advertised[ss->xtnData.numAdvertised++] =
+ ssl_extended_master_secret_xtn;
+ }
+
+ return extension_length;
+
+loser:
+ return -1;
+}
+
+
+static SECStatus
+ssl3_HandleExtendedMasterSecretXtn(sslSocket * ss, PRUint16 ex_type,
+ SECItem *data)
+{
+ if (ss->version < SSL_LIBRARY_VERSION_TLS_1_0) {
+ return SECSuccess;
+ }
+
+ if (!ss->opt.enableExtendedMS) {
+ return SECSuccess;
+ }
+
+#ifndef NO_PKCS11_BYPASS
+ /* Extended MS can only be used w/o bypass mode */
+ if (ss->opt.bypassPKCS11) {
+ PORT_Assert(0);
+ PORT_SetError(PR_NOT_IMPLEMENTED_ERROR);
+ return SECFailure;
+ }
+#endif
+
+ if (data->len != 0) {
+ SSL_TRC(30, ("%d: SSL3[%d]: Bogus extended master secret extension",
+ SSL_GETPID(), ss->fd));
+ return SECFailure;
+ }
+
+ SSL_DBG(("%d: SSL[%d]: Negotiated extended master secret extension.",
+ SSL_GETPID(), ss->fd));
+
+ /* Keep track of negotiated extensions. */
+ ss->xtnData.negotiated[ss->xtnData.numNegotiated++] = ex_type;
+
+ if (ss->sec.isServer) {
+ return ssl3_RegisterServerHelloExtensionSender(
+ ss, ex_type, ssl3_SendExtendedMasterSecretXtn);
+ }
+ return SECSuccess;
+}
diff --git a/lib/ssl/sslerr.h b/lib/ssl/sslerr.h
index 4e905438e..192a10758 100644
--- a/lib/ssl/sslerr.h
+++ b/lib/ssl/sslerr.h
@@ -205,6 +205,9 @@ SSL_ERROR_RX_SHORT_DTLS_READ = (SSL_ERROR_BASE + 133),
SSL_ERROR_NO_SUPPORTED_SIGNATURE_ALGORITHM = (SSL_ERROR_BASE + 134),
SSL_ERROR_UNSUPPORTED_SIGNATURE_ALGORITHM = (SSL_ERROR_BASE + 135),
+SSL_ERROR_MISSING_EXTENDED_MASTER_SECRET = (SSL_ERROR_BASE + 136),
+SSL_ERROR_UNEXPECTED_EXTENDED_MASTER_SECRET = (SSL_ERROR_BASE + 137),
+
SSL_ERROR_END_OF_LIST /* let the c compiler determine the value of this. */
} SSLErrorCodes;
#endif /* NO_SECURITY_ERROR_ENUM */
diff --git a/lib/ssl/sslimpl.h b/lib/ssl/sslimpl.h
index e155a0800..41b51d8a8 100644
--- a/lib/ssl/sslimpl.h
+++ b/lib/ssl/sslimpl.h
@@ -346,6 +346,7 @@ typedef struct sslOptionsStr {
unsigned int reuseServerECDHEKey : 1; /* 28 */
unsigned int enableFallbackSCSV : 1; /* 29 */
unsigned int enableServerDhe : 1; /* 30 */
+ unsigned int enableExtendedMS : 1; /* 31 */
} sslOptions;
typedef enum { sslHandshakingUndetermined = 0,
@@ -518,6 +519,7 @@ typedef struct {
PRUint16 wrapped_master_secret_len;
PRUint8 msIsWrapped;
PRUint8 resumable;
+ PRUint8 extendedMasterSecretUsed;
} ssl3SidKeys; /* 52 bytes */
typedef struct {
@@ -1070,6 +1072,7 @@ typedef struct SessionTicketStr {
CK_MECHANISM_TYPE msWrapMech;
PRUint16 ms_length;
SSL3Opaque master_secret[48];
+ PRBool extendedMasterSecretUsed;
ClientIdentity client_identity;
SECItem peer_cert;
PRUint32 timestamp;
@@ -1595,7 +1598,7 @@ extern PRBool ssl3_VersionIsSupported(SSLProtocolVariant protocolVariant,
extern SECStatus ssl3_KeyAndMacDeriveBypass(ssl3CipherSpec * pwSpec,
const unsigned char * cr, const unsigned char * sr,
PRBool isTLS, PRBool isExport);
-extern SECStatus ssl3_MasterKeyDeriveBypass( ssl3CipherSpec * pwSpec,
+extern SECStatus ssl3_MasterSecretDeriveBypass( ssl3CipherSpec * pwSpec,
const unsigned char * cr, const unsigned char * sr,
const SECItem * pms, PRBool isTLS, PRBool isRSA);
@@ -1846,7 +1849,7 @@ extern PRBool ssl_GetSessionTicketKeysPKCS11(SECKEYPrivateKey *svrPrivKey,
/* 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 (0x0100)
+#define TLS_EX_SESS_TICKET_VERSION (0x0101)
extern SECStatus ssl3_ValidateNextProtoNego(const unsigned char* data,
unsigned int length);
diff --git a/lib/ssl/sslinfo.c b/lib/ssl/sslinfo.c
index d2df8c2ec..216ab0fa0 100644
--- a/lib/ssl/sslinfo.c
+++ b/lib/ssl/sslinfo.c
@@ -67,6 +67,8 @@ SSL_GetChannelInfo(PRFileDesc *fd, SSLChannelInfo *info, PRUintn len)
inf.creationTime = sid->creationTime;
inf.lastAccessTime = sid->lastAccessTime;
inf.expirationTime = sid->expirationTime;
+ inf.extendedMasterSecretUsed = sid->u.ssl3.keys.extendedMasterSecretUsed;
+
if (ss->version < SSL_LIBRARY_VERSION_3_0) { /* SSL2 */
inf.sessionIDLength = SSL2_SESSIONID_BYTES;
memcpy(inf.sessionID, sid->u.ssl2.sessionID,
diff --git a/lib/ssl/sslsnce.c b/lib/ssl/sslsnce.c
index 6d908c86e..16bfbe49b 100644
--- a/lib/ssl/sslsnce.c
+++ b/lib/ssl/sslsnce.c
@@ -120,14 +120,14 @@ struct sidCacheEntryStr {
/* 2 */ ssl3CipherSuite cipherSuite;
/* 2 */ PRUint16 compression; /* SSLCompressionMethod */
-/* 52 */ ssl3SidKeys keys; /* keys, wrapped as needed. */
+/* 54 */ ssl3SidKeys keys; /* keys, wrapped as needed. */
/* 4 */ PRUint32 masterWrapMech;
/* 4 */ SSL3KEAType exchKeyType;
/* 4 */ PRInt32 certIndex;
/* 4 */ PRInt32 srvNameIndex;
/* 32 */ PRUint8 srvNameHash[SHA256_LENGTH]; /* SHA256 name hash */
-/*104 */} ssl3;
+/*108 */} ssl3;
/* force sizeof(sidCacheEntry) to be a multiple of cache line size */
struct {
/*120 */ PRUint8 filler[120]; /* 72+120==192, a multiple of 16 */
@@ -507,7 +507,6 @@ ConvertFromSID(sidCacheEntry *to, sslSessionID *from)
to->sessionIDLength = from->u.ssl3.sessionIDLength;
to->u.ssl3.certIndex = -1;
to->u.ssl3.srvNameIndex = -1;
-
PORT_Memcpy(to->sessionID, from->u.ssl3.sessionID,
to->sessionIDLength);
@@ -637,7 +636,7 @@ ConvertToSID(sidCacheEntry * from,
to->authKeyBits = from->authKeyBits;
to->keaType = from->keaType;
to->keaKeyBits = from->keaKeyBits;
-
+
return to;
loser:
diff --git a/lib/ssl/sslsock.c b/lib/ssl/sslsock.c
index 2ab9d2d52..f73500925 100644
--- a/lib/ssl/sslsock.c
+++ b/lib/ssl/sslsock.c
@@ -85,6 +85,7 @@ static sslOptions ssl_defaults = {
PR_TRUE, /* reuseServerECDHEKey */
PR_FALSE, /* enableFallbackSCSV */
PR_TRUE, /* enableServerDhe */
+ PR_FALSE /* enableExtendedMS */
};
/*
@@ -825,6 +826,10 @@ SSL_OptionSet(PRFileDesc *fd, PRInt32 which, PRBool on)
ss->opt.enableServerDhe = on;
break;
+ case SSL_ENABLE_EXTENDED_MASTER_SECRET:
+ ss->opt.enableExtendedMS = on;
+ break;
+
default:
PORT_SetError(SEC_ERROR_INVALID_ARGS);
rv = SECFailure;
@@ -901,6 +906,8 @@ SSL_OptionGet(PRFileDesc *fd, PRInt32 which, PRBool *pOn)
on = ss->opt.reuseServerECDHEKey; break;
case SSL_ENABLE_FALLBACK_SCSV: on = ss->opt.enableFallbackSCSV; break;
case SSL_ENABLE_SERVER_DHE: on = ss->opt.enableServerDhe; break;
+ case SSL_ENABLE_EXTENDED_MASTER_SECRET:
+ on = ss->opt.enableExtendedMS; break;
default:
PORT_SetError(SEC_ERROR_INVALID_ARGS);
@@ -973,6 +980,9 @@ SSL_OptionGetDefault(PRInt32 which, PRBool *pOn)
case SSL_ENABLE_SERVER_DHE:
on = ssl_defaults.enableServerDhe;
break;
+ case SSL_ENABLE_EXTENDED_MASTER_SECRET:
+ on = ssl_defaults.enableExtendedMS;
+ break;
default:
PORT_SetError(SEC_ERROR_INVALID_ARGS);
@@ -1160,6 +1170,10 @@ SSL_OptionSetDefault(PRInt32 which, PRBool on)
ssl_defaults.enableServerDhe = on;
break;
+ case SSL_ENABLE_EXTENDED_MASTER_SECRET:
+ ssl_defaults.enableExtendedMS = on;
+ break;
+
default:
PORT_SetError(SEC_ERROR_INVALID_ARGS);
return SECFailure;
diff --git a/lib/ssl/sslt.h b/lib/ssl/sslt.h
index f9d83c851..cd742bbb2 100644
--- a/lib/ssl/sslt.h
+++ b/lib/ssl/sslt.h
@@ -145,6 +145,12 @@ typedef struct SSLChannelInfoStr {
/* compression method info */
const char * compressionMethodName;
SSLCompressionMethod compressionMethod;
+
+ /* The following fields are added in NSS 3.21.
+ * This field only has meaning in TLS < 1.3 and will be set to
+ * PR_FALSE in TLS 1.3.
+ */
+ PRBool extendedMasterSecretUsed;
} SSLChannelInfo;
/* Preliminary channel info */
@@ -229,13 +235,14 @@ typedef enum {
ssl_use_srtp_xtn = 14,
ssl_app_layer_protocol_xtn = 16,
ssl_padding_xtn = 21,
+ ssl_extended_master_secret_xtn = 23,
ssl_session_ticket_xtn = 35,
ssl_next_proto_nego_xtn = 13172,
ssl_renegotiation_info_xtn = 0xff01,
ssl_tls13_draft_version_xtn = 0xff02 /* experimental number */
} SSLExtensionType;
-#define SSL_MAX_EXTENSIONS 11 /* doesn't include ssl_padding_xtn. */
+#define SSL_MAX_EXTENSIONS 12 /* doesn't include ssl_padding_xtn. */
typedef enum {
ssl_dhe_group_none = 0,