diff options
author | Tim Taubert <ttaubert@mozilla.com> | 2015-10-02 22:04:07 +0200 |
---|---|---|
committer | Tim Taubert <ttaubert@mozilla.com> | 2015-10-02 22:04:07 +0200 |
commit | df3f6e80bd87bd74519d2b0144577ebc4595ae1a (patch) | |
tree | 22190dbb4efc9bf8b5c597ded225e5d7f266571d | |
parent | 2c3845e519b15b1a6623194aaac2c802ef9b7639 (diff) | |
download | nss-hg-df3f6e80bd87bd74519d2b0144577ebc4595ae1a.tar.gz |
Bug 998524 - Improve SNI handling for NameType r=mt,ekr
-rw-r--r-- | lib/ssl/ssl3con.c | 18 | ||||
-rw-r--r-- | lib/ssl/ssl3ext.c | 129 | ||||
-rw-r--r-- | lib/ssl/sslimpl.h | 5 | ||||
-rw-r--r-- | lib/ssl/sslsock.c | 5 |
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); } /* |