diff options
author | agl@chromium.org <agl@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2010-09-20 19:30:41 +0000 |
---|---|---|
committer | agl@chromium.org <agl@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2010-09-20 19:30:41 +0000 |
commit | 17d48e91ad0ee5fe7d3f74c47e455aa8954e131f (patch) | |
tree | 7802bbaf4d8cdcf1763bd5c946efa501715e1b4a /net/third_party | |
parent | 015e850f64af9428d24d916dd3165df23aab3812 (diff) | |
download | chromium_src-17d48e91ad0ee5fe7d3f74c47e455aa8954e131f.zip chromium_src-17d48e91ad0ee5fe7d3f74c47e455aa8954e131f.tar.gz chromium_src-17d48e91ad0ee5fe7d3f74c47e455aa8954e131f.tar.bz2 |
NSS: Snap Start NPN support and other fixes.
Snap Start now works with NPN.
In the case that the server doesn't support Snap Start,
SSL_GetPredictedServerHelloData will no longer return any data to
allow the application not to cache Snap Start information for servers
that don't support it.
Previously Snap Start wasn't filling in the certificates in all cases.
(Test cases didn't check the certificates on the socket; but
Chrome noticed.)
BUG=none
TEST=nsstests (not in tree)
http://codereview.chromium.org/3430007/show
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@59957 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'net/third_party')
-rw-r--r-- | net/third_party/nss/ssl/snapstart.c | 99 | ||||
-rw-r--r-- | net/third_party/nss/ssl/ssl3con.c | 20 | ||||
-rw-r--r-- | net/third_party/nss/ssl/ssl3ext.c | 2 | ||||
-rw-r--r-- | net/third_party/nss/ssl/sslimpl.h | 3 |
4 files changed, 108 insertions, 16 deletions
diff --git a/net/third_party/nss/ssl/snapstart.c b/net/third_party/nss/ssl/snapstart.c index 4999ae2..ca2cafa 100644 --- a/net/third_party/nss/ssl/snapstart.c +++ b/net/third_party/nss/ssl/snapstart.c @@ -450,6 +450,9 @@ ssl3_FindOrbit(const unsigned char *data, unsigned int length, void *ptr) /* ssl3_CanSnapStart returns true if we are able to perform Snap Start on ** the given socket. +** extensions: on successful return, this is filled in with the contents of +** the server's predicted extensions. This points within +** |ss->ssl3.serverHelloPredictionData|. ** resuming: PR_TRUE iff we wish to attempt a Snap Start resume ** out_orbit: if this function returns PR_TRUE, then |out_orbit| is filled ** with the server's predicted orbit value. @@ -458,13 +461,12 @@ ssl3_FindOrbit(const unsigned char *data, unsigned int length, void *ptr) ** be modified on failure). */ static PRBool -ssl3_CanSnapStart(sslSocket *ss, PRBool resuming, +ssl3_CanSnapStart(sslSocket *ss, SECItem *extensions, PRBool resuming, unsigned char out_orbit[8]) { const unsigned char *server_hello; unsigned int server_hello_len, session_id_len, cipher_suite_offset; unsigned int extensions_offset, cipher_suite, compression_method; unsigned char orbit[9]; - SECItem extensions; SECStatus rv; SSL3ProtocolVersion version; @@ -508,12 +510,12 @@ ssl3_CanSnapStart(sslSocket *ss, PRBool resuming, } ss->ssl3.hs.compression = ssl_compression_null; - extensions.data = (unsigned char *) server_hello + extensions_offset; - extensions.len = server_hello_len - extensions_offset; + extensions->data = (unsigned char *) server_hello + extensions_offset; + extensions->len = server_hello_len - extensions_offset; /* The last byte is used to indictate that the previous eight are valid. */ orbit[8] = 0; - if (!ssl3_ForEachExtension(&extensions, resuming, ssl3_FindOrbit, orbit)) + if (!ssl3_ForEachExtension(extensions, resuming, ssl3_FindOrbit, orbit)) return PR_FALSE; if (!orbit[8]) @@ -562,6 +564,68 @@ ssl3_UpdateClientHelloLengths(sslSocket *ss, PutBE16(&ss->sec.ci.sendBuf.buf[offset], new_length); } +/* ssl3_FindServerNPNExtension is a callback function for ssl3_ForEachExtension. + * It looks for a Next Protocol Negotiation and saves the payload of the + * extension in the given SECItem */ +static void +ssl3_FindServerNPNExtension(const unsigned char* data, unsigned int length, + void *ctx) +{ + SECItem *server_npn_extension = (SECItem*) ctx; + + unsigned int extension_num = GetBE16(data); + if (extension_num == ssl_next_proto_neg_xtn && length >= 4) { + server_npn_extension->data = (unsigned char*)data + 4; + server_npn_extension->len = length - 4; + } +} + +/* ssl3_MaybeWriteNextProtocol deals with the interaction of Next Protocol + * Negotiation and Snap Start. It's called just before we serialise the embedded + * Finished message in the extension. At this point, if NPN is enabled, we have + * to include a NextProtocol message. */ +static SECStatus +ssl3_MaybeWriteNextProtocol(sslSocket *ss, SECItem *server_hello_extensions) +{ + PRUint16 i16; + SECItem server_npn_extension; + + for (i16 = 0; i16 < ss->xtnData.numAdvertised; i16++) { + if (ss->xtnData.advertised[i16] == ssl_next_proto_neg_xtn) + break; + } + + if (i16 == ss->xtnData.numAdvertised) { + /* We didn't send an NPN extension, so no need to do anything here. */ + return SECSuccess; + } + + memset(&server_npn_extension, 0, sizeof(server_npn_extension)); + + ssl3_ForEachExtension( + server_hello_extensions, PR_FALSE /* is_resuming: value doesn't matter + in this case */, ssl3_FindServerNPNExtension, &server_npn_extension); + + if (server_npn_extension.data == NULL) { + /* We predicted that the server doesn't support NPN, so nothing to do + * here. */ + return SECSuccess; + } + + ssl3_ClientHandleNextProtoNegoXtn(ss, ssl_next_proto_neg_xtn, + &server_npn_extension); + + if (ss->ssl3.nextProtoState == SSL_NEXT_PROTO_NO_SUPPORT) { + /* The server's predicted NPN extension was malformed. We're didn't pick + * a protocol so we won't send a NextProtocol message. However, this is + * probably fatal to the connection. */ + return SECSuccess; + } + + return ssl3_AppendSnapStartHandshakeRecord(ss, ssl3_SendNextProto, + PR_TRUE /* encrypt */); +} + /* ssl3_SendSnapStartXtn appends a Snap Start extension. It assumes that the * inchoate ClientHello is in |ss->sec.ci.sendBuf|. */ PRInt32 @@ -579,6 +643,7 @@ ssl3_SendSnapStartXtn(sslSocket *ss, PRBool append, PRUint32 maxBytes) unsigned int snap_start_extension_len_offset, original_sendbuf_len; ssl3CipherSpec *temp; sslSessionID *sid; + SECItem server_extensions; if (!ss->opt.enableSnapStart) return 0; @@ -609,7 +674,7 @@ ssl3_SendSnapStartXtn(sslSocket *ss, PRBool append, PRUint32 maxBytes) resuming = PR_TRUE; } - if (!ssl3_CanSnapStart(ss, resuming, orbit)) + if (!ssl3_CanSnapStart(ss, &server_extensions, resuming, orbit)) return ssl3_SendEmptySnapStartXtn(ss, append, maxBytes); /* At this point we are happy that we are going to send a non-empty Snap @@ -689,6 +754,7 @@ ssl3_SendSnapStartXtn(sslSocket *ss, PRBool append, PRUint32 maxBytes) if (sid->peerCert != NULL) { ss->sec.peerCert = CERT_DupCertificate(sid->peerCert); + ssl3_CopyPeerCertsFromSID(ss, sid); } rv = ssl3_InitPendingCipherSpec(ss, NULL /* re-use master secret */); @@ -740,6 +806,10 @@ ssl3_SendSnapStartXtn(sslSocket *ss, PRBool append, PRUint32 maxBytes) ss->ssl3.cwSpec->write_seq_num.low = 0; ssl_ReleaseSpecWriteLock(ss); + rv = ssl3_MaybeWriteNextProtocol(ss, &server_extensions); + if (rv != SECSuccess) + goto loser; + /* Write Finished */ rv = ssl3_AppendSnapStartHandshakeRecord(ss, ssl3_SendSnapStartFinished, PR_TRUE /* encrypt */); @@ -796,9 +866,11 @@ loser: SECStatus ssl3_ClientHandleSnapStartXtn(sslSocket *ss, PRUint16 ex_type, SECItem *data) { - /* This is a no-op handler for when the server echos our Snap Start - * extension. The work of saving the ServerHello is done in - * ssl3_HandleServerHello, where its contents are available. */ + /* The work of saving the ServerHello is done in ssl3_HandleServerHello, + * where its contents are available. Here we renognise that the saved + * ServerHello message contains a Snap Start extension and mark it as + * valid. */ + ss->ssl3.serverHelloPredictionDataValid = PR_TRUE; return SECSuccess; } @@ -857,8 +929,13 @@ SSL_GetPredictedServerHelloData(PRFileDesc *fd, const unsigned char **data, return SECFailure; } - *data = ss->ssl3.serverHelloPredictionData.data; - *data_len = ss->ssl3.serverHelloPredictionData.len; + if (!ss->ssl3.serverHelloPredictionDataValid) { + *data = NULL; + *data_len = 0; + } else { + *data = ss->ssl3.serverHelloPredictionData.data; + *data_len = ss->ssl3.serverHelloPredictionData.len; + } return SECSuccess; } diff --git a/net/third_party/nss/ssl/ssl3con.c b/net/third_party/nss/ssl/ssl3con.c index 16ef9df..9ab2a1c 100644 --- a/net/third_party/nss/ssl/ssl3con.c +++ b/net/third_party/nss/ssl/ssl3con.c @@ -72,7 +72,8 @@ #endif static void ssl3_CleanupPeerCerts(sslSocket *ss); -static void ssl3_CopyPeerCertsFromSID(sslSocket *ss, sslSessionID *sid); +static void ssl3_CopyPeerCertsToSID(ssl3CertNode *certs, + sslSessionID *sid); static PK11SymKey *ssl3_GenerateRSAPMS(sslSocket *ss, ssl3CipherSpec *spec, PK11SlotInfo * serverKeySlot); static SECStatus ssl3_DeriveMasterSecret(sslSocket *ss, PK11SymKey *pms); @@ -82,7 +83,6 @@ static SECStatus ssl3_InitState( sslSocket *ss); static SECStatus ssl3_SendCertificate( sslSocket *ss); static SECStatus ssl3_SendEmptyCertificate( sslSocket *ss); static SECStatus ssl3_SendCertificateRequest(sslSocket *ss); -static SECStatus ssl3_SendNextProto( sslSocket *ss); static SECStatus ssl3_SendServerHello( sslSocket *ss); static SECStatus ssl3_SendServerHelloDone( sslSocket *ss); static SECStatus ssl3_SendServerKeyExchange( sslSocket *ss); @@ -5008,6 +5008,12 @@ ssl3_HandleServerHello(sslSocket *ss, SSL3Opaque *b, PRUint32 length) if (SECITEM_AllocItem(NULL, &ss->ssl3.serverHelloPredictionData, length)) memcpy(ss->ssl3.serverHelloPredictionData.data, b, length); + /* ss->ssl3.serverHelloPredictionDataValid is still false at this + * point. We have to record the contents of the ServerHello here + * because we don't have a pointer to the whole message when handling + * the extensions. However, we wait until the Snap Start extenion + * handler to recognise that the server supports Snap Start and to set + * serverHelloPredictionDataValid. */ } temp = ssl3_ConsumeHandshakeNumber(ss, 2, &b, &length); @@ -7604,6 +7610,12 @@ ssl3_HandleNewSessionTicket(sslSocket *ss, SSL3Opaque *b, PRUint32 length) return SECFailure; /* malformed */ } + if (ss->sec.ci.sid->peerCert == NULL) { + ss->sec.ci.sid->peerCert = CERT_DupCertificate(ss->sec.peerCert); + ssl3_CopyPeerCertsToSID((ssl3CertNode *)ss->ssl3.peerCertChain, + ss->sec.ci.sid); + } + rv = ssl3_SetSIDSessionTicket(ss->sec.ci.sid, &session_ticket); if (rv != SECSuccess) { (void)SSL3_SendAlert(ss, alert_fatal, handshake_failure); @@ -7795,7 +7807,7 @@ ssl3_CleanupPeerCerts(sslSocket *ss) ss->ssl3.peerCertChain = NULL; } -static void +void ssl3_CopyPeerCertsFromSID(sslSocket *ss, sslSessionID *sid) { PRArenaPool *arena; @@ -8246,7 +8258,7 @@ ssl3_ComputeTLSFinished(ssl3CipherSpec *spec, /* called from ssl3_HandleServerHelloDone */ -static SECStatus +SECStatus ssl3_SendNextProto(sslSocket *ss) { SECStatus rv; diff --git a/net/third_party/nss/ssl/ssl3ext.c b/net/third_party/nss/ssl/ssl3ext.c index 648389f..a7ae062 100644 --- a/net/third_party/nss/ssl/ssl3ext.c +++ b/net/third_party/nss/ssl/ssl3ext.c @@ -578,7 +578,7 @@ ssl3_ValidateNextProtoNego(const unsigned char* data, unsigned short length) SECStatus ssl3_ClientHandleNextProtoNegoXtn(sslSocket *ss, PRUint16 ex_type, - SECItem *data) + SECItem *data) { unsigned int i, j; SECStatus rv; diff --git a/net/third_party/nss/ssl/sslimpl.h b/net/third_party/nss/ssl/sslimpl.h index 487d658..f708696 100644 --- a/net/third_party/nss/ssl/sslimpl.h +++ b/net/third_party/nss/ssl/sslimpl.h @@ -846,6 +846,7 @@ struct ssl3StateStr { CERTCertificate ** predictedCertChain; /* An array terminated with a NULL. */ SECItem serverHelloPredictionData; + PRBool serverHelloPredictionDataValid; /* data needed to predict the ServerHello from * this server. */ SECItem snapStartApplicationData; @@ -1287,6 +1288,7 @@ extern sslSessionID *ssl3_NewSessionID(sslSocket *ss, PRBool is_server); extern sslSessionID *ssl_LookupSID(const PRIPv6Addr *addr, PRUint16 port, const char *peerID, const char *urlSvrName); extern void ssl_FreeSID(sslSessionID *sid); +extern void ssl3_CopyPeerCertsFromSID(sslSocket *ss, sslSessionID *sid); extern int ssl3_SendApplicationData(sslSocket *ss, const PRUint8 *in, int len, int flags); @@ -1542,6 +1544,7 @@ extern void ssl3_CleanupPredictedPeerCertificates(sslSocket *ss); extern const ssl3CipherSuiteDef* ssl_LookupCipherSuiteDef(ssl3CipherSuite suite); extern SECStatus ssl3_SetupPendingCipherSpec(sslSocket *ss); extern SECStatus ssl3_SendClientKeyExchange(sslSocket *ss); +extern SECStatus ssl3_SendNextProto(sslSocket *ss); extern SECStatus ssl3_SendFinished(sslSocket *ss, PRInt32 flags); extern SECStatus ssl3_CompressMACEncryptRecord (sslSocket * ss, |