diff options
Diffstat (limited to 'chromium/net/third_party/nss')
29 files changed, 2786 insertions, 614 deletions
diff --git a/chromium/net/third_party/nss/README.chromium b/chromium/net/third_party/nss/README.chromium index 4a0f2d3ec19..8c4e008c70c 100644 --- a/chromium/net/third_party/nss/README.chromium +++ b/chromium/net/third_party/nss/README.chromium @@ -57,6 +57,7 @@ Patches: * Add support for TLS Channel IDs patches/channelid.patch + patches/channelid2.patch * Add support for extracting the tls-unique channel binding value patches/tlsunique.patch @@ -108,10 +109,13 @@ Patches: libraries at run time. patches/aesgcmchromium.patch - * Prefer to generate SHA-1 signatures for TLS 1.2 client authentication if - the client private key is in a CAPI service provider on Windows or if the - client private key is a 1024-bit RSA or DSA key. + * Support generating SHA-1 signatures for TLS 1.2 client authentication. Use + SHA-1 instead of SHA-256 if the server's preferences do not allow for + SHA-256 or if the client private key may only support SHA-1 signatures. The + latter happens when the key is in a CAPI service provider on Windows or if + it is a 1024-bit RSA or DSA key. patches/tls12backuphash.patch + patches/tls12backuphash2.patch * Support ChaCha20+Poly1305 ciphersuites http://tools.ietf.org/html/draft-agl-tls-chacha20poly1305-01 @@ -139,6 +143,36 @@ Patches: https://bugzilla.mozilla.org/show_bug.cgi?id=934016 patches/nullcipher_934016.patch + * In the case that a ClientHello record is between 256 and 511 bytes long, + add an extension to make it 512 bytes. This works around a bug in F5 + terminators. + patches/paddingextension.patch + patches/paddingextensionall.patch + + * Support the Certificate Transparency (RFC 6962) TLS extension + signed_certificate_timestamp (client only). + patches/signedcertificatetimestamps.patch + + * Add a function to allow the cipher suites preference order to be set. + patches/cipherorder.patch + + * Add TLS_FALLBACK_SCSV cipher suite to version fallback connections. + patches/fallbackscsv.patch + + * Disable session ticket renewal. + https://bugzilla.mozilla.org/show_bug.cgi?id=930857 + patches/disableticketrenewal.patch + + * Add explicit functions for managing the SSL/TLS session cache. + This is a temporary workaround until Chromium migrates to NSS's + asynchronous certificate verification. + patches/sessioncache.patch + + * Remove static storage qualifier from variables in sslnonce.c. Due to + a clang codegen bug on Mac, this caused an infinite loop. + https://code.google.com/p/chromium/issues/detail?id=326011 + patches/sslnoncestatics.patch + Apply the patches to NSS by running the patches/applypatches.sh script. Read the comments at the top of patches/applypatches.sh for instructions. diff --git a/chromium/net/third_party/nss/patches/applypatches.sh b/chromium/net/third_party/nss/patches/applypatches.sh index 947cf5e1b57..89d97bc922f 100755 --- a/chromium/net/third_party/nss/patches/applypatches.sh +++ b/chromium/net/third_party/nss/patches/applypatches.sh @@ -65,3 +65,23 @@ patch -p4 < $patches_dir/peercertchain2.patch patch -p4 < $patches_dir/canfalsestart.patch patch -p4 < $patches_dir/nullcipher_934016.patch + +patch -p4 < $patches_dir/paddingextension.patch + +patch -p4 < $patches_dir/paddingextensionall.patch + +patch -p4 < $patches_dir/channelid2.patch + +patch -p5 < $patches_dir/signedcertificatetimestamps.patch + +patch -p4 < $patches_dir/cipherorder.patch + +patch -p5 < $patches_dir/tls12backuphash2.patch + +patch -p4 < $patches_dir/fallbackscsv.patch + +patch -p4 < $patches_dir/disableticketrenewal.patch + +patch -p4 < $patches_dir/sessioncache.patch + +patch -p4 < $patches_dir/sslnoncestatics.patch diff --git a/chromium/net/third_party/nss/patches/canfalsestart.patch b/chromium/net/third_party/nss/patches/canfalsestart.patch index d2a9752c070..a3fb1813d21 100644 --- a/chromium/net/third_party/nss/patches/canfalsestart.patch +++ b/chromium/net/third_party/nss/patches/canfalsestart.patch @@ -1,8 +1,8 @@ Index: net/third_party/nss/ssl/ssl.h =================================================================== ---- net/third_party/nss/ssl/ssl.h (revision 227363) +--- net/third_party/nss/ssl/ssl.h (revision 227672) +++ net/third_party/nss/ssl/ssl.h (working copy) -@@ -121,14 +121,22 @@ +@@ -121,14 +121,17 @@ #define SSL_ENABLE_FALSE_START 22 /* Enable SSL false start (off by */ /* default, applies only to */ /* clients). False start is a */ @@ -22,62 +22,42 @@ Index: net/third_party/nss/ssl/ssl.h + * it saves a round trip for client-speaks-first protocols when performing a + * full handshake. + * -+ * See SSL_DefaultCanFalseStart for the default criteria that NSS uses to -+ * determine whether to false start or not. See SSL_SetCanFalseStartCallback -+ * for how to change that criteria. In addition to those criteria, false start -+ * will only be done when the server selects a cipher suite with an effective -+ * key length of 80 bits or more (including RC4-128). Also, see -+ * SSL_HandshakeCallback for a description on how false start affects when the -+ * handshake callback gets called. ++ * In addition to enabling this option, the application must register a ++ * callback using the SSL_SetCanFalseStartCallback function. + */ /* For SSL 3.0 and TLS 1.0, by default we prevent chosen plaintext attacks * on SSL CBC mode cipher suites (see RFC 4346 Section F.3) by splitting -@@ -741,14 +749,59 @@ +@@ -741,14 +744,45 @@ SSL_IMPORT SECStatus SSL_InheritMPServerSIDCache(const char * envString); /* -** Set the callback on a particular socket that gets called when we finish -** performing a handshake. -+** Set the callback that normally gets called when the TLS handshake -+** is complete. If false start is not enabled, then the handshake callback is -+** called after verifying the peer's Finished message and before sending -+** outgoing application data and before processing incoming application data. ++** Set the callback that gets called when a TLS handshake is complete. The ++** handshake callback is called after verifying the peer's Finished message and ++** before processing incoming application data. +** -+** If false start is enabled and there is a custom CanFalseStartCallback -+** callback set, then the handshake callback gets called after the peer's -+** Finished message has been verified, which may be after application data is -+** sent. -+** -+** If false start is enabled and there is not a custom CanFalseStartCallback -+** callback established with SSL_SetCanFalseStartCallback then the handshake -+** callback gets called before any application data is sent, which may be -+** before the peer's Finished message has been verified. ++** For the initial handshake: If the handshake false started (see ++** SSL_ENABLE_FALSE_START), then application data may already have been sent ++** before the handshake callback is called. If we did not false start then the ++** callback will get called before any application data is sent. */ typedef void (PR_CALLBACK *SSLHandshakeCallback)(PRFileDesc *fd, void *client_data); SSL_IMPORT SECStatus SSL_HandshakeCallback(PRFileDesc *fd, SSLHandshakeCallback cb, void *client_data); -+/* Applications that wish to customize TLS false start should set this callback ++/* Applications that wish to enable TLS false start must set this callback +** function. NSS will invoke the functon to determine if a particular +** connection should use false start or not. SECSuccess indicates that the +** callback completed successfully, and if so *canFalseStart indicates if false +** start can be used. If the callback does not return SECSuccess then the -+** handshake will be canceled. -+** -+** Applications that do not set the callback will use an internal set of -+** criteria to determine if the connection should false start. If -+** the callback is set false start will never be used without invoking the -+** callback function, but some connections (e.g. resumed connections) will -+** never use false start and therefore will not invoke the callback. -+** -+** NSS's internal criteria for this connection can be evaluated by calling -+** SSL_DefaultCanFalseStart() from the custom callback. ++** handshake will be canceled. NSS's recommended criteria can be evaluated by ++** calling SSL_RecommendedCanFalseStart. +** -+** See the description of SSL_HandshakeCallback for important information on -+** how registering a custom false start callback affects when the handshake -+** callback gets called. ++** If no false start callback is registered then false start will never be ++** done, even if the SSL_ENABLE_FALSE_START option is enabled. +**/ +typedef SECStatus (PR_CALLBACK *SSLCanFalseStartCallback)( + PRFileDesc *fd, void *arg, PRBool *canFalseStart); @@ -85,62 +65,420 @@ Index: net/third_party/nss/ssl/ssl.h +SSL_IMPORT SECStatus SSL_SetCanFalseStartCallback( + PRFileDesc *fd, SSLCanFalseStartCallback callback, void *arg); + -+/* A utility function that can be called from a custom CanFalseStartCallback -+** function to determine what NSS would have done for this connection if the -+** custom callback was not implemented. -+**/ -+SSL_IMPORT SECStatus SSL_DefaultCanFalseStart(PRFileDesc *fd, -+ PRBool *canFalseStart); ++/* This function sets *canFalseStart according to the recommended criteria for ++** false start. These criteria may change from release to release and may depend ++** on which handshake features have been negotiated and/or properties of the ++** certifciates/keys used on the connection. ++*/ ++SSL_IMPORT SECStatus SSL_RecommendedCanFalseStart(PRFileDesc *fd, ++ PRBool *canFalseStart); + /* ** For the server, request a new handshake. For the client, begin a new ** handshake. If flushCache is non-zero, the SSL3 cache entry will be +Index: net/third_party/nss/ssl/ssl3con.c +=================================================================== +--- net/third_party/nss/ssl/ssl3con.c (revision 227672) ++++ net/third_party/nss/ssl/ssl3con.c (working copy) +@@ -2890,7 +2890,7 @@ + SSL_TRC(3, ("%d: SSL3[%d] SendRecord type: %s nIn=%d", + SSL_GETPID(), ss->fd, ssl3_DecodeContentType(type), + nIn)); +- PRINT_BUF(3, (ss, "Send record (plain text)", pIn, nIn)); ++ PRINT_BUF(50, (ss, "Send record (plain text)", pIn, nIn)); + + PORT_Assert( ss->opt.noLocks || ssl_HaveXmitBufLock(ss) ); + +@@ -7344,36 +7344,72 @@ + return rv; + } + ++static SECStatus ++ssl3_CheckFalseStart(sslSocket *ss) ++{ ++ PORT_Assert( ss->opt.noLocks || ssl_HaveSSL3HandshakeLock(ss) ); ++ PORT_Assert( !ss->ssl3.hs.authCertificatePending ); ++ PORT_Assert( !ss->ssl3.hs.canFalseStart ); ++ ++ if (!ss->canFalseStartCallback) { ++ SSL_TRC(3, ("%d: SSL[%d]: no false start callback so no false start", ++ SSL_GETPID(), ss->fd)); ++ } else { ++ PRBool maybeFalseStart; ++ SECStatus rv; ++ ++ /* An attacker can control the selected ciphersuite so we only wish to ++ * do False Start in the case that the selected ciphersuite is ++ * sufficiently strong that the attack can gain no advantage. ++ * Therefore we always require an 80-bit cipher. */ ++ ssl_GetSpecReadLock(ss); ++ maybeFalseStart = ss->ssl3.cwSpec->cipher_def->secret_key_size >= 10; ++ ssl_ReleaseSpecReadLock(ss); ++ ++ if (!maybeFalseStart) { ++ SSL_TRC(3, ("%d: SSL[%d]: no false start due to weak cipher", ++ SSL_GETPID(), ss->fd)); ++ } else { ++ rv = (ss->canFalseStartCallback)(ss->fd, ++ ss->canFalseStartCallbackData, ++ &ss->ssl3.hs.canFalseStart); ++ if (rv == SECSuccess) { ++ SSL_TRC(3, ("%d: SSL[%d]: false start callback returned %s", ++ SSL_GETPID(), ss->fd, ++ ss->ssl3.hs.canFalseStart ? "TRUE" : "FALSE")); ++ } else { ++ SSL_TRC(3, ("%d: SSL[%d]: false start callback failed (%s)", ++ SSL_GETPID(), ss->fd, ++ PR_ErrorToName(PR_GetError()))); ++ } ++ return rv; ++ } ++ } ++ ++ ss->ssl3.hs.canFalseStart = PR_FALSE; ++ return SECSuccess; ++} ++ + PRBool +-ssl3_CanFalseStart(sslSocket *ss) { +- PRBool rv; ++ssl3_WaitingForStartOfServerSecondRound(sslSocket *ss) ++{ ++ PRBool result; + + PORT_Assert( ss->opt.noLocks || ssl_HaveSSL3HandshakeLock(ss) ); + +- /* XXX: does not take into account whether we are waiting for +- * SSL_AuthCertificateComplete or SSL_RestartHandshakeAfterCertReq. If/when +- * that is done, this function could return different results each time it +- * would be called. +- */ ++ switch (ss->ssl3.hs.ws) { ++ case wait_new_session_ticket: ++ result = PR_TRUE; ++ break; ++ case wait_change_cipher: ++ result = !ssl3_ExtensionNegotiated(ss, ssl_session_ticket_xtn); ++ break; ++ default: ++ result = PR_FALSE; ++ break; ++ } + +- ssl_GetSpecReadLock(ss); +- rv = ss->opt.enableFalseStart && +- !ss->sec.isServer && +- !ss->ssl3.hs.isResuming && +- ss->ssl3.cwSpec && +- +- /* An attacker can control the selected ciphersuite so we only wish to +- * do False Start in the case that the selected ciphersuite is +- * sufficiently strong that the attack can gain no advantage. +- * Therefore we require an 80-bit cipher and a forward-secret key +- * exchange. */ +- ss->ssl3.cwSpec->cipher_def->secret_key_size >= 10 && +- (ss->ssl3.hs.kea_def->kea == kea_dhe_dss || +- ss->ssl3.hs.kea_def->kea == kea_dhe_rsa || +- ss->ssl3.hs.kea_def->kea == kea_ecdhe_ecdsa || +- ss->ssl3.hs.kea_def->kea == kea_ecdhe_rsa); +- ssl_ReleaseSpecReadLock(ss); +- return rv; ++ return result; + } + + static SECStatus ssl3_SendClientSecondRound(sslSocket *ss); +@@ -7463,6 +7499,9 @@ + } + if (ss->ssl3.hs.authCertificatePending && + (sendClientCert || ss->ssl3.sendEmptyCert || ss->firstHsDone)) { ++ SSL_TRC(3, ("%d: SSL3[%p]: deferring ssl3_SendClientSecondRound because" ++ " certificate authentication is still pending.", ++ SSL_GETPID(), ss->fd)); + ss->ssl3.hs.restartTarget = ssl3_SendClientSecondRound; + return SECWouldBlock; + } +@@ -7500,20 +7539,59 @@ + goto loser; /* err code was set. */ + } + +- /* XXX: If the server's certificate hasn't been authenticated by this +- * point, then we may be leaking this NPN message to an attacker. ++ /* This must be done after we've set ss->ssl3.cwSpec in ++ * ssl3_SendChangeCipherSpecs because SSL_GetChannelInfo uses information ++ * from cwSpec. This must be done before we call ssl3_CheckFalseStart ++ * because the false start callback (if any) may need the information from ++ * the functions that depend on this being set. + */ ++ ss->enoughFirstHsDone = PR_TRUE; ++ + if (!ss->firstHsDone) { ++ /* XXX: If the server's certificate hasn't been authenticated by this ++ * point, then we may be leaking this NPN message to an attacker. ++ */ + rv = ssl3_SendNextProto(ss); + if (rv != SECSuccess) { + goto loser; /* err code was set. */ + } + } ++ + rv = ssl3_SendEncryptedExtensions(ss); + if (rv != SECSuccess) { + goto loser; /* err code was set. */ + } + ++ if (!ss->firstHsDone) { ++ if (ss->opt.enableFalseStart) { ++ if (!ss->ssl3.hs.authCertificatePending) { ++ /* When we fix bug 589047, we will need to know whether we are ++ * false starting before we try to flush the client second ++ * round to the network. With that in mind, we purposefully ++ * call ssl3_CheckFalseStart before calling ssl3_SendFinished, ++ * which includes a call to ssl3_FlushHandshake, so that ++ * no application develops a reliance on such flushing being ++ * done before its false start callback is called. ++ */ ++ ssl_ReleaseXmitBufLock(ss); ++ rv = ssl3_CheckFalseStart(ss); ++ ssl_GetXmitBufLock(ss); ++ if (rv != SECSuccess) { ++ goto loser; ++ } ++ } else { ++ /* The certificate authentication and the server's Finished ++ * message are racing each other. If the certificate ++ * authentication wins, then we will try to false start in ++ * ssl3_AuthCertificateComplete. ++ */ ++ SSL_TRC(3, ("%d: SSL3[%p]: deferring false start check because" ++ " certificate authentication is still pending.", ++ SSL_GETPID(), ss->fd)); ++ } ++ } ++ } ++ + rv = ssl3_SendFinished(ss, 0); + if (rv != SECSuccess) { + goto loser; /* err code was set. */ +@@ -7526,10 +7604,7 @@ + else + ss->ssl3.hs.ws = wait_change_cipher; + +- /* Do the handshake callback for sslv3 here, if we can false start. */ +- if (ss->handshakeCallback != NULL && ssl3_CanFalseStart(ss)) { +- (ss->handshakeCallback)(ss->fd, ss->handshakeCallbackData); +- } ++ PORT_Assert(ssl3_WaitingForStartOfServerSecondRound(ss)); + + return SECSuccess; + +@@ -10147,13 +10222,6 @@ + + ss->ssl3.hs.authCertificatePending = PR_TRUE; + rv = SECSuccess; +- +- /* XXX: Async cert validation and False Start don't work together +- * safely yet; if we leave False Start enabled, we may end up false +- * starting (sending application data) before we +- * SSL_AuthCertificateComplete has been called. +- */ +- ss->opt.enableFalseStart = PR_FALSE; + } + + if (rv != SECSuccess) { +@@ -10278,6 +10346,12 @@ + } else if (ss->ssl3.hs.restartTarget != NULL) { + sslRestartTarget target = ss->ssl3.hs.restartTarget; + ss->ssl3.hs.restartTarget = NULL; ++ ++ if (target == ssl3_FinishHandshake) { ++ SSL_TRC(3,("%d: SSL3[%p]: certificate authentication lost the race" ++ " with peer's finished message", SSL_GETPID(), ss->fd)); ++ } ++ + rv = target(ss); + /* Even if we blocked here, we have accomplished enough to claim + * success. Any remaining work will be taken care of by subsequent +@@ -10287,7 +10361,27 @@ + rv = SECSuccess; + } + } else { +- rv = SECSuccess; ++ SSL_TRC(3, ("%d: SSL3[%p]: certificate authentication won the race with" ++ " peer's finished message", SSL_GETPID(), ss->fd)); ++ ++ PORT_Assert(!ss->firstHsDone); ++ PORT_Assert(!ss->sec.isServer); ++ PORT_Assert(!ss->ssl3.hs.isResuming); ++ PORT_Assert(ss->ssl3.hs.ws != idle_handshake); ++ ++ if (ss->opt.enableFalseStart && ++ !ss->firstHsDone && ++ !ss->sec.isServer && ++ !ss->ssl3.hs.isResuming && ++ ssl3_WaitingForStartOfServerSecondRound(ss)) { ++ /* ssl3_SendClientSecondRound deferred the false start check because ++ * certificate authentication was pending, so we do it now if we still ++ * haven't received any of the server's second round yet. ++ */ ++ rv = ssl3_CheckFalseStart(ss); ++ } else { ++ rv = SECSuccess; ++ } + } + + done: +@@ -10913,9 +11007,6 @@ + return rv; + } + +- ss->gs.writeOffset = 0; +- ss->gs.readOffset = 0; +- + if (ss->ssl3.hs.kea_def->kea == kea_ecdhe_rsa) { + effectiveExchKeyType = kt_rsa; + } else { +@@ -10980,6 +11071,9 @@ + return rv; + } + ++/* The return type is SECStatus instead of void because this function needs ++ * to have type sslRestartTarget. ++ */ + SECStatus + ssl3_FinishHandshake(sslSocket * ss) + { +@@ -10989,19 +11083,16 @@ + + /* The first handshake is now completed. */ + ss->handshake = NULL; +- ss->firstHsDone = PR_TRUE; + + if (ss->ssl3.hs.cacheSID) { + (*ss->sec.cache)(ss->sec.ci.sid); + ss->ssl3.hs.cacheSID = PR_FALSE; + } + ++ ss->ssl3.hs.canFalseStart = PR_FALSE; /* False Start phase is complete */ + ss->ssl3.hs.ws = idle_handshake; + +- /* Do the handshake callback for sslv3 here, if we cannot false start. */ +- if (ss->handshakeCallback != NULL && !ssl3_CanFalseStart(ss)) { +- (ss->handshakeCallback)(ss->fd, ss->handshakeCallbackData); +- } ++ ssl_FinishHandshake(ss); + + return SECSuccess; + } +@@ -11966,7 +12057,6 @@ + + ssl_ReleaseSSL3HandshakeLock(ss); + return rv; +- + } + + /* Index: net/third_party/nss/ssl/ssl3gthr.c =================================================================== ---- net/third_party/nss/ssl/ssl3gthr.c (revision 227363) +--- net/third_party/nss/ssl/ssl3gthr.c (revision 227672) +++ net/third_party/nss/ssl/ssl3gthr.c (working copy) -@@ -374,9 +374,7 @@ - */ - if (ss->opt.enableFalseStart) { - ssl_GetSSL3HandshakeLock(ss); +@@ -275,11 +275,17 @@ + { + SSL3Ciphertext cText; + int rv; +- PRBool canFalseStart = PR_FALSE; ++ PRBool keepGoing = PR_TRUE; + + SSL_TRC(30, ("ssl3_GatherCompleteHandshake")); + ++ /* ssl3_HandleRecord may end up eventually calling ssl_FinishHandshake, ++ * which requires the 1stHandshakeLock, which must be acquired before the ++ * RecvBufLock. ++ */ ++ PORT_Assert( ss->opt.noLocks || ssl_Have1stHandshakeLock(ss) ); + PORT_Assert( ss->opt.noLocks || ssl_HaveRecvBufLock(ss) ); ++ + do { + PRBool handleRecordNow = PR_FALSE; + +@@ -364,24 +370,52 @@ + + cText.buf = &ss->gs.inbuf; + rv = ssl3_HandleRecord(ss, &cText, &ss->gs.buf); ++ ++ if (rv == (int) SECSuccess && ss->gs.buf.len > 0) { ++ /* We have application data to return to the application. This ++ * prioritizes returning application data to the application over ++ * completing any renegotiation handshake we may be doing. ++ */ ++ PORT_Assert(ss->firstHsDone); ++ PORT_Assert(cText.type == content_application_data); ++ break; ++ } + } + if (rv < 0) { + return ss->recvdCloseNotify ? 0 : rv; + } + +- /* If we kicked off a false start in ssl3_HandleServerHelloDone, break +- * out of this loop early without finishing the handshake. +- */ +- if (ss->opt.enableFalseStart) { +- ssl_GetSSL3HandshakeLock(ss); - canFalseStart = (ss->ssl3.hs.ws == wait_change_cipher || - ss->ssl3.hs.ws == wait_new_session_ticket) && - ssl3_CanFalseStart(ss); -+ canFalseStart = ss->ssl3.hs.canFalseStart; - ssl_ReleaseSSL3HandshakeLock(ss); +- ssl_ReleaseSSL3HandshakeLock(ss); ++ PORT_Assert(keepGoing); ++ ssl_GetSSL3HandshakeLock(ss); ++ if (ss->ssl3.hs.ws == idle_handshake) { ++ /* We are done with the current handshake so stop trying to ++ * handshake. Note that it would be safe to test ss->firstHsDone ++ * instead of ss->ssl3.hs.ws. By testing ss->ssl3.hs.ws instead, ++ * we prioritize completing a renegotiation handshake over sending ++ * application data. ++ */ ++ PORT_Assert(ss->firstHsDone); ++ PORT_Assert(!ss->ssl3.hs.canFalseStart); ++ keepGoing = PR_FALSE; ++ } else if (ss->ssl3.hs.canFalseStart) { ++ /* Prioritize sending application data over trying to complete ++ * the handshake if we're false starting. ++ * ++ * If we were to do this check at the beginning of the loop instead ++ * of here, then this function would become be a no-op after ++ * receiving the ServerHelloDone in the false start case, and we ++ * would never complete the handshake. ++ */ ++ PORT_Assert(!ss->firstHsDone); ++ ++ if (ssl3_WaitingForStartOfServerSecondRound(ss)) { ++ keepGoing = PR_FALSE; ++ } else { ++ ss->ssl3.hs.canFalseStart = PR_FALSE; ++ } } - } while (ss->ssl3.hs.ws != idle_handshake && -Index: net/third_party/nss/ssl/sslinfo.c -=================================================================== ---- net/third_party/nss/ssl/sslinfo.c (revision 227363) -+++ net/third_party/nss/ssl/sslinfo.c (working copy) -@@ -26,7 +26,6 @@ - sslSocket * ss; - SSLChannelInfo inf; - sslSessionID * sid; -- PRBool enoughFirstHsDone = PR_FALSE; - - if (!info || len < sizeof inf.length) { - PORT_SetError(SEC_ERROR_INVALID_ARGS); -@@ -43,14 +42,7 @@ - memset(&inf, 0, sizeof inf); - inf.length = PR_MIN(sizeof inf, len); +- } while (ss->ssl3.hs.ws != idle_handshake && +- !canFalseStart && +- ss->gs.buf.len == 0); ++ ssl_ReleaseSSL3HandshakeLock(ss); ++ } while (keepGoing); + + ss->gs.readOffset = 0; + ss->gs.writeOffset = ss->gs.buf.len; +@@ -404,7 +438,10 @@ + { + int rv; -- if (ss->firstHsDone) { -- enoughFirstHsDone = PR_TRUE; -- } else if (ss->version >= SSL_LIBRARY_VERSION_3_0 && -- ssl3_CanFalseStart(ss)) { -- enoughFirstHsDone = PR_TRUE; -- } -- -- if (ss->opt.useSecurity && enoughFirstHsDone) { -+ if (ss->opt.useSecurity && ss->enoughFirstHsDone) { - sid = ss->sec.ci.sid; - inf.protocolVersion = ss->version; - inf.authKeyBits = ss->sec.authKeyBits; ++ /* ssl3_GatherCompleteHandshake requires both of these locks. */ ++ PORT_Assert( ss->opt.noLocks || ssl_Have1stHandshakeLock(ss) ); + PORT_Assert( ss->opt.noLocks || ssl_HaveRecvBufLock(ss) ); ++ + do { + rv = ssl3_GatherCompleteHandshake(ss, flags); + } while (rv > 0 && ss->gs.buf.len == 0); Index: net/third_party/nss/ssl/sslauth.c =================================================================== ---- net/third_party/nss/ssl/sslauth.c (revision 227363) +--- net/third_party/nss/ssl/sslauth.c (revision 227672) +++ net/third_party/nss/ssl/sslauth.c (working copy) @@ -100,7 +100,6 @@ sslSocket *ss; @@ -168,7 +506,7 @@ Index: net/third_party/nss/ssl/sslauth.c } else { Index: net/third_party/nss/ssl/sslimpl.h =================================================================== ---- net/third_party/nss/ssl/sslimpl.h (revision 227363) +--- net/third_party/nss/ssl/sslimpl.h (revision 227672) +++ net/third_party/nss/ssl/sslimpl.h (working copy) @@ -881,6 +881,8 @@ /* Shared state between ssl3_HandleFinished and ssl3_FinishHandshake */ @@ -199,28 +537,69 @@ Index: net/third_party/nss/ssl/sslimpl.h void *pkcs11PinArg; SSLNextProtoCallback nextProtoCallback; void *nextProtoArg; -@@ -1423,7 +1431,6 @@ +@@ -1423,7 +1431,19 @@ extern SECStatus ssl_EnableNagleDelay(sslSocket *ss, PRBool enabled); -extern PRBool ssl3_CanFalseStart(sslSocket *ss); ++extern void ssl_FinishHandshake(sslSocket *ss); ++ ++/* Returns PR_TRUE if we are still waiting for the server to respond to our ++ * client second round. Once we've received any part of the server's second ++ * round then we don't bother trying to false start since it is almost always ++ * the case that the NewSessionTicket, ChangeCipherSoec, and Finished messages ++ * were sent in the same packet and we want to process them all at the same ++ * time. If we were to try to false start in the middle of the server's second ++ * round, then we would increase the number of I/O operations ++ * (SSL_ForceHandshake/PR_Recv/PR_Send/etc.) needed to finish the handshake. ++ */ ++extern PRBool ssl3_WaitingForStartOfServerSecondRound(sslSocket *ss); ++ extern SECStatus ssl3_CompressMACEncryptRecord(ssl3CipherSpec * cwSpec, PRBool isServer, +Index: net/third_party/nss/ssl/sslinfo.c +=================================================================== +--- net/third_party/nss/ssl/sslinfo.c (revision 227672) ++++ net/third_party/nss/ssl/sslinfo.c (working copy) +@@ -26,7 +26,6 @@ + sslSocket * ss; + SSLChannelInfo inf; + sslSessionID * sid; +- PRBool enoughFirstHsDone = PR_FALSE; + + if (!info || len < sizeof inf.length) { + PORT_SetError(SEC_ERROR_INVALID_ARGS); +@@ -43,14 +42,7 @@ + memset(&inf, 0, sizeof inf); + inf.length = PR_MIN(sizeof inf, len); + +- if (ss->firstHsDone) { +- enoughFirstHsDone = PR_TRUE; +- } else if (ss->version >= SSL_LIBRARY_VERSION_3_0 && +- ssl3_CanFalseStart(ss)) { +- enoughFirstHsDone = PR_TRUE; +- } +- +- if (ss->opt.useSecurity && enoughFirstHsDone) { ++ if (ss->opt.useSecurity && ss->enoughFirstHsDone) { + sid = ss->sec.ci.sid; + inf.protocolVersion = ss->version; + inf.authKeyBits = ss->sec.authKeyBits; Index: net/third_party/nss/ssl/sslsecur.c =================================================================== ---- net/third_party/nss/ssl/sslsecur.c (revision 227363) +--- net/third_party/nss/ssl/sslsecur.c (revision 227672) +++ net/third_party/nss/ssl/sslsecur.c (working copy) -@@ -99,21 +99,12 @@ +@@ -97,23 +97,13 @@ + ss->securityHandshake = 0; + } if (ss->handshake == 0) { - ssl_GetRecvBufLock(ss); - ss->gs.recordLen = 0; -+ ss->gs.writeOffset = 0; -+ ss->gs.readOffset = 0; - ssl_ReleaseRecvBufLock(ss); - - SSL_TRC(3, ("%d: SSL[%d]: handshake is completed", - SSL_GETPID(), ss->fd)); +- ssl_GetRecvBufLock(ss); +- ss->gs.recordLen = 0; +- ssl_ReleaseRecvBufLock(ss); +- +- SSL_TRC(3, ("%d: SSL[%d]: handshake is completed", +- SSL_GETPID(), ss->fd)); - /* call handshake callback for ssl v2 */ - /* for v3 this is done in ssl3_HandleFinished() */ - if ((ss->handshakeCallback != NULL) && /* has callback */ @@ -228,14 +607,45 @@ Index: net/third_party/nss/ssl/sslsecur.c - (ss->version < SSL_LIBRARY_VERSION_3_0)) { /* not ssl3 */ - ss->firstHsDone = PR_TRUE; - (ss->handshakeCallback)(ss->fd, ss->handshakeCallbackData); -- } ++ /* for v3 this is done in ssl3_FinishHandshake */ ++ if (!ss->firstHsDone && ss->version < SSL_LIBRARY_VERSION_3_0) { ++ ssl_GetRecvBufLock(ss); ++ ss->gs.recordLen = 0; ++ ssl_FinishHandshake(ss); ++ ssl_ReleaseRecvBufLock(ss); + } - ss->firstHsDone = PR_TRUE; - ss->gs.writeOffset = 0; - ss->gs.readOffset = 0; break; } rv = (*ss->handshake)(ss); -@@ -206,6 +197,7 @@ +@@ -134,6 +124,24 @@ + return rv; + } + ++void ++ssl_FinishHandshake(sslSocket *ss) ++{ ++ PORT_Assert( ss->opt.noLocks || ssl_Have1stHandshakeLock(ss) ); ++ PORT_Assert( ss->opt.noLocks || ssl_HaveRecvBufLock(ss) ); ++ ++ SSL_TRC(3, ("%d: SSL[%d]: handshake is completed", SSL_GETPID(), ss->fd)); ++ ++ ss->firstHsDone = PR_TRUE; ++ ss->enoughFirstHsDone = PR_TRUE; ++ ss->gs.writeOffset = 0; ++ ss->gs.readOffset = 0; ++ ++ if (ss->handshakeCallback) { ++ (ss->handshakeCallback)(ss->fd, ss->handshakeCallbackData); ++ } ++} ++ + /* + * Handshake function that blocks. Used to force a + * retry on a connection on the next read/write. +@@ -206,6 +214,7 @@ ssl_Get1stHandshakeLock(ss); ss->firstHsDone = PR_FALSE; @@ -243,7 +653,7 @@ Index: net/third_party/nss/ssl/sslsecur.c if ( asServer ) { ss->handshake = ssl2_BeginServerHandshake; ss->handshaking = sslHandshakingAsServer; -@@ -221,6 +213,8 @@ +@@ -221,6 +230,8 @@ ssl_ReleaseRecvBufLock(ss); ssl_GetSSL3HandshakeLock(ss); @@ -252,16 +662,7 @@ Index: net/third_party/nss/ssl/sslsecur.c /* ** Blow away old security state and get a fresh setup. -@@ -266,7 +260,7 @@ - - /* SSL v2 protocol does not support subsequent handshakes. */ - if (ss->version < SSL_LIBRARY_VERSION_3_0) { -- PORT_SetError(SEC_ERROR_INVALID_ARGS); -+ PORT_SetError(SSL_ERROR_FEATURE_NOT_SUPPORTED_FOR_SSL2); - rv = SECFailure; - } else { - ssl_GetSSL3HandshakeLock(ss); -@@ -331,6 +325,75 @@ +@@ -331,6 +342,71 @@ return SECSuccess; } @@ -270,7 +671,7 @@ Index: net/third_party/nss/ssl/sslsecur.c +*/ +SECStatus +SSL_SetCanFalseStartCallback(PRFileDesc *fd, SSLCanFalseStartCallback cb, -+ void *client_data) ++ void *arg) +{ + sslSocket *ss; + @@ -290,7 +691,7 @@ Index: net/third_party/nss/ssl/sslsecur.c + ssl_GetSSL3HandshakeLock(ss); + + ss->canFalseStartCallback = cb; -+ ss->canFalseStartCallbackData = client_data; ++ ss->canFalseStartCallbackData = arg; + + ssl_ReleaseSSL3HandshakeLock(ss); + ssl_Release1stHandshakeLock(ss); @@ -298,19 +699,15 @@ Index: net/third_party/nss/ssl/sslsecur.c + return SECSuccess; +} + -+/* A utility function that can be called from a custom SSLCanFalseStartCallback -+** function to determine what NSS would have done for this connection if the -+** custom callback was not implemented. -+*/ +SECStatus -+SSL_DefaultCanFalseStart(PRFileDesc *fd, PRBool *canFalseStart) ++SSL_RecommendedCanFalseStart(PRFileDesc *fd, PRBool *canFalseStart) +{ + sslSocket *ss; + + *canFalseStart = PR_FALSE; + ss = ssl_FindSocket(fd); + if (!ss) { -+ SSL_DBG(("%d: SSL[%d]: bad socket in SSL_DefaultCanFalseStart", ++ SSL_DBG(("%d: SSL[%d]: bad socket in SSL_RecommendedCanFalseStart", + SSL_GETPID(), fd)); + return SECFailure; + } @@ -337,9 +734,43 @@ Index: net/third_party/nss/ssl/sslsecur.c /* Try to make progress on an SSL handshake by attempting to read the ** next handshake from the peer, and sending any responses. ** For non-blocking sockets, returns PR_ERROR_WOULD_BLOCK if it cannot -@@ -1195,12 +1258,7 @@ +@@ -524,6 +600,9 @@ + int amount; + int available; + ++ /* ssl3_GatherAppDataRecord may call ssl_FinishHandshake, which needs the ++ * 1stHandshakeLock. */ ++ ssl_Get1stHandshakeLock(ss); + ssl_GetRecvBufLock(ss); + + available = ss->gs.writeOffset - ss->gs.readOffset; +@@ -590,6 +669,7 @@ + + done: + ssl_ReleaseRecvBufLock(ss); ++ ssl_Release1stHandshakeLock(ss); + return rv; + } + +@@ -1156,7 +1236,8 @@ + int + ssl_SecureSend(sslSocket *ss, const unsigned char *buf, int len, int flags) + { +- int rv = 0; ++ int rv = 0; ++ PRBool falseStart = PR_FALSE; + + SSL_TRC(2, ("%d: SSL[%d]: SecureSend: sending %d bytes", + SSL_GETPID(), ss->fd, len)); +@@ -1191,19 +1272,14 @@ + ss->writerThread = PR_GetCurrentThread(); + /* If any of these is non-zero, the initial handshake is not done. */ + if (!ss->firstHsDone) { +- PRBool canFalseStart = PR_FALSE; ssl_Get1stHandshakeLock(ss); - if (ss->version >= SSL_LIBRARY_VERSION_3_0) { +- if (ss->version >= SSL_LIBRARY_VERSION_3_0) { ++ if (ss->opt.enableFalseStart && ++ ss->version >= SSL_LIBRARY_VERSION_3_0) { ssl_GetSSL3HandshakeLock(ss); - if ((ss->ssl3.hs.ws == wait_change_cipher || - ss->ssl3.hs.ws == wait_finished || @@ -347,15 +778,46 @@ Index: net/third_party/nss/ssl/sslsecur.c - ssl3_CanFalseStart(ss)) { - canFalseStart = PR_TRUE; - } -+ canFalseStart = ss->ssl3.hs.canFalseStart; ++ falseStart = ss->ssl3.hs.canFalseStart; ssl_ReleaseSSL3HandshakeLock(ss); } - if (!canFalseStart && +- if (!canFalseStart && ++ if (!falseStart && + (ss->handshake || ss->nextHandshake || ss->securityHandshake)) { + rv = ssl_Do1stHandshake(ss); + } +@@ -1228,6 +1304,17 @@ + goto done; + } + ++ if (!ss->firstHsDone) { ++ PORT_Assert(ss->version >= SSL_LIBRARY_VERSION_3_0); ++#ifdef DEBUG ++ ssl_GetSSL3HandshakeLock(ss); ++ PORT_Assert(ss->ssl3.hs.canFalseStart); ++ ssl_ReleaseSSL3HandshakeLock(ss); ++#endif ++ SSL_TRC(3, ("%d: SSL[%d]: SecureSend: sending data due to false start", ++ SSL_GETPID(), ss->fd)); ++ } ++ + /* Send out the data using one of these functions: + * ssl2_SendClear, ssl2_SendStream, ssl2_SendBlock, + * ssl3_SendApplicationData Index: net/third_party/nss/ssl/sslsock.c =================================================================== ---- net/third_party/nss/ssl/sslsock.c (revision 227363) +--- net/third_party/nss/ssl/sslsock.c (revision 227672) +++ net/third_party/nss/ssl/sslsock.c (working copy) -@@ -2457,10 +2457,14 @@ +@@ -366,6 +366,8 @@ + ss->badCertArg = os->badCertArg; + ss->handshakeCallback = os->handshakeCallback; + ss->handshakeCallbackData = os->handshakeCallbackData; ++ ss->canFalseStartCallback = os->canFalseStartCallback; ++ ss->canFalseStartCallbackData = os->canFalseStartCallbackData; + ss->pkcs11PinArg = os->pkcs11PinArg; + ss->getChannelID = os->getChannelID; + ss->getChannelIDArg = os->getChannelIDArg; +@@ -2457,10 +2459,14 @@ } else if (new_flags & PR_POLL_WRITE) { /* The caller is trying to write, but the handshake is ** blocked waiting for data to read, and the first @@ -373,265 +835,3 @@ Index: net/third_party/nss/ssl/sslsock.c } } } else if ((new_flags & PR_POLL_READ) && (SSL_DataPending(fd) > 0)) { -Index: net/third_party/nss/ssl/ssl3con.c -=================================================================== ---- net/third_party/nss/ssl/ssl3con.c (revision 227363) -+++ net/third_party/nss/ssl/ssl3con.c (working copy) -@@ -2890,7 +2890,7 @@ - SSL_TRC(3, ("%d: SSL3[%d] SendRecord type: %s nIn=%d", - SSL_GETPID(), ss->fd, ssl3_DecodeContentType(type), - nIn)); -- PRINT_BUF(3, (ss, "Send record (plain text)", pIn, nIn)); -+ PRINT_BUF(50, (ss, "Send record (plain text)", pIn, nIn)); - - PORT_Assert( ss->opt.noLocks || ssl_HaveXmitBufLock(ss) ); - -@@ -7344,35 +7344,42 @@ - return rv; - } - --PRBool --ssl3_CanFalseStart(sslSocket *ss) { -- PRBool rv; -+static SECStatus -+ssl3_CheckFalseStart(sslSocket *ss) -+{ -+ SECStatus rv; -+ PRBool maybeFalseStart = PR_TRUE; - - PORT_Assert( ss->opt.noLocks || ssl_HaveSSL3HandshakeLock(ss) ); -+ PORT_Assert( !ss->ssl3.hs.authCertificatePending ); - -- /* XXX: does not take into account whether we are waiting for -- * SSL_AuthCertificateComplete or SSL_RestartHandshakeAfterCertReq. If/when -- * that is done, this function could return different results each time it -- * would be called. -- */ -+ /* An attacker can control the selected ciphersuite so we only wish to -+ * do False Start in the case that the selected ciphersuite is -+ * sufficiently strong that the attack can gain no advantage. -+ * Therefore we always require an 80-bit cipher. */ - - ssl_GetSpecReadLock(ss); -- rv = ss->opt.enableFalseStart && -- !ss->sec.isServer && -- !ss->ssl3.hs.isResuming && -- ss->ssl3.cwSpec && -+ if (ss->ssl3.cwSpec->cipher_def->secret_key_size < 10) { -+ ss->ssl3.hs.canFalseStart = PR_FALSE; -+ maybeFalseStart = PR_FALSE; -+ } -+ ssl_ReleaseSpecReadLock(ss); -+ if (!maybeFalseStart) { -+ return SECSuccess; -+ } - -- /* An attacker can control the selected ciphersuite so we only wish to -- * do False Start in the case that the selected ciphersuite is -- * sufficiently strong that the attack can gain no advantage. -- * Therefore we require an 80-bit cipher and a forward-secret key -- * exchange. */ -- ss->ssl3.cwSpec->cipher_def->secret_key_size >= 10 && -- (ss->ssl3.hs.kea_def->kea == kea_dhe_dss || -- ss->ssl3.hs.kea_def->kea == kea_dhe_rsa || -- ss->ssl3.hs.kea_def->kea == kea_ecdhe_ecdsa || -- ss->ssl3.hs.kea_def->kea == kea_ecdhe_rsa); -- ssl_ReleaseSpecReadLock(ss); -+ if (!ss->canFalseStartCallback) { -+ rv = SSL_DefaultCanFalseStart(ss->fd, &ss->ssl3.hs.canFalseStart); -+ } else { -+ rv = (ss->canFalseStartCallback)(ss->fd, -+ ss->canFalseStartCallbackData, -+ &ss->ssl3.hs.canFalseStart); -+ } -+ -+ if (rv != SECSuccess) { -+ ss->ssl3.hs.canFalseStart = PR_FALSE; -+ } -+ - return rv; - } - -@@ -7500,20 +7507,59 @@ - goto loser; /* err code was set. */ - } - -- /* XXX: If the server's certificate hasn't been authenticated by this -- * point, then we may be leaking this NPN message to an attacker. -+ /* This must be done after we've set ss->ssl3.cwSpec in -+ * ssl3_SendChangeCipherSpecs because SSL_GetChannelInfo uses information -+ * from cwSpec. This must be done before we call ssl3_CheckFalseStart -+ * because the false start callback (if any) may need the information from -+ * the functions that depend on this being set. - */ -+ ss->enoughFirstHsDone = PR_TRUE; -+ - if (!ss->firstHsDone) { -+ /* XXX: If the server's certificate hasn't been authenticated by this -+ * point, then we may be leaking this NPN message to an attacker. -+ */ - rv = ssl3_SendNextProto(ss); - if (rv != SECSuccess) { - goto loser; /* err code was set. */ - } - } -+ - rv = ssl3_SendEncryptedExtensions(ss); - if (rv != SECSuccess) { - goto loser; /* err code was set. */ - } - -+ if (!ss->firstHsDone) { -+ if (ss->opt.enableFalseStart) { -+ if (!ss->ssl3.hs.authCertificatePending) { -+ /* When we fix bug 589047, we will need to know whether we are -+ * false starting before we try to flush the client second -+ * round to the network. With that in mind, we purposefully -+ * call ssl3_CheckFalseStart before calling ssl3_SendFinished, -+ * which includes a call to ssl3_FlushHandshake, so that -+ * no application develops a reliance on such flushing being -+ * done before its false start callback is called. -+ */ -+ ssl_ReleaseXmitBufLock(ss); -+ rv = ssl3_CheckFalseStart(ss); -+ ssl_GetXmitBufLock(ss); -+ if (rv != SECSuccess) { -+ goto loser; -+ } -+ } else { -+ /* The certificate authentication and the server's Finished -+ * message are racing each other. If the certificate -+ * authentication wins, then we will try to false start in -+ * ssl3_AuthCertificateComplete. -+ */ -+ SSL_TRC(3, ("%d: SSL3[%p]: deferring false start check because" -+ " certificate authentication is still pending.", -+ SSL_GETPID(), ss->fd)); -+ } -+ } -+ } -+ - rv = ssl3_SendFinished(ss, 0); - if (rv != SECSuccess) { - goto loser; /* err code was set. */ -@@ -7526,8 +7572,16 @@ - else - ss->ssl3.hs.ws = wait_change_cipher; - -- /* Do the handshake callback for sslv3 here, if we can false start. */ -- if (ss->handshakeCallback != NULL && ssl3_CanFalseStart(ss)) { -+ if (ss->handshakeCallback && -+ (ss->ssl3.hs.canFalseStart && !ss->canFalseStartCallback)) { -+ /* Call the handshake callback here for backwards compatibility with -+ * applications that were using false start before -+ * canFalseStartCallback was added. Note that we do this after calling -+ * ssl3_SendFinished, which includes a call to ssl3_FlushHandshake, -+ * just in case the application is relying on having the handshake -+ * messages flushed to the network before its handshake callback is -+ * called. -+ */ - (ss->handshakeCallback)(ss->fd, ss->handshakeCallbackData); - } - -@@ -10147,13 +10201,6 @@ - - ss->ssl3.hs.authCertificatePending = PR_TRUE; - rv = SECSuccess; -- -- /* XXX: Async cert validation and False Start don't work together -- * safely yet; if we leave False Start enabled, we may end up false -- * starting (sending application data) before we -- * SSL_AuthCertificateComplete has been called. -- */ -- ss->opt.enableFalseStart = PR_FALSE; - } - - if (rv != SECSuccess) { -@@ -10278,6 +10325,12 @@ - } else if (ss->ssl3.hs.restartTarget != NULL) { - sslRestartTarget target = ss->ssl3.hs.restartTarget; - ss->ssl3.hs.restartTarget = NULL; -+ -+ if (target == ssl3_FinishHandshake) { -+ SSL_TRC(3,("%d: SSL3[%p]: certificate authentication lost the race" -+ " with peer's finished message", SSL_GETPID(), ss->fd)); -+ } -+ - rv = target(ss); - /* Even if we blocked here, we have accomplished enough to claim - * success. Any remaining work will be taken care of by subsequent -@@ -10287,7 +10340,39 @@ - rv = SECSuccess; - } - } else { -- rv = SECSuccess; -+ SSL_TRC(3, ("%d: SSL3[%p]: certificate authentication won the race" -+ " with peer's finished message", SSL_GETPID(), ss->fd)); -+ -+ PORT_Assert(!ss->firstHsDone); -+ PORT_Assert(!ss->sec.isServer); -+ PORT_Assert(!ss->ssl3.hs.isResuming); -+ PORT_Assert(ss->ssl3.hs.ws == wait_change_cipher || -+ ss->ssl3.hs.ws == wait_finished || -+ ss->ssl3.hs.ws == wait_new_session_ticket); -+ -+ /* ssl3_SendClientSecondRound deferred the false start check because -+ * certificate authentication was pending, so we have to do it now. -+ */ -+ if (ss->opt.enableFalseStart && -+ !ss->firstHsDone && -+ !ss->sec.isServer && -+ !ss->ssl3.hs.isResuming && -+ (ss->ssl3.hs.ws == wait_change_cipher || -+ ss->ssl3.hs.ws == wait_finished || -+ ss->ssl3.hs.ws == wait_new_session_ticket)) { -+ rv = ssl3_CheckFalseStart(ss); -+ if (rv == SECSuccess && -+ ss->handshakeCallback && -+ (ss->ssl3.hs.canFalseStart && !ss->canFalseStartCallback)) { -+ /* Call the handshake callback here for backwards compatibility -+ * with applications that were using false start before -+ * canFalseStartCallback was added. -+ */ -+ (ss->handshakeCallback)(ss->fd, ss->handshakeCallbackData); -+ } -+ } else { -+ rv = SECSuccess; -+ } - } - - done: -@@ -10983,6 +11068,8 @@ - SECStatus - ssl3_FinishHandshake(sslSocket * ss) - { -+ PRBool falseStarted; -+ - PORT_Assert( ss->opt.noLocks || ssl_HaveRecvBufLock(ss) ); - PORT_Assert( ss->opt.noLocks || ssl_HaveSSL3HandshakeLock(ss) ); - PORT_Assert( ss->ssl3.hs.restartTarget == NULL ); -@@ -10990,6 +11077,7 @@ - /* The first handshake is now completed. */ - ss->handshake = NULL; - ss->firstHsDone = PR_TRUE; -+ ss->enoughFirstHsDone = PR_TRUE; - - if (ss->ssl3.hs.cacheSID) { - (*ss->sec.cache)(ss->sec.ci.sid); -@@ -10997,9 +11085,14 @@ - } - - ss->ssl3.hs.ws = idle_handshake; -+ falseStarted = ss->ssl3.hs.canFalseStart; -+ ss->ssl3.hs.canFalseStart = PR_FALSE; /* False Start phase is complete */ - -- /* Do the handshake callback for sslv3 here, if we cannot false start. */ -- if (ss->handshakeCallback != NULL && !ssl3_CanFalseStart(ss)) { -+ /* Call the handshake callback for sslv3 here, unless we called it already -+ * for the case where false start was done without a canFalseStartCallback. -+ */ -+ if (ss->handshakeCallback && -+ !(falseStarted && !ss->canFalseStartCallback)) { - (ss->handshakeCallback)(ss->fd, ss->handshakeCallbackData); - } - diff --git a/chromium/net/third_party/nss/patches/chacha20poly1305.patch b/chromium/net/third_party/nss/patches/chacha20poly1305.patch index c858413f3c3..89a71bbf6d7 100644 --- a/chromium/net/third_party/nss/patches/chacha20poly1305.patch +++ b/chromium/net/third_party/nss/patches/chacha20poly1305.patch @@ -9,15 +9,15 @@ index 8be517c..53c29f0 100644 +/* This is a bodge to allow this code to be compiled against older NSS + * headers. */ +#ifndef CKM_NSS_CHACHA20_POLY1305 -+#define CKM_NSS_CHACHA20_POLY1305 (CKM_NSS + 25) ++#define CKM_NSS_CHACHA20_POLY1305 (CKM_NSS + 26) + -+typedef struct CK_AEAD_PARAMS { -+ CK_BYTE_PTR pIv; /* This is the nonce. */ -+ CK_ULONG ulIvLen; -+ CK_BYTE_PTR pAAD; -+ CK_ULONG ulAADLen; -+ CK_ULONG ulTagBits; -+} CK_AEAD_PARAMS; ++typedef struct CK_NSS_AEAD_PARAMS { ++ CK_BYTE_PTR pIv; /* This is the nonce. */ ++ CK_ULONG ulIvLen; ++ CK_BYTE_PTR pAAD; ++ CK_ULONG ulAADLen; ++ CK_ULONG ulTagLen; ++} CK_NSS_AEAD_PARAMS; + +#endif + @@ -77,18 +77,18 @@ index 8be517c..53c29f0 100644 + SECItem param; + SECStatus rv = SECFailure; + unsigned int uOutLen; -+ CK_AEAD_PARAMS aeadParams; ++ CK_NSS_AEAD_PARAMS aeadParams; + static const int tagSize = 16; + + param.type = siBuffer; + param.len = sizeof(aeadParams); + param.data = (unsigned char *) &aeadParams; -+ memset(&aeadParams, 0, sizeof(CK_AEAD_PARAMS)); ++ memset(&aeadParams, 0, sizeof(aeadParams)); + aeadParams.pIv = (unsigned char *) additionalData; + aeadParams.ulIvLen = 8; + aeadParams.pAAD = (unsigned char *) additionalData; + aeadParams.ulAADLen = additionalDataLen; -+ aeadParams.ulTagBits = tagSize * 8; ++ aeadParams.ulTagLen = tagSize; + + if (doDecrypt) { + rv = pk11_decrypt(keys->write_key, CKM_NSS_CHACHA20_POLY1305, ¶m, diff --git a/chromium/net/third_party/nss/patches/channelid.patch b/chromium/net/third_party/nss/patches/channelid.patch index 46554f9014f..b2ab19d2831 100644 --- a/chromium/net/third_party/nss/patches/channelid.patch +++ b/chromium/net/third_party/nss/patches/channelid.patch @@ -151,7 +151,7 @@ diff -pu a/nss/lib/ssl/ssl3con.c b/nss/lib/ssl/ssl3con.c + spki = SECKEY_EncodeDERSubjectPublicKeyInfo(ss->ssl3.channelIDPub); + + if (spki->len != sizeof(P256_SPKI_PREFIX) + CHANNEL_ID_PUBLIC_KEY_LENGTH || -+ memcmp(spki->data, P256_SPKI_PREFIX, sizeof(P256_SPKI_PREFIX) != 0)) { ++ memcmp(spki->data, P256_SPKI_PREFIX, sizeof(P256_SPKI_PREFIX)) != 0) { + PORT_SetError(SSL_ERROR_INVALID_CHANNEL_ID_KEY); + rv = SECFailure; + goto loser; diff --git a/chromium/net/third_party/nss/patches/channelid2.patch b/chromium/net/third_party/nss/patches/channelid2.patch new file mode 100644 index 00000000000..1425c2a80b0 --- /dev/null +++ b/chromium/net/third_party/nss/patches/channelid2.patch @@ -0,0 +1,155 @@ +diff --git a/nss/lib/ssl/ssl3con.c b/nss/lib/ssl/ssl3con.c +index 882e356..396c408 100644 +--- a/nss/lib/ssl/ssl3con.c ++++ b/nss/lib/ssl/ssl3con.c +@@ -7594,6 +7594,33 @@ ssl3_SendClientSecondRound(sslSocket *ss) + + ssl_ReleaseXmitBufLock(ss); /*******************************/ + ++ if (!ss->ssl3.hs.isResuming && ++ ssl3_ExtensionNegotiated(ss, ssl_channel_id_xtn)) { ++ /* If we are negotiating ChannelID on a full handshake then we record ++ * the handshake hashes in |sid| at this point. They will be needed in ++ * the event that we resume this session and use ChannelID on the ++ * resumption handshake. */ ++ SSL3Hashes hashes; ++ SECItem *originalHandshakeHash = ++ &ss->sec.ci.sid->u.ssl3.originalHandshakeHash; ++ PORT_Assert(ss->sec.ci.sid->cached == never_cached); ++ ++ ssl_GetSpecReadLock(ss); ++ PORT_Assert(ss->version > SSL_LIBRARY_VERSION_3_0); ++ rv = ssl3_ComputeHandshakeHashes(ss, ss->ssl3.cwSpec, &hashes, 0); ++ ssl_ReleaseSpecReadLock(ss); ++ if (rv != SECSuccess) { ++ return rv; ++ } ++ ++ PORT_Assert(originalHandshakeHash->len == 0); ++ originalHandshakeHash->data = PORT_Alloc(hashes.len); ++ if (!originalHandshakeHash->data) ++ return SECFailure; ++ originalHandshakeHash->len = hashes.len; ++ memcpy(originalHandshakeHash->data, hashes.u.raw, hashes.len); ++ } ++ + if (ssl3_ExtensionNegotiated(ss, ssl_session_ticket_xtn)) + ss->ssl3.hs.ws = wait_new_session_ticket; + else +@@ -10590,6 +10617,7 @@ static SECStatus + ssl3_SendEncryptedExtensions(sslSocket *ss) + { + static const char CHANNEL_ID_MAGIC[] = "TLS Channel ID signature"; ++ static const char CHANNEL_ID_RESUMPTION_MAGIC[] = "Resumption"; + /* This is the ASN.1 prefix for a P-256 public key. Specifically it's: + * SEQUENCE + * SEQUENCE +@@ -10615,7 +10643,10 @@ ssl3_SendEncryptedExtensions(sslSocket *ss) + SECItem *spki = NULL; + SSL3Hashes hashes; + const unsigned char *pub_bytes; +- unsigned char signed_data[sizeof(CHANNEL_ID_MAGIC) + sizeof(SSL3Hashes)]; ++ unsigned char signed_data[sizeof(CHANNEL_ID_MAGIC) + ++ sizeof(CHANNEL_ID_RESUMPTION_MAGIC) + ++ sizeof(SSL3Hashes)*2]; ++ size_t signed_data_len; + unsigned char digest[SHA256_LENGTH]; + SECItem digest_item; + unsigned char signature[64]; +@@ -10665,11 +10696,26 @@ ssl3_SendEncryptedExtensions(sslSocket *ss) + + pub_bytes = spki->data + sizeof(P256_SPKI_PREFIX); + +- memcpy(signed_data, CHANNEL_ID_MAGIC, sizeof(CHANNEL_ID_MAGIC)); +- memcpy(signed_data + sizeof(CHANNEL_ID_MAGIC), hashes.u.raw, hashes.len); ++ signed_data_len = 0; ++ memcpy(signed_data + signed_data_len, CHANNEL_ID_MAGIC, ++ sizeof(CHANNEL_ID_MAGIC)); ++ signed_data_len += sizeof(CHANNEL_ID_MAGIC); ++ if (ss->ssl3.hs.isResuming) { ++ SECItem *originalHandshakeHash = ++ &ss->sec.ci.sid->u.ssl3.originalHandshakeHash; ++ PORT_Assert(originalHandshakeHash->len > 0); + +- rv = PK11_HashBuf(SEC_OID_SHA256, digest, signed_data, +- sizeof(CHANNEL_ID_MAGIC) + hashes.len); ++ memcpy(signed_data + signed_data_len, CHANNEL_ID_RESUMPTION_MAGIC, ++ sizeof(CHANNEL_ID_RESUMPTION_MAGIC)); ++ signed_data_len += sizeof(CHANNEL_ID_RESUMPTION_MAGIC); ++ memcpy(signed_data + signed_data_len, originalHandshakeHash->data, ++ originalHandshakeHash->len); ++ signed_data_len += originalHandshakeHash->len; ++ } ++ memcpy(signed_data + signed_data_len, hashes.u.raw, hashes.len); ++ signed_data_len += hashes.len; ++ ++ rv = PK11_HashBuf(SEC_OID_SHA256, digest, signed_data, signed_data_len); + if (rv != SECSuccess) + goto loser; + +diff --git a/nss/lib/ssl/ssl3ext.c b/nss/lib/ssl/ssl3ext.c +index 03cf05c..166022c 100644 +--- a/nss/lib/ssl/ssl3ext.c ++++ b/nss/lib/ssl/ssl3ext.c +@@ -812,6 +812,15 @@ ssl3_ClientSendChannelIDXtn(sslSocket * ss, PRBool append, + return 0; + } + ++ if (ss->sec.ci.sid->cached != never_cached && ++ ss->sec.ci.sid->u.ssl3.originalHandshakeHash.len == 0) { ++ /* We can't do ChannelID on a connection if we're resuming and didn't ++ * do ChannelID on the original connection: without ChannelID on the ++ * original connection we didn't record the handshake hashes needed for ++ * the signature. */ ++ return 0; ++ } ++ + if (append) { + SECStatus rv; + rv = ssl3_AppendHandshakeNumber(ss, ssl_channel_id_xtn, 2); +diff --git a/nss/lib/ssl/sslimpl.h b/nss/lib/ssl/sslimpl.h +index 9c789bf..ca68727 100644 +--- a/nss/lib/ssl/sslimpl.h ++++ b/nss/lib/ssl/sslimpl.h +@@ -705,6 +705,14 @@ struct sslSessionIDStr { + */ + NewSessionTicket sessionTicket; + SECItem srvName; ++ ++ /* originalHandshakeHash contains the hash of the original, full ++ * handshake prior to the server's final flow. This is either a ++ * SHA-1/MD5 combination (for TLS < 1.2) or the TLS PRF hash (for ++ * TLS 1.2). This is recorded and used only when ChannelID is ++ * negotiated as it's used to bind the ChannelID signature on the ++ * resumption handshake to the original handshake. */ ++ SECItem originalHandshakeHash; + } ssl3; + } u; + }; +diff --git a/nss/lib/ssl/sslnonce.c b/nss/lib/ssl/sslnonce.c +index a6f7349..eb5004c 100644 +--- a/nss/lib/ssl/sslnonce.c ++++ b/nss/lib/ssl/sslnonce.c +@@ -148,6 +148,9 @@ ssl_DestroySID(sslSessionID *sid) + if (sid->u.ssl3.srvName.data) { + SECITEM_FreeItem(&sid->u.ssl3.srvName, PR_FALSE); + } ++ if (sid->u.ssl3.originalHandshakeHash.data) { ++ SECITEM_FreeItem(&sid->u.ssl3.originalHandshakeHash, PR_FALSE); ++ } + + PORT_ZFree(sid, sizeof(sslSessionID)); + } +diff --git a/nss/lib/ssl/sslt.h b/nss/lib/ssl/sslt.h +index e4d188f..b813c04 100644 +--- a/nss/lib/ssl/sslt.h ++++ b/nss/lib/ssl/sslt.h +@@ -204,7 +204,7 @@ typedef enum { + ssl_app_layer_protocol_xtn = 16, + ssl_session_ticket_xtn = 35, + ssl_next_proto_nego_xtn = 13172, +- ssl_channel_id_xtn = 30031, ++ ssl_channel_id_xtn = 30032, + ssl_padding_xtn = 35655, + ssl_renegotiation_info_xtn = 0xff01 /* experimental number */ + } SSLExtensionType; diff --git a/chromium/net/third_party/nss/patches/cipherorder.patch b/chromium/net/third_party/nss/patches/cipherorder.patch new file mode 100644 index 00000000000..16d4745dcd8 --- /dev/null +++ b/chromium/net/third_party/nss/patches/cipherorder.patch @@ -0,0 +1,106 @@ +diff --git a/nss/lib/ssl/ssl.h b/nss/lib/ssl/ssl.h +index 4cf02aa..24627ed 100644 +--- a/nss/lib/ssl/ssl.h ++++ b/nss/lib/ssl/ssl.h +@@ -265,6 +265,13 @@ SSL_IMPORT SECStatus SSL_CipherPrefGetDefault(PRInt32 cipher, PRBool *enabled); + SSL_IMPORT SECStatus SSL_CipherPolicySet(PRInt32 cipher, PRInt32 policy); + SSL_IMPORT SECStatus SSL_CipherPolicyGet(PRInt32 cipher, PRInt32 *policy); + ++/* SSL_CipherOrderSet sets the cipher suite preference order from |ciphers|, ++ * which must be an array of cipher suite ids of length |len|. All the given ++ * cipher suite ids must appear in the array that is returned by ++ * |SSL_GetImplementedCiphers| and may only appear once, at most. */ ++SSL_IMPORT SECStatus SSL_CipherOrderSet(PRFileDesc *fd, const PRUint16 *ciphers, ++ unsigned int len); ++ + /* SSLChannelBindingType enumerates the types of supported channel binding + * values. See RFC 5929. */ + typedef enum SSLChannelBindingType { +diff --git a/nss/lib/ssl/ssl3con.c b/nss/lib/ssl/ssl3con.c +index c2d9eeb..350d09c 100644 +--- a/nss/lib/ssl/ssl3con.c ++++ b/nss/lib/ssl/ssl3con.c +@@ -12423,6 +12423,46 @@ ssl3_CipherPrefGet(sslSocket *ss, ssl3CipherSuite which, PRBool *enabled) + return rv; + } + ++SECStatus ++ssl3_CipherOrderSet(sslSocket *ss, const ssl3CipherSuite *ciphers, unsigned int len) ++{ ++ /* |i| iterates over |ciphers| while |done| and |j| iterate over ++ * |ss->cipherSuites|. */ ++ unsigned int i, done; ++ ++ for (i = done = 0; i < len; i++) { ++ PRUint16 id = ciphers[i]; ++ unsigned int existingIndex, j; ++ PRBool found = PR_FALSE; ++ ++ for (j = done; j < ssl_V3_SUITES_IMPLEMENTED; j++) { ++ if (ss->cipherSuites[j].cipher_suite == id) { ++ existingIndex = j; ++ found = PR_TRUE; ++ break; ++ } ++ } ++ ++ if (!found) { ++ continue; ++ } ++ ++ if (existingIndex != done) { ++ const ssl3CipherSuiteCfg temp = ss->cipherSuites[done]; ++ ss->cipherSuites[done] = ss->cipherSuites[existingIndex]; ++ ss->cipherSuites[existingIndex] = temp; ++ } ++ done++; ++ } ++ ++ /* Disable all cipher suites that weren't included. */ ++ for (; done < ssl_V3_SUITES_IMPLEMENTED; done++) { ++ ss->cipherSuites[done].enabled = 0; ++ } ++ ++ return SECSuccess; ++} ++ + /* copy global default policy into socket. */ + void + ssl3_InitSocketPolicy(sslSocket *ss) +diff --git a/nss/lib/ssl/sslimpl.h b/nss/lib/ssl/sslimpl.h +index 1e4655f..7521dba 100644 +--- a/nss/lib/ssl/sslimpl.h ++++ b/nss/lib/ssl/sslimpl.h +@@ -1711,6 +1711,8 @@ extern SECStatus ssl3_CipherPrefSet(sslSocket *ss, ssl3CipherSuite which, PRBool + extern SECStatus ssl3_CipherPrefGet(sslSocket *ss, ssl3CipherSuite which, PRBool *on); + extern SECStatus ssl2_CipherPrefSet(sslSocket *ss, PRInt32 which, PRBool enabled); + extern SECStatus ssl2_CipherPrefGet(sslSocket *ss, PRInt32 which, PRBool *enabled); ++extern SECStatus ssl3_CipherOrderSet(sslSocket *ss, const ssl3CipherSuite *cipher, ++ unsigned int len); + + extern SECStatus ssl3_SetPolicy(ssl3CipherSuite which, PRInt32 policy); + extern SECStatus ssl3_GetPolicy(ssl3CipherSuite which, PRInt32 *policy); +diff --git a/nss/lib/ssl/sslsock.c b/nss/lib/ssl/sslsock.c +index 965215d..9f8286c 100644 +--- a/nss/lib/ssl/sslsock.c ++++ b/nss/lib/ssl/sslsock.c +@@ -1344,6 +1344,19 @@ SSL_CipherPrefSet(PRFileDesc *fd, PRInt32 which, PRBool enabled) + return rv; + } + ++SECStatus ++SSL_CipherOrderSet(PRFileDesc *fd, const PRUint16 *ciphers, unsigned int len) ++{ ++ sslSocket *ss = ssl_FindSocket(fd); ++ ++ if (!ss) { ++ SSL_DBG(("%d: SSL[%d]: bad socket in CipherOrderSet", SSL_GETPID(), ++ fd)); ++ return SECFailure; ++ } ++ return ssl3_CipherOrderSet(ss, ciphers, len); ++} ++ + SECStatus + SSL_CipherPrefGet(PRFileDesc *fd, PRInt32 which, PRBool *enabled) + { diff --git a/chromium/net/third_party/nss/patches/disableticketrenewal.patch b/chromium/net/third_party/nss/patches/disableticketrenewal.patch new file mode 100644 index 00000000000..ec40174bc3f --- /dev/null +++ b/chromium/net/third_party/nss/patches/disableticketrenewal.patch @@ -0,0 +1,17 @@ +Index: net/third_party/nss/ssl/sslnonce.c +=================================================================== +--- net/third_party/nss/ssl/sslnonce.c (revision 240143) ++++ net/third_party/nss/ssl/sslnonce.c (working copy) +@@ -438,6 +438,12 @@ + /* We need to lock the cache, as this sid might already be in the cache. */ + LOCK_CACHE; + ++ /* Don't modify sid if it has ever been cached. */ ++ if (sid->cached != never_cached) { ++ UNLOCK_CACHE; ++ return SECSuccess; ++ } ++ + /* A server might have sent us an empty ticket, which has the + * effect of clearing the previously known ticket. + */ diff --git a/chromium/net/third_party/nss/patches/fallbackscsv.patch b/chromium/net/third_party/nss/patches/fallbackscsv.patch new file mode 100644 index 00000000000..f8acb2575d8 --- /dev/null +++ b/chromium/net/third_party/nss/patches/fallbackscsv.patch @@ -0,0 +1,207 @@ +diff --git a/nss/lib/ssl/SSLerrs.h b/nss/lib/ssl/SSLerrs.h +index c0d26cc..4ff0b7d 100644 +--- a/nss/lib/ssl/SSLerrs.h ++++ b/nss/lib/ssl/SSLerrs.h +@@ -421,3 +421,8 @@ ER3(SSL_ERROR_INVALID_CHANNEL_ID_KEY, (SSL_ERROR_BASE + 130), + + ER3(SSL_ERROR_GET_CHANNEL_ID_FAILED, (SSL_ERROR_BASE + 131), + "The application could not get a TLS Channel ID.") ++ ++ER3(SSL_ERROR_INAPPROPRIATE_FALLBACK_ALERT, (SSL_ERROR_BASE + 132), ++"The connection was using a lesser TLS version as a result of a previous" ++" handshake failure, but the server indicated that it should not have been" ++" needed.") +diff --git a/nss/lib/ssl/ssl.h b/nss/lib/ssl/ssl.h +index 24627ed..067938c 100644 +--- a/nss/lib/ssl/ssl.h ++++ b/nss/lib/ssl/ssl.h +@@ -163,6 +163,8 @@ SSL_IMPORT PRFileDesc *DTLS_ImportFD(PRFileDesc *model, PRFileDesc *fd); + #define SSL_ENABLE_OCSP_STAPLING 24 /* Request OCSP stapling (client) */ + /* Request Signed Certificate Timestamps via TLS extension (client) */ + #define SSL_ENABLE_SIGNED_CERT_TIMESTAMPS 25 ++#define SSL_ENABLE_FALLBACK_SCSV 26 /* Send fallback SCSV in ++ * handshakes. */ + + #ifdef SSL_DEPRECATED_FUNCTION + /* Old deprecated function names */ +diff --git a/nss/lib/ssl/ssl3con.c b/nss/lib/ssl/ssl3con.c +index cf7ef32..946f780 100644 +--- a/nss/lib/ssl/ssl3con.c ++++ b/nss/lib/ssl/ssl3con.c +@@ -3469,6 +3469,9 @@ ssl3_HandleAlert(sslSocket *ss, sslBuffer *buf) + case certificate_unknown: error = SSL_ERROR_CERTIFICATE_UNKNOWN_ALERT; + break; + case illegal_parameter: error = SSL_ERROR_ILLEGAL_PARAMETER_ALERT;break; ++ case inappropriate_fallback: ++ error = SSL_ERROR_INAPPROPRIATE_FALLBACK_ALERT; ++ break; + + /* All alerts below are TLS only. */ + case unknown_ca: error = SSL_ERROR_UNKNOWN_CA_ALERT; break; +@@ -4973,7 +4976,7 @@ ssl3_SendClientHello(sslSocket *ss, PRBool resending) + int num_suites; + int actual_count = 0; + PRBool isTLS = PR_FALSE; +- PRBool requestingResume = PR_FALSE; ++ PRBool requestingResume = PR_FALSE, fallbackSCSV = PR_FALSE; + PRInt32 total_exten_len = 0; + unsigned paddingExtensionLen; + unsigned numCompressionMethods; +@@ -5223,8 +5226,15 @@ ssl3_SendClientHello(sslSocket *ss, PRBool resending) + num_suites = count_cipher_suites(ss, ss->ssl3.policy, PR_TRUE); + if (!num_suites) + return SECFailure; /* count_cipher_suites has set error code. */ ++ ++ fallbackSCSV = ss->opt.enableFallbackSCSV && (!requestingResume || ++ ss->version < sid->version); ++ /* make room for SCSV */ + if (ss->ssl3.hs.sendingSCSV) { +- ++num_suites; /* make room for SCSV */ ++ ++num_suites; ++ } ++ if (fallbackSCSV) { ++ ++num_suites; + } + + /* count compression methods */ +@@ -5322,6 +5332,14 @@ ssl3_SendClientHello(sslSocket *ss, PRBool resending) + } + actual_count++; + } ++ if (fallbackSCSV) { ++ rv = ssl3_AppendHandshakeNumber(ss, TLS_FALLBACK_SCSV, ++ sizeof(ssl3CipherSuite)); ++ if (rv != SECSuccess) { ++ return rv; /* err set by ssl3_AppendHandshake* */ ++ } ++ actual_count++; ++ } + for (i = 0; i < ssl_V3_SUITES_IMPLEMENTED; i++) { + ssl3CipherSuiteCfg *suite = &ss->cipherSuites[i]; + if (config_match(suite, ss->ssl3.policy, PR_TRUE, &ss->vrange)) { +@@ -8037,6 +8055,19 @@ ssl3_HandleClientHello(sslSocket *ss, SSL3Opaque *b, PRUint32 length) + goto loser; /* malformed */ + } + ++ /* If the ClientHello version is less than our maximum version, check for a ++ * TLS_FALLBACK_SCSV and reject the connection if found. */ ++ if (ss->vrange.max > ss->clientHelloVersion) { ++ for (i = 0; i + 1 < suites.len; i += 2) { ++ PRUint16 suite_i = (suites.data[i] << 8) | suites.data[i + 1]; ++ if (suite_i != TLS_FALLBACK_SCSV) ++ continue; ++ desc = inappropriate_fallback; ++ errCode = SSL_ERROR_INAPPROPRIATE_FALLBACK_ALERT; ++ goto alert_loser; ++ } ++ } ++ + /* grab the list of compression methods. */ + rv = ssl3_ConsumeHandshakeVariable(ss, &comps, 1, &b, &length); + if (rv != SECSuccess) { +diff --git a/nss/lib/ssl/ssl3prot.h b/nss/lib/ssl/ssl3prot.h +index 0eab970..4c19ade 100644 +--- a/nss/lib/ssl/ssl3prot.h ++++ b/nss/lib/ssl/ssl3prot.h +@@ -98,6 +98,7 @@ typedef enum { + protocol_version = 70, + insufficient_security = 71, + internal_error = 80, ++ inappropriate_fallback = 86, /* could also be sent for SSLv3 */ + user_canceled = 90, + no_renegotiation = 100, + +diff --git a/nss/lib/ssl/sslerr.h b/nss/lib/ssl/sslerr.h +index 5a949c9..82ae7df 100644 +--- a/nss/lib/ssl/sslerr.h ++++ b/nss/lib/ssl/sslerr.h +@@ -196,6 +196,7 @@ SSL_ERROR_INCORRECT_SIGNATURE_ALGORITHM = (SSL_ERROR_BASE + 128), + SSL_ERROR_BAD_CHANNEL_ID_DATA = (SSL_ERROR_BASE + 129), + SSL_ERROR_INVALID_CHANNEL_ID_KEY = (SSL_ERROR_BASE + 130), + SSL_ERROR_GET_CHANNEL_ID_FAILED = (SSL_ERROR_BASE + 131), ++SSL_ERROR_INAPPROPRIATE_FALLBACK_ALERT = (SSL_ERROR_BASE + 132), + + SSL_ERROR_END_OF_LIST /* let the c compiler determine the value of this. */ + } SSLErrorCodes; +diff --git a/nss/lib/ssl/sslimpl.h b/nss/lib/ssl/sslimpl.h +index 7521dba..6d0bc15 100644 +--- a/nss/lib/ssl/sslimpl.h ++++ b/nss/lib/ssl/sslimpl.h +@@ -336,6 +336,7 @@ typedef struct sslOptionsStr { + unsigned int cbcRandomIV : 1; /* 24 */ + unsigned int enableOCSPStapling : 1; /* 25 */ + unsigned int enableSignedCertTimestamps : 1; /* 26 */ ++ unsigned int enableFallbackSCSV : 1; /* 27 */ + } sslOptions; + + typedef enum { sslHandshakingUndetermined = 0, +diff --git a/nss/lib/ssl/sslproto.h b/nss/lib/ssl/sslproto.h +index 6b60a28..621ef37 100644 +--- a/nss/lib/ssl/sslproto.h ++++ b/nss/lib/ssl/sslproto.h +@@ -172,6 +172,11 @@ + */ + #define TLS_EMPTY_RENEGOTIATION_INFO_SCSV 0x00FF + ++/* TLS_FALLBACK_SCSV is a signaling cipher suite value that indicates that a ++ * handshake is the result of TLS version fallback. This value is not IANA ++ * assigned. */ ++#define TLS_FALLBACK_SCSV 0x5600 ++ + /* Cipher Suite Values starting with 0xC000 are defined in informational + * RFCs. + */ +diff --git a/nss/lib/ssl/sslsock.c b/nss/lib/ssl/sslsock.c +index 9f8286c..f7d44d4 100644 +--- a/nss/lib/ssl/sslsock.c ++++ b/nss/lib/ssl/sslsock.c +@@ -174,7 +174,8 @@ static sslOptions ssl_defaults = { + PR_FALSE, /* enableFalseStart */ + PR_TRUE, /* cbcRandomIV */ + PR_FALSE, /* enableOCSPStapling */ +- PR_FALSE /* enableSignedCertTimestamps */ ++ PR_FALSE, /* enableSignedCertTimestamps */ ++ PR_FALSE /* enableFallbackSCSV */ + }; + + /* +@@ -870,6 +871,10 @@ SSL_OptionSet(PRFileDesc *fd, PRInt32 which, PRBool on) + ss->opt.enableSignedCertTimestamps = on; + break; + ++ case SSL_ENABLE_FALLBACK_SCSV: ++ ss->opt.enableFallbackSCSV = on; ++ break; ++ + default: + PORT_SetError(SEC_ERROR_INVALID_ARGS); + rv = SECFailure; +@@ -943,6 +948,7 @@ SSL_OptionGet(PRFileDesc *fd, PRInt32 which, PRBool *pOn) + case SSL_ENABLE_SIGNED_CERT_TIMESTAMPS: + on = ss->opt.enableSignedCertTimestamps; + break; ++ case SSL_ENABLE_FALLBACK_SCSV: on = ss->opt.enableFallbackSCSV; break; + + default: + PORT_SetError(SEC_ERROR_INVALID_ARGS); +@@ -1007,6 +1013,9 @@ SSL_OptionGetDefault(PRInt32 which, PRBool *pOn) + case SSL_ENABLE_SIGNED_CERT_TIMESTAMPS: + on = ssl_defaults.enableSignedCertTimestamps; + break; ++ case SSL_ENABLE_FALLBACK_SCSV: ++ on = ssl_defaults.enableFallbackSCSV; ++ break; + + default: + PORT_SetError(SEC_ERROR_INVALID_ARGS); +@@ -1178,6 +1187,10 @@ SSL_OptionSetDefault(PRInt32 which, PRBool on) + ssl_defaults.enableSignedCertTimestamps = on; + break; + ++ case SSL_ENABLE_FALLBACK_SCSV: ++ ssl_defaults.enableFallbackSCSV = on; ++ break; ++ + default: + PORT_SetError(SEC_ERROR_INVALID_ARGS); + return SECFailure; diff --git a/chromium/net/third_party/nss/patches/paddingextension.patch b/chromium/net/third_party/nss/patches/paddingextension.patch new file mode 100644 index 00000000000..966c4903b21 --- /dev/null +++ b/chromium/net/third_party/nss/patches/paddingextension.patch @@ -0,0 +1,142 @@ +diff --git a/nss/lib/ssl/ssl3con.c b/nss/lib/ssl/ssl3con.c +index 8b8b758..882e356 100644 +--- a/nss/lib/ssl/ssl3con.c ++++ b/nss/lib/ssl/ssl3con.c +@@ -4975,6 +4975,7 @@ ssl3_SendClientHello(sslSocket *ss, PRBool resending) + PRBool isTLS = PR_FALSE; + PRBool requestingResume = PR_FALSE; + PRInt32 total_exten_len = 0; ++ unsigned paddingExtensionLen; + unsigned numCompressionMethods; + PRInt32 flags; + +@@ -5241,6 +5242,20 @@ ssl3_SendClientHello(sslSocket *ss, PRBool resending) + length += 1 + ss->ssl3.hs.cookieLen; + } + ++ /* A padding extension may be included to ensure that the record containing ++ * the ClientHello doesn't have a length between 256 and 511 bytes ++ * (inclusive). Initial, ClientHello records with such lengths trigger bugs ++ * in F5 devices. ++ * ++ * This is not done for DTLS nor for renegotiation. */ ++ if (!IS_DTLS(ss) && isTLS && !ss->firstHsDone) { ++ paddingExtensionLen = ssl3_CalculatePaddingExtensionLength(length); ++ total_exten_len += paddingExtensionLen; ++ length += paddingExtensionLen; ++ } else { ++ paddingExtensionLen = 0; ++ } ++ + rv = ssl3_AppendHandshakeHeader(ss, client_hello, length); + if (rv != SECSuccess) { + return rv; /* err set by ssl3_AppendHandshake* */ +@@ -5360,6 +5375,13 @@ ssl3_SendClientHello(sslSocket *ss, PRBool resending) + return SECFailure; + } + maxBytes -= extLen; ++ ++ extLen = ssl3_AppendPaddingExtension(ss, paddingExtensionLen, maxBytes); ++ if (extLen < 0) { ++ return SECFailure; ++ } ++ maxBytes -= extLen; ++ + PORT_Assert(!maxBytes); + } + if (ss->ssl3.hs.sendingSCSV) { +diff --git a/nss/lib/ssl/ssl3ext.c b/nss/lib/ssl/ssl3ext.c +index 0415770..cdebcc9 100644 +--- a/nss/lib/ssl/ssl3ext.c ++++ b/nss/lib/ssl/ssl3ext.c +@@ -2297,3 +2297,56 @@ ssl3_ClientSendSigAlgsXtn(sslSocket * ss, PRBool append, PRUint32 maxBytes) + loser: + return -1; + } ++ ++unsigned int ++ssl3_CalculatePaddingExtensionLength(unsigned int clientHelloLength) ++{ ++ unsigned int recordLength = 1 /* handshake message type */ + ++ 3 /* handshake message length */ + ++ clientHelloLength; ++ unsigned int extensionLength; ++ ++ if (recordLength < 256 || recordLength >= 512) { ++ return 0; ++ } ++ ++ extensionLength = 512 - recordLength; ++ /* Extensions take at least four bytes to encode. */ ++ if (extensionLength < 4) { ++ extensionLength = 4; ++ } ++ ++ return extensionLength; ++} ++ ++/* ssl3_AppendPaddingExtension possibly adds an extension which ensures that a ++ * ClientHello record is either < 256 bytes or is >= 512 bytes. This ensures ++ * that we don't trigger bugs in F5 products. */ ++PRInt32 ++ssl3_AppendPaddingExtension(sslSocket *ss, unsigned int extensionLen, ++ PRUint32 maxBytes) ++{ ++ unsigned int paddingLen = extensionLen - 4; ++ unsigned char padding[256]; ++ ++ if (extensionLen == 0) { ++ return 0; ++ } ++ ++ if (extensionLen < 4 || ++ extensionLen > maxBytes || ++ paddingLen > sizeof(padding)) { ++ PORT_Assert(0); ++ return -1; ++ } ++ ++ if (SECSuccess != ssl3_AppendHandshakeNumber(ss, ssl_padding_xtn, 2)) ++ return -1; ++ if (SECSuccess != ssl3_AppendHandshakeNumber(ss, paddingLen, 2)) ++ return -1; ++ memset(padding, 0, paddingLen); ++ if (SECSuccess != ssl3_AppendHandshake(ss, padding, paddingLen)) ++ return -1; ++ ++ return extensionLen; ++} +diff --git a/nss/lib/ssl/sslimpl.h b/nss/lib/ssl/sslimpl.h +index 614eed1..9c789bf 100644 +--- a/nss/lib/ssl/sslimpl.h ++++ b/nss/lib/ssl/sslimpl.h +@@ -237,6 +237,13 @@ extern PRInt32 + ssl3_CallHelloExtensionSenders(sslSocket *ss, PRBool append, PRUint32 maxBytes, + const ssl3HelloExtensionSender *sender); + ++extern unsigned int ++ssl3_CalculatePaddingExtensionLength(unsigned int clientHelloLength); ++ ++extern PRInt32 ++ssl3_AppendPaddingExtension(sslSocket *ss, unsigned int extensionLen, ++ PRUint32 maxBytes); ++ + /* Socket ops */ + struct sslSocketOpsStr { + int (*connect) (sslSocket *, const PRNetAddr *); +diff --git a/nss/lib/ssl/sslt.h b/nss/lib/ssl/sslt.h +index a8007d8..e4d188f 100644 +--- a/nss/lib/ssl/sslt.h ++++ b/nss/lib/ssl/sslt.h +@@ -205,9 +205,10 @@ typedef enum { + ssl_session_ticket_xtn = 35, + ssl_next_proto_nego_xtn = 13172, + ssl_channel_id_xtn = 30031, ++ ssl_padding_xtn = 35655, + ssl_renegotiation_info_xtn = 0xff01 /* experimental number */ + } SSLExtensionType; + +-#define SSL_MAX_EXTENSIONS 11 ++#define SSL_MAX_EXTENSIONS 11 /* doesn't include ssl_padding_xtn. */ + + #endif /* __sslt_h_ */ diff --git a/chromium/net/third_party/nss/patches/paddingextensionall.patch b/chromium/net/third_party/nss/patches/paddingextensionall.patch new file mode 100644 index 00000000000..f226aacaf68 --- /dev/null +++ b/chromium/net/third_party/nss/patches/paddingextensionall.patch @@ -0,0 +1,26 @@ +diff --git a/nss/lib/ssl/ssl3ext.c b/nss/lib/ssl/ssl3ext.c +index cdebcc9..03cf05c 100644 +--- a/nss/lib/ssl/ssl3ext.c ++++ b/nss/lib/ssl/ssl3ext.c +@@ -2306,7 +2306,11 @@ ssl3_CalculatePaddingExtensionLength(unsigned int clientHelloLength) + clientHelloLength; + unsigned int extensionLength; + +- if (recordLength < 256 || recordLength >= 512) { ++ /* This condition should be: ++ * if (recordLength < 256 || recordLength >= 512) { ++ * It has been changed, temporarily, to test whether 512 byte ClientHellos ++ * are a compatibility problem. */ ++ if (recordLength >= 512) { + return 0; + } + +@@ -2327,7 +2331,7 @@ ssl3_AppendPaddingExtension(sslSocket *ss, unsigned int extensionLen, + PRUint32 maxBytes) + { + unsigned int paddingLen = extensionLen - 4; +- unsigned char padding[256]; ++ unsigned char padding[512]; + + if (extensionLen == 0) { + return 0; diff --git a/chromium/net/third_party/nss/patches/sessioncache.patch b/chromium/net/third_party/nss/patches/sessioncache.patch new file mode 100644 index 00000000000..11fd9fc8e2c --- /dev/null +++ b/chromium/net/third_party/nss/patches/sessioncache.patch @@ -0,0 +1,100 @@ +diff --git a/net/third_party/nss/ssl/exports_win.def b/net/third_party/nss/ssl/exports_win.def +index e0624f1..a1045bb 100644 +--- a/net/third_party/nss/ssl/exports_win.def ++++ b/net/third_party/nss/ssl/exports_win.def +@@ -62,3 +62,5 @@ SSL_RestartHandshakeAfterChannelIDReq + SSL_GetChannelBinding + SSL_PeerSignedCertTimestamps + SSL_CipherOrderSet ++SSL_CacheSession ++SSL_CacheSessionUnlocked +diff --git a/net/third_party/nss/ssl/ssl.h b/net/third_party/nss/ssl/ssl.h +index bef33fc..6f7c988 100644 +--- a/net/third_party/nss/ssl/ssl.h ++++ b/net/third_party/nss/ssl/ssl.h +@@ -872,6 +872,18 @@ SSL_IMPORT int SSL_DataPending(PRFileDesc *fd); + SSL_IMPORT SECStatus SSL_InvalidateSession(PRFileDesc *fd); + + /* ++** Cache the SSL session associated with fd, if it has not already been cached. ++*/ ++SSL_IMPORT SECStatus SSL_CacheSession(PRFileDesc *fd); ++ ++/* ++** Cache the SSL session associated with fd, if it has not already been cached. ++** This function may only be called when processing within a callback assigned ++** via SSL_HandshakeCallback ++*/ ++SSL_IMPORT SECStatus SSL_CacheSessionUnlocked(PRFileDesc *fd); ++ ++/* + ** Return a SECItem containing the SSL session ID associated with the fd. + */ + SSL_IMPORT SECItem *SSL_GetSessionID(PRFileDesc *fd); +diff --git a/net/third_party/nss/ssl/ssl3con.c b/net/third_party/nss/ssl/ssl3con.c +index 307a0fe..e2be5e6 100644 +--- a/net/third_party/nss/ssl/ssl3con.c ++++ b/net/third_party/nss/ssl/ssl3con.c +@@ -11240,7 +11240,7 @@ ssl3_FinishHandshake(sslSocket * ss) + /* The first handshake is now completed. */ + ss->handshake = NULL; + +- if (ss->ssl3.hs.cacheSID) { ++ if (ss->ssl3.hs.cacheSID && ss->sec.isServer) { + (*ss->sec.cache)(ss->sec.ci.sid); + ss->ssl3.hs.cacheSID = PR_FALSE; + } +diff --git a/net/third_party/nss/ssl/sslsecur.c b/net/third_party/nss/ssl/sslsecur.c +index 31c343f..99538e5 100644 +--- a/net/third_party/nss/ssl/sslsecur.c ++++ b/net/third_party/nss/ssl/sslsecur.c +@@ -1474,6 +1474,49 @@ SSL_InvalidateSession(PRFileDesc *fd) + return rv; + } + ++static void ++ssl3_CacheSessionUnlocked(sslSocket *ss) ++{ ++ PORT_Assert(!ss->sec.isServer); ++ ++ if (ss->ssl3.hs.cacheSID) { ++ ss->sec.cache(ss->sec.ci.sid); ++ ss->ssl3.hs.cacheSID = PR_FALSE; ++ } ++} ++ ++SECStatus ++SSL_CacheSession(PRFileDesc *fd) ++{ ++ sslSocket * ss = ssl_FindSocket(fd); ++ SECStatus rv = SECFailure; ++ ++ if (ss) { ++ ssl_Get1stHandshakeLock(ss); ++ ssl_GetSSL3HandshakeLock(ss); ++ ++ ssl3_CacheSessionUnlocked(ss); ++ rv = SECSuccess; ++ ++ ssl_ReleaseSSL3HandshakeLock(ss); ++ ssl_Release1stHandshakeLock(ss); ++ } ++ return rv; ++} ++ ++SECStatus ++SSL_CacheSessionUnlocked(PRFileDesc *fd) ++{ ++ sslSocket * ss = ssl_FindSocket(fd); ++ SECStatus rv = SECFailure; ++ ++ if (ss) { ++ ssl3_CacheSessionUnlocked(ss); ++ rv = SECSuccess; ++ } ++ return rv; ++} ++ + SECItem * + SSL_GetSessionID(PRFileDesc *fd) + { diff --git a/chromium/net/third_party/nss/patches/signedcertificatetimestamps.patch b/chromium/net/third_party/nss/patches/signedcertificatetimestamps.patch new file mode 100644 index 00000000000..8ac3079f19f --- /dev/null +++ b/chromium/net/third_party/nss/patches/signedcertificatetimestamps.patch @@ -0,0 +1,421 @@ +diff --git a/net/third_party/nss/ssl/ssl.h b/net/third_party/nss/ssl/ssl.h +index 67cc3a7..4cf02aa 100644 +--- a/net/third_party/nss/ssl/ssl.h ++++ b/net/third_party/nss/ssl/ssl.h +@@ -161,6 +161,8 @@ SSL_IMPORT PRFileDesc *DTLS_ImportFD(PRFileDesc *model, PRFileDesc *fd); + */ + #define SSL_CBC_RANDOM_IV 23 + #define SSL_ENABLE_OCSP_STAPLING 24 /* Request OCSP stapling (client) */ ++/* Request Signed Certificate Timestamps via TLS extension (client) */ ++#define SSL_ENABLE_SIGNED_CERT_TIMESTAMPS 25 + + #ifdef SSL_DEPRECATED_FUNCTION + /* Old deprecated function names */ +@@ -464,6 +466,23 @@ SSL_IMPORT CERTCertList *SSL_PeerCertificateChain(PRFileDesc *fd); + */ + SSL_IMPORT const SECItemArray * SSL_PeerStapledOCSPResponses(PRFileDesc *fd); + ++/* SSL_PeerSignedCertTimestamps returns the signed_certificate_timestamp ++ * extension data provided by the TLS server. The return value is a pointer ++ * to an internal SECItem that contains the returned response (as a serialized ++ * SignedCertificateTimestampList, see RFC 6962). The returned pointer is only ++ * valid until the callback function that calls SSL_PeerSignedCertTimestamps ++ * (e.g. the authenticate certificate hook, or the handshake callback) returns. ++ * ++ * If no Signed Certificate Timestamps were given by the server then the result ++ * will be empty. If there was an error, then the result will be NULL. ++ * ++ * You must set the SSL_ENABLE_SIGNED_CERT_TIMESTAMPS option to indicate support ++ * for Signed Certificate Timestamps to a server. ++ * ++ * libssl does not do any parsing or validation of the response itself. ++ */ ++SSL_IMPORT const SECItem * SSL_PeerSignedCertTimestamps(PRFileDesc *fd); ++ + /* SSL_SetStapledOCSPResponses stores an array of one or multiple OCSP responses + * in the fd's data, which may be sent as part of a server side cert_status + * handshake message. Parameter |responses| is for the server certificate of +diff --git a/net/third_party/nss/ssl/ssl3con.c b/net/third_party/nss/ssl/ssl3con.c +index 0f1eea4..c2d9eeb 100644 +--- a/net/third_party/nss/ssl/ssl3con.c ++++ b/net/third_party/nss/ssl/ssl3con.c +@@ -6639,10 +6639,22 @@ ssl3_HandleServerHello(sslSocket *ss, SSL3Opaque *b, PRUint32 length) + sid->u.ssl3.sessionIDLength = sidBytes.len; + PORT_Memcpy(sid->u.ssl3.sessionID, sidBytes.data, sidBytes.len); + ++ /* Copy Signed Certificate Timestamps, if any. */ ++ if (ss->xtnData.signedCertTimestamps.data) { ++ rv = SECITEM_CopyItem(NULL, &sid->u.ssl3.signedCertTimestamps, ++ &ss->xtnData.signedCertTimestamps); ++ if (rv != SECSuccess) ++ goto loser; ++ } ++ + ss->ssl3.hs.isResuming = PR_FALSE; + ss->ssl3.hs.ws = wait_server_cert; + + winner: ++ /* Clean up the temporary pointer to the handshake buffer. */ ++ ss->xtnData.signedCertTimestamps.data = NULL; ++ ss->xtnData.signedCertTimestamps.len = 0; ++ + /* If we will need a ChannelID key then we make the callback now. This + * allows the handshake to be restarted cleanly if the callback returns + * SECWouldBlock. */ +@@ -6668,6 +6680,9 @@ alert_loser: + (void)SSL3_SendAlert(ss, alert_fatal, desc); + + loser: ++ /* Clean up the temporary pointer to the handshake buffer. */ ++ ss->xtnData.signedCertTimestamps.data = NULL; ++ ss->xtnData.signedCertTimestamps.len = 0; + errCode = ssl_MapLowLevelError(errCode); + return SECFailure; + } +diff --git a/net/third_party/nss/ssl/ssl3ext.c b/net/third_party/nss/ssl/ssl3ext.c +index adb81ed..02e104d 100644 +--- a/net/third_party/nss/ssl/ssl3ext.c ++++ b/net/third_party/nss/ssl/ssl3ext.c +@@ -81,6 +81,12 @@ static PRInt32 ssl3_ClientSendSigAlgsXtn(sslSocket *ss, PRBool append, + PRUint32 maxBytes); + static SECStatus ssl3_ServerHandleSigAlgsXtn(sslSocket *ss, PRUint16 ex_type, + SECItem *data); ++static PRInt32 ssl3_ClientSendSignedCertTimestampXtn(sslSocket *ss, ++ PRBool append, ++ PRUint32 maxBytes); ++static SECStatus ssl3_ClientHandleSignedCertTimestampXtn(sslSocket *ss, ++ PRUint16 ex_type, ++ SECItem *data); + + /* + * Write bytes. Using this function means the SECItem structure +@@ -259,6 +265,8 @@ static const ssl3HelloExtensionHandler serverHelloHandlersTLS[] = { + { ssl_use_srtp_xtn, &ssl3_HandleUseSRTPXtn }, + { ssl_channel_id_xtn, &ssl3_ClientHandleChannelIDXtn }, + { ssl_cert_status_xtn, &ssl3_ClientHandleStatusRequestXtn }, ++ { ssl_signed_certificate_timestamp_xtn, ++ &ssl3_ClientHandleSignedCertTimestampXtn }, + { -1, NULL } + }; + +@@ -287,7 +295,9 @@ ssl3HelloExtensionSender clientHelloSendersTLS[SSL_MAX_EXTENSIONS] = { + { ssl_use_srtp_xtn, &ssl3_SendUseSRTPXtn }, + { ssl_channel_id_xtn, &ssl3_ClientSendChannelIDXtn }, + { ssl_cert_status_xtn, &ssl3_ClientSendStatusRequestXtn }, +- { ssl_signature_algorithms_xtn, &ssl3_ClientSendSigAlgsXtn } ++ { ssl_signature_algorithms_xtn, &ssl3_ClientSendSigAlgsXtn }, ++ { ssl_signed_certificate_timestamp_xtn, ++ &ssl3_ClientSendSignedCertTimestampXtn } + /* any extra entries will appear as { 0, NULL } */ + }; + +@@ -2364,3 +2374,65 @@ ssl3_AppendPaddingExtension(sslSocket *ss, unsigned int extensionLen, + + return extensionLen; + } ++ ++/* ssl3_ClientSendSignedCertTimestampXtn sends the signed_certificate_timestamp ++ * extension for TLS ClientHellos. */ ++static PRInt32 ++ssl3_ClientSendSignedCertTimestampXtn(sslSocket *ss, PRBool append, ++ PRUint32 maxBytes) ++{ ++ PRInt32 extension_length = 2 /* extension_type */ + ++ 2 /* length(extension_data) */; ++ ++ /* Only send the extension if processing is enabled. */ ++ if (!ss->opt.enableSignedCertTimestamps) ++ return 0; ++ ++ if (append && maxBytes >= extension_length) { ++ SECStatus rv; ++ /* extension_type */ ++ rv = ssl3_AppendHandshakeNumber(ss, ++ ssl_signed_certificate_timestamp_xtn, ++ 2); ++ if (rv != SECSuccess) ++ goto loser; ++ /* zero length */ ++ rv = ssl3_AppendHandshakeNumber(ss, 0, 2); ++ if (rv != SECSuccess) ++ goto loser; ++ ss->xtnData.advertised[ss->xtnData.numAdvertised++] = ++ ssl_signed_certificate_timestamp_xtn; ++ } else if (maxBytes < extension_length) { ++ PORT_Assert(0); ++ return 0; ++ } ++ ++ return extension_length; ++loser: ++ return -1; ++} ++ ++static SECStatus ++ssl3_ClientHandleSignedCertTimestampXtn(sslSocket *ss, PRUint16 ex_type, ++ SECItem *data) ++{ ++ /* We do not yet know whether we'll be resuming a session or creating ++ * a new one, so we keep a pointer to the data in the TLSExtensionData ++ * structure. This pointer is only valid in the scope of ++ * ssl3_HandleServerHello, and, if not resuming a session, the data is ++ * copied once a new session structure has been set up. ++ * All parsing is currently left to the application and we accept ++ * everything, including empty data. ++ */ ++ SECItem *scts = &ss->xtnData.signedCertTimestamps; ++ PORT_Assert(!scts->data && !scts->len); ++ ++ if (!data->len) { ++ /* Empty extension data: RFC 6962 mandates non-empty contents. */ ++ return SECFailure; ++ } ++ *scts = *data; ++ /* Keep track of negotiated extensions. */ ++ ss->xtnData.negotiated[ss->xtnData.numNegotiated++] = ex_type; ++ return SECSuccess; ++} +diff --git a/net/third_party/nss/ssl/sslimpl.h b/net/third_party/nss/ssl/sslimpl.h +index 79aca60..1e4655f 100644 +--- a/net/third_party/nss/ssl/sslimpl.h ++++ b/net/third_party/nss/ssl/sslimpl.h +@@ -312,29 +312,30 @@ typedef struct sslOptionsStr { + * list of supported protocols. */ + SECItem nextProtoNego; + +- unsigned int useSecurity : 1; /* 1 */ +- unsigned int useSocks : 1; /* 2 */ +- unsigned int requestCertificate : 1; /* 3 */ +- unsigned int requireCertificate : 2; /* 4-5 */ +- unsigned int handshakeAsClient : 1; /* 6 */ +- unsigned int handshakeAsServer : 1; /* 7 */ +- unsigned int enableSSL2 : 1; /* 8 */ +- unsigned int unusedBit9 : 1; /* 9 */ +- unsigned int unusedBit10 : 1; /* 10 */ +- unsigned int noCache : 1; /* 11 */ +- unsigned int fdx : 1; /* 12 */ +- unsigned int v2CompatibleHello : 1; /* 13 */ +- unsigned int detectRollBack : 1; /* 14 */ +- unsigned int noStepDown : 1; /* 15 */ +- unsigned int bypassPKCS11 : 1; /* 16 */ +- unsigned int noLocks : 1; /* 17 */ +- unsigned int enableSessionTickets : 1; /* 18 */ +- unsigned int enableDeflate : 1; /* 19 */ +- unsigned int enableRenegotiation : 2; /* 20-21 */ +- unsigned int requireSafeNegotiation : 1; /* 22 */ +- unsigned int enableFalseStart : 1; /* 23 */ +- unsigned int cbcRandomIV : 1; /* 24 */ +- unsigned int enableOCSPStapling : 1; /* 25 */ ++ unsigned int useSecurity : 1; /* 1 */ ++ unsigned int useSocks : 1; /* 2 */ ++ unsigned int requestCertificate : 1; /* 3 */ ++ unsigned int requireCertificate : 2; /* 4-5 */ ++ unsigned int handshakeAsClient : 1; /* 6 */ ++ unsigned int handshakeAsServer : 1; /* 7 */ ++ unsigned int enableSSL2 : 1; /* 8 */ ++ unsigned int unusedBit9 : 1; /* 9 */ ++ unsigned int unusedBit10 : 1; /* 10 */ ++ unsigned int noCache : 1; /* 11 */ ++ unsigned int fdx : 1; /* 12 */ ++ unsigned int v2CompatibleHello : 1; /* 13 */ ++ unsigned int detectRollBack : 1; /* 14 */ ++ unsigned int noStepDown : 1; /* 15 */ ++ unsigned int bypassPKCS11 : 1; /* 16 */ ++ unsigned int noLocks : 1; /* 17 */ ++ unsigned int enableSessionTickets : 1; /* 18 */ ++ unsigned int enableDeflate : 1; /* 19 */ ++ unsigned int enableRenegotiation : 2; /* 20-21 */ ++ unsigned int requireSafeNegotiation : 1; /* 22 */ ++ unsigned int enableFalseStart : 1; /* 23 */ ++ unsigned int cbcRandomIV : 1; /* 24 */ ++ unsigned int enableOCSPStapling : 1; /* 25 */ ++ unsigned int enableSignedCertTimestamps : 1; /* 26 */ + } sslOptions; + + typedef enum { sslHandshakingUndetermined = 0, +@@ -713,6 +714,11 @@ struct sslSessionIDStr { + * negotiated as it's used to bind the ChannelID signature on the + * resumption handshake to the original handshake. */ + SECItem originalHandshakeHash; ++ ++ /* Signed certificate timestamps received in a TLS extension. ++ ** (used only in client). ++ */ ++ SECItem signedCertTimestamps; + } ssl3; + } u; + }; +@@ -804,6 +810,18 @@ struct TLSExtensionDataStr { + * is beyond ssl3_HandleClientHello function. */ + SECItem *sniNameArr; + PRUint32 sniNameArrSize; ++ ++ /* Signed Certificate Timestamps extracted from the TLS extension. ++ * (client only). ++ * This container holds a temporary pointer to the extension data, ++ * until a session structure (the sec.ci.sid of an sslSocket) is setup ++ * that can hold a permanent copy of the data ++ * (in sec.ci.sid.u.ssl3.signedCertTimestamps). ++ * The data pointed to by this structure is neither explicitly allocated ++ * nor copied: the pointer points to the handshake message buffer and is ++ * only valid in the scope of ssl3_HandleServerHello. ++ */ ++ SECItem signedCertTimestamps; + }; + + typedef SECStatus (*sslRestartTarget)(sslSocket *); +diff --git a/net/third_party/nss/ssl/sslnonce.c b/net/third_party/nss/ssl/sslnonce.c +index eb5004c..1ca19ca 100644 +--- a/net/third_party/nss/ssl/sslnonce.c ++++ b/net/third_party/nss/ssl/sslnonce.c +@@ -122,7 +122,21 @@ ssl_DestroySID(sslSessionID *sid) + if (sid->version < SSL_LIBRARY_VERSION_3_0) { + SECITEM_ZfreeItem(&sid->u.ssl2.masterKey, PR_FALSE); + SECITEM_ZfreeItem(&sid->u.ssl2.cipherArg, PR_FALSE); ++ } else { ++ if (sid->u.ssl3.sessionTicket.ticket.data) { ++ SECITEM_FreeItem(&sid->u.ssl3.sessionTicket.ticket, PR_FALSE); ++ } ++ if (sid->u.ssl3.srvName.data) { ++ SECITEM_FreeItem(&sid->u.ssl3.srvName, PR_FALSE); ++ } ++ if (sid->u.ssl3.signedCertTimestamps.data) { ++ SECITEM_FreeItem(&sid->u.ssl3.signedCertTimestamps, PR_FALSE); ++ } ++ if (sid->u.ssl3.originalHandshakeHash.data) { ++ SECITEM_FreeItem(&sid->u.ssl3.originalHandshakeHash, PR_FALSE); ++ } + } ++ + if (sid->peerID != NULL) + PORT_Free((void *)sid->peerID); /* CONST */ + +@@ -142,16 +156,7 @@ ssl_DestroySID(sslSessionID *sid) + if ( sid->localCert ) { + CERT_DestroyCertificate(sid->localCert); + } +- if (sid->u.ssl3.sessionTicket.ticket.data) { +- SECITEM_FreeItem(&sid->u.ssl3.sessionTicket.ticket, PR_FALSE); +- } +- if (sid->u.ssl3.srvName.data) { +- SECITEM_FreeItem(&sid->u.ssl3.srvName, PR_FALSE); +- } +- if (sid->u.ssl3.originalHandshakeHash.data) { +- SECITEM_FreeItem(&sid->u.ssl3.originalHandshakeHash, PR_FALSE); +- } +- ++ + PORT_ZFree(sid, sizeof(sslSessionID)); + } + +diff --git a/net/third_party/nss/ssl/sslsock.c b/net/third_party/nss/ssl/sslsock.c +index b5c17f0..965215d 100644 +--- a/net/third_party/nss/ssl/sslsock.c ++++ b/net/third_party/nss/ssl/sslsock.c +@@ -173,7 +173,8 @@ static sslOptions ssl_defaults = { + PR_FALSE, /* requireSafeNegotiation */ + PR_FALSE, /* enableFalseStart */ + PR_TRUE, /* cbcRandomIV */ +- PR_FALSE /* enableOCSPStapling */ ++ PR_FALSE, /* enableOCSPStapling */ ++ PR_FALSE /* enableSignedCertTimestamps */ + }; + + /* +@@ -865,6 +866,10 @@ SSL_OptionSet(PRFileDesc *fd, PRInt32 which, PRBool on) + ss->opt.enableOCSPStapling = on; + break; + ++ case SSL_ENABLE_SIGNED_CERT_TIMESTAMPS: ++ ss->opt.enableSignedCertTimestamps = on; ++ break; ++ + default: + PORT_SetError(SEC_ERROR_INVALID_ARGS); + rv = SECFailure; +@@ -935,6 +940,9 @@ SSL_OptionGet(PRFileDesc *fd, PRInt32 which, PRBool *pOn) + case SSL_ENABLE_FALSE_START: on = ss->opt.enableFalseStart; break; + case SSL_CBC_RANDOM_IV: on = ss->opt.cbcRandomIV; break; + case SSL_ENABLE_OCSP_STAPLING: on = ss->opt.enableOCSPStapling; break; ++ case SSL_ENABLE_SIGNED_CERT_TIMESTAMPS: ++ on = ss->opt.enableSignedCertTimestamps; ++ break; + + default: + PORT_SetError(SEC_ERROR_INVALID_ARGS); +@@ -996,6 +1004,9 @@ SSL_OptionGetDefault(PRInt32 which, PRBool *pOn) + case SSL_ENABLE_OCSP_STAPLING: + on = ssl_defaults.enableOCSPStapling; + break; ++ case SSL_ENABLE_SIGNED_CERT_TIMESTAMPS: ++ on = ssl_defaults.enableSignedCertTimestamps; ++ break; + + default: + PORT_SetError(SEC_ERROR_INVALID_ARGS); +@@ -1163,6 +1174,10 @@ SSL_OptionSetDefault(PRInt32 which, PRBool on) + ssl_defaults.enableOCSPStapling = on; + break; + ++ case SSL_ENABLE_SIGNED_CERT_TIMESTAMPS: ++ ssl_defaults.enableSignedCertTimestamps = on; ++ break; ++ + default: + PORT_SetError(SEC_ERROR_INVALID_ARGS); + return SECFailure; +@@ -1993,6 +2008,29 @@ SSL_PeerStapledOCSPResponses(PRFileDesc *fd) + return &ss->sec.ci.sid->peerCertStatus; + } + ++const SECItem * ++SSL_PeerSignedCertTimestamps(PRFileDesc *fd) ++{ ++ sslSocket *ss = ssl_FindSocket(fd); ++ ++ if (!ss) { ++ SSL_DBG(("%d: SSL[%d]: bad socket in SSL_PeerSignedCertTimestamps", ++ SSL_GETPID(), fd)); ++ return NULL; ++ } ++ ++ if (!ss->sec.ci.sid) { ++ PORT_SetError(SEC_ERROR_NOT_INITIALIZED); ++ return NULL; ++ } ++ ++ if (ss->sec.ci.sid->version < SSL_LIBRARY_VERSION_3_0) { ++ PORT_SetError(SSL_ERROR_FEATURE_NOT_SUPPORTED_FOR_SSL2); ++ return NULL; ++ } ++ return &ss->sec.ci.sid->u.ssl3.signedCertTimestamps; ++} ++ + SECStatus + SSL_HandshakeResumedSession(PRFileDesc *fd, PRBool *handshake_resumed) { + sslSocket *ss = ssl_FindSocket(fd); +@@ -3133,4 +3171,3 @@ loser: + } + return ss; + } +- +diff --git a/net/third_party/nss/ssl/sslt.h b/net/third_party/nss/ssl/sslt.h +index b813c04..1f5e2c6 100644 +--- a/net/third_party/nss/ssl/sslt.h ++++ b/net/third_party/nss/ssl/sslt.h +@@ -202,6 +202,7 @@ typedef enum { + ssl_signature_algorithms_xtn = 13, + ssl_use_srtp_xtn = 14, + ssl_app_layer_protocol_xtn = 16, ++ ssl_signed_certificate_timestamp_xtn = 18, /* RFC 6962 */ + ssl_session_ticket_xtn = 35, + ssl_next_proto_nego_xtn = 13172, + ssl_channel_id_xtn = 30032, +@@ -209,6 +210,6 @@ typedef enum { + ssl_renegotiation_info_xtn = 0xff01 /* 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. */ + + #endif /* __sslt_h_ */ diff --git a/chromium/net/third_party/nss/patches/sslnoncestatics.patch b/chromium/net/third_party/nss/patches/sslnoncestatics.patch new file mode 100644 index 00000000000..336fe1d5587 --- /dev/null +++ b/chromium/net/third_party/nss/patches/sslnoncestatics.patch @@ -0,0 +1,15 @@ +diff --git a/net/third_party/nss/ssl/sslnonce.c b/net/third_party/nss/ssl/sslnonce.c +index 758aa4e..a3e6e0a 100644 +--- a/net/third_party/nss/ssl/sslnonce.c ++++ b/net/third_party/nss/ssl/sslnonce.c +@@ -21,8 +21,8 @@ + PRUint32 ssl_sid_timeout = 100; + PRUint32 ssl3_sid_timeout = 86400L; /* 24 hours */ + +-static sslSessionID *cache = NULL; +-static PZLock * cacheLock = NULL; ++sslSessionID *cache = NULL; ++PZLock * cacheLock = NULL; + + /* sids can be in one of 4 states: + * diff --git a/chromium/net/third_party/nss/patches/tls12backuphash2.patch b/chromium/net/third_party/nss/patches/tls12backuphash2.patch new file mode 100644 index 00000000000..85e5308db6b --- /dev/null +++ b/chromium/net/third_party/nss/patches/tls12backuphash2.patch @@ -0,0 +1,127 @@ +diff --git a/net/third_party/nss/ssl/ssl3con.c b/net/third_party/nss/ssl/ssl3con.c +index 06992e0..cf7ef32 100644 +--- a/net/third_party/nss/ssl/ssl3con.c ++++ b/net/third_party/nss/ssl/ssl3con.c +@@ -6973,14 +6973,27 @@ no_memory: /* no-memory error has already been set. */ + + + /* +- * Returns true if the client authentication key is an RSA or DSA key that +- * may be able to sign only SHA-1 hashes. ++ * Returns the TLS signature algorithm for the client authentication key and ++ * whether it is an RSA or DSA key that may be able to sign only SHA-1 hashes. + */ +-static PRBool +-ssl3_ClientKeyPrefersSHA1(sslSocket *ss) ++static SECStatus ++ssl3_ExtractClientKeyInfo(sslSocket *ss, ++ TLSSignatureAlgorithm *sigAlg, ++ PRBool *preferSha1) + { ++ SECStatus rv = SECSuccess; + SECKEYPublicKey *pubk; +- PRBool prefer_sha1 = PR_FALSE; ++ ++ pubk = CERT_ExtractPublicKey(ss->ssl3.clientCertificate); ++ if (pubk == NULL) { ++ rv = SECFailure; ++ goto done; ++ } ++ ++ rv = ssl3_TLSSignatureAlgorithmForKeyType(pubk->keyType, sigAlg); ++ if (rv != SECSuccess) { ++ goto done; ++ } + + #if defined(NSS_PLATFORM_CLIENT_AUTH) && defined(_WIN32) + /* If the key is in CAPI, assume conservatively that the CAPI service +@@ -6989,7 +7002,8 @@ ssl3_ClientKeyPrefersSHA1(sslSocket *ss) + if (ss->ssl3.platformClientKey->dwKeySpec != CERT_NCRYPT_KEY_SPEC) { + /* CAPI only supports RSA and DSA signatures, so we don't need to + * check the key type. */ +- return PR_TRUE; ++ *preferSha1 = PR_TRUE; ++ goto done; + } + #endif /* NSS_PLATFORM_CLIENT_AUTH && _WIN32 */ + +@@ -6999,38 +7013,61 @@ ssl3_ClientKeyPrefersSHA1(sslSocket *ss) + * older, DSA key size is at most 1024 bits and the hash function must + * be SHA-1. + */ +- pubk = CERT_ExtractPublicKey(ss->ssl3.clientCertificate); +- if (pubk == NULL) { +- return PR_FALSE; +- } + if (pubk->keyType == rsaKey || pubk->keyType == dsaKey) { +- prefer_sha1 = SECKEY_PublicKeyStrength(pubk) <= 128; ++ *preferSha1 = SECKEY_PublicKeyStrength(pubk) <= 128; ++ } else { ++ *preferSha1 = PR_FALSE; + } +- SECKEY_DestroyPublicKey(pubk); +- return prefer_sha1; ++ ++ done: ++ if (pubk) ++ SECKEY_DestroyPublicKey(pubk); ++ return rv; + } + +-/* Destroys the backup handshake hash context if we don't need it. */ ++/* Destroys the backup handshake hash context if we don't need it. Note that ++ * this function selects the hash algorithm for client authentication ++ * signatures; ssl3_SendCertificateVerify uses the presence of the backup hash ++ * to determine whether to use SHA-1 or SHA-256. */ + static void + ssl3_DestroyBackupHandshakeHashIfNotNeeded(sslSocket *ss, + const SECItem *algorithms) + { +- PRBool need_backup_hash = PR_FALSE; ++ SECStatus rv; ++ TLSSignatureAlgorithm sigAlg; ++ PRBool preferSha1; ++ PRBool supportsSha1 = PR_FALSE; ++ PRBool supportsSha256 = PR_FALSE; ++ PRBool needBackupHash = PR_FALSE; + unsigned int i; + + PORT_Assert(ss->ssl3.hs.md5); +- if (ssl3_ClientKeyPrefersSHA1(ss)) { +- /* Use SHA-1 if the server supports it. */ +- for (i = 0; i < algorithms->len; i += 2) { +- if (algorithms->data[i] == tls_hash_sha1 && +- (algorithms->data[i+1] == tls_sig_rsa || +- algorithms->data[i+1] == tls_sig_dsa)) { +- need_backup_hash = PR_TRUE; +- break; ++ ++ /* Determine the key's signature algorithm and whether it prefers SHA-1. */ ++ rv = ssl3_ExtractClientKeyInfo(ss, &sigAlg, &preferSha1); ++ if (rv != SECSuccess) { ++ goto done; ++ } ++ ++ /* Determine the server's hash support for that signature algorithm. */ ++ for (i = 0; i < algorithms->len; i += 2) { ++ if (algorithms->data[i+1] == sigAlg) { ++ if (algorithms->data[i] == tls_hash_sha1) { ++ supportsSha1 = PR_TRUE; ++ } else if (algorithms->data[i] == tls_hash_sha256) { ++ supportsSha256 = PR_TRUE; + } + } + } +- if (!need_backup_hash) { ++ ++ /* If either the server does not support SHA-256 or the client key prefers ++ * SHA-1, leave the backup hash. */ ++ if (supportsSha1 && (preferSha1 || !supportsSha256)) { ++ needBackupHash = PR_TRUE; ++ } ++ ++done: ++ if (!needBackupHash) { + PK11_DestroyContext(ss->ssl3.hs.md5, PR_TRUE); + ss->ssl3.hs.md5 = NULL; + } diff --git a/chromium/net/third_party/nss/ssl/SSLerrs.h b/chromium/net/third_party/nss/ssl/SSLerrs.h index c0d26ccfadc..4ff0b7ddda4 100644 --- a/chromium/net/third_party/nss/ssl/SSLerrs.h +++ b/chromium/net/third_party/nss/ssl/SSLerrs.h @@ -421,3 +421,8 @@ ER3(SSL_ERROR_INVALID_CHANNEL_ID_KEY, (SSL_ERROR_BASE + 130), ER3(SSL_ERROR_GET_CHANNEL_ID_FAILED, (SSL_ERROR_BASE + 131), "The application could not get a TLS Channel ID.") + +ER3(SSL_ERROR_INAPPROPRIATE_FALLBACK_ALERT, (SSL_ERROR_BASE + 132), +"The connection was using a lesser TLS version as a result of a previous" +" handshake failure, but the server indicated that it should not have been" +" needed.") diff --git a/chromium/net/third_party/nss/ssl/exports_win.def b/chromium/net/third_party/nss/ssl/exports_win.def index 09c70b0b410..a1045bb9212 100644 --- a/chromium/net/third_party/nss/ssl/exports_win.def +++ b/chromium/net/third_party/nss/ssl/exports_win.def @@ -50,6 +50,8 @@ SSL_ExportKeyingMaterial SSL_VersionRangeSet SSL_GetSRTPCipher SSL_SetSRTPCiphers +SSL_RecommendedCanFalseStart +SSL_SetCanFalseStartCallback ; Chromium patches SSL_PeerCertificateChain @@ -58,3 +60,7 @@ SSL_GetPlatformClientAuthDataHook SSL_HandshakeResumedSession SSL_RestartHandshakeAfterChannelIDReq SSL_GetChannelBinding +SSL_PeerSignedCertTimestamps +SSL_CipherOrderSet +SSL_CacheSession +SSL_CacheSessionUnlocked diff --git a/chromium/net/third_party/nss/ssl/ssl.h b/chromium/net/third_party/nss/ssl/ssl.h index 47468a0a289..6f7c9889f00 100644 --- a/chromium/net/third_party/nss/ssl/ssl.h +++ b/chromium/net/third_party/nss/ssl/ssl.h @@ -129,13 +129,8 @@ SSL_IMPORT PRFileDesc *DTLS_ImportFD(PRFileDesc *model, PRFileDesc *fd); * it saves a round trip for client-speaks-first protocols when performing a * full handshake. * - * See SSL_DefaultCanFalseStart for the default criteria that NSS uses to - * determine whether to false start or not. See SSL_SetCanFalseStartCallback - * for how to change that criteria. In addition to those criteria, false start - * will only be done when the server selects a cipher suite with an effective - * key length of 80 bits or more (including RC4-128). Also, see - * SSL_HandshakeCallback for a description on how false start affects when the - * handshake callback gets called. + * In addition to enabling this option, the application must register a + * callback using the SSL_SetCanFalseStartCallback function. */ /* For SSL 3.0 and TLS 1.0, by default we prevent chosen plaintext attacks @@ -166,6 +161,10 @@ SSL_IMPORT PRFileDesc *DTLS_ImportFD(PRFileDesc *model, PRFileDesc *fd); */ #define SSL_CBC_RANDOM_IV 23 #define SSL_ENABLE_OCSP_STAPLING 24 /* Request OCSP stapling (client) */ +/* Request Signed Certificate Timestamps via TLS extension (client) */ +#define SSL_ENABLE_SIGNED_CERT_TIMESTAMPS 25 +#define SSL_ENABLE_FALLBACK_SCSV 26 /* Send fallback SCSV in + * handshakes. */ #ifdef SSL_DEPRECATED_FUNCTION /* Old deprecated function names */ @@ -268,6 +267,13 @@ SSL_IMPORT SECStatus SSL_CipherPrefGetDefault(PRInt32 cipher, PRBool *enabled); SSL_IMPORT SECStatus SSL_CipherPolicySet(PRInt32 cipher, PRInt32 policy); SSL_IMPORT SECStatus SSL_CipherPolicyGet(PRInt32 cipher, PRInt32 *policy); +/* SSL_CipherOrderSet sets the cipher suite preference order from |ciphers|, + * which must be an array of cipher suite ids of length |len|. All the given + * cipher suite ids must appear in the array that is returned by + * |SSL_GetImplementedCiphers| and may only appear once, at most. */ +SSL_IMPORT SECStatus SSL_CipherOrderSet(PRFileDesc *fd, const PRUint16 *ciphers, + unsigned int len); + /* SSLChannelBindingType enumerates the types of supported channel binding * values. See RFC 5929. */ typedef enum SSLChannelBindingType { @@ -469,6 +475,23 @@ SSL_IMPORT CERTCertList *SSL_PeerCertificateChain(PRFileDesc *fd); */ SSL_IMPORT const SECItemArray * SSL_PeerStapledOCSPResponses(PRFileDesc *fd); +/* SSL_PeerSignedCertTimestamps returns the signed_certificate_timestamp + * extension data provided by the TLS server. The return value is a pointer + * to an internal SECItem that contains the returned response (as a serialized + * SignedCertificateTimestampList, see RFC 6962). The returned pointer is only + * valid until the callback function that calls SSL_PeerSignedCertTimestamps + * (e.g. the authenticate certificate hook, or the handshake callback) returns. + * + * If no Signed Certificate Timestamps were given by the server then the result + * will be empty. If there was an error, then the result will be NULL. + * + * You must set the SSL_ENABLE_SIGNED_CERT_TIMESTAMPS option to indicate support + * for Signed Certificate Timestamps to a server. + * + * libssl does not do any parsing or validation of the response itself. + */ +SSL_IMPORT const SECItem * SSL_PeerSignedCertTimestamps(PRFileDesc *fd); + /* SSL_SetStapledOCSPResponses stores an array of one or multiple OCSP responses * in the fd's data, which may be sent as part of a server side cert_status * handshake message. Parameter |responses| is for the server certificate of @@ -749,45 +772,30 @@ SSL_IMPORT SECStatus SSL_SetMaxServerCacheLocks(PRUint32 maxLocks); SSL_IMPORT SECStatus SSL_InheritMPServerSIDCache(const char * envString); /* -** Set the callback that normally gets called when the TLS handshake -** is complete. If false start is not enabled, then the handshake callback is -** called after verifying the peer's Finished message and before sending -** outgoing application data and before processing incoming application data. -** -** If false start is enabled and there is a custom CanFalseStartCallback -** callback set, then the handshake callback gets called after the peer's -** Finished message has been verified, which may be after application data is -** sent. +** Set the callback that gets called when a TLS handshake is complete. The +** handshake callback is called after verifying the peer's Finished message and +** before processing incoming application data. ** -** If false start is enabled and there is not a custom CanFalseStartCallback -** callback established with SSL_SetCanFalseStartCallback then the handshake -** callback gets called before any application data is sent, which may be -** before the peer's Finished message has been verified. +** For the initial handshake: If the handshake false started (see +** SSL_ENABLE_FALSE_START), then application data may already have been sent +** before the handshake callback is called. If we did not false start then the +** callback will get called before any application data is sent. */ typedef void (PR_CALLBACK *SSLHandshakeCallback)(PRFileDesc *fd, void *client_data); SSL_IMPORT SECStatus SSL_HandshakeCallback(PRFileDesc *fd, SSLHandshakeCallback cb, void *client_data); -/* Applications that wish to customize TLS false start should set this callback +/* Applications that wish to enable TLS false start must set this callback ** function. NSS will invoke the functon to determine if a particular ** connection should use false start or not. SECSuccess indicates that the ** callback completed successfully, and if so *canFalseStart indicates if false ** start can be used. If the callback does not return SECSuccess then the -** handshake will be canceled. -** -** Applications that do not set the callback will use an internal set of -** criteria to determine if the connection should false start. If -** the callback is set false start will never be used without invoking the -** callback function, but some connections (e.g. resumed connections) will -** never use false start and therefore will not invoke the callback. -** -** NSS's internal criteria for this connection can be evaluated by calling -** SSL_DefaultCanFalseStart() from the custom callback. +** handshake will be canceled. NSS's recommended criteria can be evaluated by +** calling SSL_RecommendedCanFalseStart. ** -** See the description of SSL_HandshakeCallback for important information on -** how registering a custom false start callback affects when the handshake -** callback gets called. +** If no false start callback is registered then false start will never be +** done, even if the SSL_ENABLE_FALSE_START option is enabled. **/ typedef SECStatus (PR_CALLBACK *SSLCanFalseStartCallback)( PRFileDesc *fd, void *arg, PRBool *canFalseStart); @@ -795,12 +803,13 @@ typedef SECStatus (PR_CALLBACK *SSLCanFalseStartCallback)( SSL_IMPORT SECStatus SSL_SetCanFalseStartCallback( PRFileDesc *fd, SSLCanFalseStartCallback callback, void *arg); -/* A utility function that can be called from a custom CanFalseStartCallback -** function to determine what NSS would have done for this connection if the -** custom callback was not implemented. -**/ -SSL_IMPORT SECStatus SSL_DefaultCanFalseStart(PRFileDesc *fd, - PRBool *canFalseStart); +/* This function sets *canFalseStart according to the recommended criteria for +** false start. These criteria may change from release to release and may depend +** on which handshake features have been negotiated and/or properties of the +** certifciates/keys used on the connection. +*/ +SSL_IMPORT SECStatus SSL_RecommendedCanFalseStart(PRFileDesc *fd, + PRBool *canFalseStart); /* ** For the server, request a new handshake. For the client, begin a new @@ -863,6 +872,18 @@ SSL_IMPORT int SSL_DataPending(PRFileDesc *fd); SSL_IMPORT SECStatus SSL_InvalidateSession(PRFileDesc *fd); /* +** Cache the SSL session associated with fd, if it has not already been cached. +*/ +SSL_IMPORT SECStatus SSL_CacheSession(PRFileDesc *fd); + +/* +** Cache the SSL session associated with fd, if it has not already been cached. +** This function may only be called when processing within a callback assigned +** via SSL_HandshakeCallback +*/ +SSL_IMPORT SECStatus SSL_CacheSessionUnlocked(PRFileDesc *fd); + +/* ** Return a SECItem containing the SSL session ID associated with the fd. */ SSL_IMPORT SECItem *SSL_GetSessionID(PRFileDesc *fd); diff --git a/chromium/net/third_party/nss/ssl/ssl3con.c b/chromium/net/third_party/nss/ssl/ssl3con.c index 8b8b758c0b4..e2be5e6f5da 100644 --- a/chromium/net/third_party/nss/ssl/ssl3con.c +++ b/chromium/net/third_party/nss/ssl/ssl3con.c @@ -3469,6 +3469,9 @@ ssl3_HandleAlert(sslSocket *ss, sslBuffer *buf) case certificate_unknown: error = SSL_ERROR_CERTIFICATE_UNKNOWN_ALERT; break; case illegal_parameter: error = SSL_ERROR_ILLEGAL_PARAMETER_ALERT;break; + case inappropriate_fallback: + error = SSL_ERROR_INAPPROPRIATE_FALLBACK_ALERT; + break; /* All alerts below are TLS only. */ case unknown_ca: error = SSL_ERROR_UNKNOWN_CA_ALERT; break; @@ -4973,8 +4976,9 @@ ssl3_SendClientHello(sslSocket *ss, PRBool resending) int num_suites; int actual_count = 0; PRBool isTLS = PR_FALSE; - PRBool requestingResume = PR_FALSE; + PRBool requestingResume = PR_FALSE, fallbackSCSV = PR_FALSE; PRInt32 total_exten_len = 0; + unsigned paddingExtensionLen; unsigned numCompressionMethods; PRInt32 flags; @@ -5222,8 +5226,15 @@ ssl3_SendClientHello(sslSocket *ss, PRBool resending) num_suites = count_cipher_suites(ss, ss->ssl3.policy, PR_TRUE); if (!num_suites) return SECFailure; /* count_cipher_suites has set error code. */ + + fallbackSCSV = ss->opt.enableFallbackSCSV && (!requestingResume || + ss->version < sid->version); + /* make room for SCSV */ if (ss->ssl3.hs.sendingSCSV) { - ++num_suites; /* make room for SCSV */ + ++num_suites; + } + if (fallbackSCSV) { + ++num_suites; } /* count compression methods */ @@ -5241,6 +5252,20 @@ ssl3_SendClientHello(sslSocket *ss, PRBool resending) length += 1 + ss->ssl3.hs.cookieLen; } + /* A padding extension may be included to ensure that the record containing + * the ClientHello doesn't have a length between 256 and 511 bytes + * (inclusive). Initial, ClientHello records with such lengths trigger bugs + * in F5 devices. + * + * This is not done for DTLS nor for renegotiation. */ + if (!IS_DTLS(ss) && isTLS && !ss->firstHsDone) { + paddingExtensionLen = ssl3_CalculatePaddingExtensionLength(length); + total_exten_len += paddingExtensionLen; + length += paddingExtensionLen; + } else { + paddingExtensionLen = 0; + } + rv = ssl3_AppendHandshakeHeader(ss, client_hello, length); if (rv != SECSuccess) { return rv; /* err set by ssl3_AppendHandshake* */ @@ -5307,6 +5332,14 @@ ssl3_SendClientHello(sslSocket *ss, PRBool resending) } actual_count++; } + if (fallbackSCSV) { + rv = ssl3_AppendHandshakeNumber(ss, TLS_FALLBACK_SCSV, + sizeof(ssl3CipherSuite)); + if (rv != SECSuccess) { + return rv; /* err set by ssl3_AppendHandshake* */ + } + actual_count++; + } for (i = 0; i < ssl_V3_SUITES_IMPLEMENTED; i++) { ssl3CipherSuiteCfg *suite = &ss->cipherSuites[i]; if (config_match(suite, ss->ssl3.policy, PR_TRUE, &ss->vrange)) { @@ -5360,6 +5393,13 @@ ssl3_SendClientHello(sslSocket *ss, PRBool resending) return SECFailure; } maxBytes -= extLen; + + extLen = ssl3_AppendPaddingExtension(ss, paddingExtensionLen, maxBytes); + if (extLen < 0) { + return SECFailure; + } + maxBytes -= extLen; + PORT_Assert(!maxBytes); } if (ss->ssl3.hs.sendingSCSV) { @@ -6617,10 +6657,22 @@ ssl3_HandleServerHello(sslSocket *ss, SSL3Opaque *b, PRUint32 length) sid->u.ssl3.sessionIDLength = sidBytes.len; PORT_Memcpy(sid->u.ssl3.sessionID, sidBytes.data, sidBytes.len); + /* Copy Signed Certificate Timestamps, if any. */ + if (ss->xtnData.signedCertTimestamps.data) { + rv = SECITEM_CopyItem(NULL, &sid->u.ssl3.signedCertTimestamps, + &ss->xtnData.signedCertTimestamps); + if (rv != SECSuccess) + goto loser; + } + ss->ssl3.hs.isResuming = PR_FALSE; ss->ssl3.hs.ws = wait_server_cert; winner: + /* Clean up the temporary pointer to the handshake buffer. */ + ss->xtnData.signedCertTimestamps.data = NULL; + ss->xtnData.signedCertTimestamps.len = 0; + /* If we will need a ChannelID key then we make the callback now. This * allows the handshake to be restarted cleanly if the callback returns * SECWouldBlock. */ @@ -6646,6 +6698,9 @@ alert_loser: (void)SSL3_SendAlert(ss, alert_fatal, desc); loser: + /* Clean up the temporary pointer to the handshake buffer. */ + ss->xtnData.signedCertTimestamps.data = NULL; + ss->xtnData.signedCertTimestamps.len = 0; errCode = ssl_MapLowLevelError(errCode); return SECFailure; } @@ -6936,14 +6991,27 @@ no_memory: /* no-memory error has already been set. */ /* - * Returns true if the client authentication key is an RSA or DSA key that - * may be able to sign only SHA-1 hashes. + * Returns the TLS signature algorithm for the client authentication key and + * whether it is an RSA or DSA key that may be able to sign only SHA-1 hashes. */ -static PRBool -ssl3_ClientKeyPrefersSHA1(sslSocket *ss) +static SECStatus +ssl3_ExtractClientKeyInfo(sslSocket *ss, + TLSSignatureAlgorithm *sigAlg, + PRBool *preferSha1) { + SECStatus rv = SECSuccess; SECKEYPublicKey *pubk; - PRBool prefer_sha1 = PR_FALSE; + + pubk = CERT_ExtractPublicKey(ss->ssl3.clientCertificate); + if (pubk == NULL) { + rv = SECFailure; + goto done; + } + + rv = ssl3_TLSSignatureAlgorithmForKeyType(pubk->keyType, sigAlg); + if (rv != SECSuccess) { + goto done; + } #if defined(NSS_PLATFORM_CLIENT_AUTH) && defined(_WIN32) /* If the key is in CAPI, assume conservatively that the CAPI service @@ -6952,7 +7020,8 @@ ssl3_ClientKeyPrefersSHA1(sslSocket *ss) if (ss->ssl3.platformClientKey->dwKeySpec != CERT_NCRYPT_KEY_SPEC) { /* CAPI only supports RSA and DSA signatures, so we don't need to * check the key type. */ - return PR_TRUE; + *preferSha1 = PR_TRUE; + goto done; } #endif /* NSS_PLATFORM_CLIENT_AUTH && _WIN32 */ @@ -6962,38 +7031,61 @@ ssl3_ClientKeyPrefersSHA1(sslSocket *ss) * older, DSA key size is at most 1024 bits and the hash function must * be SHA-1. */ - pubk = CERT_ExtractPublicKey(ss->ssl3.clientCertificate); - if (pubk == NULL) { - return PR_FALSE; - } if (pubk->keyType == rsaKey || pubk->keyType == dsaKey) { - prefer_sha1 = SECKEY_PublicKeyStrength(pubk) <= 128; + *preferSha1 = SECKEY_PublicKeyStrength(pubk) <= 128; + } else { + *preferSha1 = PR_FALSE; } - SECKEY_DestroyPublicKey(pubk); - return prefer_sha1; + + done: + if (pubk) + SECKEY_DestroyPublicKey(pubk); + return rv; } -/* Destroys the backup handshake hash context if we don't need it. */ +/* Destroys the backup handshake hash context if we don't need it. Note that + * this function selects the hash algorithm for client authentication + * signatures; ssl3_SendCertificateVerify uses the presence of the backup hash + * to determine whether to use SHA-1 or SHA-256. */ static void ssl3_DestroyBackupHandshakeHashIfNotNeeded(sslSocket *ss, const SECItem *algorithms) { - PRBool need_backup_hash = PR_FALSE; + SECStatus rv; + TLSSignatureAlgorithm sigAlg; + PRBool preferSha1; + PRBool supportsSha1 = PR_FALSE; + PRBool supportsSha256 = PR_FALSE; + PRBool needBackupHash = PR_FALSE; unsigned int i; PORT_Assert(ss->ssl3.hs.md5); - if (ssl3_ClientKeyPrefersSHA1(ss)) { - /* Use SHA-1 if the server supports it. */ - for (i = 0; i < algorithms->len; i += 2) { - if (algorithms->data[i] == tls_hash_sha1 && - (algorithms->data[i+1] == tls_sig_rsa || - algorithms->data[i+1] == tls_sig_dsa)) { - need_backup_hash = PR_TRUE; - break; + + /* Determine the key's signature algorithm and whether it prefers SHA-1. */ + rv = ssl3_ExtractClientKeyInfo(ss, &sigAlg, &preferSha1); + if (rv != SECSuccess) { + goto done; + } + + /* Determine the server's hash support for that signature algorithm. */ + for (i = 0; i < algorithms->len; i += 2) { + if (algorithms->data[i+1] == sigAlg) { + if (algorithms->data[i] == tls_hash_sha1) { + supportsSha1 = PR_TRUE; + } else if (algorithms->data[i] == tls_hash_sha256) { + supportsSha256 = PR_TRUE; } } } - if (!need_backup_hash) { + + /* If either the server does not support SHA-256 or the client key prefers + * SHA-1, leave the backup hash. */ + if (supportsSha1 && (preferSha1 || !supportsSha256)) { + needBackupHash = PR_TRUE; + } + +done: + if (!needBackupHash) { PK11_DestroyContext(ss->ssl3.hs.md5, PR_TRUE); ss->ssl3.hs.md5 = NULL; } @@ -7352,40 +7444,69 @@ ssl3_RestartHandshakeAfterCertReq(sslSocket * ss, static SECStatus ssl3_CheckFalseStart(sslSocket *ss) { - SECStatus rv; - PRBool maybeFalseStart = PR_TRUE; - PORT_Assert( ss->opt.noLocks || ssl_HaveSSL3HandshakeLock(ss) ); PORT_Assert( !ss->ssl3.hs.authCertificatePending ); - - /* An attacker can control the selected ciphersuite so we only wish to - * do False Start in the case that the selected ciphersuite is - * sufficiently strong that the attack can gain no advantage. - * Therefore we always require an 80-bit cipher. */ - - ssl_GetSpecReadLock(ss); - if (ss->ssl3.cwSpec->cipher_def->secret_key_size < 10) { - ss->ssl3.hs.canFalseStart = PR_FALSE; - maybeFalseStart = PR_FALSE; - } - ssl_ReleaseSpecReadLock(ss); - if (!maybeFalseStart) { - return SECSuccess; - } + PORT_Assert( !ss->ssl3.hs.canFalseStart ); if (!ss->canFalseStartCallback) { - rv = SSL_DefaultCanFalseStart(ss->fd, &ss->ssl3.hs.canFalseStart); + SSL_TRC(3, ("%d: SSL[%d]: no false start callback so no false start", + SSL_GETPID(), ss->fd)); } else { - rv = (ss->canFalseStartCallback)(ss->fd, - ss->canFalseStartCallbackData, - &ss->ssl3.hs.canFalseStart); + PRBool maybeFalseStart; + SECStatus rv; + + /* An attacker can control the selected ciphersuite so we only wish to + * do False Start in the case that the selected ciphersuite is + * sufficiently strong that the attack can gain no advantage. + * Therefore we always require an 80-bit cipher. */ + ssl_GetSpecReadLock(ss); + maybeFalseStart = ss->ssl3.cwSpec->cipher_def->secret_key_size >= 10; + ssl_ReleaseSpecReadLock(ss); + + if (!maybeFalseStart) { + SSL_TRC(3, ("%d: SSL[%d]: no false start due to weak cipher", + SSL_GETPID(), ss->fd)); + } else { + rv = (ss->canFalseStartCallback)(ss->fd, + ss->canFalseStartCallbackData, + &ss->ssl3.hs.canFalseStart); + if (rv == SECSuccess) { + SSL_TRC(3, ("%d: SSL[%d]: false start callback returned %s", + SSL_GETPID(), ss->fd, + ss->ssl3.hs.canFalseStart ? "TRUE" : "FALSE")); + } else { + SSL_TRC(3, ("%d: SSL[%d]: false start callback failed (%s)", + SSL_GETPID(), ss->fd, + PR_ErrorToName(PR_GetError()))); + } + return rv; + } } - if (rv != SECSuccess) { - ss->ssl3.hs.canFalseStart = PR_FALSE; + ss->ssl3.hs.canFalseStart = PR_FALSE; + return SECSuccess; +} + +PRBool +ssl3_WaitingForStartOfServerSecondRound(sslSocket *ss) +{ + PRBool result; + + PORT_Assert( ss->opt.noLocks || ssl_HaveSSL3HandshakeLock(ss) ); + + switch (ss->ssl3.hs.ws) { + case wait_new_session_ticket: + result = PR_TRUE; + break; + case wait_change_cipher: + result = !ssl3_ExtensionNegotiated(ss, ssl_session_ticket_xtn); + break; + default: + result = PR_FALSE; + break; } - return rv; + return result; } static SECStatus ssl3_SendClientSecondRound(sslSocket *ss); @@ -7475,6 +7596,9 @@ ssl3_SendClientSecondRound(sslSocket *ss) } if (ss->ssl3.hs.authCertificatePending && (sendClientCert || ss->ssl3.sendEmptyCert || ss->firstHsDone)) { + SSL_TRC(3, ("%d: SSL3[%p]: deferring ssl3_SendClientSecondRound because" + " certificate authentication is still pending.", + SSL_GETPID(), ss->fd)); ss->ssl3.hs.restartTarget = ssl3_SendClientSecondRound; return SECWouldBlock; } @@ -7544,7 +7668,7 @@ ssl3_SendClientSecondRound(sslSocket *ss) * call ssl3_CheckFalseStart before calling ssl3_SendFinished, * which includes a call to ssl3_FlushHandshake, so that * no application develops a reliance on such flushing being - * done before its false start callback is called. + * done before its false start callback is called. */ ssl_ReleaseXmitBufLock(ss); rv = ssl3_CheckFalseStart(ss); @@ -7572,23 +7696,39 @@ ssl3_SendClientSecondRound(sslSocket *ss) ssl_ReleaseXmitBufLock(ss); /*******************************/ + if (!ss->ssl3.hs.isResuming && + ssl3_ExtensionNegotiated(ss, ssl_channel_id_xtn)) { + /* If we are negotiating ChannelID on a full handshake then we record + * the handshake hashes in |sid| at this point. They will be needed in + * the event that we resume this session and use ChannelID on the + * resumption handshake. */ + SSL3Hashes hashes; + SECItem *originalHandshakeHash = + &ss->sec.ci.sid->u.ssl3.originalHandshakeHash; + PORT_Assert(ss->sec.ci.sid->cached == never_cached); + + ssl_GetSpecReadLock(ss); + PORT_Assert(ss->version > SSL_LIBRARY_VERSION_3_0); + rv = ssl3_ComputeHandshakeHashes(ss, ss->ssl3.cwSpec, &hashes, 0); + ssl_ReleaseSpecReadLock(ss); + if (rv != SECSuccess) { + return rv; + } + + PORT_Assert(originalHandshakeHash->len == 0); + originalHandshakeHash->data = PORT_Alloc(hashes.len); + if (!originalHandshakeHash->data) + return SECFailure; + originalHandshakeHash->len = hashes.len; + memcpy(originalHandshakeHash->data, hashes.u.raw, hashes.len); + } + if (ssl3_ExtensionNegotiated(ss, ssl_session_ticket_xtn)) ss->ssl3.hs.ws = wait_new_session_ticket; else ss->ssl3.hs.ws = wait_change_cipher; - if (ss->handshakeCallback && - (ss->ssl3.hs.canFalseStart && !ss->canFalseStartCallback)) { - /* Call the handshake callback here for backwards compatibility with - * applications that were using false start before - * canFalseStartCallback was added. Note that we do this after calling - * ssl3_SendFinished, which includes a call to ssl3_FlushHandshake, - * just in case the application is relying on having the handshake - * messages flushed to the network before its handshake callback is - * called. - */ - (ss->handshakeCallback)(ss->fd, ss->handshakeCallbackData); - } + PORT_Assert(ssl3_WaitingForStartOfServerSecondRound(ss)); return SECSuccess; @@ -7915,6 +8055,19 @@ ssl3_HandleClientHello(sslSocket *ss, SSL3Opaque *b, PRUint32 length) goto loser; /* malformed */ } + /* If the ClientHello version is less than our maximum version, check for a + * TLS_FALLBACK_SCSV and reject the connection if found. */ + if (ss->vrange.max > ss->clientHelloVersion) { + for (i = 0; i + 1 < suites.len; i += 2) { + PRUint16 suite_i = (suites.data[i] << 8) | suites.data[i + 1]; + if (suite_i != TLS_FALLBACK_SCSV) + continue; + desc = inappropriate_fallback; + errCode = SSL_ERROR_INAPPROPRIATE_FALLBACK_ALERT; + goto alert_loser; + } + } + /* grab the list of compression methods. */ rv = ssl3_ConsumeHandshakeVariable(ss, &comps, 1, &b, &length); if (rv != SECSuccess) { @@ -10345,36 +10498,24 @@ ssl3_AuthCertificateComplete(sslSocket *ss, PRErrorCode error) rv = SECSuccess; } } else { - SSL_TRC(3, ("%d: SSL3[%p]: certificate authentication won the race" - " with peer's finished message", SSL_GETPID(), ss->fd)); + SSL_TRC(3, ("%d: SSL3[%p]: certificate authentication won the race with" + " peer's finished message", SSL_GETPID(), ss->fd)); PORT_Assert(!ss->firstHsDone); PORT_Assert(!ss->sec.isServer); PORT_Assert(!ss->ssl3.hs.isResuming); - PORT_Assert(ss->ssl3.hs.ws == wait_change_cipher || - ss->ssl3.hs.ws == wait_finished || - ss->ssl3.hs.ws == wait_new_session_ticket); + PORT_Assert(ss->ssl3.hs.ws != idle_handshake); - /* ssl3_SendClientSecondRound deferred the false start check because - * certificate authentication was pending, so we have to do it now. - */ if (ss->opt.enableFalseStart && !ss->firstHsDone && !ss->sec.isServer && !ss->ssl3.hs.isResuming && - (ss->ssl3.hs.ws == wait_change_cipher || - ss->ssl3.hs.ws == wait_finished || - ss->ssl3.hs.ws == wait_new_session_ticket)) { + ssl3_WaitingForStartOfServerSecondRound(ss)) { + /* ssl3_SendClientSecondRound deferred the false start check because + * certificate authentication was pending, so we do it now if we still + * haven't received any of the server's second round yet. + */ rv = ssl3_CheckFalseStart(ss); - if (rv == SECSuccess && - ss->handshakeCallback && - (ss->ssl3.hs.canFalseStart && !ss->canFalseStartCallback)) { - /* Call the handshake callback here for backwards compatibility - * with applications that were using false start before - * canFalseStartCallback was added. - */ - (ss->handshakeCallback)(ss->fd, ss->handshakeCallbackData); - } } else { rv = SECSuccess; } @@ -10568,6 +10709,7 @@ static SECStatus ssl3_SendEncryptedExtensions(sslSocket *ss) { static const char CHANNEL_ID_MAGIC[] = "TLS Channel ID signature"; + static const char CHANNEL_ID_RESUMPTION_MAGIC[] = "Resumption"; /* This is the ASN.1 prefix for a P-256 public key. Specifically it's: * SEQUENCE * SEQUENCE @@ -10593,7 +10735,10 @@ ssl3_SendEncryptedExtensions(sslSocket *ss) SECItem *spki = NULL; SSL3Hashes hashes; const unsigned char *pub_bytes; - unsigned char signed_data[sizeof(CHANNEL_ID_MAGIC) + sizeof(SSL3Hashes)]; + unsigned char signed_data[sizeof(CHANNEL_ID_MAGIC) + + sizeof(CHANNEL_ID_RESUMPTION_MAGIC) + + sizeof(SSL3Hashes)*2]; + size_t signed_data_len; unsigned char digest[SHA256_LENGTH]; SECItem digest_item; unsigned char signature[64]; @@ -10635,7 +10780,7 @@ ssl3_SendEncryptedExtensions(sslSocket *ss) spki = SECKEY_EncodeDERSubjectPublicKeyInfo(ss->ssl3.channelIDPub); if (spki->len != sizeof(P256_SPKI_PREFIX) + CHANNEL_ID_PUBLIC_KEY_LENGTH || - memcmp(spki->data, P256_SPKI_PREFIX, sizeof(P256_SPKI_PREFIX) != 0)) { + memcmp(spki->data, P256_SPKI_PREFIX, sizeof(P256_SPKI_PREFIX)) != 0) { PORT_SetError(SSL_ERROR_INVALID_CHANNEL_ID_KEY); rv = SECFailure; goto loser; @@ -10643,11 +10788,26 @@ ssl3_SendEncryptedExtensions(sslSocket *ss) pub_bytes = spki->data + sizeof(P256_SPKI_PREFIX); - memcpy(signed_data, CHANNEL_ID_MAGIC, sizeof(CHANNEL_ID_MAGIC)); - memcpy(signed_data + sizeof(CHANNEL_ID_MAGIC), hashes.u.raw, hashes.len); - - rv = PK11_HashBuf(SEC_OID_SHA256, digest, signed_data, - sizeof(CHANNEL_ID_MAGIC) + hashes.len); + signed_data_len = 0; + memcpy(signed_data + signed_data_len, CHANNEL_ID_MAGIC, + sizeof(CHANNEL_ID_MAGIC)); + signed_data_len += sizeof(CHANNEL_ID_MAGIC); + if (ss->ssl3.hs.isResuming) { + SECItem *originalHandshakeHash = + &ss->sec.ci.sid->u.ssl3.originalHandshakeHash; + PORT_Assert(originalHandshakeHash->len > 0); + + memcpy(signed_data + signed_data_len, CHANNEL_ID_RESUMPTION_MAGIC, + sizeof(CHANNEL_ID_RESUMPTION_MAGIC)); + signed_data_len += sizeof(CHANNEL_ID_RESUMPTION_MAGIC); + memcpy(signed_data + signed_data_len, originalHandshakeHash->data, + originalHandshakeHash->len); + signed_data_len += originalHandshakeHash->len; + } + memcpy(signed_data + signed_data_len, hashes.u.raw, hashes.len); + signed_data_len += hashes.len; + + rv = PK11_HashBuf(SEC_OID_SHA256, digest, signed_data, signed_data_len); if (rv != SECSuccess) goto loser; @@ -11003,9 +11163,6 @@ xmit_loser: return rv; } - ss->gs.writeOffset = 0; - ss->gs.readOffset = 0; - if (ss->ssl3.hs.kea_def->kea == kea_ecdhe_rsa) { effectiveExchKeyType = kt_rsa; } else { @@ -11070,36 +11227,28 @@ xmit_loser: return rv; } +/* The return type is SECStatus instead of void because this function needs + * to have type sslRestartTarget. + */ SECStatus ssl3_FinishHandshake(sslSocket * ss) { - PRBool falseStarted; - PORT_Assert( ss->opt.noLocks || ssl_HaveRecvBufLock(ss) ); PORT_Assert( ss->opt.noLocks || ssl_HaveSSL3HandshakeLock(ss) ); PORT_Assert( ss->ssl3.hs.restartTarget == NULL ); /* The first handshake is now completed. */ ss->handshake = NULL; - ss->firstHsDone = PR_TRUE; - ss->enoughFirstHsDone = PR_TRUE; - if (ss->ssl3.hs.cacheSID) { + if (ss->ssl3.hs.cacheSID && ss->sec.isServer) { (*ss->sec.cache)(ss->sec.ci.sid); ss->ssl3.hs.cacheSID = PR_FALSE; } - ss->ssl3.hs.ws = idle_handshake; - falseStarted = ss->ssl3.hs.canFalseStart; ss->ssl3.hs.canFalseStart = PR_FALSE; /* False Start phase is complete */ + ss->ssl3.hs.ws = idle_handshake; - /* Call the handshake callback for sslv3 here, unless we called it already - * for the case where false start was done without a canFalseStartCallback. - */ - if (ss->handshakeCallback && - !(falseStarted && !ss->canFalseStartCallback)) { - (ss->handshakeCallback)(ss->fd, ss->handshakeCallbackData); - } + ssl_FinishHandshake(ss); return SECSuccess; } @@ -12064,7 +12213,6 @@ process_it: ssl_ReleaseSSL3HandshakeLock(ss); return rv; - } /* @@ -12343,6 +12491,46 @@ ssl3_CipherPrefGet(sslSocket *ss, ssl3CipherSuite which, PRBool *enabled) return rv; } +SECStatus +ssl3_CipherOrderSet(sslSocket *ss, const ssl3CipherSuite *ciphers, unsigned int len) +{ + /* |i| iterates over |ciphers| while |done| and |j| iterate over + * |ss->cipherSuites|. */ + unsigned int i, done; + + for (i = done = 0; i < len; i++) { + PRUint16 id = ciphers[i]; + unsigned int existingIndex, j; + PRBool found = PR_FALSE; + + for (j = done; j < ssl_V3_SUITES_IMPLEMENTED; j++) { + if (ss->cipherSuites[j].cipher_suite == id) { + existingIndex = j; + found = PR_TRUE; + break; + } + } + + if (!found) { + continue; + } + + if (existingIndex != done) { + const ssl3CipherSuiteCfg temp = ss->cipherSuites[done]; + ss->cipherSuites[done] = ss->cipherSuites[existingIndex]; + ss->cipherSuites[existingIndex] = temp; + } + done++; + } + + /* Disable all cipher suites that weren't included. */ + for (; done < ssl_V3_SUITES_IMPLEMENTED; done++) { + ss->cipherSuites[done].enabled = 0; + } + + return SECSuccess; +} + /* copy global default policy into socket. */ void ssl3_InitSocketPolicy(sslSocket *ss) diff --git a/chromium/net/third_party/nss/ssl/ssl3ext.c b/chromium/net/third_party/nss/ssl/ssl3ext.c index 04157701e90..f2db28c924f 100644 --- a/chromium/net/third_party/nss/ssl/ssl3ext.c +++ b/chromium/net/third_party/nss/ssl/ssl3ext.c @@ -81,6 +81,12 @@ static PRInt32 ssl3_ClientSendSigAlgsXtn(sslSocket *ss, PRBool append, PRUint32 maxBytes); static SECStatus ssl3_ServerHandleSigAlgsXtn(sslSocket *ss, PRUint16 ex_type, SECItem *data); +static PRInt32 ssl3_ClientSendSignedCertTimestampXtn(sslSocket *ss, + PRBool append, + PRUint32 maxBytes); +static SECStatus ssl3_ClientHandleSignedCertTimestampXtn(sslSocket *ss, + PRUint16 ex_type, + SECItem *data); /* * Write bytes. Using this function means the SECItem structure @@ -259,6 +265,8 @@ static const ssl3HelloExtensionHandler serverHelloHandlersTLS[] = { { ssl_use_srtp_xtn, &ssl3_HandleUseSRTPXtn }, { ssl_channel_id_xtn, &ssl3_ClientHandleChannelIDXtn }, { ssl_cert_status_xtn, &ssl3_ClientHandleStatusRequestXtn }, + { ssl_signed_certificate_timestamp_xtn, + &ssl3_ClientHandleSignedCertTimestampXtn }, { -1, NULL } }; @@ -287,7 +295,9 @@ ssl3HelloExtensionSender clientHelloSendersTLS[SSL_MAX_EXTENSIONS] = { { ssl_use_srtp_xtn, &ssl3_SendUseSRTPXtn }, { ssl_channel_id_xtn, &ssl3_ClientSendChannelIDXtn }, { ssl_cert_status_xtn, &ssl3_ClientSendStatusRequestXtn }, - { ssl_signature_algorithms_xtn, &ssl3_ClientSendSigAlgsXtn } + { ssl_signature_algorithms_xtn, &ssl3_ClientSendSigAlgsXtn }, + { ssl_signed_certificate_timestamp_xtn, + &ssl3_ClientSendSignedCertTimestampXtn } /* any extra entries will appear as { 0, NULL } */ }; @@ -812,6 +822,15 @@ ssl3_ClientSendChannelIDXtn(sslSocket * ss, PRBool append, return 0; } + if (ss->sec.ci.sid->cached != never_cached && + ss->sec.ci.sid->u.ssl3.originalHandshakeHash.len == 0) { + /* We can't do ChannelID on a connection if we're resuming and didn't + * do ChannelID on the original connection: without ChannelID on the + * original connection we didn't record the handshake hashes needed for + * the signature. */ + return 0; + } + if (append) { SECStatus rv; rv = ssl3_AppendHandshakeNumber(ss, ssl_channel_id_xtn, 2); @@ -2297,3 +2316,118 @@ ssl3_ClientSendSigAlgsXtn(sslSocket * ss, PRBool append, PRUint32 maxBytes) loser: return -1; } + +unsigned int +ssl3_CalculatePaddingExtensionLength(unsigned int clientHelloLength) +{ + unsigned int recordLength = 1 /* handshake message type */ + + 3 /* handshake message length */ + + clientHelloLength; + unsigned int extensionLength; + + if (recordLength < 256 || recordLength >= 512) { + return 0; + } + + extensionLength = 512 - recordLength; + /* Extensions take at least four bytes to encode. */ + if (extensionLength < 4) { + extensionLength = 4; + } + + return extensionLength; +} + +/* ssl3_AppendPaddingExtension possibly adds an extension which ensures that a + * ClientHello record is either < 256 bytes or is >= 512 bytes. This ensures + * that we don't trigger bugs in F5 products. */ +PRInt32 +ssl3_AppendPaddingExtension(sslSocket *ss, unsigned int extensionLen, + PRUint32 maxBytes) +{ + unsigned int paddingLen = extensionLen - 4; + unsigned char padding[256]; + + if (extensionLen == 0) { + return 0; + } + + if (extensionLen < 4 || + extensionLen > maxBytes || + paddingLen > sizeof(padding)) { + PORT_Assert(0); + return -1; + } + + if (SECSuccess != ssl3_AppendHandshakeNumber(ss, ssl_padding_xtn, 2)) + return -1; + if (SECSuccess != ssl3_AppendHandshakeNumber(ss, paddingLen, 2)) + return -1; + memset(padding, 0, paddingLen); + if (SECSuccess != ssl3_AppendHandshake(ss, padding, paddingLen)) + return -1; + + return extensionLen; +} + +/* ssl3_ClientSendSignedCertTimestampXtn sends the signed_certificate_timestamp + * extension for TLS ClientHellos. */ +static PRInt32 +ssl3_ClientSendSignedCertTimestampXtn(sslSocket *ss, PRBool append, + PRUint32 maxBytes) +{ + PRInt32 extension_length = 2 /* extension_type */ + + 2 /* length(extension_data) */; + + /* Only send the extension if processing is enabled. */ + if (!ss->opt.enableSignedCertTimestamps) + return 0; + + if (append && maxBytes >= extension_length) { + SECStatus rv; + /* extension_type */ + rv = ssl3_AppendHandshakeNumber(ss, + ssl_signed_certificate_timestamp_xtn, + 2); + if (rv != SECSuccess) + goto loser; + /* zero length */ + rv = ssl3_AppendHandshakeNumber(ss, 0, 2); + if (rv != SECSuccess) + goto loser; + ss->xtnData.advertised[ss->xtnData.numAdvertised++] = + ssl_signed_certificate_timestamp_xtn; + } else if (maxBytes < extension_length) { + PORT_Assert(0); + return 0; + } + + return extension_length; +loser: + return -1; +} + +static SECStatus +ssl3_ClientHandleSignedCertTimestampXtn(sslSocket *ss, PRUint16 ex_type, + SECItem *data) +{ + /* We do not yet know whether we'll be resuming a session or creating + * a new one, so we keep a pointer to the data in the TLSExtensionData + * structure. This pointer is only valid in the scope of + * ssl3_HandleServerHello, and, if not resuming a session, the data is + * copied once a new session structure has been set up. + * All parsing is currently left to the application and we accept + * everything, including empty data. + */ + SECItem *scts = &ss->xtnData.signedCertTimestamps; + PORT_Assert(!scts->data && !scts->len); + + if (!data->len) { + /* Empty extension data: RFC 6962 mandates non-empty contents. */ + return SECFailure; + } + *scts = *data; + /* Keep track of negotiated extensions. */ + ss->xtnData.negotiated[ss->xtnData.numNegotiated++] = ex_type; + return SECSuccess; +} diff --git a/chromium/net/third_party/nss/ssl/ssl3gthr.c b/chromium/net/third_party/nss/ssl/ssl3gthr.c index 7385d6504e8..39cefa7c310 100644 --- a/chromium/net/third_party/nss/ssl/ssl3gthr.c +++ b/chromium/net/third_party/nss/ssl/ssl3gthr.c @@ -275,11 +275,17 @@ ssl3_GatherCompleteHandshake(sslSocket *ss, int flags) { SSL3Ciphertext cText; int rv; - PRBool canFalseStart = PR_FALSE; + PRBool keepGoing = PR_TRUE; SSL_TRC(30, ("ssl3_GatherCompleteHandshake")); + /* ssl3_HandleRecord may end up eventually calling ssl_FinishHandshake, + * which requires the 1stHandshakeLock, which must be acquired before the + * RecvBufLock. + */ + PORT_Assert( ss->opt.noLocks || ssl_Have1stHandshakeLock(ss) ); PORT_Assert( ss->opt.noLocks || ssl_HaveRecvBufLock(ss) ); + do { PRBool handleRecordNow = PR_FALSE; @@ -364,22 +370,52 @@ ssl3_GatherCompleteHandshake(sslSocket *ss, int flags) cText.buf = &ss->gs.inbuf; rv = ssl3_HandleRecord(ss, &cText, &ss->gs.buf); + + if (rv == (int) SECSuccess && ss->gs.buf.len > 0) { + /* We have application data to return to the application. This + * prioritizes returning application data to the application over + * completing any renegotiation handshake we may be doing. + */ + PORT_Assert(ss->firstHsDone); + PORT_Assert(cText.type == content_application_data); + break; + } } if (rv < 0) { return ss->recvdCloseNotify ? 0 : rv; } - /* If we kicked off a false start in ssl3_HandleServerHelloDone, break - * out of this loop early without finishing the handshake. - */ - if (ss->opt.enableFalseStart) { - ssl_GetSSL3HandshakeLock(ss); - canFalseStart = ss->ssl3.hs.canFalseStart; - ssl_ReleaseSSL3HandshakeLock(ss); + PORT_Assert(keepGoing); + ssl_GetSSL3HandshakeLock(ss); + if (ss->ssl3.hs.ws == idle_handshake) { + /* We are done with the current handshake so stop trying to + * handshake. Note that it would be safe to test ss->firstHsDone + * instead of ss->ssl3.hs.ws. By testing ss->ssl3.hs.ws instead, + * we prioritize completing a renegotiation handshake over sending + * application data. + */ + PORT_Assert(ss->firstHsDone); + PORT_Assert(!ss->ssl3.hs.canFalseStart); + keepGoing = PR_FALSE; + } else if (ss->ssl3.hs.canFalseStart) { + /* Prioritize sending application data over trying to complete + * the handshake if we're false starting. + * + * If we were to do this check at the beginning of the loop instead + * of here, then this function would become be a no-op after + * receiving the ServerHelloDone in the false start case, and we + * would never complete the handshake. + */ + PORT_Assert(!ss->firstHsDone); + + if (ssl3_WaitingForStartOfServerSecondRound(ss)) { + keepGoing = PR_FALSE; + } else { + ss->ssl3.hs.canFalseStart = PR_FALSE; + } } - } while (ss->ssl3.hs.ws != idle_handshake && - !canFalseStart && - ss->gs.buf.len == 0); + ssl_ReleaseSSL3HandshakeLock(ss); + } while (keepGoing); ss->gs.readOffset = 0; ss->gs.writeOffset = ss->gs.buf.len; @@ -402,7 +438,10 @@ ssl3_GatherAppDataRecord(sslSocket *ss, int flags) { int rv; + /* ssl3_GatherCompleteHandshake requires both of these locks. */ + PORT_Assert( ss->opt.noLocks || ssl_Have1stHandshakeLock(ss) ); PORT_Assert( ss->opt.noLocks || ssl_HaveRecvBufLock(ss) ); + do { rv = ssl3_GatherCompleteHandshake(ss, flags); } while (rv > 0 && ss->gs.buf.len == 0); diff --git a/chromium/net/third_party/nss/ssl/ssl3prot.h b/chromium/net/third_party/nss/ssl/ssl3prot.h index 0eab970bc6a..4c19ade8d6a 100644 --- a/chromium/net/third_party/nss/ssl/ssl3prot.h +++ b/chromium/net/third_party/nss/ssl/ssl3prot.h @@ -98,6 +98,7 @@ typedef enum { protocol_version = 70, insufficient_security = 71, internal_error = 80, + inappropriate_fallback = 86, /* could also be sent for SSLv3 */ user_canceled = 90, no_renegotiation = 100, diff --git a/chromium/net/third_party/nss/ssl/sslerr.h b/chromium/net/third_party/nss/ssl/sslerr.h index 5a949c9a248..82ae7dfb1f0 100644 --- a/chromium/net/third_party/nss/ssl/sslerr.h +++ b/chromium/net/third_party/nss/ssl/sslerr.h @@ -196,6 +196,7 @@ SSL_ERROR_INCORRECT_SIGNATURE_ALGORITHM = (SSL_ERROR_BASE + 128), SSL_ERROR_BAD_CHANNEL_ID_DATA = (SSL_ERROR_BASE + 129), SSL_ERROR_INVALID_CHANNEL_ID_KEY = (SSL_ERROR_BASE + 130), SSL_ERROR_GET_CHANNEL_ID_FAILED = (SSL_ERROR_BASE + 131), +SSL_ERROR_INAPPROPRIATE_FALLBACK_ALERT = (SSL_ERROR_BASE + 132), SSL_ERROR_END_OF_LIST /* let the c compiler determine the value of this. */ } SSLErrorCodes; diff --git a/chromium/net/third_party/nss/ssl/sslimpl.h b/chromium/net/third_party/nss/ssl/sslimpl.h index 614eed145ec..6d0bc154aaf 100644 --- a/chromium/net/third_party/nss/ssl/sslimpl.h +++ b/chromium/net/third_party/nss/ssl/sslimpl.h @@ -237,6 +237,13 @@ extern PRInt32 ssl3_CallHelloExtensionSenders(sslSocket *ss, PRBool append, PRUint32 maxBytes, const ssl3HelloExtensionSender *sender); +extern unsigned int +ssl3_CalculatePaddingExtensionLength(unsigned int clientHelloLength); + +extern PRInt32 +ssl3_AppendPaddingExtension(sslSocket *ss, unsigned int extensionLen, + PRUint32 maxBytes); + /* Socket ops */ struct sslSocketOpsStr { int (*connect) (sslSocket *, const PRNetAddr *); @@ -305,29 +312,31 @@ typedef struct sslOptionsStr { * list of supported protocols. */ SECItem nextProtoNego; - unsigned int useSecurity : 1; /* 1 */ - unsigned int useSocks : 1; /* 2 */ - unsigned int requestCertificate : 1; /* 3 */ - unsigned int requireCertificate : 2; /* 4-5 */ - unsigned int handshakeAsClient : 1; /* 6 */ - unsigned int handshakeAsServer : 1; /* 7 */ - unsigned int enableSSL2 : 1; /* 8 */ - unsigned int unusedBit9 : 1; /* 9 */ - unsigned int unusedBit10 : 1; /* 10 */ - unsigned int noCache : 1; /* 11 */ - unsigned int fdx : 1; /* 12 */ - unsigned int v2CompatibleHello : 1; /* 13 */ - unsigned int detectRollBack : 1; /* 14 */ - unsigned int noStepDown : 1; /* 15 */ - unsigned int bypassPKCS11 : 1; /* 16 */ - unsigned int noLocks : 1; /* 17 */ - unsigned int enableSessionTickets : 1; /* 18 */ - unsigned int enableDeflate : 1; /* 19 */ - unsigned int enableRenegotiation : 2; /* 20-21 */ - unsigned int requireSafeNegotiation : 1; /* 22 */ - unsigned int enableFalseStart : 1; /* 23 */ - unsigned int cbcRandomIV : 1; /* 24 */ - unsigned int enableOCSPStapling : 1; /* 25 */ + unsigned int useSecurity : 1; /* 1 */ + unsigned int useSocks : 1; /* 2 */ + unsigned int requestCertificate : 1; /* 3 */ + unsigned int requireCertificate : 2; /* 4-5 */ + unsigned int handshakeAsClient : 1; /* 6 */ + unsigned int handshakeAsServer : 1; /* 7 */ + unsigned int enableSSL2 : 1; /* 8 */ + unsigned int unusedBit9 : 1; /* 9 */ + unsigned int unusedBit10 : 1; /* 10 */ + unsigned int noCache : 1; /* 11 */ + unsigned int fdx : 1; /* 12 */ + unsigned int v2CompatibleHello : 1; /* 13 */ + unsigned int detectRollBack : 1; /* 14 */ + unsigned int noStepDown : 1; /* 15 */ + unsigned int bypassPKCS11 : 1; /* 16 */ + unsigned int noLocks : 1; /* 17 */ + unsigned int enableSessionTickets : 1; /* 18 */ + unsigned int enableDeflate : 1; /* 19 */ + unsigned int enableRenegotiation : 2; /* 20-21 */ + unsigned int requireSafeNegotiation : 1; /* 22 */ + unsigned int enableFalseStart : 1; /* 23 */ + unsigned int cbcRandomIV : 1; /* 24 */ + unsigned int enableOCSPStapling : 1; /* 25 */ + unsigned int enableSignedCertTimestamps : 1; /* 26 */ + unsigned int enableFallbackSCSV : 1; /* 27 */ } sslOptions; typedef enum { sslHandshakingUndetermined = 0, @@ -698,6 +707,19 @@ struct sslSessionIDStr { */ NewSessionTicket sessionTicket; SECItem srvName; + + /* originalHandshakeHash contains the hash of the original, full + * handshake prior to the server's final flow. This is either a + * SHA-1/MD5 combination (for TLS < 1.2) or the TLS PRF hash (for + * TLS 1.2). This is recorded and used only when ChannelID is + * negotiated as it's used to bind the ChannelID signature on the + * resumption handshake to the original handshake. */ + SECItem originalHandshakeHash; + + /* Signed certificate timestamps received in a TLS extension. + ** (used only in client). + */ + SECItem signedCertTimestamps; } ssl3; } u; }; @@ -789,6 +811,18 @@ struct TLSExtensionDataStr { * is beyond ssl3_HandleClientHello function. */ SECItem *sniNameArr; PRUint32 sniNameArrSize; + + /* Signed Certificate Timestamps extracted from the TLS extension. + * (client only). + * This container holds a temporary pointer to the extension data, + * until a session structure (the sec.ci.sid of an sslSocket) is setup + * that can hold a permanent copy of the data + * (in sec.ci.sid.u.ssl3.signedCertTimestamps). + * The data pointed to by this structure is neither explicitly allocated + * nor copied: the pointer points to the handshake message buffer and is + * only valid in the scope of ssl3_HandleServerHello. + */ + SECItem signedCertTimestamps; }; typedef SECStatus (*sslRestartTarget)(sslSocket *); @@ -1431,6 +1465,19 @@ extern void ssl3_SetAlwaysBlock(sslSocket *ss); extern SECStatus ssl_EnableNagleDelay(sslSocket *ss, PRBool enabled); +extern void ssl_FinishHandshake(sslSocket *ss); + +/* Returns PR_TRUE if we are still waiting for the server to respond to our + * client second round. Once we've received any part of the server's second + * round then we don't bother trying to false start since it is almost always + * the case that the NewSessionTicket, ChangeCipherSoec, and Finished messages + * were sent in the same packet and we want to process them all at the same + * time. If we were to try to false start in the middle of the server's second + * round, then we would increase the number of I/O operations + * (SSL_ForceHandshake/PR_Recv/PR_Send/etc.) needed to finish the handshake. + */ +extern PRBool ssl3_WaitingForStartOfServerSecondRound(sslSocket *ss); + extern SECStatus ssl3_CompressMACEncryptRecord(ssl3CipherSpec * cwSpec, PRBool isServer, @@ -1665,6 +1712,8 @@ extern SECStatus ssl3_CipherPrefSet(sslSocket *ss, ssl3CipherSuite which, PRBool extern SECStatus ssl3_CipherPrefGet(sslSocket *ss, ssl3CipherSuite which, PRBool *on); extern SECStatus ssl2_CipherPrefSet(sslSocket *ss, PRInt32 which, PRBool enabled); extern SECStatus ssl2_CipherPrefGet(sslSocket *ss, PRInt32 which, PRBool *enabled); +extern SECStatus ssl3_CipherOrderSet(sslSocket *ss, const ssl3CipherSuite *cipher, + unsigned int len); extern SECStatus ssl3_SetPolicy(ssl3CipherSuite which, PRInt32 policy); extern SECStatus ssl3_GetPolicy(ssl3CipherSuite which, PRInt32 *policy); diff --git a/chromium/net/third_party/nss/ssl/sslnonce.c b/chromium/net/third_party/nss/ssl/sslnonce.c index a6f734948a3..a3e6e0a33f9 100644 --- a/chromium/net/third_party/nss/ssl/sslnonce.c +++ b/chromium/net/third_party/nss/ssl/sslnonce.c @@ -21,8 +21,8 @@ PRUint32 ssl_sid_timeout = 100; PRUint32 ssl3_sid_timeout = 86400L; /* 24 hours */ -static sslSessionID *cache = NULL; -static PZLock * cacheLock = NULL; +sslSessionID *cache = NULL; +PZLock * cacheLock = NULL; /* sids can be in one of 4 states: * @@ -122,7 +122,21 @@ ssl_DestroySID(sslSessionID *sid) if (sid->version < SSL_LIBRARY_VERSION_3_0) { SECITEM_ZfreeItem(&sid->u.ssl2.masterKey, PR_FALSE); SECITEM_ZfreeItem(&sid->u.ssl2.cipherArg, PR_FALSE); + } else { + if (sid->u.ssl3.sessionTicket.ticket.data) { + SECITEM_FreeItem(&sid->u.ssl3.sessionTicket.ticket, PR_FALSE); + } + if (sid->u.ssl3.srvName.data) { + SECITEM_FreeItem(&sid->u.ssl3.srvName, PR_FALSE); + } + if (sid->u.ssl3.signedCertTimestamps.data) { + SECITEM_FreeItem(&sid->u.ssl3.signedCertTimestamps, PR_FALSE); + } + if (sid->u.ssl3.originalHandshakeHash.data) { + SECITEM_FreeItem(&sid->u.ssl3.originalHandshakeHash, PR_FALSE); + } } + if (sid->peerID != NULL) PORT_Free((void *)sid->peerID); /* CONST */ @@ -142,13 +156,7 @@ ssl_DestroySID(sslSessionID *sid) if ( sid->localCert ) { CERT_DestroyCertificate(sid->localCert); } - if (sid->u.ssl3.sessionTicket.ticket.data) { - SECITEM_FreeItem(&sid->u.ssl3.sessionTicket.ticket, PR_FALSE); - } - if (sid->u.ssl3.srvName.data) { - SECITEM_FreeItem(&sid->u.ssl3.srvName, PR_FALSE); - } - + PORT_ZFree(sid, sizeof(sslSessionID)); } @@ -430,6 +438,12 @@ ssl3_SetSIDSessionTicket(sslSessionID *sid, NewSessionTicket *session_ticket) /* We need to lock the cache, as this sid might already be in the cache. */ LOCK_CACHE; + /* Don't modify sid if it has ever been cached. */ + if (sid->cached != never_cached) { + UNLOCK_CACHE; + return SECSuccess; + } + /* A server might have sent us an empty ticket, which has the * effect of clearing the previously known ticket. */ diff --git a/chromium/net/third_party/nss/ssl/sslproto.h b/chromium/net/third_party/nss/ssl/sslproto.h index 6b60a28616f..621ef375460 100644 --- a/chromium/net/third_party/nss/ssl/sslproto.h +++ b/chromium/net/third_party/nss/ssl/sslproto.h @@ -172,6 +172,11 @@ */ #define TLS_EMPTY_RENEGOTIATION_INFO_SCSV 0x00FF +/* TLS_FALLBACK_SCSV is a signaling cipher suite value that indicates that a + * handshake is the result of TLS version fallback. This value is not IANA + * assigned. */ +#define TLS_FALLBACK_SCSV 0x5600 + /* Cipher Suite Values starting with 0xC000 are defined in informational * RFCs. */ diff --git a/chromium/net/third_party/nss/ssl/sslsecur.c b/chromium/net/third_party/nss/ssl/sslsecur.c index 6c7532e2552..99538e532a6 100644 --- a/chromium/net/third_party/nss/ssl/sslsecur.c +++ b/chromium/net/third_party/nss/ssl/sslsecur.c @@ -97,14 +97,13 @@ ssl_Do1stHandshake(sslSocket *ss) ss->securityHandshake = 0; } if (ss->handshake == 0) { - ssl_GetRecvBufLock(ss); - ss->gs.recordLen = 0; - ss->gs.writeOffset = 0; - ss->gs.readOffset = 0; - ssl_ReleaseRecvBufLock(ss); - - SSL_TRC(3, ("%d: SSL[%d]: handshake is completed", - SSL_GETPID(), ss->fd)); + /* for v3 this is done in ssl3_FinishHandshake */ + if (!ss->firstHsDone && ss->version < SSL_LIBRARY_VERSION_3_0) { + ssl_GetRecvBufLock(ss); + ss->gs.recordLen = 0; + ssl_FinishHandshake(ss); + ssl_ReleaseRecvBufLock(ss); + } break; } rv = (*ss->handshake)(ss); @@ -125,6 +124,24 @@ ssl_Do1stHandshake(sslSocket *ss) return rv; } +void +ssl_FinishHandshake(sslSocket *ss) +{ + PORT_Assert( ss->opt.noLocks || ssl_Have1stHandshakeLock(ss) ); + PORT_Assert( ss->opt.noLocks || ssl_HaveRecvBufLock(ss) ); + + SSL_TRC(3, ("%d: SSL[%d]: handshake is completed", SSL_GETPID(), ss->fd)); + + ss->firstHsDone = PR_TRUE; + ss->enoughFirstHsDone = PR_TRUE; + ss->gs.writeOffset = 0; + ss->gs.readOffset = 0; + + if (ss->handshakeCallback) { + (ss->handshakeCallback)(ss->fd, ss->handshakeCallbackData); + } +} + /* * Handshake function that blocks. Used to force a * retry on a connection on the next read/write. @@ -260,7 +277,7 @@ SSL_ReHandshake(PRFileDesc *fd, PRBool flushCache) /* SSL v2 protocol does not support subsequent handshakes. */ if (ss->version < SSL_LIBRARY_VERSION_3_0) { - PORT_SetError(SSL_ERROR_FEATURE_NOT_SUPPORTED_FOR_SSL2); + PORT_SetError(SEC_ERROR_INVALID_ARGS); rv = SECFailure; } else { ssl_GetSSL3HandshakeLock(ss); @@ -330,7 +347,7 @@ SSL_HandshakeCallback(PRFileDesc *fd, SSLHandshakeCallback cb, */ SECStatus SSL_SetCanFalseStartCallback(PRFileDesc *fd, SSLCanFalseStartCallback cb, - void *client_data) + void *arg) { sslSocket *ss; @@ -350,7 +367,7 @@ SSL_SetCanFalseStartCallback(PRFileDesc *fd, SSLCanFalseStartCallback cb, ssl_GetSSL3HandshakeLock(ss); ss->canFalseStartCallback = cb; - ss->canFalseStartCallbackData = client_data; + ss->canFalseStartCallbackData = arg; ssl_ReleaseSSL3HandshakeLock(ss); ssl_Release1stHandshakeLock(ss); @@ -358,19 +375,15 @@ SSL_SetCanFalseStartCallback(PRFileDesc *fd, SSLCanFalseStartCallback cb, return SECSuccess; } -/* A utility function that can be called from a custom SSLCanFalseStartCallback -** function to determine what NSS would have done for this connection if the -** custom callback was not implemented. -*/ SECStatus -SSL_DefaultCanFalseStart(PRFileDesc *fd, PRBool *canFalseStart) +SSL_RecommendedCanFalseStart(PRFileDesc *fd, PRBool *canFalseStart) { sslSocket *ss; *canFalseStart = PR_FALSE; ss = ssl_FindSocket(fd); if (!ss) { - SSL_DBG(("%d: SSL[%d]: bad socket in SSL_DefaultCanFalseStart", + SSL_DBG(("%d: SSL[%d]: bad socket in SSL_RecommendedCanFalseStart", SSL_GETPID(), fd)); return SECFailure; } @@ -587,6 +600,9 @@ DoRecv(sslSocket *ss, unsigned char *out, int len, int flags) int amount; int available; + /* ssl3_GatherAppDataRecord may call ssl_FinishHandshake, which needs the + * 1stHandshakeLock. */ + ssl_Get1stHandshakeLock(ss); ssl_GetRecvBufLock(ss); available = ss->gs.writeOffset - ss->gs.readOffset; @@ -653,6 +669,7 @@ DoRecv(sslSocket *ss, unsigned char *out, int len, int flags) done: ssl_ReleaseRecvBufLock(ss); + ssl_Release1stHandshakeLock(ss); return rv; } @@ -1219,7 +1236,8 @@ ssl_SecureRead(sslSocket *ss, unsigned char *buf, int len) int ssl_SecureSend(sslSocket *ss, const unsigned char *buf, int len, int flags) { - int rv = 0; + int rv = 0; + PRBool falseStart = PR_FALSE; SSL_TRC(2, ("%d: SSL[%d]: SecureSend: sending %d bytes", SSL_GETPID(), ss->fd, len)); @@ -1254,14 +1272,14 @@ ssl_SecureSend(sslSocket *ss, const unsigned char *buf, int len, int flags) ss->writerThread = PR_GetCurrentThread(); /* If any of these is non-zero, the initial handshake is not done. */ if (!ss->firstHsDone) { - PRBool canFalseStart = PR_FALSE; ssl_Get1stHandshakeLock(ss); - if (ss->version >= SSL_LIBRARY_VERSION_3_0) { + if (ss->opt.enableFalseStart && + ss->version >= SSL_LIBRARY_VERSION_3_0) { ssl_GetSSL3HandshakeLock(ss); - canFalseStart = ss->ssl3.hs.canFalseStart; + falseStart = ss->ssl3.hs.canFalseStart; ssl_ReleaseSSL3HandshakeLock(ss); } - if (!canFalseStart && + if (!falseStart && (ss->handshake || ss->nextHandshake || ss->securityHandshake)) { rv = ssl_Do1stHandshake(ss); } @@ -1286,6 +1304,17 @@ ssl_SecureSend(sslSocket *ss, const unsigned char *buf, int len, int flags) goto done; } + if (!ss->firstHsDone) { + PORT_Assert(ss->version >= SSL_LIBRARY_VERSION_3_0); +#ifdef DEBUG + ssl_GetSSL3HandshakeLock(ss); + PORT_Assert(ss->ssl3.hs.canFalseStart); + ssl_ReleaseSSL3HandshakeLock(ss); +#endif + SSL_TRC(3, ("%d: SSL[%d]: SecureSend: sending data due to false start", + SSL_GETPID(), ss->fd)); + } + /* Send out the data using one of these functions: * ssl2_SendClear, ssl2_SendStream, ssl2_SendBlock, * ssl3_SendApplicationData @@ -1445,6 +1474,49 @@ SSL_InvalidateSession(PRFileDesc *fd) return rv; } +static void +ssl3_CacheSessionUnlocked(sslSocket *ss) +{ + PORT_Assert(!ss->sec.isServer); + + if (ss->ssl3.hs.cacheSID) { + ss->sec.cache(ss->sec.ci.sid); + ss->ssl3.hs.cacheSID = PR_FALSE; + } +} + +SECStatus +SSL_CacheSession(PRFileDesc *fd) +{ + sslSocket * ss = ssl_FindSocket(fd); + SECStatus rv = SECFailure; + + if (ss) { + ssl_Get1stHandshakeLock(ss); + ssl_GetSSL3HandshakeLock(ss); + + ssl3_CacheSessionUnlocked(ss); + rv = SECSuccess; + + ssl_ReleaseSSL3HandshakeLock(ss); + ssl_Release1stHandshakeLock(ss); + } + return rv; +} + +SECStatus +SSL_CacheSessionUnlocked(PRFileDesc *fd) +{ + sslSocket * ss = ssl_FindSocket(fd); + SECStatus rv = SECFailure; + + if (ss) { + ssl3_CacheSessionUnlocked(ss); + rv = SECSuccess; + } + return rv; +} + SECItem * SSL_GetSessionID(PRFileDesc *fd) { diff --git a/chromium/net/third_party/nss/ssl/sslsock.c b/chromium/net/third_party/nss/ssl/sslsock.c index 072fad5ba0b..998c1371999 100644 --- a/chromium/net/third_party/nss/ssl/sslsock.c +++ b/chromium/net/third_party/nss/ssl/sslsock.c @@ -173,7 +173,9 @@ static sslOptions ssl_defaults = { PR_FALSE, /* requireSafeNegotiation */ PR_FALSE, /* enableFalseStart */ PR_TRUE, /* cbcRandomIV */ - PR_FALSE /* enableOCSPStapling */ + PR_FALSE, /* enableOCSPStapling */ + PR_FALSE, /* enableSignedCertTimestamps */ + PR_FALSE /* enableFallbackSCSV */ }; /* @@ -366,6 +368,8 @@ ssl_DupSocket(sslSocket *os) ss->badCertArg = os->badCertArg; ss->handshakeCallback = os->handshakeCallback; ss->handshakeCallbackData = os->handshakeCallbackData; + ss->canFalseStartCallback = os->canFalseStartCallback; + ss->canFalseStartCallbackData = os->canFalseStartCallbackData; ss->pkcs11PinArg = os->pkcs11PinArg; ss->getChannelID = os->getChannelID; ss->getChannelIDArg = os->getChannelIDArg; @@ -863,6 +867,14 @@ SSL_OptionSet(PRFileDesc *fd, PRInt32 which, PRBool on) ss->opt.enableOCSPStapling = on; break; + case SSL_ENABLE_SIGNED_CERT_TIMESTAMPS: + ss->opt.enableSignedCertTimestamps = on; + break; + + case SSL_ENABLE_FALLBACK_SCSV: + ss->opt.enableFallbackSCSV = on; + break; + default: PORT_SetError(SEC_ERROR_INVALID_ARGS); rv = SECFailure; @@ -933,6 +945,10 @@ SSL_OptionGet(PRFileDesc *fd, PRInt32 which, PRBool *pOn) case SSL_ENABLE_FALSE_START: on = ss->opt.enableFalseStart; break; case SSL_CBC_RANDOM_IV: on = ss->opt.cbcRandomIV; break; case SSL_ENABLE_OCSP_STAPLING: on = ss->opt.enableOCSPStapling; break; + case SSL_ENABLE_SIGNED_CERT_TIMESTAMPS: + on = ss->opt.enableSignedCertTimestamps; + break; + case SSL_ENABLE_FALLBACK_SCSV: on = ss->opt.enableFallbackSCSV; break; default: PORT_SetError(SEC_ERROR_INVALID_ARGS); @@ -994,6 +1010,12 @@ SSL_OptionGetDefault(PRInt32 which, PRBool *pOn) case SSL_ENABLE_OCSP_STAPLING: on = ssl_defaults.enableOCSPStapling; break; + case SSL_ENABLE_SIGNED_CERT_TIMESTAMPS: + on = ssl_defaults.enableSignedCertTimestamps; + break; + case SSL_ENABLE_FALLBACK_SCSV: + on = ssl_defaults.enableFallbackSCSV; + break; default: PORT_SetError(SEC_ERROR_INVALID_ARGS); @@ -1161,6 +1183,14 @@ SSL_OptionSetDefault(PRInt32 which, PRBool on) ssl_defaults.enableOCSPStapling = on; break; + case SSL_ENABLE_SIGNED_CERT_TIMESTAMPS: + ssl_defaults.enableSignedCertTimestamps = on; + break; + + case SSL_ENABLE_FALLBACK_SCSV: + ssl_defaults.enableFallbackSCSV = on; + break; + default: PORT_SetError(SEC_ERROR_INVALID_ARGS); return SECFailure; @@ -1327,6 +1357,19 @@ SSL_CipherPrefSet(PRFileDesc *fd, PRInt32 which, PRBool enabled) return rv; } +SECStatus +SSL_CipherOrderSet(PRFileDesc *fd, const PRUint16 *ciphers, unsigned int len) +{ + sslSocket *ss = ssl_FindSocket(fd); + + if (!ss) { + SSL_DBG(("%d: SSL[%d]: bad socket in CipherOrderSet", SSL_GETPID(), + fd)); + return SECFailure; + } + return ssl3_CipherOrderSet(ss, ciphers, len); +} + SECStatus SSL_CipherPrefGet(PRFileDesc *fd, PRInt32 which, PRBool *enabled) { @@ -1991,6 +2034,29 @@ SSL_PeerStapledOCSPResponses(PRFileDesc *fd) return &ss->sec.ci.sid->peerCertStatus; } +const SECItem * +SSL_PeerSignedCertTimestamps(PRFileDesc *fd) +{ + sslSocket *ss = ssl_FindSocket(fd); + + if (!ss) { + SSL_DBG(("%d: SSL[%d]: bad socket in SSL_PeerSignedCertTimestamps", + SSL_GETPID(), fd)); + return NULL; + } + + if (!ss->sec.ci.sid) { + PORT_SetError(SEC_ERROR_NOT_INITIALIZED); + return NULL; + } + + if (ss->sec.ci.sid->version < SSL_LIBRARY_VERSION_3_0) { + PORT_SetError(SSL_ERROR_FEATURE_NOT_SUPPORTED_FOR_SSL2); + return NULL; + } + return &ss->sec.ci.sid->u.ssl3.signedCertTimestamps; +} + SECStatus SSL_HandshakeResumedSession(PRFileDesc *fd, PRBool *handshake_resumed) { sslSocket *ss = ssl_FindSocket(fd); @@ -3131,4 +3197,3 @@ loser: } return ss; } - diff --git a/chromium/net/third_party/nss/ssl/sslt.h b/chromium/net/third_party/nss/ssl/sslt.h index a8007d8b4cf..1f5e2c659ff 100644 --- a/chromium/net/third_party/nss/ssl/sslt.h +++ b/chromium/net/third_party/nss/ssl/sslt.h @@ -202,12 +202,14 @@ typedef enum { ssl_signature_algorithms_xtn = 13, ssl_use_srtp_xtn = 14, ssl_app_layer_protocol_xtn = 16, + ssl_signed_certificate_timestamp_xtn = 18, /* RFC 6962 */ ssl_session_ticket_xtn = 35, ssl_next_proto_nego_xtn = 13172, - ssl_channel_id_xtn = 30031, + ssl_channel_id_xtn = 30032, + ssl_padding_xtn = 35655, ssl_renegotiation_info_xtn = 0xff01 /* experimental number */ } SSLExtensionType; -#define SSL_MAX_EXTENSIONS 11 +#define SSL_MAX_EXTENSIONS 12 /* doesn't include ssl_padding_xtn. */ #endif /* __sslt_h_ */ |