Chromium Code Reviews| Index: net/third_party/nss/patches/falsestart.patch |
| diff --git a/net/third_party/nss/patches/falsestart.patch b/net/third_party/nss/patches/falsestart.patch |
| new file mode 100644 |
| index 0000000000000000000000000000000000000000..2bcb88f749b29cfcbd2fb1ab093751d6a5fa84ad |
| --- /dev/null |
| +++ b/net/third_party/nss/patches/falsestart.patch |
| @@ -0,0 +1,806 @@ |
| +diff --git a/mozilla/security/nss/cmd/strsclnt/strsclnt.c b/mozilla/security/nss/cmd/strsclnt/strsclnt.c |
|
wtc
2010/02/20 00:39:51
Remove the NPN changes from this patch.
|
| +index c266644..1f71434 100644 |
| +--- a/mozilla/security/nss/cmd/strsclnt/strsclnt.c |
| ++++ b/mozilla/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/mozilla/security/nss/cmd/tstclnt/tstclnt.c b/mozilla/security/nss/cmd/tstclnt/tstclnt.c |
| +index c15a0ad..d209a33 100644 |
| +--- a/mozilla/security/nss/cmd/tstclnt/tstclnt.c |
| ++++ b/mozilla/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,20 @@ int main(int argc, char **argv) |
| + SECU_PrintError(progName, "error enabling compression"); |
| + return 1; |
| + } |
| +- |
| ++ |
| ++ rv = SSL_SetNextProtoNego(s, "\004flip\004http1.1", 10); |
| ++ if (rv != SECSuccess) { |
| ++ SECU_PrintError(progName, "error enabling next protocol negotiation"); |
| ++ 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/mozilla/security/nss/lib/ssl/ssl.def b/mozilla/security/nss/lib/ssl/ssl.def |
| +index d3f455c..a1f4b51 100644 |
| +--- a/mozilla/security/nss/lib/ssl/ssl.def |
| ++++ b/mozilla/security/nss/lib/ssl/ssl.def |
| +@@ -152,3 +152,10 @@ SSL_SNISocketConfigHook; |
| + ;+ local: |
| + ;+*; |
| + ;+}; |
| ++;+NSS_CHROMIUM { |
| ++;+ global: |
| ++SSL_GetNextProto; |
| ++SSL_SetNextProtoNego; |
| ++;+ local: |
| ++;+*; |
| ++;+}; |
| +diff --git a/mozilla/security/nss/lib/ssl/ssl.h b/mozilla/security/nss/lib/ssl/ssl.h |
| +index e285ab4..60fc9b5 100644 |
| +--- a/mozilla/security/nss/lib/ssl/ssl.h |
| ++++ b/mozilla/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 */ |
| ++/* verifing 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 decrypt 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 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 */ |
| +@@ -142,6 +153,18 @@ SSL_IMPORT SECStatus SSL_OptionSetDefault(PRInt32 option, PRBool on); |
| + SSL_IMPORT SECStatus SSL_OptionGetDefault(PRInt32 option, PRBool *on); |
| + SSL_IMPORT SECStatus SSL_CertDBHandleSet(PRFileDesc *fd, CERTCertDBHandle *dbHandle); |
| + |
| ++SSL_IMPORT SECStatus SSL_SetNextProtoNego(PRFileDesc *fd, |
| ++ const unsigned char *data, |
| ++ unsigned short length); |
| ++SSL_IMPORT SECStatus SSL_GetNextProto(PRFileDesc *fd, |
| ++ int *state, |
| ++ unsigned char *buf, |
| ++ unsigned *length, |
| ++ unsigned buf_len); |
| ++#define SSL_NEXT_PROTO_NO_SUPPORT 0 /* No peer support */ |
| ++#define SSL_NEXT_PROTO_NEGOTIATED 1 /* Mutual agreement */ |
| ++#define SSL_NEXT_PROTO_NO_OVERLAP 2 /* No protocol overlap found */ |
| ++ |
| + /* |
| + ** Control ciphers that SSL uses. If on is non-zero then the named cipher |
| + ** is enabled, otherwise it is disabled. |
| +diff --git a/mozilla/security/nss/lib/ssl/ssl3con.c b/mozilla/security/nss/lib/ssl/ssl3con.c |
| +index 6b37c4f..dd1ac73 100644 |
| +--- a/mozilla/security/nss/lib/ssl/ssl3con.c |
| ++++ b/mozilla/security/nss/lib/ssl/ssl3con.c |
| +@@ -81,6 +81,7 @@ static SECStatus ssl3_InitState( sslSocket *ss); |
| + static SECStatus ssl3_SendCertificate( sslSocket *ss); |
| + static SECStatus ssl3_SendEmptyCertificate( sslSocket *ss); |
| + static SECStatus ssl3_SendCertificateRequest(sslSocket *ss); |
| ++static SECStatus ssl3_SendNextProto( sslSocket *ss); |
| + static SECStatus ssl3_SendFinished( sslSocket *ss, PRInt32 flags); |
| + static SECStatus ssl3_SendServerHello( sslSocket *ss); |
| + static SECStatus ssl3_SendServerHelloDone( sslSocket *ss); |
| +@@ -5656,7 +5657,15 @@ 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 == kt_rsa; |
| ++} |
| + |
| + /* Called from ssl3_HandleHandshakeMessage() when it has deciphered a complete |
| + * ssl3 Server Hello Done message. |
| +@@ -5717,6 +5726,12 @@ ssl3_HandleServerHelloDone(sslSocket *ss) |
| + if (rv != SECSuccess) { |
| + goto loser; /* err code was set. */ |
| + } |
| ++ |
| ++ rv = ssl3_SendNextProto(ss); |
| ++ if (rv != SECSuccess) { |
| ++ goto loser; /* err code was set. */ |
| ++ } |
| ++ |
| + rv = ssl3_SendFinished(ss, 0); |
| + if (rv != SECSuccess) { |
| + goto loser; /* err code was set. */ |
| +@@ -5728,6 +5743,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 (ss->handshakeCallback != NULL && ssl3_CanFalseStart(ss)) { |
| ++ (ss->handshakeCallback)(ss->fd, ss->handshakeCallbackData); |
| ++ } |
| ++ |
| + return SECSuccess; |
| + |
| + loser: |
| +@@ -8138,6 +8159,40 @@ ssl3_ComputeTLSFinished(ssl3CipherSpec *spec, |
| + } |
| + |
| + /* called from ssl3_HandleServerHelloDone |
| ++ */ |
| ++static SECStatus |
| ++ssl3_SendNextProto(sslSocket *ss) |
| ++{ |
| ++ SECStatus rv; |
| ++ int padding_len; |
| ++ static const unsigned char padding[32] = {0}; |
| ++ |
| ++ if (ss->ssl3.nextProtoState == SSL_NEXT_PROTO_NO_SUPPORT) |
| ++ return SECSuccess; |
| ++ |
| ++ PORT_Assert( ss->opt.noLocks || ssl_HaveXmitBufLock(ss)); |
| ++ PORT_Assert( ss->opt.noLocks || ssl_HaveSSL3HandshakeLock(ss)); |
| ++ |
| ++ padding_len = 32 - ((ss->ssl3.nextProto.len + 2) % 32); |
| ++ |
| ++ rv = ssl3_AppendHandshakeHeader(ss, next_proto, ss->ssl3.nextProto.len + |
| ++ 2 + padding_len); |
| ++ if (rv != SECSuccess) { |
| ++ return rv; /* error code set by AppendHandshakeHeader */ |
| ++ } |
| ++ rv = ssl3_AppendHandshakeVariable(ss, ss->ssl3.nextProto.data, |
| ++ ss->ssl3.nextProto.len, 1); |
| ++ if (rv != SECSuccess) { |
| ++ return rv; /* error code set by AppendHandshake */ |
| ++ } |
| ++ rv = ssl3_AppendHandshakeVariable(ss, padding, padding_len, 1); |
| ++ if (rv != SECSuccess) { |
| ++ return rv; /* error code set by AppendHandshake */ |
| ++ } |
| ++ return rv; |
| ++} |
| ++ |
| ++/* called from ssl3_HandleServerHelloDone |
| + * ssl3_HandleClientHello |
| + * ssl3_HandleFinished |
| + */ |
| +@@ -8468,7 +8523,7 @@ xmit_loser: |
| + ss->ssl3.hs.ws = idle_handshake; |
| + |
| + /* Do the handshake callback for sslv3 here. */ |
| +- if (ss->handshakeCallback != NULL) { |
| ++ if (ss->handshakeCallback != NULL && !ssl3_CanFalseStart(ss)) { |
| + (ss->handshakeCallback)(ss->fd, ss->handshakeCallbackData); |
| + } |
| + |
| +@@ -9457,6 +9512,11 @@ ssl3_DestroySSL3Info(sslSocket *ss) |
| + ssl3_DestroyCipherSpec(&ss->ssl3.specs[1], PR_TRUE/*freeSrvName*/); |
| + |
| + ss->ssl3.initialized = PR_FALSE; |
| ++ |
| ++ if (ss->ssl3.nextProto.data) { |
| ++ PORT_Free(ss->ssl3.nextProto.data); |
| ++ ss->ssl3.nextProto.data = NULL; |
| ++ } |
| + } |
| + |
| + /* End of ssl3con.c */ |
| +diff --git a/mozilla/security/nss/lib/ssl/ssl3ext.c b/mozilla/security/nss/lib/ssl/ssl3ext.c |
| +index fd0d9b9..ead0cfd 100644 |
| +--- a/mozilla/security/nss/lib/ssl/ssl3ext.c |
| ++++ b/mozilla/security/nss/lib/ssl/ssl3ext.c |
| +@@ -235,6 +235,7 @@ static const ssl3HelloExtensionHandler clientHelloHandlers[] = { |
| + #endif |
| + { ssl_session_ticket_xtn, &ssl3_ServerHandleSessionTicketXtn }, |
| + { ssl_renegotiation_info_xtn, &ssl3_HandleRenegotiationInfoXtn }, |
| ++ { ssl_next_proto_neg_xtn, &ssl3_ServerHandleNextProtoNegoXtn }, |
| + { -1, NULL } |
| + }; |
| + |
| +@@ -245,6 +246,7 @@ static const ssl3HelloExtensionHandler serverHelloHandlersTLS[] = { |
| + /* TODO: add a handler for ssl_ec_point_formats_xtn */ |
| + { ssl_session_ticket_xtn, &ssl3_ClientHandleSessionTicketXtn }, |
| + { ssl_renegotiation_info_xtn, &ssl3_HandleRenegotiationInfoXtn }, |
| ++ { ssl_next_proto_neg_xtn, &ssl3_ClientHandleNextProtoNegoXtn }, |
| + { -1, NULL } |
| + }; |
| + |
| +@@ -267,7 +269,8 @@ ssl3HelloExtensionSender clientHelloSendersTLS[SSL_MAX_EXTENSIONS] = { |
| + { ssl_elliptic_curves_xtn, &ssl3_SendSupportedCurvesXtn }, |
| + { ssl_ec_point_formats_xtn, &ssl3_SendSupportedPointFormatsXtn }, |
| + #endif |
| +- { ssl_session_ticket_xtn, &ssl3_SendSessionTicketXtn } |
| ++ { ssl_session_ticket_xtn, &ssl3_SendSessionTicketXtn }, |
| ++ { ssl_next_proto_neg_xtn, &ssl3_ClientSendNextProtoNegoXtn } |
| + /* any extra entries will appear as { 0, NULL } */ |
| + }; |
| + |
| +@@ -532,6 +535,123 @@ ssl3_SendSessionTicketXtn( |
| + return -1; |
| + } |
| + |
| ++/* handle an incoming Next Protocol Negotiation extension. */ |
| ++SECStatus |
| ++ssl3_ServerHandleNextProtoNegoXtn(sslSocket * ss, PRUint16 ex_type, SECItem *data) |
| ++{ |
| ++ if (data->len != 0) { |
| ++ /* Clients MUST send an empty NPN extension, if any. */ |
| ++ return SECFailure; |
| ++ } |
| ++ |
| ++ ss->ssl3.hs.nextProtoNego = PR_TRUE; |
| ++ return SECSuccess; |
| ++} |
| ++ |
| ++/* ssl3_ValidateNextProtoNego checks that the given block of data is valid: none |
| ++ * of the length may be 0 and the sum of the lengths must equal the length of |
| ++ * the block. */ |
| ++SECStatus |
| ++ssl3_ValidateNextProtoNego(const unsigned char* data, unsigned short length) |
| ++{ |
| ++ unsigned int offset = 0; |
| ++ |
| ++ while (offset < length) { |
| ++ if (data[offset] == 0) { |
| ++ return SECFailure; |
| ++ } |
| ++ offset += (unsigned int)data[offset] + 1; |
| ++ } |
| ++ |
| ++ if (offset > length) |
| ++ return SECFailure; |
| ++ |
| ++ return SECSuccess; |
| ++} |
| ++ |
| ++SECStatus |
| ++ssl3_ClientHandleNextProtoNegoXtn(sslSocket *ss, PRUint16 ex_type, |
| ++ SECItem *data) |
| ++{ |
| ++ unsigned int i, j; |
| ++ SECStatus rv; |
| ++ unsigned char *result; |
| ++ |
| ++ if (data->len == 0) { |
| ++ /* The server supports the extension, but doesn't have any |
| ++ * protocols configured. In this case we request our favoured |
| ++ * protocol. */ |
| ++ goto pick_first; |
| ++ } |
| ++ |
| ++ rv = ssl3_ValidateNextProtoNego(data->data, data->len); |
| ++ if (rv != SECSuccess) |
| ++ return rv; |
| ++ |
| ++ /* For each protocol in server preference order, see if we support it. */ |
| ++ for (i = 0; i < data->len; ) { |
| ++ for (j = 0; j < ss->opt.nextProtoNego.len; ) { |
| ++ if (data->data[i] == ss->opt.nextProtoNego.data[j] && |
| ++ memcmp(&data->data[i+1], &ss->opt.nextProtoNego.data[j+1], |
| ++ data->data[i]) == 0) { |
| ++ /* We found a match */ |
| ++ ss->ssl3.nextProtoState = SSL_NEXT_PROTO_NEGOTIATED; |
| ++ result = &data->data[i]; |
| ++ goto found; |
| ++ } |
| ++ j += (unsigned int)ss->opt.nextProtoNego.data[j] + 1; |
| ++ } |
| ++ |
| ++ i += (unsigned int)data->data[i] + 1; |
| ++ } |
| ++ |
| ++ pick_first: |
| ++ ss->ssl3.nextProtoState = SSL_NEXT_PROTO_NO_OVERLAP; |
| ++ result = ss->opt.nextProtoNego.data; |
| ++ |
| ++ found: |
| ++ if (ss->ssl3.nextProto.data) |
| ++ PORT_Free(ss->ssl3.nextProto.data); |
| ++ ss->ssl3.nextProto.data = PORT_Alloc(result[0]); |
| ++ PORT_Memcpy(ss->ssl3.nextProto.data, result + 1, result[0]); |
| ++ ss->ssl3.nextProto.len = result[0]; |
| ++ return SECSuccess; |
| ++} |
| ++ |
| ++PRInt32 |
| ++ssl3_ClientSendNextProtoNegoXtn(sslSocket * ss, |
| ++ PRBool append, |
| ++ PRUint32 maxBytes) |
| ++{ |
| ++ PRInt32 extension_length; |
| ++ |
| ++ /* Renegotiations do not send this extension. */ |
| ++ if (ss->opt.nextProtoNego.len == 0 || ss->firstHsDone) { |
| ++ return 0; |
| ++ } |
| ++ |
| ++ extension_length = 4; |
| ++ |
| ++ if (append && maxBytes >= extension_length) { |
| ++ SECStatus rv; |
| ++ rv = ssl3_AppendHandshakeNumber(ss, ssl_next_proto_neg_xtn, 2); |
| ++ if (rv != SECSuccess) |
| ++ goto loser; |
| ++ rv = ssl3_AppendHandshakeNumber(ss, 0, 2); |
| ++ if (rv != SECSuccess) |
| ++ goto loser; |
| ++ ss->xtnData.advertised[ss->xtnData.numAdvertised++] = |
| ++ ssl_next_proto_neg_xtn; |
| ++ } else if (maxBytes < extension_length) { |
| ++ return 0; |
| ++ } |
| ++ |
| ++ return extension_length; |
| ++ |
| ++ loser: |
| ++ return -1; |
| ++} |
| ++ |
| + /* |
| + * NewSessionTicket |
| + * Called from ssl3_HandleFinished |
| +diff --git a/mozilla/security/nss/lib/ssl/ssl3gthr.c b/mozilla/security/nss/lib/ssl/ssl3gthr.c |
| +index bdd2958..28fe154 100644 |
| +--- a/mozilla/security/nss/lib/ssl/ssl3gthr.c |
| ++++ b/mozilla/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 { |
| +@@ -207,7 +208,17 @@ 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 (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/mozilla/security/nss/lib/ssl/ssl3prot.h b/mozilla/security/nss/lib/ssl/ssl3prot.h |
| +index 0fc1675..c82c891 100644 |
| +--- a/mozilla/security/nss/lib/ssl/ssl3prot.h |
| ++++ b/mozilla/security/nss/lib/ssl/ssl3prot.h |
| +@@ -157,7 +157,8 @@ typedef enum { |
| + server_hello_done = 14, |
| + certificate_verify = 15, |
| + client_key_exchange = 16, |
| +- finished = 20 |
| ++ finished = 20, |
| ++ next_proto = 67 |
| + } SSL3HandshakeType; |
| + |
| + typedef struct { |
| +diff --git a/mozilla/security/nss/lib/ssl/sslimpl.h b/mozilla/security/nss/lib/ssl/sslimpl.h |
| +index 7581b98..a800d56 100644 |
| +--- a/mozilla/security/nss/lib/ssl/sslimpl.h |
| ++++ b/mozilla/security/nss/lib/ssl/sslimpl.h |
| +@@ -313,6 +313,11 @@ typedef struct { |
| + #endif /* NSS_ENABLE_ECC */ |
| + |
| + typedef struct sslOptionsStr { |
| ++ /* For clients, this is a validated list of protocols in preference order |
| ++ * and wire format. For servers, this is the list of support protocols, |
| ++ * also in wire format. */ |
| ++ SECItem nextProtoNego; |
| ++ |
| + unsigned int useSecurity : 1; /* 1 */ |
| + unsigned int useSocks : 1; /* 2 */ |
| + unsigned int requestCertificate : 1; /* 3 */ |
| +@@ -333,6 +338,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, |
| +@@ -785,6 +791,7 @@ const ssl3CipherSuiteDef *suite_def; |
| + #ifdef NSS_ENABLE_ECC |
| + PRUint32 negotiatedECCurves; /* bit mask */ |
| + #endif /* NSS_ENABLE_ECC */ |
| ++ PRBool nextProtoNego;/* Our peer has sent this extension */ |
| + } SSL3HandshakeState; |
| + |
| + |
| +@@ -826,6 +833,16 @@ struct ssl3StateStr { |
| + PRBool initialized; |
| + SSL3HandshakeState hs; |
| + ssl3CipherSpec specs[2]; /* one is current, one is pending. */ |
| ++ |
| ++ /* In a client: if the server supports Next Protocol Negotiation, then |
| ++ * this is the protocol that was requested. |
| ++ * In a server: this is the protocol that the client requested via Next |
| ++ * Protocol Negotiation. |
| ++ * |
| ++ * In either case, if the data pointer is non-NULL, then it is malloced |
| ++ * data. */ |
| ++ SECItem nextProto; |
| ++ int nextProtoState; /* See SSL_NEXT_PROTO_* defines */ |
| + }; |
| + |
| + typedef struct { |
| +@@ -1250,6 +1267,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) |
| +@@ -1491,8 +1510,12 @@ extern SECStatus ssl3_HandleSupportedPointFormatsXtn(sslSocket * ss, |
| + PRUint16 ex_type, SECItem *data); |
| + extern SECStatus ssl3_ClientHandleSessionTicketXtn(sslSocket *ss, |
| + PRUint16 ex_type, SECItem *data); |
| ++extern SECStatus ssl3_ClientHandleNextProtoNegoXtn(sslSocket *ss, |
| ++ PRUint16 ex_type, SECItem *data); |
| + extern SECStatus ssl3_ServerHandleSessionTicketXtn(sslSocket *ss, |
| + PRUint16 ex_type, SECItem *data); |
| ++extern SECStatus ssl3_ServerHandleNextProtoNegoXtn(sslSocket *ss, |
| ++ PRUint16 ex_type, SECItem *data); |
| + |
| + /* ClientHello and ServerHello extension senders. |
| + * Note that not all extension senders are exposed here; only those that |
| +@@ -1523,6 +1546,10 @@ extern PRInt32 ssl3_SendSupportedCurvesXtn(sslSocket *ss, |
| + extern PRInt32 ssl3_SendSupportedPointFormatsXtn(sslSocket *ss, |
| + PRBool append, PRUint32 maxBytes); |
| + #endif |
| ++extern PRInt32 ssl3_ClientSendNextProtoNegoXtn(sslSocket *ss, PRBool append, |
| ++ PRUint32 maxBytes); |
| ++extern SECStatus ssl3_ValidateNextProtoNego(const unsigned char* data, |
| ++ unsigned short length); |
| + |
| + /* call the registered extension handlers. */ |
| + extern SECStatus ssl3_HandleHelloExtensions(sslSocket *ss, |
| +diff --git a/mozilla/security/nss/lib/ssl/sslsecur.c b/mozilla/security/nss/lib/ssl/sslsecur.c |
| +index 8f79135..33ad2c3 100644 |
| +--- a/mozilla/security/nss/lib/ssl/sslsecur.c |
| ++++ b/mozilla/security/nss/lib/ssl/sslsecur.c |
| +@@ -148,6 +148,12 @@ ssl_Do1stHandshake(sslSocket *ss) |
| + ss->gs.readOffset = 0; |
| + break; |
| + } |
| ++ if (ss->version >= SSL_LIBRARY_VERSION_3_0 && |
| ++ ssl3_CanFalseStart(ss) && |
| ++ (ss->ssl3.hs.ws == wait_change_cipher || |
| ++ ss->ssl3.hs.ws == wait_new_session_ticket)) { |
| ++ break; |
| ++ } |
| + rv = (*ss->handshake)(ss); |
| + ++loopCount; |
| + /* This code must continue to loop on SECWouldBlock, |
| +@@ -1307,6 +1313,10 @@ SSL_SetURL(PRFileDesc *fd, const char *url) |
| + SECStatus |
| + SSL_SetTrustAnchors(PRFileDesc *fd, CERTCertList *certList) |
| + { |
| ++ PORT_SetError(PR_NOT_IMPLEMENTED_ERROR); |
| ++ PR_NOT_REACHED("not implemented"); |
| ++ return SECFailure; |
| ++#if 0 |
| + sslSocket * ss = ssl_FindSocket(fd); |
| + CERTDistNames *names = NULL; |
| + |
| +@@ -1334,6 +1344,7 @@ SSL_SetTrustAnchors(PRFileDesc *fd, CERTCertList *certList) |
| + ssl_Release1stHandshakeLock(ss); |
| + |
| + return SECSuccess; |
| ++#endif |
| + } |
| + |
| + /* |
| +diff --git a/mozilla/security/nss/lib/ssl/sslsock.c b/mozilla/security/nss/lib/ssl/sslsock.c |
| +index aab48d6..c4611a0 100644 |
| +--- a/mozilla/security/nss/lib/ssl/sslsock.c |
| ++++ b/mozilla/security/nss/lib/ssl/sslsock.c |
| +@@ -163,6 +163,7 @@ static const sslSocketOps ssl_secure_ops = { /* SSL. */ |
| + ** default settings for socket enables |
| + */ |
| + static sslOptions ssl_defaults = { |
| ++ { siBuffer, NULL, 0 }, /* nextProtoNego */ |
| + PR_TRUE, /* useSecurity */ |
| + PR_FALSE, /* useSocks */ |
| + PR_FALSE, /* requestCertificate */ |
| +@@ -183,6 +184,7 @@ static sslOptions ssl_defaults = { |
| + PR_FALSE, /* enableDeflate */ |
| + 2, /* enableRenegotiation (default: requires extension) */ |
| + PR_FALSE, /* requireSafeNegotiation */ |
| ++ PR_FALSE, /* enableFalseStart */ |
| + }; |
| + |
| + sslSessionIDLookupFunc ssl_sid_lookup; |
| +@@ -437,6 +439,10 @@ ssl_DestroySocketContents(sslSocket *ss) |
| + ssl3_FreeKeyPair(ss->ephemeralECDHKeyPair); |
| + ss->ephemeralECDHKeyPair = NULL; |
| + } |
| ++ if (ss->opt.nextProtoNego.data) { |
| ++ PORT_Free(ss->opt.nextProtoNego.data); |
| ++ ss->opt.nextProtoNego.data = NULL; |
| ++ } |
| + PORT_Assert(!ss->xtnData.sniNameArr); |
| + if (ss->xtnData.sniNameArr) { |
| + PORT_Free(ss->xtnData.sniNameArr); |
| +@@ -728,6 +734,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 +801,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 +852,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 +996,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; |
| +@@ -1255,9 +1271,83 @@ SSL_ImportFD(PRFileDesc *model, PRFileDesc *fd) |
| + return fd; |
| + } |
| + |
| ++/* SSL_SetNextProtoNego sets the list of supported protocols for the given |
| ++ * socket. The list is a series of 8-bit, length prefixed strings. */ |
| ++SECStatus |
| ++SSL_SetNextProtoNego(PRFileDesc *fd, const unsigned char *data, |
| ++ unsigned short length) |
| ++{ |
| ++ sslSocket *ss = ssl_FindSocket(fd); |
| ++ |
| ++ if (!ss) { |
| ++ SSL_DBG(("%d: SSL[%d]: bad socket in SSL_SetNextProtoNego", SSL_GETPID(), |
| ++ fd)); |
| ++ return SECFailure; |
| ++ } |
| ++ |
| ++ if (ssl3_ValidateNextProtoNego(data, length) != SECSuccess) |
| ++ return SECFailure; |
| ++ |
| ++ ssl_GetSSL3HandshakeLock(ss); |
| ++ if (ss->opt.nextProtoNego.data) |
| ++ PORT_Free(ss->opt.nextProtoNego.data); |
| ++ ss->opt.nextProtoNego.data = PORT_Alloc(length); |
| ++ if (!ss->opt.nextProtoNego.data) { |
| ++ ssl_ReleaseSSL3HandshakeLock(ss); |
| ++ return SECFailure; |
| ++ } |
| ++ memcpy(ss->opt.nextProtoNego.data, data, length); |
| ++ ss->opt.nextProtoNego.len = length; |
| ++ ss->opt.nextProtoNego.type = siBuffer; |
| ++ ssl_ReleaseSSL3HandshakeLock(ss); |
| ++ |
| ++ return SECSuccess; |
| ++} |
| ++ |
| ++/* SSL_GetNextProto reads the resulting Next Protocol Negotiation result for |
| ++ * the given socket. It's only valid to call this once the handshake has |
| ++ * completed. |
| ++ * |
| ++ * state is set to one of the SSL_NEXT_PROTO_* constants. The negotiated |
| ++ * protocol, if any, is written into buf, which must be at least buf_len |
| ++ * bytes long. If the negotiated protocol is longer than this, it is truncated. |
| ++ * The number of bytes copied is written into length. |
| ++ */ |
| ++SECStatus |
| ++SSL_GetNextProto(PRFileDesc *fd, int *state, unsigned char *buf, |
| ++ unsigned int *length, unsigned int buf_len) |
| ++{ |
| ++ sslSocket *ss = ssl_FindSocket(fd); |
| ++ |
| ++ if (!ss) { |
| ++ SSL_DBG(("%d: SSL[%d]: bad socket in SSL_GetNextProto", SSL_GETPID(), |
| ++ fd)); |
| ++ return SECFailure; |
| ++ } |
| ++ |
| ++ *state = ss->ssl3.nextProtoState; |
| ++ |
| ++ if (ss->ssl3.nextProtoState != SSL_NEXT_PROTO_NO_SUPPORT && |
| ++ ss->ssl3.nextProto.data) { |
| ++ *length = ss->ssl3.nextProto.len; |
| ++ if (*length > buf_len) |
| ++ *length = buf_len; |
| ++ PORT_Memcpy(buf, ss->ssl3.nextProto.data, *length); |
| ++ } else { |
| ++ *length = 0; |
| ++ } |
| ++ |
| ++ return SECSuccess; |
| ++} |
| ++ |
| + PRFileDesc * |
| + SSL_ReconfigFD(PRFileDesc *model, PRFileDesc *fd) |
| + { |
| ++ PORT_SetError(PR_NOT_IMPLEMENTED_ERROR); |
| ++ PR_NOT_REACHED("not implemented"); |
| ++ return NULL; |
| ++ |
| ++#if 0 |
| + sslSocket * sm = NULL, *ss = NULL; |
| + int i; |
| + sslServerCerts * mc = sm->serverCerts; |
| +@@ -1360,6 +1450,7 @@ SSL_ReconfigFD(PRFileDesc *model, PRFileDesc *fd) |
| + return fd; |
| + loser: |
| + return NULL; |
| ++#endif |
| + } |
| + |
| + /************************************************************************/ |
| +diff --git a/mozilla/security/nss/lib/ssl/sslt.h b/mozilla/security/nss/lib/ssl/sslt.h |
| +index c7d4553..f6e0b62 100644 |
| +--- a/mozilla/security/nss/lib/ssl/sslt.h |
| ++++ b/mozilla/security/nss/lib/ssl/sslt.h |
| +@@ -203,9 +203,10 @@ typedef enum { |
| + ssl_ec_point_formats_xtn = 11, |
| + #endif |
| + ssl_session_ticket_xtn = 35, |
| ++ ssl_next_proto_neg_xtn = 13172, |
| + ssl_renegotiation_info_xtn = 0xff01 /* experimental number */ |
| + } SSLExtensionType; |
| + |
| +-#define SSL_MAX_EXTENSIONS 5 |
| ++#define SSL_MAX_EXTENSIONS 6 |
| + |
| + #endif /* __sslt_h_ */ |
| +diff --git a/mozilla/security/nss/tests/ssl/sslstress.txt b/mozilla/security/nss/tests/ssl/sslstress.txt |
| +index 9a3aae8..c2a5c76 100644 |
| +--- a/mozilla/security/nss/tests/ssl/sslstress.txt |
| ++++ b/mozilla/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_-h 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_-h 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_-h 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_-h 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) |
| + |