summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorTim Taubert <ttaubert@mozilla.com>2015-10-02 22:04:07 +0200
committerTim Taubert <ttaubert@mozilla.com>2015-10-02 22:04:07 +0200
commitdf3f6e80bd87bd74519d2b0144577ebc4595ae1a (patch)
tree22190dbb4efc9bf8b5c597ded225e5d7f266571d
parent2c3845e519b15b1a6623194aaac2c802ef9b7639 (diff)
downloadnss-hg-df3f6e80bd87bd74519d2b0144577ebc4595ae1a.tar.gz
Bug 998524 - Improve SNI handling for NameType r=mt,ekr
-rw-r--r--lib/ssl/ssl3con.c18
-rw-r--r--lib/ssl/ssl3ext.c129
-rw-r--r--lib/ssl/sslimpl.h5
-rw-r--r--lib/ssl/sslsock.c5
4 files changed, 79 insertions, 78 deletions
diff --git a/lib/ssl/ssl3con.c b/lib/ssl/ssl3con.c
index 1b8676629..7711d3e5b 100644
--- a/lib/ssl/ssl3con.c
+++ b/lib/ssl/ssl3con.c
@@ -8513,16 +8513,7 @@ ssl3_ServerCallSNICallback(sslSocket *ss)
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 function or
- * the callers (*HandleClientHelloPart2) and the callers
- must not use it after this point. */
- if (ss->xtnData.sniNameArr) {
- PORT_Free(ss->xtnData.sniNameArr);
- ss->xtnData.sniNameArr = NULL;
- ss->xtnData.sniNameArrSize = 0;
- }
+ ssl3_FreeSniNameArray(&ss->xtnData);
if (ret <= SSL_SNI_SEND_ALERT) {
/* desc and errCode should be set. */
goto alert_loser;
@@ -9256,12 +9247,7 @@ compression_found:
}
/* Clean up sni name array */
- if (ssl3_ExtensionNegotiated(ss, ssl_server_name_xtn) &&
- ss->xtnData.sniNameArr) {
- PORT_Free(ss->xtnData.sniNameArr);
- ss->xtnData.sniNameArr = NULL;
- ss->xtnData.sniNameArrSize = 0;
- }
+ ssl3_FreeSniNameArray(&ss->xtnData);
ssl_GetXmitBufLock(ss);
haveXmitBufLock = PR_TRUE;
diff --git a/lib/ssl/ssl3ext.c b/lib/ssl/ssl3ext.c
index df3e134d8..3a0108377 100644
--- a/lib/ssl/ssl3ext.c
+++ b/lib/ssl/ssl3ext.c
@@ -467,14 +467,12 @@ ssl3_SendServerNameXtn(sslSocket *ss, PRBool append,
return 4;
}
-/* handle an incoming SNI extension, by ignoring it. */
+/* Handle an incoming SNI extension. */
SECStatus
ssl3_HandleServerNameXtn(sslSocket *ss, PRUint16 ex_type, SECItem *data)
{
SECItem *names = NULL;
- PRUint32 listCount = 0, namesPos = 0, i;
TLSExtensionData *xtnData = &ss->xtnData;
- SECItem ldata;
PRInt32 listLenBytes = 0;
if (!ss->sec.isServer) {
@@ -486,79 +484,94 @@ ssl3_HandleServerNameXtn(sslSocket *ss, PRUint16 ex_type, SECItem *data)
if (!ss->sniSocketConfig) {
return SECSuccess;
}
+
/* length of server_name_list */
listLenBytes = ssl3_ConsumeHandshakeNumber(ss, 2, &data->data, &data->len);
if (listLenBytes < 0) {
- return SECFailure;
+ goto loser; /* alert already sent */
}
if (listLenBytes == 0 || listLenBytes != data->len) {
- (void)ssl3_DecodeError(ss);
- return SECFailure;
+ goto alert_loser;
}
- ldata = *data;
- /* Calculate the size of the array.*/
- while (listLenBytes > 0) {
- SECItem litem;
+
+ /* Read ServerNameList. */
+ while (data->len > 0) {
+ SECItem tmp;
SECStatus rv;
PRInt32 type;
- /* Skip Name Type (sni_host_name); checks are on the second pass */
- type = ssl3_ConsumeHandshakeNumber(ss, 1, &ldata.data, &ldata.len);
+
+ /* Read Name Type. */
+ type = ssl3_ConsumeHandshakeNumber(ss, 1, &data->data, &data->len);
if (type < 0) { /* i.e., SECFailure cast to PRint32 */
- return SECFailure;
+ /* alert sent in ConsumeHandshakeNumber */
+ goto loser;
}
- rv = ssl3_ConsumeHandshakeVariable(ss, &litem, 2, &ldata.data, &ldata.len);
+
+ /* Read ServerName (length and value). */
+ rv = ssl3_ConsumeHandshakeVariable(ss, &tmp, 2, &data->data, &data->len);
if (rv != SECSuccess) {
- return rv;
+ goto loser;
}
- /* Adjust total length for consumed item, item len and type.*/
- listLenBytes -= litem.len + 3;
- if (listLenBytes > 0 && !ldata.len) {
- (void)ssl3_DecodeError(ss);
- return SECFailure;
+
+ /* Record the value for host_name(0). */
+ if (type == sni_nametype_hostname) {
+ /* Fail if we encounter a second host_name entry. */
+ if (names) {
+ goto alert_loser;
+ }
+
+ /* Create an array for the only supported NameType. */
+ names = PORT_ZNewArray(SECItem, 1);
+ if (!names) {
+ goto loser;
+ }
+
+ /* Copy ServerName into the array. */
+ if (SECITEM_CopyItem(NULL, &names[0], &tmp) != SECSuccess) {
+ goto loser;
+ }
}
- listCount += 1;
+
+ /* Even if we don't support NameTypes other than host_name at the
+ * moment, we continue parsing the whole list to check its validity.
+ * We do not check for duplicate entries with NameType != host_name(0).
+ */
}
- names = PORT_ZNewArray(SECItem, listCount);
- if (!names) {
- return SECFailure;
+ if (names) {
+ /* Free old and set the new data. */
+ ssl3_FreeSniNameArray(xtnData);
+ xtnData->sniNameArr = names;
+ xtnData->sniNameArrSize = 1;
+ xtnData->negotiated[xtnData->numNegotiated++] = ssl_server_name_xtn;
}
- for (i = 0; i < listCount; i++) {
- unsigned int j;
- PRInt32 type;
- SECStatus rv;
- PRBool nametypePresent = PR_FALSE;
- /* Name Type (sni_host_name) */
- type = ssl3_ConsumeHandshakeNumber(ss, 1, &data->data, &data->len);
- /* Check if we have such type in the list */
- for (j = 0; j < listCount && names[j].data; j++) {
- /* TODO bug 998524: .type is not assigned a value */
- if (names[j].type == type) {
- nametypePresent = PR_TRUE;
- break;
- }
- }
- /* HostName (length and value) */
- rv = ssl3_ConsumeHandshakeVariable(ss, &names[namesPos], 2,
- &data->data, &data->len);
- if (rv != SECSuccess) {
- PORT_Assert(0);
- PORT_Free(names);
- PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
- return rv;
- }
- if (nametypePresent == PR_FALSE) {
- namesPos += 1;
- }
+ return SECSuccess;
+
+alert_loser:
+ (void)ssl3_DecodeError(ss);
+loser:
+ if (names) {
+ PORT_Free(names);
+ }
+ return SECFailure;
+}
+
+/* Frees a given xtnData->sniNameArr and its elements. */
+void
+ssl3_FreeSniNameArray(TLSExtensionData* xtnData)
+{
+ PRUint32 i;
+
+ if (!xtnData->sniNameArr) {
+ return;
}
- /* Free old and set the new data. */
- if (xtnData->sniNameArr) {
- PORT_Free(ss->xtnData.sniNameArr);
+
+ for (i = 0; i < xtnData->sniNameArrSize; i++) {
+ SECITEM_FreeItem(&xtnData->sniNameArr[i], PR_FALSE);
}
- xtnData->sniNameArr = names;
- xtnData->sniNameArrSize = namesPos;
- xtnData->negotiated[xtnData->numNegotiated++] = ssl_server_name_xtn;
- return SECSuccess;
+ PORT_Free(xtnData->sniNameArr);
+ xtnData->sniNameArr = NULL;
+ xtnData->sniNameArrSize = 0;
}
/* Called by both clients and servers.
diff --git a/lib/ssl/sslimpl.h b/lib/ssl/sslimpl.h
index 0f701b950..622a35f77 100644
--- a/lib/ssl/sslimpl.h
+++ b/lib/ssl/sslimpl.h
@@ -834,6 +834,10 @@ struct TLSExtensionDataStr {
SECItem signedCertTimestamps;
};
+typedef enum {
+ sni_nametype_hostname
+} SNINameType;
+
typedef SECStatus (*sslRestartTarget)(sslSocket *);
/*
@@ -1756,6 +1760,7 @@ extern SECStatus ssl3_VerifySignedHashes(SSL3Hashes *hash,
extern SECStatus ssl3_CacheWrappedMasterSecret(
sslSocket *ss, sslSessionID *sid,
ssl3CipherSpec *spec, SSLAuthType authType);
+extern void ssl3_FreeSniNameArray(TLSExtensionData* xtnData);
/* Functions that handle ClientHello and ServerHello extensions. */
extern SECStatus ssl3_HandleServerNameXtn(sslSocket *ss,
diff --git a/lib/ssl/sslsock.c b/lib/ssl/sslsock.c
index 24793753e..d9b288346 100644
--- a/lib/ssl/sslsock.c
+++ b/lib/ssl/sslsock.c
@@ -404,10 +404,7 @@ ssl_DestroySocketContents(sslSocket *ss)
ss->dheKeyPair = NULL;
}
SECITEM_FreeItem(&ss->opt.nextProtoNego, PR_FALSE);
- if (ss->xtnData.sniNameArr) {
- PORT_Free(ss->xtnData.sniNameArr);
- ss->xtnData.sniNameArr = NULL;
- }
+ ssl3_FreeSniNameArray(&ss->xtnData);
}
/*