summaryrefslogtreecommitdiff
path: root/security/nss/lib/ssl/ssl3con.c
diff options
context:
space:
mode:
Diffstat (limited to 'security/nss/lib/ssl/ssl3con.c')
-rw-r--r--security/nss/lib/ssl/ssl3con.c227
1 files changed, 219 insertions, 8 deletions
diff --git a/security/nss/lib/ssl/ssl3con.c b/security/nss/lib/ssl/ssl3con.c
index 25157fe29..bd3df17e6 100644
--- a/security/nss/lib/ssl/ssl3con.c
+++ b/security/nss/lib/ssl/ssl3con.c
@@ -1168,7 +1168,7 @@ ssl3_CleanupKeyMaterial(ssl3KeyMaterial *mat)
** Caller must hold SpecWriteLock.
*/
static void
-ssl3_DestroyCipherSpec(ssl3CipherSpec *spec)
+ssl3_DestroyCipherSpec(ssl3CipherSpec *spec, PRBool freeSrvName)
{
PRBool freeit = (PRBool)(!spec->bypassCiphers);
/* PORT_Assert( ss->opt.noLocks || ssl_HaveSpecWriteLock(ss)); Don't have ss! */
@@ -1186,6 +1186,9 @@ ssl3_DestroyCipherSpec(ssl3CipherSpec *spec)
spec->destroyDecompressContext(spec->decompressContext, 1);
spec->decompressContext = NULL;
}
+ if (freeSrvName && spec->srvVirtName.data) {
+ SECITEM_FreeItem(&spec->srvVirtName, PR_FALSE);
+ }
if (spec->master_secret != NULL) {
PK11_FreeSymKey(spec->master_secret);
spec->master_secret = NULL;
@@ -1444,8 +1447,8 @@ const ssl3BulkCipherDef *cipher_def;
SSLCompressionMethod compression_method;
SECStatus rv;
- PORT_Assert( ss->opt.noLocks || ssl_HaveSSL3HandshakeLock(ss));
-
+ PORT_Assert(ss->opt.noLocks || ssl_HaveSSL3HandshakeLock(ss));
+ PORT_Assert(ss->opt.noLocks || ssl_HaveSpecWriteLock(ss));
PORT_Assert(ss->ssl3.prSpec == ss->ssl3.pwSpec);
pwSpec = ss->ssl3.pwSpec;
@@ -1557,6 +1560,14 @@ const ssl3BulkCipherDef *cipher_def;
* is decrypting, and vice versa.
*/
optArg1 = !optArg1;
+ break;
+ /* kill warnings. */
+ case ssl_calg_null:
+ case ssl_calg_rc4:
+ case ssl_calg_rc2:
+ case ssl_calg_idea:
+ case ssl_calg_fortezza:
+ break;
}
rv = (*initFn)(clientContext,
@@ -1625,7 +1636,7 @@ const ssl3BulkCipherDef *cipher_def;
SSLCipherAlgorithm calg;
PORT_Assert( ss->opt.noLocks || ssl_HaveSSL3HandshakeLock(ss));
-
+ PORT_Assert( ss->opt.noLocks || ssl_HaveSpecWriteLock(ss));
PORT_Assert(ss->ssl3.prSpec == ss->ssl3.pwSpec);
pwSpec = ss->ssl3.pwSpec;
@@ -2722,7 +2733,7 @@ ssl3_SendChangeCipherSpecs(sslSocket *ss)
* (Both the read and write sides have changed) destroy it.
*/
if (ss->ssl3.prSpec == ss->ssl3.pwSpec) {
- ssl3_DestroyCipherSpec(ss->ssl3.pwSpec);
+ ssl3_DestroyCipherSpec(ss->ssl3.pwSpec, PR_FALSE/*freeSrvName*/);
}
ssl_ReleaseSpecWriteLock(ss); /**************************************/
@@ -2784,7 +2795,7 @@ ssl3_HandleChangeCipherSpecs(sslSocket *ss, sslBuffer *buf)
* (Both the read and write sides have changed) destroy it.
*/
if (ss->ssl3.prSpec == ss->ssl3.pwSpec) {
- ssl3_DestroyCipherSpec(ss->ssl3.prSpec);
+ ssl3_DestroyCipherSpec(ss->ssl3.prSpec, PR_FALSE/*freeSrvName*/);
}
ssl_ReleaseSpecWriteLock(ss); /*************************************/
return SECSuccess;
@@ -5672,6 +5683,25 @@ ssl3_SendHelloRequest(sslSocket *ss)
return SECSuccess;
}
+/*
+ * Called from:
+ * ssl3_HandleClientHello()
+ */
+static SECComparison
+ssl3_ServerNameCompare(const SECItem *name1, const SECItem *name2)
+{
+ if (!name1 != !name2) {
+ return SECLessThan;
+ }
+ if (!name1) {
+ return SECEqual;
+ }
+ if (name1->type != name2->type) {
+ return SECLessThan;
+ }
+ return SECITEM_CompareItem(name1, name2);
+}
+
/* Sets memory error when returning NULL.
* Called from:
* ssl3_SendClientHello()
@@ -5688,6 +5718,21 @@ ssl3_NewSessionID(sslSocket *ss, PRBool is_server)
if (sid == NULL)
return sid;
+ if (is_server) {
+ const SECItem * srvName;
+ SECStatus rv = SECSuccess;
+
+ ssl_GetSpecReadLock(ss); /********************************/
+ srvName = &ss->ssl3.prSpec->srvVirtName;
+ if (srvName->len && srvName->data) {
+ rv = SECITEM_CopyItem(NULL, &sid->u.ssl3.srvName, srvName);
+ }
+ ssl_ReleaseSpecReadLock(ss); /************************************/
+ if (rv != SECSuccess) {
+ PORT_Free(sid);
+ return NULL;
+ }
+ }
sid->peerID = (ss->peerID == NULL) ? NULL : PORT_Strdup(ss->peerID);
sid->urlSvrName = (ss->url == NULL) ? NULL : PORT_Strdup(ss->url);
sid->addr = ss->sec.ci.peer;
@@ -6225,6 +6270,32 @@ compression_found:
ss->sec.localCert =
CERT_DupCertificate(ss->serverCerts[sid->keaType].serverCert);
+ /* Copy cached name in to pending spec */
+ if (sid != NULL &&
+ sid->version > SSL_LIBRARY_VERSION_3_0 &&
+ sid->u.ssl3.srvName.len && sid->u.ssl3.srvName.data) {
+ /* Set server name from sid */
+ SECItem *sidName = &sid->u.ssl3.srvName;
+ SECItem *pwsName = &ss->ssl3.pwSpec->srvVirtName;
+ if (pwsName->data) {
+ SECITEM_FreeItem(pwsName, PR_FALSE);
+ }
+ rv = SECITEM_CopyItem(NULL, pwsName, sidName);
+ if (rv != SECSuccess) {
+ errCode = PORT_GetError();
+ desc = internal_error;
+ goto alert_loser;
+ }
+ }
+
+ /* Clean up sni name array */
+ if (ssl3_ExtensionNegotiated(ss, server_name_xtn) &&
+ ss->xtnData.sniNameArr) {
+ PORT_Free(ss->xtnData.sniNameArr);
+ ss->xtnData.sniNameArr = NULL;
+ ss->xtnData.sniNameArrSize = 0;
+ }
+
ssl_GetXmitBufLock(ss); haveXmitBufLock = PR_TRUE;
rv = ssl3_SendServerHello(ss);
@@ -6278,6 +6349,146 @@ compression_found:
}
SSL_AtomicIncrementLong(& ssl3stats.hch_sid_cache_misses );
+ if (ssl3_ExtensionNegotiated(ss, server_name_xtn)) {
+ int ret = 0;
+ if (ss->sniSocketConfig) do { /* not a loop */
+ ret = SSL_SNI_SEND_ALERT;
+ /* If extension is negotiated, the len of names should > 0. */
+ if (ss->xtnData.sniNameArrSize) {
+ /* Calling client callback to reconfigure the socket. */
+ ret = (SECStatus)(*ss->sniSocketConfig)(ss->fd,
+ ss->xtnData.sniNameArr,
+ ss->xtnData.sniNameArrSize,
+ ss->sniSocketConfigArg);
+ }
+ if (ret <= SSL_SNI_SEND_ALERT) {
+ /* Application does not know the name or was not able to
+ * properly reconfigure the socket. */
+ errCode = SSL_ERROR_UNRECOGNIZED_NAME_ALERT;
+ desc = unrecognized_name;
+ break;
+ } else if (ret == SSL_SNI_CURRENT_CONFIG_IS_USED) {
+ SECStatus rv = SECSuccess;
+ SECItem * cwsName, *pwsName;
+
+ ssl_GetSpecWriteLock(ss); /*******************************/
+ pwsName = &ss->ssl3.pwSpec->srvVirtName;
+ cwsName = &ss->ssl3.cwSpec->srvVirtName;
+#ifndef SSL_SNI_ALLOW_NAME_CHANGE_2HS
+ /* not allow name change on the 2d HS */
+ if (ss->firstHsDone) {
+ if (ssl3_ServerNameCompare(pwsName, cwsName)) {
+ ssl_ReleaseSpecWriteLock(ss); /******************/
+ errCode = SSL_ERROR_UNRECOGNIZED_NAME_ALERT;
+ desc = handshake_failure;
+ ret = SSL_SNI_SEND_ALERT;
+ break;
+ }
+ }
+#endif
+ if (pwsName->data) {
+ SECITEM_FreeItem(pwsName, PR_FALSE);
+ }
+ if (cwsName->data) {
+ rv = SECITEM_CopyItem(NULL, pwsName, cwsName);
+ }
+ ssl_ReleaseSpecWriteLock(ss); /**************************/
+ if (rv != SECSuccess) {
+ errCode = SSL_ERROR_INTERNAL_ERROR_ALERT;
+ desc = internal_error;
+ ret = SSL_SNI_SEND_ALERT;
+ break;
+ }
+ } else if (ret < ss->xtnData.sniNameArrSize) {
+ /* Application has configured new socket info. Lets check it
+ * and save the name. */
+ SECStatus rv;
+ SECItem * name = &ss->xtnData.sniNameArr[ret];
+ int configedCiphers;
+ SECItem * pwsName;
+
+ /* get rid of the old name and save the newly picked. */
+ /* This code is protected by ssl3HandshakeLock. */
+ ssl_GetSpecWriteLock(ss); /*******************************/
+#ifndef SSL_SNI_ALLOW_NAME_CHANGE_2HS
+ /* not allow name change on the 2d HS */
+ if (ss->firstHsDone) {
+ SECItem *cwsName = &ss->ssl3.cwSpec->srvVirtName;
+ if (ssl3_ServerNameCompare(name, cwsName)) {
+ ssl_ReleaseSpecWriteLock(ss); /******************/
+ errCode = SSL_ERROR_UNRECOGNIZED_NAME_ALERT;
+ desc = handshake_failure;
+ ret = SSL_SNI_SEND_ALERT;
+ break;
+ }
+ }
+#endif
+ pwsName = &ss->ssl3.pwSpec->srvVirtName;
+ if (pwsName->data) {
+ SECITEM_FreeItem(pwsName, PR_FALSE);
+ }
+ rv = SECITEM_CopyItem(NULL, pwsName, name);
+ ssl_ReleaseSpecWriteLock(ss); /***************************/
+ if (rv != SECSuccess) {
+ errCode = SSL_ERROR_INTERNAL_ERROR_ALERT;
+ desc = internal_error;
+ ret = SSL_SNI_SEND_ALERT;
+ break;
+ }
+ configedCiphers = ssl3_config_match_init(ss);
+ if (configedCiphers <= 0) {
+ /* no ciphers are working/supported */
+ errCode = PORT_GetError();
+ desc = handshake_failure;
+ ret = SSL_SNI_SEND_ALERT;
+ break;
+ }
+ /* Need to tell the client that application has picked
+ * the name from the offered list and reconfigured the socket.
+ */
+ ssl3_RegisterServerHelloExtensionSender(ss, server_name_xtn,
+ ssl3_SendServerNameXtn);
+ } else {
+ /* Callback returned index outside of the boundary. */
+ PORT_Assert(ret < ss->xtnData.sniNameArrSize);
+ errCode = SSL_ERROR_INTERNAL_ERROR_ALERT;
+ desc = internal_error;
+ ret = SSL_SNI_SEND_ALERT;
+ break;
+ }
+ } while (0);
+ /* Free sniNameArr. The data that each SECItem in the array
+ * points into is the data from the input buffer "b". It will
+ * not be available outside the scope of this or it's child
+ * functions.*/
+ if (ss->xtnData.sniNameArr) {
+ PORT_Free(ss->xtnData.sniNameArr);
+ ss->xtnData.sniNameArr = NULL;
+ ss->xtnData.sniNameArrSize = 0;
+ }
+ if (ret <= SSL_SNI_SEND_ALERT) {
+ /* desc and errCode should be set. */
+ goto alert_loser;
+ }
+ }
+#ifndef SSL_SNI_ALLOW_NAME_CHANGE_2HS
+ else if (ss->firstHsDone) {
+ /* Check that we don't have the name is current spec
+ * if this extension was not negotiated on the 2d hs. */
+ PRBool passed = PR_TRUE;
+ ssl_GetSpecReadLock(ss); /*******************************/
+ if (ss->ssl3.cwSpec->srvVirtName.data) {
+ passed = PR_FALSE;
+ }
+ ssl_ReleaseSpecReadLock(ss); /***************************/
+ if (!passed) {
+ errCode = SSL_ERROR_UNRECOGNIZED_NAME_ALERT;
+ desc = handshake_failure;
+ goto alert_loser;
+ }
+ }
+#endif
+
sid = ssl3_NewSessionID(ss, PR_TRUE);
if (sid == NULL) {
errCode = PORT_GetError();
@@ -9069,8 +9280,8 @@ ssl3_DestroySSL3Info(sslSocket *ss)
PORT_Free(ss->ssl3.hs.msg_body.buf);
/* free up the CipherSpecs */
- ssl3_DestroyCipherSpec(&ss->ssl3.specs[0]);
- ssl3_DestroyCipherSpec(&ss->ssl3.specs[1]);
+ ssl3_DestroyCipherSpec(&ss->ssl3.specs[0], PR_TRUE/*freeSrvName*/);
+ ssl3_DestroyCipherSpec(&ss->ssl3.specs[1], PR_TRUE/*freeSrvName*/);
ss->ssl3.initialized = PR_FALSE;
}