diff options
author | wtc%google.com <devnull@localhost> | 2010-07-31 04:33:52 +0000 |
---|---|---|
committer | wtc%google.com <devnull@localhost> | 2010-07-31 04:33:52 +0000 |
commit | d6d306a5e73b4b4925de21f76179c68b03434936 (patch) | |
tree | 39da3db5bbf67e10e8fb28e3dcdeb5c3add5b130 | |
parent | 25c8423db8df53cce7467b085999902d7e3c7f42 (diff) | |
download | nss-hg-d6d306a5e73b4b4925de21f76179c68b03434936.tar.gz |
Bug 525092: Support TLS false start. The patch is contributed by AdamNSS_3_12_8_BETA1
Langley of Google <agl@chromium.org>. r=wtc.
Modified Files:
Tag: NSS_3_12_BRANCH
cmd/strsclnt/strsclnt.c cmd/tstclnt/tstclnt.c lib/ssl/ssl.h
lib/ssl/ssl3con.c lib/ssl/ssl3gthr.c lib/ssl/sslimpl.h
lib/ssl/sslsecur.c lib/ssl/sslsock.c tests/ssl/sslstress.txt
-rw-r--r-- | security/nss/cmd/strsclnt/strsclnt.c | 14 | ||||
-rw-r--r-- | security/nss/cmd/tstclnt/tstclnt.c | 15 | ||||
-rw-r--r-- | security/nss/lib/ssl/ssl.h | 11 | ||||
-rw-r--r-- | security/nss/lib/ssl/ssl3con.c | 22 | ||||
-rw-r--r-- | security/nss/lib/ssl/ssl3gthr.c | 18 | ||||
-rw-r--r-- | security/nss/lib/ssl/sslimpl.h | 3 | ||||
-rw-r--r-- | security/nss/lib/ssl/sslsecur.c | 11 | ||||
-rw-r--r-- | security/nss/lib/ssl/sslsock.c | 11 | ||||
-rw-r--r-- | security/nss/tests/ssl/sslstress.txt | 4 |
9 files changed, 100 insertions, 9 deletions
diff --git a/security/nss/cmd/strsclnt/strsclnt.c b/security/nss/cmd/strsclnt/strsclnt.c index ae4feb9d1..786b6bcf7 100644 --- a/security/nss/cmd/strsclnt/strsclnt.c +++ b/security/nss/cmd/strsclnt/strsclnt.c @@ -162,6 +162,7 @@ static PRBool disableLocking = PR_FALSE; static PRBool ignoreErrors = PR_FALSE; static PRBool enableSessionTickets = PR_FALSE; static PRBool enableCompression = PR_FALSE; +static PRBool enableFalseStart = PR_FALSE; PRIntervalTime maxInterval = PR_INTERVAL_NO_TIMEOUT; @@ -197,7 +198,8 @@ Usage(const char *progName) " -U means enable throttling up threads\n" " -B bypasses the PKCS11 layer for SSL encryption and MACing\n" " -u enable TLS Session Ticket extension\n" - " -z enable compression\n", + " -z enable compression\n" + " -g enable false start\n", progName); exit(1); } @@ -1244,6 +1246,12 @@ client_main( errExit("SSL_OptionSet SSL_ENABLE_DEFLATE"); } + if (enableFalseStart) { + rv = SSL_OptionSet(model_sock, SSL_ENABLE_FALSE_START, PR_TRUE); + if (rv != SECSuccess) + errExit("SSL_OptionSet SSL_ENABLE_FALSE_START"); + } + SSL_SetURL(model_sock, hostName); SSL_AuthCertificateHook(model_sock, mySSLAuthCertificate, @@ -1354,7 +1362,7 @@ main(int argc, char **argv) optstate = PL_CreateOptState(argc, argv, - "23BC:DNP:TUW:a:c:d:f:in:op:qst:uvw:z"); + "23BC:DNP:TUW:a:c:d:f:gin:op:qst:uvw:z"); while ((status = PL_GetNextOpt(optstate)) == PL_OPT_OK) { switch(optstate->option) { @@ -1384,6 +1392,8 @@ main(int argc, char **argv) case 'f': fileName = optstate->value; break; + case 'g': enableFalseStart = PR_TRUE; break; + case 'i': ignoreErrors = PR_TRUE; break; case 'n': nickName = PL_strdup(optstate->value); break; diff --git a/security/nss/cmd/tstclnt/tstclnt.c b/security/nss/cmd/tstclnt/tstclnt.c index c15a0ad47..55684e685 100644 --- a/security/nss/cmd/tstclnt/tstclnt.c +++ b/security/nss/cmd/tstclnt/tstclnt.c @@ -225,6 +225,7 @@ static void Usage(const char *progName) fprintf(stderr, "%-20s Renegotiate N times (resuming session if N>1).\n", "-r N"); fprintf(stderr, "%-20s Enable the session ticket extension.\n", "-u"); fprintf(stderr, "%-20s Enable compression.\n", "-z"); + fprintf(stderr, "%-20s Enable false start.\n", "-g"); fprintf(stderr, "%-20s Letter(s) chosen from the following list\n", "-c ciphers"); fprintf(stderr, @@ -521,6 +522,7 @@ int main(int argc, char **argv) int useExportPolicy = 0; int enableSessionTickets = 0; int enableCompression = 0; + int enableFalseStart = 0; PRSocketOptionData opt; PRNetAddr addr; PRPollDesc pollset[2]; @@ -551,7 +553,7 @@ int main(int argc, char **argv) } optstate = PL_CreateOptState(argc, argv, - "23BSTW:a:c:d:fh:m:n:op:qr:suvw:xz"); + "23BSTW:a:c:d:fgh:m:n:op:qr:suvw:xz"); while ((optstatus = PL_GetNextOpt(optstate)) == PL_OPT_OK) { switch (optstate->option) { case '?': @@ -578,6 +580,8 @@ int main(int argc, char **argv) case 'c': cipherString = PORT_Strdup(optstate->value); break; + case 'g': enableFalseStart = 1; break; + case 'd': certDir = PORT_Strdup(optstate->value); break; case 'f': clientSpeaksFirst = PR_TRUE; break; @@ -863,7 +867,14 @@ int main(int argc, char **argv) SECU_PrintError(progName, "error enabling compression"); return 1; } - + + /* enable false start. */ + rv = SSL_OptionSet(s, SSL_ENABLE_FALSE_START, enableFalseStart); + if (rv != SECSuccess) { + SECU_PrintError(progName, "error enabling false start"); + return 1; + } + SSL_SetPKCS11PinArg(s, &pwdata); SSL_AuthCertificateHook(s, SSL_AuthCertificate, (void *)handle); diff --git a/security/nss/lib/ssl/ssl.h b/security/nss/lib/ssl/ssl.h index 70c53f541..e294a67cf 100644 --- a/security/nss/lib/ssl/ssl.h +++ b/security/nss/lib/ssl/ssl.h @@ -128,6 +128,17 @@ SSL_IMPORT PRFileDesc *SSL_ImportFD(PRFileDesc *model, PRFileDesc *fd); /* Renegotiation Info (RI) */ /* extension in ALL handshakes. */ /* default: off */ +#define SSL_ENABLE_FALSE_START 22 /* Enable SSL false start (off by */ + /* default, applies only to */ + /* clients). False start is a */ +/* mode where an SSL client will start sending application data before */ +/* verifying the server's Finished message. This means that we could end up */ +/* sending data to an imposter. However, the data will be encrypted and */ +/* only the true server can derive the session key. Thus, so long as the */ +/* cipher isn't broken this is safe. Because of this, False Start will only */ +/* occur on RSA or DH ciphersuites where the cipher's key length is >= 80 */ +/* bits. The advantage of False Start is that it saves a round trip for */ +/* client-speaks-first protocols when performing a full handshake. */ #ifdef SSL_DEPRECATED_FUNCTION /* Old deprecated function names */ diff --git a/security/nss/lib/ssl/ssl3con.c b/security/nss/lib/ssl/ssl3con.c index 7a7bc1043..754ebadda 100644 --- a/security/nss/lib/ssl/ssl3con.c +++ b/security/nss/lib/ssl/ssl3con.c @@ -5665,7 +5665,17 @@ ssl3_RestartHandshakeAfterCertReq(sslSocket * ss, return rv; } - +PRBool +ssl3_CanFalseStart(sslSocket *ss) { + return ss->opt.enableFalseStart && + !ss->sec.isServer && + !ss->ssl3.hs.isResuming && + ss->ssl3.cwSpec && + ss->ssl3.cwSpec->cipher_def->secret_key_size >= 10 && + (ss->ssl3.hs.kea_def->exchKeyType == ssl_kea_rsa || + ss->ssl3.hs.kea_def->exchKeyType == ssl_kea_dh || + ss->ssl3.hs.kea_def->exchKeyType == ssl_kea_ecdh); +} /* Called from ssl3_HandleHandshakeMessage() when it has deciphered a complete * ssl3 Server Hello Done message. @@ -5737,6 +5747,12 @@ ssl3_HandleServerHelloDone(sslSocket *ss) ss->ssl3.hs.ws = wait_new_session_ticket; 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); + } + return SECSuccess; loser: @@ -8476,8 +8492,8 @@ xmit_loser: } ss->ssl3.hs.ws = idle_handshake; - /* Do the handshake callback for sslv3 here. */ - if (ss->handshakeCallback != NULL) { + /* 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); } diff --git a/security/nss/lib/ssl/ssl3gthr.c b/security/nss/lib/ssl/ssl3gthr.c index 4465c4359..437a9293e 100644 --- a/security/nss/lib/ssl/ssl3gthr.c +++ b/security/nss/lib/ssl/ssl3gthr.c @@ -188,6 +188,7 @@ ssl3_GatherCompleteHandshake(sslSocket *ss, int flags) { SSL3Ciphertext cText; int rv; + PRBool canFalseStart = PR_FALSE; PORT_Assert( ss->opt.noLocks || ssl_HaveRecvBufLock(ss) ); do { @@ -199,6 +200,8 @@ ssl3_GatherCompleteHandshake(sslSocket *ss, int flags) /* decipher it, and handle it if it's a handshake. * If it's application data, ss->gs.buf will not be empty upon return. + * If it's a change cipher spec, alert, or handshake message, + * ss->gs.buf.len will be 0 when ssl3_HandleRecord returns SECSuccess. */ cText.type = (SSL3ContentType)ss->gs.hdr[0]; cText.version = (ss->gs.hdr[1] << 8) | ss->gs.hdr[2]; @@ -207,7 +210,20 @@ ssl3_GatherCompleteHandshake(sslSocket *ss, int flags) if (rv < 0) { return ss->recvdCloseNotify ? 0 : rv; } - } while (ss->ssl3.hs.ws != idle_handshake && ss->gs.buf.len == 0); + + /* 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); + ssl_ReleaseSSL3HandshakeLock(ss); + } + } while (ss->ssl3.hs.ws != idle_handshake && + !canFalseStart && + ss->gs.buf.len == 0); ss->gs.readOffset = 0; ss->gs.writeOffset = ss->gs.buf.len; diff --git a/security/nss/lib/ssl/sslimpl.h b/security/nss/lib/ssl/sslimpl.h index e21420a5c..bc0102b40 100644 --- a/security/nss/lib/ssl/sslimpl.h +++ b/security/nss/lib/ssl/sslimpl.h @@ -333,6 +333,7 @@ typedef struct sslOptionsStr { unsigned int enableDeflate : 1; /* 19 */ unsigned int enableRenegotiation : 2; /* 20-21 */ unsigned int requireSafeNegotiation : 1; /* 22 */ + unsigned int enableFalseStart : 1; /* 23 */ } sslOptions; typedef enum { sslHandshakingUndetermined = 0, @@ -1250,6 +1251,8 @@ extern void ssl_SetAlwaysBlock(sslSocket *ss); extern SECStatus ssl_EnableNagleDelay(sslSocket *ss, PRBool enabled); +extern PRBool ssl3_CanFalseStart(sslSocket *ss); + #define SSL_LOCK_READER(ss) if (ss->recvLock) PZ_Lock(ss->recvLock) #define SSL_UNLOCK_READER(ss) if (ss->recvLock) PZ_Unlock(ss->recvLock) #define SSL_LOCK_WRITER(ss) if (ss->sendLock) PZ_Lock(ss->sendLock) diff --git a/security/nss/lib/ssl/sslsecur.c b/security/nss/lib/ssl/sslsecur.c index fc2c73dd9..3740873b0 100644 --- a/security/nss/lib/ssl/sslsecur.c +++ b/security/nss/lib/ssl/sslsecur.c @@ -1199,8 +1199,17 @@ 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->handshake || ss->nextHandshake || ss->securityHandshake) { + if (ss->version >= SSL_LIBRARY_VERSION_3_0 && + (ss->ssl3.hs.ws == wait_change_cipher || + ss->ssl3.hs.ws == wait_finished || + ss->ssl3.hs.ws == wait_new_session_ticket) && + ssl3_CanFalseStart(ss)) { + canFalseStart = PR_TRUE; + } + if (!canFalseStart && + (ss->handshake || ss->nextHandshake || ss->securityHandshake)) { rv = ssl_Do1stHandshake(ss); } ssl_Release1stHandshakeLock(ss); diff --git a/security/nss/lib/ssl/sslsock.c b/security/nss/lib/ssl/sslsock.c index cfb5ba455..8b04e508b 100644 --- a/security/nss/lib/ssl/sslsock.c +++ b/security/nss/lib/ssl/sslsock.c @@ -183,6 +183,7 @@ static sslOptions ssl_defaults = { PR_FALSE, /* enableDeflate */ 2, /* enableRenegotiation (default: requires extension) */ PR_FALSE, /* requireSafeNegotiation */ + PR_FALSE, /* enableFalseStart */ }; sslSessionIDLookupFunc ssl_sid_lookup; @@ -728,6 +729,10 @@ SSL_OptionSet(PRFileDesc *fd, PRInt32 which, PRBool on) ss->opt.requireSafeNegotiation = on; break; + case SSL_ENABLE_FALSE_START: + ss->opt.enableFalseStart = on; + break; + default: PORT_SetError(SEC_ERROR_INVALID_ARGS); rv = SECFailure; @@ -791,6 +796,7 @@ SSL_OptionGet(PRFileDesc *fd, PRInt32 which, PRBool *pOn) on = ss->opt.enableRenegotiation; break; case SSL_REQUIRE_SAFE_NEGOTIATION: on = ss->opt.requireSafeNegotiation; break; + case SSL_ENABLE_FALSE_START: on = ss->opt.enableFalseStart; break; default: PORT_SetError(SEC_ERROR_INVALID_ARGS); @@ -841,6 +847,7 @@ SSL_OptionGetDefault(PRInt32 which, PRBool *pOn) case SSL_REQUIRE_SAFE_NEGOTIATION: on = ssl_defaults.requireSafeNegotiation; break; + case SSL_ENABLE_FALSE_START: on = ssl_defaults.enableFalseStart; break; default: PORT_SetError(SEC_ERROR_INVALID_ARGS); @@ -984,6 +991,10 @@ SSL_OptionSetDefault(PRInt32 which, PRBool on) ssl_defaults.requireSafeNegotiation = on; break; + case SSL_ENABLE_FALSE_START: + ssl_defaults.enableFalseStart = on; + break; + default: PORT_SetError(SEC_ERROR_INVALID_ARGS); return SECFailure; diff --git a/security/nss/tests/ssl/sslstress.txt b/security/nss/tests/ssl/sslstress.txt index 9a3aae849..64f6b76e3 100644 --- a/security/nss/tests/ssl/sslstress.txt +++ b/security/nss/tests/ssl/sslstress.txt @@ -42,9 +42,11 @@ noECC 0 _ -c_1000_-C_A Stress SSL2 RC4 128 with MD5 noECC 0 _ -c_1000_-C_c_-T Stress SSL3 RC4 128 with MD5 noECC 0 _ -c_1000_-C_c Stress TLS RC4 128 with MD5 + noECC 0 _ -c_1000_-C_c_-g Stress TLS RC4 128 with MD5 (false start) noECC 0 -u -2_-c_1000_-C_c_-u Stress TLS RC4 128 with MD5 (session ticket) noECC 0 -z -2_-c_1000_-C_c_-z Stress TLS RC4 128 with MD5 (compression) noECC 0 -u_-z -2_-c_1000_-C_c_-u_-z Stress TLS RC4 128 with MD5 (session ticket, compression) + noECC 0 -u_-z -2_-c_1000_-C_c_-u_-z_-g Stress TLS RC4 128 with MD5 (session ticket, compression, false start) SNI 0 -u_-a_Host-sni.Dom -2_-3_-c_1000_-C_c_-u Stress TLS RC4 128 with MD5 (session ticket, SNI) # @@ -55,7 +57,9 @@ noECC 0 -r_-r -c_100_-C_c_-N_-n_TestUser Stress TLS RC4 128 with MD5 (no reuse, client auth) noECC 0 -r_-r_-u -2_-c_100_-C_c_-n_TestUser_-u Stress TLS RC4 128 with MD5 (session ticket, client auth) noECC 0 -r_-r_-z -2_-c_100_-C_c_-n_TestUser_-z Stress TLS RC4 128 with MD5 (compression, client auth) + noECC 0 -r_-r_-z -2_-c_100_-C_c_-n_TestUser_-z_-g Stress TLS RC4 128 with MD5 (compression, client auth, false start) noECC 0 -r_-r_-u_-z -2_-c_100_-C_c_-n_TestUser_-u_-z Stress TLS RC4 128 with MD5 (session ticket, compression, client auth) + noECC 0 -r_-r_-u_-z -2_-c_100_-C_c_-n_TestUser_-u_-z_-g Stress TLS RC4 128 with MD5 (session ticket, compression, client auth, false start) SNI 0 -r_-r_-u_-a_Host-sni.Dom -2_-3_-c_1000_-C_c_-u Stress TLS RC4 128 with MD5 (session ticket, SNI, client auth, default virt host) SNI 0 -r_-r_-u_-a_Host-sni.Dom_-k_Host-sni.Dom -2_-3_-c_1000_-C_c_-u_-a_Host-sni.Dom Stress TLS RC4 128 with MD5 (session ticket, SNI, client auth, change virt host) |