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) |
+ |