diff options
author | agl@chromium.org <agl@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2010-02-11 15:20:12 +0000 |
---|---|---|
committer | agl@chromium.org <agl@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2010-02-11 15:20:12 +0000 |
commit | a121c90cf3279e6001d0f91472b74b02699e2976 (patch) | |
tree | 691ab98c9033861131d1f2efe3343b93bc53f611 /net | |
parent | c5b97aac8117ffac51a2cf3cc7a1070ab5ff6e93 (diff) | |
download | chromium_src-a121c90cf3279e6001d0f91472b74b02699e2976.zip chromium_src-a121c90cf3279e6001d0f91472b74b02699e2976.tar.gz chromium_src-a121c90cf3279e6001d0f91472b74b02699e2976.tar.bz2 |
Update our copy of libssl from NSS CVS.
http://codereview.chromium.org/596013
BUG=none
TEST=none
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@38773 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'net')
-rw-r--r-- | net/third_party/nss/README.google | 7 | ||||
-rw-r--r-- | net/third_party/nss/patches/nextproto.patch | 483 | ||||
-rw-r--r-- | net/third_party/nss/patches/versionskew.patch | 47 | ||||
-rw-r--r-- | net/third_party/nss/ssl/ssl.def | 13 | ||||
-rw-r--r-- | net/third_party/nss/ssl/ssl.h | 111 | ||||
-rw-r--r-- | net/third_party/nss/ssl/ssl3con.c | 494 | ||||
-rw-r--r-- | net/third_party/nss/ssl/ssl3ecc.c | 6 | ||||
-rw-r--r-- | net/third_party/nss/ssl/ssl3ext.c | 408 | ||||
-rw-r--r-- | net/third_party/nss/ssl/ssl3prot.h | 18 | ||||
-rw-r--r-- | net/third_party/nss/ssl/sslcon.c | 29 | ||||
-rw-r--r-- | net/third_party/nss/ssl/sslerr.h | 5 | ||||
-rw-r--r-- | net/third_party/nss/ssl/sslimpl.h | 50 | ||||
-rw-r--r-- | net/third_party/nss/ssl/sslinfo.c | 42 | ||||
-rw-r--r-- | net/third_party/nss/ssl/sslproto.h | 11 | ||||
-rw-r--r-- | net/third_party/nss/ssl/sslreveal.c | 42 | ||||
-rw-r--r-- | net/third_party/nss/ssl/sslsecur.c | 210 | ||||
-rw-r--r-- | net/third_party/nss/ssl/sslsnce.c | 335 | ||||
-rw-r--r-- | net/third_party/nss/ssl/sslsock.c | 149 | ||||
-rw-r--r-- | net/third_party/nss/ssl/sslt.h | 22 |
19 files changed, 2167 insertions, 315 deletions
diff --git a/net/third_party/nss/README.google b/net/third_party/nss/README.google index fa1e35e..d34e65e 100644 --- a/net/third_party/nss/README.google +++ b/net/third_party/nss/README.google @@ -1,12 +1,17 @@ This directory includes a copy of NSS's libssl from the CVS repo at: :pserver:anonymous@cvs-mirror.mozilla.org:/cvsroot -The snapshot was updated at Wed Dec 2 16:05:49 PST 2009 +The snapshot was updated to the CVS tag: NSS_3_12_6_BETA1 Patches: * Next protocol negotiation support. + patches/nextproto.patch http://codereview.chromium.org/415005 + * Commenting out a couple of functions because they need NSS symbols + which may not exist in the system NSS library. + patches/versionskew.patch + The ssl/bodge directory contains files taken from the NSS repo that we required for building libssl outside of its usual build environment. diff --git a/net/third_party/nss/patches/nextproto.patch b/net/third_party/nss/patches/nextproto.patch new file mode 100644 index 0000000..dbca92a --- /dev/null +++ b/net/third_party/nss/patches/nextproto.patch @@ -0,0 +1,483 @@ +diff --git a/mozilla/security/nss/cmd/tstclnt/tstclnt.c b/mozilla/security/nss/cmd/tstclnt/tstclnt.c +index f0b5701..e795b33 100644 +--- a/mozilla/security/nss/cmd/tstclnt/tstclnt.c ++++ b/mozilla/security/nss/cmd/tstclnt/tstclnt.c +@@ -863,7 +863,13 @@ 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; ++ } ++ + 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 a5b2767..287505f 100644 +--- a/mozilla/security/nss/lib/ssl/ssl.def ++++ b/mozilla/security/nss/lib/ssl/ssl.def +@@ -150,3 +150,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 d0b5aa7..5b572b2 100644 +--- a/mozilla/security/nss/lib/ssl/ssl.h ++++ b/mozilla/security/nss/lib/ssl/ssl.h +@@ -136,6 +136,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..545e51e 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); +@@ -5717,6 +5718,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. */ +@@ -8138,6 +8145,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 + */ +@@ -9457,6 +9498,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..4269028 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; ++ TLSExtensionData *xtnData = &ss->xtnData; ++ xtnData->advertised[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/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 ea36cfb..0ec579d 100644 +--- a/mozilla/security/nss/lib/ssl/sslimpl.h ++++ b/mozilla/security/nss/lib/ssl/sslimpl.h +@@ -317,6 +317,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 */ +@@ -789,6 +794,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; + + +@@ -830,6 +836,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 { +@@ -1495,8 +1511,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 +@@ -1527,6 +1547,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/sslsock.c b/mozilla/security/nss/lib/ssl/sslsock.c +index aab48d6..2ff2992 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 */ +@@ -437,6 +438,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); +@@ -1255,6 +1260,75 @@ 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) + { +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/net/third_party/nss/patches/versionskew.patch b/net/third_party/nss/patches/versionskew.patch new file mode 100644 index 0000000..1b96983 --- /dev/null +++ b/net/third_party/nss/patches/versionskew.patch @@ -0,0 +1,47 @@ +diff --git a/mozilla/security/nss/lib/ssl/sslsecur.c b/mozilla/security/nss/lib/ssl/sslsecur.c +index 8f79135..80c2ba6 100644 +--- a/mozilla/security/nss/lib/ssl/sslsecur.c ++++ b/mozilla/security/nss/lib/ssl/sslsecur.c +@@ -1307,6 +1307,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 +1338,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..01ef3bd 100644 +--- a/mozilla/security/nss/lib/ssl/sslsock.c ++++ b/mozilla/security/nss/lib/ssl/sslsock.c +@@ -1258,6 +1258,11 @@ SSL_ImportFD(PRFileDesc *model, PRFileDesc *fd) + 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 +1365,7 @@ SSL_ReconfigFD(PRFileDesc *model, PRFileDesc *fd) + return fd; + loser: + return NULL; ++#endif + } + + /************************************************************************/ diff --git a/net/third_party/nss/ssl/ssl.def b/net/third_party/nss/ssl/ssl.def index 6a11804..287505f 100644 --- a/net/third_party/nss/ssl/ssl.def +++ b/net/third_party/nss/ssl/ssl.def @@ -139,7 +139,18 @@ SSL_CanBypass; ;+ local: ;+*; ;+}; -;+NSS_CHROMIUM { # Chromium experimental +;+NSS_3.12.6 { # NSS 3.12.6 release +;+ global: +SSL_ConfigServerSessionIDCacheWithOpt; +SSL_GetNegotiatedHostInfo; +SSL_HandshakeNegotiatedExtension; +SSL_ReconfigFD; +SSL_SetTrustAnchors; +SSL_SNISocketConfigHook; +;+ local: +;+*; +;+}; +;+NSS_CHROMIUM { ;+ global: SSL_GetNextProto; SSL_SetNextProtoNego; diff --git a/net/third_party/nss/ssl/ssl.h b/net/third_party/nss/ssl/ssl.h index c17f7b1..5b572b2 100644 --- a/net/third_party/nss/ssl/ssl.h +++ b/net/third_party/nss/ssl/ssl.h @@ -36,7 +36,7 @@ * the terms of any one of the MPL, the GPL or the LGPL. * * ***** END LICENSE BLOCK ***** */ -/* $Id: ssl.h,v 1.31 2009/11/25 05:24:25 wtc%google.com Exp $ */ +/* $Id: ssl.h,v 1.35 2010/02/04 03:21:11 wtc%google.com Exp $ */ #ifndef __ssl_h_ #define __ssl_h_ @@ -117,10 +117,11 @@ SSL_IMPORT PRFileDesc *SSL_ImportFD(PRFileDesc *model, PRFileDesc *fd); #define SSL_ENABLE_DEFLATE 19 /* Enable TLS compression with */ /* DEFLATE (off by default) */ #define SSL_ENABLE_RENEGOTIATION 20 /* Values below (default: never) */ -#define SSL_REQUIRE_SAFE_NEGOTIATION 21 /* Peer must use renegotiation */ - /* extension in ALL handshakes. */ +#define SSL_REQUIRE_SAFE_NEGOTIATION 21 /* Peer must send Signalling */ + /* Cipher Suite Value (SCSV) or */ + /* Renegotiation Info (RI) */ + /* extension in ALL handshakes. */ /* default: off */ - /* NOT YET IMPLEMENTED in 3.12.5 */ #ifdef SSL_DEPRECATED_FUNCTION /* Old deprecated function names */ @@ -184,11 +185,14 @@ SSL_IMPORT SECStatus SSL_CipherPolicyGet(PRInt32 cipher, PRInt32 *policy); /* Never renegotiate at all. */ #define SSL_RENEGOTIATE_NEVER ((PRBool)0) /* Renegotiate without restriction, whether or not the peer's client hello */ -/* bears the renegotiation info extension (like we always did in the past).*/ +/* bears the renegotiation info extension. Vulnerable, as in the past. */ #define SSL_RENEGOTIATE_UNRESTRICTED ((PRBool)1) -/* Only renegotiate if the peer's hello bears the TLS renegotiation_info */ -/* extension. Cannot renegotiate in SSL 3.0 sessions. */ -#define SSL_RENEGOTIATE_REQUIRES_XTN ((PRBool)2) /* (NOT YET IMPLEMENTED) */ +/* Only renegotiate if the peer's hello bears the TLS renegotiation_info */ +/* extension. This is safe renegotiation. */ +#define SSL_RENEGOTIATE_REQUIRES_XTN ((PRBool)2) +/* Disallow all renegotiation in server sockets only, but allow clients */ +/* to continue to renegotiate with vulnerable servers. */ +#define SSL_RENEGOTIATE_CLIENT_ONLY ((PRBool)3) /* ** Reset the handshake state for fd. This will make the complete SSL @@ -282,6 +286,61 @@ SSL_IMPORT SECStatus SSL_GetClientAuthDataHook(PRFileDesc *fd, /* +** SNI extension processing callback function. +** It is called when SSL socket receives SNI extension in ClientHello message. +** Upon this callback invocation, application is responsible to reconfigure the +** socket with the data for a particular server name. +** There are three potential outcomes of this function invocation: +** * application does not recognize the name or the type and wants the +** "unrecognized_name" alert be sent to the client. In this case the callback +** function must return SSL_SNI_SEND_ALERT status. +** * application does not recognize the name, but wants to continue with +** the handshake using the current socket configuration. In this case, +** no socket reconfiguration is needed and the function should return +** SSL_SNI_CURRENT_CONFIG_IS_USED. +** * application recognizes the name and reconfigures the socket with +** appropriate certs, key, etc. There are many ways to reconfigure. NSS +** provides SSL_ReconfigFD function that can be used to update the socket +** data from model socket. To continue with the rest of the handshake, the +** implementation function should return an index of a name it has chosen. +** LibSSL will ignore any SNI extension received in a ClientHello message +** if application does not register a SSLSNISocketConfig callback. +** Each type field of SECItem indicates the name type. +** NOTE: currently RFC3546 defines only one name type: sni_host_name. +** Client is allowed to send only one name per known type. LibSSL will +** send an "unrecognized_name" alert if SNI extension name list contains more +** then one name of a type. +*/ +typedef PRInt32 (PR_CALLBACK *SSLSNISocketConfig)(PRFileDesc *fd, + const SECItem *srvNameArr, + PRUint32 srvNameArrSize, + void *arg); + +/* +** SSLSNISocketConfig should return an index within 0 and srvNameArrSize-1 +** when it has reconfigured the socket fd to use certs and keys, etc +** for a specific name. There are two other allowed return values. One +** tells libSSL to use the default cert and key. The other tells libSSL +** to send the "unrecognized_name" alert. These values are: +**/ +#define SSL_SNI_CURRENT_CONFIG_IS_USED -1 +#define SSL_SNI_SEND_ALERT -2 + +/* +** Set application implemented SNISocketConfig callback. +*/ +SSL_IMPORT SECStatus SSL_SNISocketConfigHook(PRFileDesc *fd, + SSLSNISocketConfig f, + void *arg); + +/* +** Reconfigure fd SSL socket with model socket parameters. Sets +** server certs and keys, list of trust anchor, socket options +** and all SSL socket call backs and parameters. +*/ +SSL_IMPORT PRFileDesc *SSL_ReconfigFD(PRFileDesc *model, PRFileDesc *fd); + +/* * Set the client side argument for SSL to retrieve PKCS #11 pin. * fd - the file descriptor for the connection in question * a - pkcs11 application specific data @@ -298,7 +357,7 @@ SSL_IMPORT SECStatus SSL_BadCertHook(PRFileDesc *fd, SSLBadCertHandler f, void *arg); /* -** Configure ssl for running a secure server. Needs the +** Configure SSL socket for running a secure server. Needs the ** certificate for the server and the servers private key. The arguments ** are copied. */ @@ -307,7 +366,7 @@ SSL_IMPORT SECStatus SSL_ConfigSecureServer( SECKEYPrivateKey *key, SSLKEAType kea); /* -** Configure a secure servers session-id cache. Define the maximum number +** Configure a secure server's session-id cache. Define the maximum number ** of entries in the cache, the longevity of the entires, and the directory ** where the cache files will be placed. These values can be zero, and ** if so, the implementation will choose defaults. @@ -318,6 +377,18 @@ SSL_IMPORT SECStatus SSL_ConfigServerSessionIDCache(int maxCacheEntries, PRUint32 timeout, PRUint32 ssl3_timeout, const char * directory); + +/* Configure a secure server's session-id cache. Depends on value of + * enableMPCache, configures malti-proc or single proc cache. */ +SSL_IMPORT SECStatus SSL_ConfigServerSessionIDCacheWithOpt( + PRUint32 timeout, + PRUint32 ssl3_timeout, + const char * directory, + int maxCacheEntries, + int maxCertCacheEntries, + int maxSrvNameCacheEntries, + PRBool enableMPCache); + /* ** Like SSL_ConfigServerSessionIDCache, with one important difference. ** If the application will run multiple processes (as opposed to, or in @@ -393,11 +464,17 @@ SSL_IMPORT SECStatus SSL_RedoHandshake(PRFileDesc *fd); #endif /* - * Allow the application to pass a URL or hostname into the SSL library + * Allow the application to pass a URL or hostname into the SSL library. */ SSL_IMPORT SECStatus SSL_SetURL(PRFileDesc *fd, const char *url); /* + * Allow an application to define a set of trust anchors for peer + * cert validation. + */ +SSL_IMPORT SECStatus SSL_SetTrustAnchors(PRFileDesc *fd, CERTCertList *list); + +/* ** Return the number of bytes that SSL has waiting in internal buffers. ** Return 0 if security is not enabled. */ @@ -436,7 +513,6 @@ SSL_IMPORT CERTCertificate * SSL_RevealCert(PRFileDesc * socket); SSL_IMPORT void * SSL_RevealPinArg(PRFileDesc * socket); SSL_IMPORT char * SSL_RevealURL(PRFileDesc * socket); - /* This callback may be passed to the SSL library via a call to * SSL_GetClientAuthDataHook() for each SSL client socket. * It will be invoked when SSL needs to know what certificate and private key @@ -499,6 +575,9 @@ SSL_IMPORT SECStatus SSL_GetChannelInfo(PRFileDesc *fd, SSLChannelInfo *info, SSL_IMPORT SECStatus SSL_GetCipherSuiteInfo(PRUint16 cipherSuite, SSLCipherSuiteInfo *info, PRUintn len); +/* Returnes negotiated through SNI host info. */ +SSL_IMPORT SECItem *SSL_GetNegotiatedHostInfo(PRFileDesc *fd); + /* ** Return a new reference to the certificate that was most recently sent ** to the peer on this SSL/TLS connection, or NULL if none has been sent. @@ -536,6 +615,14 @@ SSL_IMPORT SECStatus SSL_CanBypass(CERTCertificate *cert, PRUint16 *ciphers, int nciphers, PRBool *pcanbypass, void *pwArg); +/* +** Did the handshake with the peer negotiate the given extension? +** Output parameter valid only if function returns SECSuccess +*/ +SSL_IMPORT SECStatus SSL_HandshakeNegotiatedExtension(PRFileDesc * socket, + SSLExtensionType extId, + PRBool *yes); + SEC_END_PROTOS #endif /* __ssl_h_ */ diff --git a/net/third_party/nss/ssl/ssl3con.c b/net/third_party/nss/ssl/ssl3con.c index 0018859..545e51e 100644 --- a/net/third_party/nss/ssl/ssl3con.c +++ b/net/third_party/nss/ssl/ssl3con.c @@ -39,7 +39,7 @@ * the terms of any one of the MPL, the GPL or the LGPL. * * ***** END LICENSE BLOCK ***** */ -/* $Id: ssl3con.c,v 1.126 2009/12/01 17:59:46 wtc%google.com Exp $ */ +/* $Id: ssl3con.c,v 1.134 2010/02/03 03:44:29 wtc%google.com Exp $ */ #include "cert.h" #include "ssl.h" @@ -1169,7 +1169,7 @@ ssl3_CleanupKeyMaterial(ssl3KeyMaterial *mat) ** Caller must hold SpecWriteLock. */ static void -ssl3_DestroyCipherSpec(ssl3CipherSpec *spec) +ssl3_DestroyCipherSpec(ssl3CipherSpec *spec, PRBool freeSrvName) { PRBool freeit = (PRBool)(!spec->bypassCiphers); /* PORT_Assert( ss->opt.noLocks || ssl_HaveSpecWriteLock(ss)); Don't have ss! */ @@ -1187,6 +1187,9 @@ ssl3_DestroyCipherSpec(ssl3CipherSpec *spec) spec->destroyDecompressContext(spec->decompressContext, 1); spec->decompressContext = NULL; } + if (freeSrvName && spec->srvVirtName.data) { + SECITEM_FreeItem(&spec->srvVirtName, PR_FALSE); + } if (spec->master_secret != NULL) { PK11_FreeSymKey(spec->master_secret); spec->master_secret = NULL; @@ -1445,8 +1448,8 @@ const ssl3BulkCipherDef *cipher_def; SSLCompressionMethod compression_method; SECStatus rv; - PORT_Assert( ss->opt.noLocks || ssl_HaveSSL3HandshakeLock(ss)); - + PORT_Assert(ss->opt.noLocks || ssl_HaveSSL3HandshakeLock(ss)); + PORT_Assert(ss->opt.noLocks || ssl_HaveSpecWriteLock(ss)); PORT_Assert(ss->ssl3.prSpec == ss->ssl3.pwSpec); pwSpec = ss->ssl3.pwSpec; @@ -1558,6 +1561,14 @@ const ssl3BulkCipherDef *cipher_def; * is decrypting, and vice versa. */ optArg1 = !optArg1; + break; + /* kill warnings. */ + case ssl_calg_null: + case ssl_calg_rc4: + case ssl_calg_rc2: + case ssl_calg_idea: + case ssl_calg_fortezza: + break; } rv = (*initFn)(clientContext, @@ -1626,7 +1637,7 @@ const ssl3BulkCipherDef *cipher_def; SSLCipherAlgorithm calg; PORT_Assert( ss->opt.noLocks || ssl_HaveSSL3HandshakeLock(ss)); - + PORT_Assert( ss->opt.noLocks || ssl_HaveSpecWriteLock(ss)); PORT_Assert(ss->ssl3.prSpec == ss->ssl3.pwSpec); pwSpec = ss->ssl3.pwSpec; @@ -2723,7 +2734,7 @@ ssl3_SendChangeCipherSpecs(sslSocket *ss) * (Both the read and write sides have changed) destroy it. */ if (ss->ssl3.prSpec == ss->ssl3.pwSpec) { - ssl3_DestroyCipherSpec(ss->ssl3.pwSpec); + ssl3_DestroyCipherSpec(ss->ssl3.pwSpec, PR_FALSE/*freeSrvName*/); } ssl_ReleaseSpecWriteLock(ss); /**************************************/ @@ -2785,7 +2796,7 @@ ssl3_HandleChangeCipherSpecs(sslSocket *ss, sslBuffer *buf) * (Both the read and write sides have changed) destroy it. */ if (ss->ssl3.prSpec == ss->ssl3.pwSpec) { - ssl3_DestroyCipherSpec(ss->ssl3.prSpec); + ssl3_DestroyCipherSpec(ss->ssl3.prSpec, PR_FALSE/*freeSrvName*/); } ssl_ReleaseSpecWriteLock(ss); /*************************************/ return SECSuccess; @@ -3206,6 +3217,8 @@ ssl3_AppendHandshake(sslSocket *ss, const void *void_src, PRInt32 bytes) PORT_Assert( ss->opt.noLocks || ssl_HaveSSL3HandshakeLock(ss) ); /* protects sendBuf. */ + if (!bytes) + return SECSuccess; if (ss->sec.ci.sendBuf.space < MAX_SEND_BUF_LENGTH && room < bytes) { rv = sslBuffer_Grow(&ss->sec.ci.sendBuf, PR_MAX(MIN_SEND_BUF_LENGTH, PR_MIN(MAX_SEND_BUF_LENGTH, ss->sec.ci.sendBuf.len + bytes))); @@ -3715,6 +3728,7 @@ ssl3_SendClientHello(sslSocket *ss) int length; int num_suites; int actual_count = 0; + PRBool isTLS = PR_FALSE; PRInt32 total_exten_len = 0; unsigned numCompressionMethods; @@ -3728,6 +3742,7 @@ ssl3_SendClientHello(sslSocket *ss) if (rv != SECSuccess) { return rv; /* ssl3_InitState has set the error code. */ } + ss->ssl3.hs.sendingSCSV = PR_FALSE; /* Must be reset every handshake */ /* We might be starting a session renegotiation in which case we should * clear previous state. @@ -3825,6 +3840,7 @@ ssl3_SendClientHello(sslSocket *ss) } } + isTLS = (ss->version > SSL_LIBRARY_VERSION_3_0); ssl_GetSpecWriteLock(ss); cwSpec = ss->ssl3.cwSpec; if (cwSpec->mac_def->mac == mac_null) { @@ -3852,7 +3868,17 @@ ssl3_SendClientHello(sslSocket *ss) if (!num_suites) return SECFailure; /* ssl3_config_match_init has set error code. */ - if (ss->opt.enableTLS && ss->version > SSL_LIBRARY_VERSION_3_0) { + /* HACK for SCSV in SSL 3.0. On initial handshake, prepend SCSV, + * only if we're willing to complete an SSL 3.0 handshake. + */ + if (!ss->firstHsDone && ss->opt.enableSSL3) { + /* Must set this before calling Hello Extension Senders, + * to suppress sending of empty RI extension. + */ + ss->ssl3.hs.sendingSCSV = PR_TRUE; + } + + if (isTLS || (ss->firstHsDone && ss->peerRequestedProtection)) { PRUint32 maxBytes = 65535; /* 2^16 - 1 */ PRInt32 extLen; @@ -3866,8 +3892,10 @@ ssl3_SendClientHello(sslSocket *ss) if (total_exten_len > 0) total_exten_len += 2; } + #if defined(NSS_ENABLE_ECC) && !defined(NSS_ECC_MORE_THAN_SUITE_B) - else { /* SSL3 only */ + if (!total_exten_len || !isTLS) { + /* not sending the elliptic_curves and ec_point_formats extensions */ ssl3_DisableECCSuites(ss, NULL); /* disable all ECC suites */ } #endif @@ -3876,6 +3904,9 @@ ssl3_SendClientHello(sslSocket *ss) num_suites = count_cipher_suites(ss, ss->ssl3.policy, PR_TRUE); if (!num_suites) return SECFailure; /* count_cipher_suites has set error code. */ + if (ss->ssl3.hs.sendingSCSV) { + ++num_suites; /* make room for SCSV */ + } /* count compression methods */ numCompressionMethods = 0; @@ -3923,7 +3954,15 @@ ssl3_SendClientHello(sslSocket *ss) return rv; /* err set by ssl3_AppendHandshake* */ } - + if (ss->ssl3.hs.sendingSCSV) { + /* Add the actual SCSV */ + rv = ssl3_AppendHandshakeNumber(ss, TLS_RENEGO_PROTECTION_REQUEST, + 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)) { @@ -3978,9 +4017,14 @@ ssl3_SendClientHello(sslSocket *ss) } maxBytes -= extLen; PORT_Assert(!maxBytes); + } + if (ss->ssl3.hs.sendingSCSV) { + /* Since we sent the SCSV, pretend we sent empty RI extension. */ + TLSExtensionData *xtnData = &ss->xtnData; + xtnData->advertised[xtnData->numAdvertised++] = + ssl_renegotiation_info_xtn; } - rv = ssl3_FlushHandshake(ss, 0); if (rv != SECSuccess) { return rv; /* error code set by ssl3_FlushHandshake */ @@ -4491,19 +4535,6 @@ sendRSAClientKeyExchange(sslSocket * ss, SECKEYPublicKey * svrPubKey) goto loser; } -#if defined(TRACE) - if (ssl_trace >= 100) { - SECStatus extractRV = PK11_ExtractKeyValue(pms); - if (extractRV == SECSuccess) { - SECItem * keyData = PK11_GetKeyData(pms); - if (keyData && keyData->data && keyData->len) { - ssl_PrintBuf(ss, "Pre-Master Secret", - keyData->data, keyData->len); - } - } - } -#endif - /* Get the wrapped (encrypted) pre-master secret, enc_pms */ enc_pms.len = SECKEY_PublicKeyStrength(svrPubKey); enc_pms.data = (unsigned char*)PORT_Alloc(enc_pms.len); @@ -4518,6 +4549,48 @@ sendRSAClientKeyExchange(sslSocket * ss, SECKEYPublicKey * svrPubKey) goto loser; } +#if defined(TRACE) + if (ssl_trace >= 100 || ssl_keylog_iob) { + SECStatus extractRV = PK11_ExtractKeyValue(pms); + if (extractRV == SECSuccess) { + SECItem * keyData = PK11_GetKeyData(pms); + if (keyData && keyData->data && keyData->len) { + if (ssl_trace >= 100) { + ssl_PrintBuf(ss, "Pre-Master Secret", + keyData->data, keyData->len); + } + if (ssl_keylog_iob && enc_pms.len >= 8 && keyData->len == 48) { + /* https://developer.mozilla.org/en/NSS_Key_Log_Format */ + + /* There could be multiple, concurrent writers to the + * keylog, so we have to do everything in a single call to + * fwrite. */ + char buf[4 + 8*2 + 1 + 48*2 + 1]; + static const char hextable[16] = "0123456789abcdef"; + unsigned int i; + + strcpy(buf, "RSA "); + + for (i = 0; i < 8; i++) { + buf[4 + i*2] = hextable[enc_pms.data[i] >> 4]; + buf[4 + i*2 + 1] = hextable[enc_pms.data[i] & 15]; + } + buf[20] = ' '; + + for (i = 0; i < 48; i++) { + buf[21 + i*2] = hextable[keyData->data[i] >> 4]; + buf[21 + i*2 + 1] = hextable[keyData->data[i] & 15]; + } + buf[sizeof(buf) - 1] = '\n'; + + fwrite(buf, sizeof(buf), 1, ssl_keylog_iob); + fflush(ssl_keylog_iob); + } + } + } + } +#endif + rv = ssl3_InitPendingCipherSpec(ss, pms); PK11_FreeSymKey(pms); pms = NULL; @@ -4909,20 +4982,36 @@ ssl3_HandleServerHello(sslSocket *ss, SSL3Opaque *b, PRUint32 length) } ss->ssl3.hs.compression = (SSLCompressionMethod)temp; - /* Note that if !isTLS && length != 0, we do NOT goto alert_loser. + /* Note that if !isTLS and the extra stuff is not extensions, we + * do NOT goto alert_loser. * There are some old SSL 3.0 implementations that do send stuff * after the end of the server hello, and we deliberately ignore * such stuff in the interest of maximal interoperability (being * "generous in what you accept"). + * Update: Starting in NSS 3.12.6, we handle the renegotiation_info + * extension in SSL 3.0. */ - if (isTLS && length != 0) { + if (length != 0) { SECItem extensions; rv = ssl3_ConsumeHandshakeVariable(ss, &extensions, 2, &b, &length); - if (rv != SECSuccess || length != 0) - goto alert_loser; - rv = ssl3_HandleHelloExtensions(ss, &extensions.data, &extensions.len); - if (rv != SECSuccess) - goto alert_loser; + if (rv != SECSuccess || length != 0) { + if (isTLS) + goto alert_loser; + } else { + rv = ssl3_HandleHelloExtensions(ss, &extensions.data, + &extensions.len); + if (rv != SECSuccess) + goto alert_loser; + } + } + if ((ss->opt.requireSafeNegotiation || + (ss->firstHsDone && (ss->peerRequestedProtection || + ss->opt.enableRenegotiation == SSL_RENEGOTIATE_REQUIRES_XTN))) && + !ssl3_ExtensionNegotiated(ss, ssl_renegotiation_info_xtn)) { + desc = handshake_failure; + errCode = ss->firstHsDone ? SSL_ERROR_RENEGOTIATION_NOT_ALLOWED + : SSL_ERROR_UNSAFE_NEGOTIATION; + goto alert_loser; } /* Any errors after this point are not "malformed" errors. */ @@ -5037,7 +5126,7 @@ ssl3_HandleServerHello(sslSocket *ss, SSL3Opaque *b, PRUint32 length) sid->u.ssl3.sessionTicket.ticket.data != NULL) SSL_AtomicIncrementLong(& ssl3stats.hsh_sid_stateless_resumes ); - if (ssl3_ExtensionNegotiated(ss, session_ticket_xtn)) + if (ssl3_ExtensionNegotiated(ss, ssl_session_ticket_xtn)) ss->ssl3.hs.ws = wait_new_session_ticket; else ss->ssl3.hs.ws = wait_change_cipher; @@ -5642,7 +5731,7 @@ ssl3_HandleServerHelloDone(sslSocket *ss) ssl_ReleaseXmitBufLock(ss); /*******************************/ - if (ssl3_ExtensionNegotiated(ss, session_ticket_xtn)) + if (ssl3_ExtensionNegotiated(ss, ssl_session_ticket_xtn)) ss->ssl3.hs.ws = wait_new_session_ticket; else ss->ssl3.hs.ws = wait_change_cipher; @@ -5679,6 +5768,25 @@ ssl3_SendHelloRequest(sslSocket *ss) return SECSuccess; } +/* + * Called from: + * ssl3_HandleClientHello() + */ +static SECComparison +ssl3_ServerNameCompare(const SECItem *name1, const SECItem *name2) +{ + if (!name1 != !name2) { + return SECLessThan; + } + if (!name1) { + return SECEqual; + } + if (name1->type != name2->type) { + return SECLessThan; + } + return SECITEM_CompareItem(name1, name2); +} + /* Sets memory error when returning NULL. * Called from: * ssl3_SendClientHello() @@ -5695,6 +5803,21 @@ ssl3_NewSessionID(sslSocket *ss, PRBool is_server) if (sid == NULL) return sid; + if (is_server) { + const SECItem * srvName; + SECStatus rv = SECSuccess; + + ssl_GetSpecReadLock(ss); /********************************/ + srvName = &ss->ssl3.prSpec->srvVirtName; + if (srvName->len && srvName->data) { + rv = SECITEM_CopyItem(NULL, &sid->u.ssl3.srvName, srvName); + } + ssl_ReleaseSpecReadLock(ss); /************************************/ + if (rv != SECSuccess) { + PORT_Free(sid); + return NULL; + } + } sid->peerID = (ss->peerID == NULL) ? NULL : PORT_Strdup(ss->peerID); sid->urlSvrName = (ss->url == NULL) ? NULL : PORT_Strdup(ss->url); sid->addr = ss->sec.ci.peer; @@ -5802,6 +5925,9 @@ ssl3_SendServerHelloSequence(sslSocket *ss) return SECSuccess; } +/* An empty TLS Renegotiation Info (RI) extension */ +static const PRUint8 emptyRIext[5] = {0xff, 0x01, 0x00, 0x01, 0x00}; + /* Called from ssl3_HandleHandshakeMessage() when it has deciphered a complete * ssl3 Client Hello message. * Caller must hold Handshake and RecvBuf locks. @@ -5854,7 +5980,8 @@ ssl3_HandleClientHello(sslSocket *ss, SSL3Opaque *b, PRUint32 length) goto alert_loser; } if (ss->ssl3.hs.ws == idle_handshake && - ss->opt.enableRenegotiation == SSL_RENEGOTIATE_NEVER) { + (ss->opt.enableRenegotiation == SSL_RENEGOTIATE_NEVER || + ss->opt.enableRenegotiation == SSL_RENEGOTIATE_CLIENT_ONLY)) { desc = no_renegotiation; level = alert_warning; errCode = SSL_ERROR_RENEGOTIATION_NOT_ALLOWED; @@ -5923,13 +6050,43 @@ ssl3_HandleClientHello(sslSocket *ss, SSL3Opaque *b, PRUint32 length) goto loser; /* malformed */ } } + if (!ssl3_ExtensionNegotiated(ss, ssl_renegotiation_info_xtn)) { + /* If we didn't receive an RI extension, look for the SCSV, + * and if found, treat it just like an empty RI extension + * by processing a local copy of an empty RI extension. + */ + for (i = 0; i + 1 < suites.len; i += 2) { + PRUint16 suite_i = (suites.data[i] << 8) | suites.data[i + 1]; + if (suite_i == TLS_RENEGO_PROTECTION_REQUEST) { + SSL3Opaque * b2 = (SSL3Opaque *)emptyRIext; + PRUint32 L2 = sizeof emptyRIext; + (void)ssl3_HandleHelloExtensions(ss, &b2, &L2); + break; + } + } + } + if (ss->firstHsDone && + ss->opt.enableRenegotiation == SSL_RENEGOTIATE_REQUIRES_XTN && + !ssl3_ExtensionNegotiated(ss, ssl_renegotiation_info_xtn)) { + desc = no_renegotiation; + level = alert_warning; + errCode = SSL_ERROR_RENEGOTIATION_NOT_ALLOWED; + goto alert_loser; + } + if ((ss->opt.requireSafeNegotiation || + (ss->firstHsDone && ss->peerRequestedProtection)) && + !ssl3_ExtensionNegotiated(ss, ssl_renegotiation_info_xtn)) { + desc = handshake_failure; + errCode = SSL_ERROR_UNSAFE_NEGOTIATION; + goto alert_loser; + } /* We do stateful resumes only if either of the following * conditions are satisfied: (1) the client does not support the * session ticket extension, or (2) the client support the session * ticket extension, but sent an empty ticket. */ - if (!ssl3_ExtensionNegotiated(ss, session_ticket_xtn) || + if (!ssl3_ExtensionNegotiated(ss, ssl_session_ticket_xtn) || ss->xtnData.emptySessionTicket) { if (sidBytes.len > 0 && !ss->opt.noCache) { SSL_TRC(7, ("%d: SSL3[%d]: server, lookup client session-id for 0x%08x%08x%08x%08x", @@ -5973,9 +6130,9 @@ ssl3_HandleClientHello(sslSocket *ss, SSL3Opaque *b, PRUint32 length) * but OpenSSL-0.9.8g does not accept session tickets while * resuming.) */ - if (ssl3_ExtensionNegotiated(ss, session_ticket_xtn) && sid == NULL) { + if (ssl3_ExtensionNegotiated(ss, ssl_session_ticket_xtn) && sid == NULL) { ssl3_RegisterServerHelloExtensionSender(ss, - session_ticket_xtn, ssl3_SendSessionTicketXtn); + ssl_session_ticket_xtn, ssl3_SendSessionTicketXtn); } if (sid != NULL) { @@ -6053,10 +6210,9 @@ ssl3_HandleClientHello(sslSocket *ss, SSL3Opaque *b, PRUint32 length) break; #endif /* Double check that the cached cipher suite is in the client's list */ - for (i = 0; i < suites.len; i += 2) { - if ((suites.data[i] == MSB(suite->cipher_suite)) && - (suites.data[i + 1] == LSB(suite->cipher_suite))) { - + for (i = 0; i + 1 < suites.len; i += 2) { + PRUint16 suite_i = (suites.data[i] << 8) | suites.data[i + 1]; + if (suite_i == suite->cipher_suite) { ss->ssl3.hs.cipher_suite = suite->cipher_suite; ss->ssl3.hs.suite_def = ssl_LookupCipherSuiteDef(ss->ssl3.hs.cipher_suite); @@ -6087,10 +6243,9 @@ ssl3_HandleClientHello(sslSocket *ss, SSL3Opaque *b, PRUint32 length) ssl3CipherSuiteCfg *suite = &ss->cipherSuites[j]; if (!config_match(suite, ss->ssl3.policy, PR_TRUE)) continue; - for (i = 0; i < suites.len; i += 2) { - if ((suites.data[i] == MSB(suite->cipher_suite)) && - (suites.data[i + 1] == LSB(suite->cipher_suite))) { - + for (i = 0; i + 1 < suites.len; i += 2) { + PRUint16 suite_i = (suites.data[i] << 8) | suites.data[i + 1]; + if (suite_i == suite->cipher_suite) { ss->ssl3.hs.cipher_suite = suite->cipher_suite; ss->ssl3.hs.suite_def = ssl_LookupCipherSuiteDef(ss->ssl3.hs.cipher_suite); @@ -6232,6 +6387,32 @@ compression_found: ss->sec.localCert = CERT_DupCertificate(ss->serverCerts[sid->keaType].serverCert); + /* Copy cached name in to pending spec */ + if (sid != NULL && + sid->version > SSL_LIBRARY_VERSION_3_0 && + sid->u.ssl3.srvName.len && sid->u.ssl3.srvName.data) { + /* Set server name from sid */ + SECItem *sidName = &sid->u.ssl3.srvName; + SECItem *pwsName = &ss->ssl3.pwSpec->srvVirtName; + if (pwsName->data) { + SECITEM_FreeItem(pwsName, PR_FALSE); + } + rv = SECITEM_CopyItem(NULL, pwsName, sidName); + if (rv != SECSuccess) { + errCode = PORT_GetError(); + desc = internal_error; + goto alert_loser; + } + } + + /* Clean up sni name array */ + if (ssl3_ExtensionNegotiated(ss, ssl_server_name_xtn) && + ss->xtnData.sniNameArr) { + PORT_Free(ss->xtnData.sniNameArr); + ss->xtnData.sniNameArr = NULL; + ss->xtnData.sniNameArrSize = 0; + } + ssl_GetXmitBufLock(ss); haveXmitBufLock = PR_TRUE; rv = ssl3_SendServerHello(ss); @@ -6285,6 +6466,146 @@ compression_found: } SSL_AtomicIncrementLong(& ssl3stats.hch_sid_cache_misses ); + if (ssl3_ExtensionNegotiated(ss, ssl_server_name_xtn)) { + int ret = 0; + if (ss->sniSocketConfig) do { /* not a loop */ + ret = SSL_SNI_SEND_ALERT; + /* If extension is negotiated, the len of names should > 0. */ + if (ss->xtnData.sniNameArrSize) { + /* Calling client callback to reconfigure the socket. */ + ret = (SECStatus)(*ss->sniSocketConfig)(ss->fd, + ss->xtnData.sniNameArr, + ss->xtnData.sniNameArrSize, + ss->sniSocketConfigArg); + } + if (ret <= SSL_SNI_SEND_ALERT) { + /* Application does not know the name or was not able to + * properly reconfigure the socket. */ + errCode = SSL_ERROR_UNRECOGNIZED_NAME_ALERT; + desc = unrecognized_name; + break; + } else if (ret == SSL_SNI_CURRENT_CONFIG_IS_USED) { + SECStatus rv = SECSuccess; + SECItem * cwsName, *pwsName; + + ssl_GetSpecWriteLock(ss); /*******************************/ + pwsName = &ss->ssl3.pwSpec->srvVirtName; + cwsName = &ss->ssl3.cwSpec->srvVirtName; +#ifndef SSL_SNI_ALLOW_NAME_CHANGE_2HS + /* not allow name change on the 2d HS */ + if (ss->firstHsDone) { + if (ssl3_ServerNameCompare(pwsName, cwsName)) { + ssl_ReleaseSpecWriteLock(ss); /******************/ + errCode = SSL_ERROR_UNRECOGNIZED_NAME_ALERT; + desc = handshake_failure; + ret = SSL_SNI_SEND_ALERT; + break; + } + } +#endif + if (pwsName->data) { + SECITEM_FreeItem(pwsName, PR_FALSE); + } + if (cwsName->data) { + rv = SECITEM_CopyItem(NULL, pwsName, cwsName); + } + ssl_ReleaseSpecWriteLock(ss); /**************************/ + if (rv != SECSuccess) { + errCode = SSL_ERROR_INTERNAL_ERROR_ALERT; + desc = internal_error; + ret = SSL_SNI_SEND_ALERT; + break; + } + } else if (ret < ss->xtnData.sniNameArrSize) { + /* Application has configured new socket info. Lets check it + * and save the name. */ + SECStatus rv; + SECItem * name = &ss->xtnData.sniNameArr[ret]; + int configedCiphers; + SECItem * pwsName; + + /* get rid of the old name and save the newly picked. */ + /* This code is protected by ssl3HandshakeLock. */ + ssl_GetSpecWriteLock(ss); /*******************************/ +#ifndef SSL_SNI_ALLOW_NAME_CHANGE_2HS + /* not allow name change on the 2d HS */ + if (ss->firstHsDone) { + SECItem *cwsName = &ss->ssl3.cwSpec->srvVirtName; + if (ssl3_ServerNameCompare(name, cwsName)) { + ssl_ReleaseSpecWriteLock(ss); /******************/ + errCode = SSL_ERROR_UNRECOGNIZED_NAME_ALERT; + desc = handshake_failure; + ret = SSL_SNI_SEND_ALERT; + break; + } + } +#endif + pwsName = &ss->ssl3.pwSpec->srvVirtName; + if (pwsName->data) { + SECITEM_FreeItem(pwsName, PR_FALSE); + } + rv = SECITEM_CopyItem(NULL, pwsName, name); + ssl_ReleaseSpecWriteLock(ss); /***************************/ + if (rv != SECSuccess) { + errCode = SSL_ERROR_INTERNAL_ERROR_ALERT; + desc = internal_error; + ret = SSL_SNI_SEND_ALERT; + break; + } + configedCiphers = ssl3_config_match_init(ss); + if (configedCiphers <= 0) { + /* no ciphers are working/supported */ + errCode = PORT_GetError(); + desc = handshake_failure; + ret = SSL_SNI_SEND_ALERT; + break; + } + /* Need to tell the client that application has picked + * the name from the offered list and reconfigured the socket. + */ + ssl3_RegisterServerHelloExtensionSender(ss, ssl_server_name_xtn, + ssl3_SendServerNameXtn); + } else { + /* Callback returned index outside of the boundary. */ + PORT_Assert(ret < ss->xtnData.sniNameArrSize); + errCode = SSL_ERROR_INTERNAL_ERROR_ALERT; + desc = internal_error; + ret = SSL_SNI_SEND_ALERT; + break; + } + } while (0); + /* Free sniNameArr. The data that each SECItem in the array + * points into is the data from the input buffer "b". It will + * not be available outside the scope of this or it's child + * functions.*/ + if (ss->xtnData.sniNameArr) { + PORT_Free(ss->xtnData.sniNameArr); + ss->xtnData.sniNameArr = NULL; + ss->xtnData.sniNameArrSize = 0; + } + if (ret <= SSL_SNI_SEND_ALERT) { + /* desc and errCode should be set. */ + goto alert_loser; + } + } +#ifndef SSL_SNI_ALLOW_NAME_CHANGE_2HS + else if (ss->firstHsDone) { + /* Check that we don't have the name is current spec + * if this extension was not negotiated on the 2d hs. */ + PRBool passed = PR_TRUE; + ssl_GetSpecReadLock(ss); /*******************************/ + if (ss->ssl3.cwSpec->srvVirtName.data) { + passed = PR_FALSE; + } + ssl_ReleaseSpecReadLock(ss); /***************************/ + if (!passed) { + errCode = SSL_ERROR_UNRECOGNIZED_NAME_ALERT; + desc = handshake_failure; + goto alert_loser; + } + } +#endif + sid = ssl3_NewSessionID(ss, PR_TRUE); if (sid == NULL) { errCode = PORT_GetError(); @@ -6430,11 +6751,9 @@ ssl3_HandleV2ClientHello(sslSocket *ss, unsigned char *buffer, int length) ssl3CipherSuiteCfg *suite = &ss->cipherSuites[j]; if (!config_match(suite, ss->ssl3.policy, PR_TRUE)) continue; - for (i = 0; i < suite_length; i += 3) { - if ((suites[i] == 0) && - (suites[i+1] == MSB(suite->cipher_suite)) && - (suites[i+2] == LSB(suite->cipher_suite))) { - + for (i = 0; i+2 < suite_length; i += 3) { + PRUint32 suite_i = (suites[i] << 16)|(suites[i+1] << 8)|suites[i+2]; + if (suite_i == suite->cipher_suite) { ss->ssl3.hs.cipher_suite = suite->cipher_suite; ss->ssl3.hs.suite_def = ssl_LookupCipherSuiteDef(ss->ssl3.hs.cipher_suite); @@ -6447,6 +6766,26 @@ ssl3_HandleV2ClientHello(sslSocket *ss, unsigned char *buffer, int length) suite_found: + /* Look for the SCSV, and if found, treat it just like an empty RI + * extension by processing a local copy of an empty RI extension. + */ + for (i = 0; i+2 < suite_length; i += 3) { + PRUint32 suite_i = (suites[i] << 16) | (suites[i+1] << 8) | suites[i+2]; + if (suite_i == TLS_RENEGO_PROTECTION_REQUEST) { + SSL3Opaque * b2 = (SSL3Opaque *)emptyRIext; + PRUint32 L2 = sizeof emptyRIext; + (void)ssl3_HandleHelloExtensions(ss, &b2, &L2); + break; + } + } + + if (ss->opt.requireSafeNegotiation && + !ssl3_ExtensionNegotiated(ss, ssl_renegotiation_info_xtn)) { + desc = handshake_failure; + errCode = SSL_ERROR_UNSAFE_NEGOTIATION; + goto alert_loser; + } + ss->ssl3.hs.compression = ssl_compression_null; ss->sec.send = ssl3_SendApplicationData; @@ -7872,6 +8211,11 @@ ssl3_SendFinished(sslSocket *ss, PRInt32 flags) } if (isTLS) { + if (isServer) + ss->ssl3.hs.finishedMsgs.tFinished[1] = tlsFinished; + else + ss->ssl3.hs.finishedMsgs.tFinished[0] = tlsFinished; + ss->ssl3.hs.finishedBytes = sizeof tlsFinished; rv = ssl3_AppendHandshakeHeader(ss, finished, sizeof tlsFinished); if (rv != SECSuccess) goto fail; /* err set by AppendHandshake. */ @@ -7879,6 +8223,11 @@ ssl3_SendFinished(sslSocket *ss, PRInt32 flags) if (rv != SECSuccess) goto fail; /* err set by AppendHandshake. */ } else { + if (isServer) + ss->ssl3.hs.finishedMsgs.sFinished[1] = hashes; + else + ss->ssl3.hs.finishedMsgs.sFinished[0] = hashes; + ss->ssl3.hs.finishedBytes = sizeof hashes; rv = ssl3_AppendHandshakeHeader(ss, finished, sizeof hashes); if (rv != SECSuccess) goto fail; /* err set by AppendHandshake. */ @@ -8017,6 +8366,11 @@ ssl3_HandleFinished(sslSocket *ss, SSL3Opaque *b, PRUint32 length, } rv = ssl3_ComputeTLSFinished(ss->ssl3.crSpec, !isServer, hashes, &tlsFinished); + if (!isServer) + ss->ssl3.hs.finishedMsgs.tFinished[1] = tlsFinished; + else + ss->ssl3.hs.finishedMsgs.tFinished[0] = tlsFinished; + ss->ssl3.hs.finishedBytes = sizeof tlsFinished; if (rv != SECSuccess || 0 != NSS_SecureMemcmp(&tlsFinished, b, length)) { (void)SSL3_SendAlert(ss, alert_fatal, decrypt_error); @@ -8030,6 +8384,11 @@ ssl3_HandleFinished(sslSocket *ss, SSL3Opaque *b, PRUint32 length, return SECFailure; } + if (!isServer) + ss->ssl3.hs.finishedMsgs.sFinished[1] = *hashes; + else + ss->ssl3.hs.finishedMsgs.sFinished[0] = *hashes; + ss->ssl3.hs.finishedBytes = sizeof *hashes; if (0 != NSS_SecureMemcmp(hashes, b, length)) { (void)ssl3_HandshakeFailure(ss); PORT_SetError(SSL_ERROR_BAD_HANDSHAKE_HASH_VALUE); @@ -8052,7 +8411,7 @@ ssl3_HandleFinished(sslSocket *ss, SSL3Opaque *b, PRUint32 length, * ServerHello message.) */ if (isServer && !ss->ssl3.hs.isResuming && - ssl3_ExtensionNegotiated(ss, session_ticket_xtn)) { + ssl3_ExtensionNegotiated(ss, ssl_session_ticket_xtn)) { rv = ssl3_SendNewSessionTicket(ss); if (rv != SECSuccess) { goto xmit_loser; @@ -8643,11 +9002,33 @@ const ssl3BulkCipherDef *cipher_def; databuf->space, plaintext->buf, plaintext->len); + if (rv != SECSuccess) { int err = ssl_MapLowLevelError(SSL_ERROR_DECOMPRESSION_FAILURE); - PORT_Free(plaintext->buf); SSL3_SendAlert(ss, alert_fatal, isTLS ? decompression_failure : bad_record_mac); + + /* There appears to be a bug with (at least) Apache + OpenSSL where + * resumed SSLv3 connections don't actually use compression. See + * comments 93-95 of + * https://bugzilla.mozilla.org/show_bug.cgi?id=275744 + * + * So, if we get a decompression error, and the record appears to + * be already uncompressed, then we return a more specific error + * code to hopefully save somebody some debugging time in the + * future. + */ + if (plaintext->len >= 4) { + unsigned int len = ((unsigned int) plaintext->buf[1] << 16) | + ((unsigned int) plaintext->buf[2] << 8) | + (unsigned int) plaintext->buf[3]; + if (len == plaintext->len - 4) { + /* This appears to be uncompressed already */ + err = SSL_ERROR_RX_UNEXPECTED_UNCOMPRESSED_RECORD; + } + } + + PORT_Free(plaintext->buf); PORT_SetError(err); return SECFailure; } @@ -8782,6 +9163,7 @@ ssl3_InitState(sslSocket *ss) ss->ssl3.crSpec = ss->ssl3.cwSpec = &ss->ssl3.specs[0]; ss->ssl3.prSpec = ss->ssl3.pwSpec = &ss->ssl3.specs[1]; ss->ssl3.hs.rehandshake = PR_FALSE; + ss->ssl3.hs.sendingSCSV = PR_FALSE; ssl3_InitCipherSpec(ss, ss->ssl3.crSpec); ssl3_InitCipherSpec(ss, ss->ssl3.prSpec); @@ -9049,7 +9431,9 @@ ssl3_RedoHandshake(sslSocket *ss, PRBool flushCache) PORT_SetError(SSL_ERROR_HANDSHAKE_NOT_COMPLETED); return SECFailure; } - if (ss->opt.enableRenegotiation == SSL_RENEGOTIATE_NEVER) { + if (ss->opt.enableRenegotiation == SSL_RENEGOTIATE_NEVER || + (ss->opt.enableRenegotiation == SSL_RENEGOTIATE_CLIENT_ONLY && + ss->sec.isServer)) { PORT_SetError(SSL_ERROR_RENEGOTIATION_NOT_ALLOWED); return SECFailure; } @@ -9110,8 +9494,8 @@ ssl3_DestroySSL3Info(sslSocket *ss) PORT_Free(ss->ssl3.hs.msg_body.buf); /* free up the CipherSpecs */ - ssl3_DestroyCipherSpec(&ss->ssl3.specs[0]); - ssl3_DestroyCipherSpec(&ss->ssl3.specs[1]); + ssl3_DestroyCipherSpec(&ss->ssl3.specs[0], PR_TRUE/*freeSrvName*/); + ssl3_DestroyCipherSpec(&ss->ssl3.specs[1], PR_TRUE/*freeSrvName*/); ss->ssl3.initialized = PR_FALSE; diff --git a/net/third_party/nss/ssl/ssl3ecc.c b/net/third_party/nss/ssl/ssl3ecc.c index fafecfa..42720e5 100644 --- a/net/third_party/nss/ssl/ssl3ecc.c +++ b/net/third_party/nss/ssl/ssl3ecc.c @@ -40,7 +40,7 @@ * ***** END LICENSE BLOCK ***** */ /* ECC code moved here from ssl3con.c */ -/* $Id: ssl3ecc.c,v 1.22 2008/03/10 00:01:28 wtc%google.com Exp $ */ +/* $Id: ssl3ecc.c,v 1.23 2010/01/28 16:14:25 kaie%kuix.de Exp $ */ #include "nss.h" #include "cert.h" @@ -1059,7 +1059,7 @@ ssl3_SendSupportedCurvesXtn( if (!ss->sec.isServer) { TLSExtensionData *xtnData = &ss->xtnData; xtnData->advertised[xtnData->numAdvertised++] = - elliptic_curves_xtn; + ssl_elliptic_curves_xtn; } } return (sizeof EClist); @@ -1083,7 +1083,7 @@ ssl3_SendSupportedPointFormatsXtn( if (!ss->sec.isServer) { TLSExtensionData *xtnData = &ss->xtnData; xtnData->advertised[xtnData->numAdvertised++] = - ec_point_formats_xtn; + ssl_ec_point_formats_xtn; } } return (sizeof ECPtFmt); diff --git a/net/third_party/nss/ssl/ssl3ext.c b/net/third_party/nss/ssl/ssl3ext.c index 1eaf47c..ead0cfd 100644 --- a/net/third_party/nss/ssl/ssl3ext.c +++ b/net/third_party/nss/ssl/ssl3ext.c @@ -41,11 +41,12 @@ * ***** END LICENSE BLOCK ***** */ /* TLS extension code moved here from ssl3ecc.c */ -/* $Id: ssl3ext.c,v 1.5 2009/11/07 18:23:06 wtc%google.com Exp $ */ +/* $Id: ssl3ext.c,v 1.11 2010/02/03 02:38:20 wtc%google.com Exp $ */ #include "nssrenam.h" #include "nss.h" #include "ssl.h" +#include "sslproto.h" #include "sslimpl.h" #include "pk11pub.h" #include "blapi.h" @@ -61,8 +62,7 @@ static unsigned char session_ticket_mac_key[SHA256_LENGTH]; static PRBool session_ticket_keys_initialized = PR_FALSE; static PRCallOnceType generate_session_keys_once; -static PRInt32 ssl3_SendServerNameXtn(sslSocket * ss, - PRBool append, PRUint32 maxBytes); +/* forward static function declarations */ static SECStatus ssl3_ParseEncryptedSessionTicket(sslSocket *ss, SECItem *data, EncryptedSessionTicket *enc_session_ticket); static SECStatus ssl3_AppendToItem(SECItem *item, const unsigned char *buf, @@ -74,6 +74,10 @@ static SECStatus ssl3_GetSessionTicketKeysPKCS11(sslSocket *ss, static SECStatus ssl3_GetSessionTicketKeys(const unsigned char **aes_key, PRUint32 *aes_key_length, const unsigned char **mac_key, PRUint32 *mac_key_length); +static PRInt32 ssl3_SendRenegotiationInfoXtn(sslSocket * ss, + PRBool append, PRUint32 maxBytes); +static SECStatus ssl3_HandleRenegotiationInfoXtn(sslSocket *ss, + PRUint16 ex_type, SECItem *data); /* * Write bytes. Using this function means the SECItem structure @@ -222,42 +226,58 @@ ssl3_GetSessionTicketKeys(const unsigned char **aes_key, * In the second generation, this table will be dynamic, and functions * will be registered here. */ +/* This table is used by the server, to handle client hello extensions. */ static const ssl3HelloExtensionHandler clientHelloHandlers[] = { - { server_name_xtn, &ssl3_HandleServerNameXtn }, + { ssl_server_name_xtn, &ssl3_HandleServerNameXtn }, #ifdef NSS_ENABLE_ECC - { elliptic_curves_xtn, &ssl3_HandleSupportedCurvesXtn }, - { ec_point_formats_xtn, &ssl3_HandleSupportedPointFormatsXtn }, + { ssl_elliptic_curves_xtn, &ssl3_HandleSupportedCurvesXtn }, + { ssl_ec_point_formats_xtn, &ssl3_HandleSupportedPointFormatsXtn }, #endif - { session_ticket_xtn, &ssl3_ServerHandleSessionTicketXtn }, - { next_proto_neg_xtn, &ssl3_ServerHandleNextProtoNegoXtn }, + { ssl_session_ticket_xtn, &ssl3_ServerHandleSessionTicketXtn }, + { ssl_renegotiation_info_xtn, &ssl3_HandleRenegotiationInfoXtn }, + { ssl_next_proto_neg_xtn, &ssl3_ServerHandleNextProtoNegoXtn }, + { -1, NULL } +}; + +/* These two tables are used by the client, to handle server hello + * extensions. */ +static const ssl3HelloExtensionHandler serverHelloHandlersTLS[] = { + { ssl_server_name_xtn, &ssl3_HandleServerNameXtn }, + /* 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 } }; -static const ssl3HelloExtensionHandler serverHelloHandlers[] = { - { server_name_xtn, &ssl3_HandleServerNameXtn }, - /* TODO: add a handler for ec_point_formats_xtn */ - { session_ticket_xtn, &ssl3_ClientHandleSessionTicketXtn }, - { next_proto_neg_xtn, &ssl3_ClientHandleNextProtoNegoXtn }, +static const ssl3HelloExtensionHandler serverHelloHandlersSSL3[] = { + { ssl_renegotiation_info_xtn, &ssl3_HandleRenegotiationInfoXtn }, { -1, NULL } }; -/* Table of functions to format TLS hello extensions, one per extension. - * This static table is for the formatting of client hello extensions. +/* Tables of functions to format TLS hello extensions, one function per + * extension. + * These static tables are for the formatting of client hello extensions. * The server's table of hello senders is dynamic, in the socket struct, * and sender functions are registered there. */ static const -ssl3HelloExtensionSender clientHelloSenders[MAX_EXTENSIONS] = { - { server_name_xtn, &ssl3_SendServerNameXtn }, +ssl3HelloExtensionSender clientHelloSendersTLS[SSL_MAX_EXTENSIONS] = { + { ssl_server_name_xtn, &ssl3_SendServerNameXtn }, + { ssl_renegotiation_info_xtn, &ssl3_SendRenegotiationInfoXtn }, #ifdef NSS_ENABLE_ECC - { elliptic_curves_xtn, &ssl3_SendSupportedCurvesXtn }, - { ec_point_formats_xtn, &ssl3_SendSupportedPointFormatsXtn }, -#else - { -1, NULL }, - { -1, NULL }, + { ssl_elliptic_curves_xtn, &ssl3_SendSupportedCurvesXtn }, + { ssl_ec_point_formats_xtn, &ssl3_SendSupportedPointFormatsXtn }, #endif - { session_ticket_xtn, ssl3_SendSessionTicketXtn }, - { next_proto_neg_xtn, ssl3_ClientSendNextProtoNegoXtn } + { ssl_session_ticket_xtn, &ssl3_SendSessionTicketXtn }, + { ssl_next_proto_neg_xtn, &ssl3_ClientSendNextProtoNegoXtn } + /* any extra entries will appear as { 0, NULL } */ +}; + +static const +ssl3HelloExtensionSender clientHelloSendersSSL3[SSL_MAX_EXTENSIONS] = { + { ssl_renegotiation_info_xtn, &ssl3_SendRenegotiationInfoXtn } + /* any extra entries will appear as { 0, NULL } */ }; static PRBool @@ -287,60 +307,159 @@ ssl3_ClientExtensionAdvertised(sslSocket *ss, PRUint16 ex_type) { /* Format an SNI extension, using the name from the socket's URL, * unless that name is a dotted decimal string. + * Used by client and server. */ -static PRInt32 -ssl3_SendServerNameXtn( - sslSocket * ss, - PRBool append, - PRUint32 maxBytes) +PRInt32 +ssl3_SendServerNameXtn(sslSocket * ss, PRBool append, + PRUint32 maxBytes) { - PRUint32 len; - PRNetAddr netAddr; - - /* must have a hostname */ - if (!ss || !ss->url || !ss->url[0]) - return 0; - /* must not be an IPv4 or IPv6 address */ - if (PR_SUCCESS == PR_StringToNetAddr(ss->url, &netAddr)) { - /* is an IP address (v4 or v6) */ - return 0; + SECStatus rv; + if (!ss->sec.isServer) { + PRUint32 len; + PRNetAddr netAddr; + + /* must have a hostname */ + if (!ss || !ss->url || !ss->url[0]) + return 0; + /* must not be an IPv4 or IPv6 address */ + if (PR_SUCCESS == PR_StringToNetAddr(ss->url, &netAddr)) { + /* is an IP address (v4 or v6) */ + return 0; + } + len = PORT_Strlen(ss->url); + if (append && maxBytes >= len + 9) { + /* extension_type */ + rv = ssl3_AppendHandshakeNumber(ss, ssl_server_name_xtn, 2); + if (rv != SECSuccess) return -1; + /* length of extension_data */ + rv = ssl3_AppendHandshakeNumber(ss, len + 5, 2); + if (rv != SECSuccess) return -1; + /* length of server_name_list */ + rv = ssl3_AppendHandshakeNumber(ss, len + 3, 2); + if (rv != SECSuccess) return -1; + /* Name Type (sni_host_name) */ + rv = ssl3_AppendHandshake(ss, "\0", 1); + if (rv != SECSuccess) return -1; + /* HostName (length and value) */ + rv = ssl3_AppendHandshakeVariable(ss, (PRUint8 *)ss->url, len, 2); + if (rv != SECSuccess) return -1; + if (!ss->sec.isServer) { + TLSExtensionData *xtnData = &ss->xtnData; + xtnData->advertised[xtnData->numAdvertised++] = + ssl_server_name_xtn; + } + } + return len + 9; } - len = PORT_Strlen(ss->url); - if (append && maxBytes >= len + 9) { - SECStatus rv; - /* extension_type */ - rv = ssl3_AppendHandshakeNumber(ss, server_name_xtn, 2); - if (rv != SECSuccess) return -1; - /* length of extension_data */ - rv = ssl3_AppendHandshakeNumber(ss, len + 5, 2); - if (rv != SECSuccess) return -1; - /* length of server_name_list */ - rv = ssl3_AppendHandshakeNumber(ss, len + 3, 2); - if (rv != SECSuccess) return -1; - /* Name Type (host_name) */ - rv = ssl3_AppendHandshake(ss, "\0", 1); - if (rv != SECSuccess) return -1; - /* HostName (length and value) */ - rv = ssl3_AppendHandshakeVariable(ss, (unsigned char *)ss->url, len, 2); - if (rv != SECSuccess) return -1; - if (!ss->sec.isServer) { - TLSExtensionData *xtnData = &ss->xtnData; - xtnData->advertised[xtnData->numAdvertised++] = server_name_xtn; - } + /* Server side */ + if (append && maxBytes >= 4) { + rv = ssl3_AppendHandshakeNumber(ss, ssl_server_name_xtn, 2); + if (rv != SECSuccess) return -1; + /* length of extension_data */ + rv = ssl3_AppendHandshakeNumber(ss, 0, 2); + if (rv != SECSuccess) return -1; } - return len + 9; + return 4; } /* handle an incoming SNI extension, by ignoring it. */ SECStatus ssl3_HandleServerNameXtn(sslSocket * ss, PRUint16 ex_type, SECItem *data) { - /* TODO: if client, should verify extension_data is empty. */ - /* TODO: if server, should send empty extension_data. */ - /* For now, we ignore this, as if we didn't understand it. :-) */ + SECItem *names = NULL; + PRUint32 listCount = 0, namesPos = 0, i; + TLSExtensionData *xtnData = &ss->xtnData; + SECItem ldata; + PRInt32 listLenBytes = 0; + + if (!ss->sec.isServer) { + /* Verify extension_data is empty. */ + if (data->data || data->len || + !ssl3_ExtensionNegotiated(ss, ssl_server_name_xtn)) { + /* malformed or was not initiated by the client.*/ + return SECFailure; + } + return SECSuccess; + } + + /* Server side - consume client data and register server sender. */ + /* do not parse the data if don't have user extension handling function. */ + if (!ss->sniSocketConfig) { + return SECSuccess; + } + /* length of server_name_list */ + listLenBytes = ssl3_ConsumeHandshakeNumber(ss, 2, &data->data, &data->len); + if (listLenBytes == 0 || listLenBytes != data->len) { + return SECFailure; + } + ldata = *data; + /* Calculate the size of the array.*/ + while (listLenBytes > 0) { + SECItem litem; + SECStatus rv; + PRInt32 type; + /* Name Type (sni_host_name) */ + type = ssl3_ConsumeHandshakeNumber(ss, 1, &ldata.data, &ldata.len); + if (!ldata.len) { + return SECFailure; + } + rv = ssl3_ConsumeHandshakeVariable(ss, &litem, 2, &ldata.data, &ldata.len); + if (rv != SECSuccess) { + return SECFailure; + } + /* Adjust total length for cunsumed item, item len and type.*/ + listLenBytes -= litem.len + 3; + if (listLenBytes > 0 && !ldata.len) { + return SECFailure; + } + listCount += 1; + } + if (!listCount) { + return SECFailure; + } + names = PORT_ZNewArray(SECItem, listCount); + if (!names) { + return SECFailure; + } + for (i = 0;i < listCount;i++) { + int j; + PRInt32 type; + SECStatus rv; + PRBool nametypePresent = PR_FALSE; + /* Name Type (sni_host_name) */ + type = ssl3_ConsumeHandshakeNumber(ss, 1, &data->data, &data->len); + /* Check if we have such type in the list */ + for (j = 0;j < listCount && names[j].data;j++) { + if (names[j].type == type) { + nametypePresent = PR_TRUE; + break; + } + } + /* HostName (length and value) */ + rv = ssl3_ConsumeHandshakeVariable(ss, &names[namesPos], 2, + &data->data, &data->len); + if (rv != SECSuccess) { + goto loser; + } + if (nametypePresent == PR_FALSE) { + namesPos += 1; + } + } + /* Free old and set the new data. */ + if (xtnData->sniNameArr) { + PORT_Free(ss->xtnData.sniNameArr); + } + xtnData->sniNameArr = names; + xtnData->sniNameArrSize = namesPos; + xtnData->negotiated[xtnData->numNegotiated++] = ssl_server_name_xtn; + return SECSuccess; -} +loser: + PORT_Free(names); + return SECFailure; +} + /* Called by both clients and servers. * Clients sends a filled in session ticket if one is available, and otherwise * sends an empty ticket. Servers always send empty tickets. @@ -386,7 +505,7 @@ ssl3_SendSessionTicketXtn( if (append && maxBytes >= extension_length) { SECStatus rv; /* extension_type */ - rv = ssl3_AppendHandshakeNumber(ss, session_ticket_xtn, 2); + rv = ssl3_AppendHandshakeNumber(ss, ssl_session_ticket_xtn, 2); if (rv != SECSuccess) goto loser; if (session_ticket && session_ticket->ticket.data && @@ -402,7 +521,8 @@ ssl3_SendSessionTicketXtn( if (!ss->sec.isServer) { TLSExtensionData *xtnData = &ss->xtnData; - xtnData->advertised[xtnData->numAdvertised++] = session_ticket_xtn; + xtnData->advertised[xtnData->numAdvertised++] = + ssl_session_ticket_xtn; } } else if (maxBytes < extension_length) { PORT_Assert(0); @@ -514,15 +634,14 @@ ssl3_ClientSendNextProtoNegoXtn(sslSocket * ss, if (append && maxBytes >= extension_length) { SECStatus rv; - TLSExtensionData *xtnData; - rv = ssl3_AppendHandshakeNumber(ss, next_proto_neg_xtn, 2); + 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; - xtnData = &ss->xtnData; - xtnData->advertised[xtnData->numAdvertised++] = next_proto_neg_xtn; + ss->xtnData.advertised[ss->xtnData.numAdvertised++] = + ssl_next_proto_neg_xtn; } else if (maxBytes < extension_length) { return 0; } @@ -575,6 +694,8 @@ ssl3_SendNewSessionTicket(sslSocket *ss) unsigned int computed_mac_length; unsigned char iv[AES_BLOCK_SIZE]; SECItem ivItem; + SECItem *srvName = NULL; + PRUint32 srvNameLen = 0; CK_MECHANISM_TYPE msWrapMech = 0; /* dummy default value, * must be >= 0 */ @@ -635,6 +756,11 @@ ssl3_SendNewSessionTicket(sslSocket *ss) } ms_is_wrapped = PR_TRUE; } + /* Prep to send negotiated name */ + srvName = &ss->ssl3.pwSpec->srvVirtName; + if (srvName->data && srvName->len) { + srvNameLen = 2 + srvName->len; /* len bytes + name len */ + } ciphertext_length = sizeof(PRUint16) /* ticket_version */ @@ -649,6 +775,8 @@ ssl3_SendNewSessionTicket(sslSocket *ss) + ms_item.len /* master_secret */ + 1 /* client_auth_type */ + cert_length /* cert */ + + 1 /* server name type */ + + srvNameLen /* name len + length field */ + sizeof(ticket.ticket_lifetime_hint); padding_length = AES_BLOCK_SIZE - (ciphertext_length % AES_BLOCK_SIZE); @@ -731,6 +859,22 @@ ssl3_SendNewSessionTicket(sslSocket *ss) sizeof(ticket.ticket_lifetime_hint)); if (rv != SECSuccess) goto loser; + if (srvNameLen) { + /* Name Type (sni_host_name) */ + rv = ssl3_AppendNumberToItem(&plaintext, srvName->type, 1); + if (rv != SECSuccess) goto loser; + /* HostName (length and value) */ + rv = ssl3_AppendNumberToItem(&plaintext, srvName->len, 2); + if (rv != SECSuccess) goto loser; + rv = ssl3_AppendToItem(&plaintext, srvName->data, srvName->len); + if (rv != SECSuccess) goto loser; + } else { + /* No Name */ + rv = ssl3_AppendNumberToItem(&plaintext, (char)TLS_STE_NO_SERVER_NAME, + 1); + if (rv != SECSuccess) goto loser; + } + PORT_Assert(plaintext.len == padding_length); for (i = 0; i < padding_length; i++) plaintext.data[i] = (unsigned char)padding_length; @@ -903,6 +1047,7 @@ ssl3_ServerHandleSessionTicketXtn(sslSocket *ss, PRUint16 ex_type, unsigned int buffer_len; PRInt32 temp; SECItem cert_item; + PRInt8 nameType = TLS_STE_NO_SERVER_NAME; /* Turn off stateless session resumption if the client sends a * SessionTicket extension, even if the extension turns out to be @@ -1155,6 +1300,20 @@ ssl3_ServerHandleSessionTicketXtn(sslSocket *ss, PRUint16 ex_type, goto no_ticket; parsed_session_ticket->timestamp = (PRUint32)temp; + /* Read server name */ + nameType = + ssl3_ConsumeHandshakeNumber(ss, 1, &buffer, &buffer_len); + if (nameType != TLS_STE_NO_SERVER_NAME) { + SECItem name_item; + rv = ssl3_ConsumeHandshakeVariable(ss, &name_item, 2, &buffer, + &buffer_len); + if (rv != SECSuccess) goto no_ticket; + rv = SECITEM_CopyItem(NULL, &parsed_session_ticket->srvName, + &name_item); + if (rv != SECSuccess) goto no_ticket; + parsed_session_ticket->srvName.type = nameType; + } + /* Done parsing. Check that all bytes have been consumed. */ if (buffer_len != padding_length) goto no_ticket; @@ -1211,6 +1370,9 @@ ssl3_ServerHandleSessionTicketXtn(sslSocket *ss, PRUint16 ex_type, goto loser; } } + if (parsed_session_ticket->srvName.data != NULL) { + sid->u.ssl3.srvName = parsed_session_ticket->srvName; + } ss->statelessResume = PR_TRUE; ss->sec.ci.sid = sid; } @@ -1293,8 +1455,15 @@ ssl3_ParseEncryptedSessionTicket(sslSocket *ss, SECItem *data, SECStatus ssl3_HandleHelloExtensions(sslSocket *ss, SSL3Opaque **b, PRUint32 *length) { - const ssl3HelloExtensionHandler * handlers = - ss->sec.isServer ? clientHelloHandlers : serverHelloHandlers; + const ssl3HelloExtensionHandler * handlers; + + if (ss->sec.isServer) { + handlers = clientHelloHandlers; + } else if (ss->version > SSL_LIBRARY_VERSION_3_0) { + handlers = serverHelloHandlersTLS; + } else { + handlers = serverHelloHandlersSSL3; + } while (*length) { const ssl3HelloExtensionHandler * handler; @@ -1347,7 +1516,7 @@ ssl3_RegisterServerHelloExtensionSender(sslSocket *ss, PRUint16 ex_type, int i; ssl3HelloExtensionSender *sender = &ss->xtnData.serverSenders[0]; - for (i = 0; i < MAX_EXTENSIONS; ++i, ++sender) { + for (i = 0; i < SSL_MAX_EXTENSIONS; ++i, ++sender) { if (!sender->ex_sender) { sender->ex_type = ex_type; sender->ex_sender = cb; @@ -1360,7 +1529,7 @@ ssl3_RegisterServerHelloExtensionSender(sslSocket *ss, PRUint16 ex_type, break; } } - PORT_Assert(i < MAX_EXTENSIONS); /* table needs to grow */ + PORT_Assert(i < SSL_MAX_EXTENSIONS); /* table needs to grow */ PORT_SetError(SEC_ERROR_LIBRARY_FAILURE); return SECFailure; } @@ -1373,10 +1542,12 @@ ssl3_CallHelloExtensionSenders(sslSocket *ss, PRBool append, PRUint32 maxBytes, PRInt32 total_exten_len = 0; int i; - if (!sender) - sender = &clientHelloSenders[0]; + if (!sender) { + sender = ss->version > SSL_LIBRARY_VERSION_3_0 ? + &clientHelloSendersTLS[0] : &clientHelloSendersSSL3[0]; + } - for (i = 0; i < MAX_EXTENSIONS; ++i, ++sender) { + for (i = 0; i < SSL_MAX_EXTENSIONS; ++i, ++sender) { if (sender->ex_sender) { PRInt32 extLen = (*sender->ex_sender)(ss, append, maxBytes); if (extLen < 0) @@ -1387,3 +1558,82 @@ ssl3_CallHelloExtensionSenders(sslSocket *ss, PRBool append, PRUint32 maxBytes, } return total_exten_len; } + + +/* Extension format: + * Extension number: 2 bytes + * Extension length: 2 bytes + * Verify Data Length: 1 byte + * Verify Data (TLS): 12 bytes (client) or 24 bytes (server) + * Verify Data (SSL): 36 bytes (client) or 72 bytes (server) + */ +static PRInt32 +ssl3_SendRenegotiationInfoXtn( + sslSocket * ss, + PRBool append, + PRUint32 maxBytes) +{ + PRInt32 len, needed; + + /* In draft-ietf-tls-renegotiation-03, it is NOT RECOMMENDED to send + * both the SCSV and the empty RI, so when we send SCSV in + * the initial handshake, we don't also send RI. + */ + if (!ss || ss->ssl3.hs.sendingSCSV) + return 0; + len = !ss->firstHsDone ? 0 : + (ss->sec.isServer ? ss->ssl3.hs.finishedBytes * 2 + : ss->ssl3.hs.finishedBytes); + needed = 5 + len; + if (append && maxBytes >= needed) { + SECStatus rv; + /* extension_type */ + rv = ssl3_AppendHandshakeNumber(ss, ssl_renegotiation_info_xtn, 2); + if (rv != SECSuccess) return -1; + /* length of extension_data */ + rv = ssl3_AppendHandshakeNumber(ss, len + 1, 2); + if (rv != SECSuccess) return -1; + /* verify_Data from previous Finished message(s) */ + rv = ssl3_AppendHandshakeVariable(ss, + ss->ssl3.hs.finishedMsgs.data, len, 1); + if (rv != SECSuccess) return -1; + if (!ss->sec.isServer) { + TLSExtensionData *xtnData = &ss->xtnData; + xtnData->advertised[xtnData->numAdvertised++] = + ssl_renegotiation_info_xtn; + } + } + return needed; +} + +/* This function runs in both the client and server. */ +static SECStatus +ssl3_HandleRenegotiationInfoXtn(sslSocket *ss, PRUint16 ex_type, SECItem *data) +{ + SECStatus rv = SECSuccess; + PRUint32 len = 0; + + if (ss->firstHsDone) { + len = ss->sec.isServer ? ss->ssl3.hs.finishedBytes + : ss->ssl3.hs.finishedBytes * 2; + } + if (data->len != 1 + len || + data->data[0] != len || (len && + NSS_SecureMemcmp(ss->ssl3.hs.finishedMsgs.data, + data->data + 1, len))) { + /* Can we do this here? Or, must we arrange for the caller to do it? */ + (void)SSL3_SendAlert(ss, alert_fatal, handshake_failure); + PORT_SetError(SSL_ERROR_BAD_HANDSHAKE_HASH_VALUE); + return SECFailure; + } + /* remember that we got this extension and it was correct. */ + ss->peerRequestedProtection = 1; + ss->xtnData.negotiated[ss->xtnData.numNegotiated++] = ex_type; + if (ss->sec.isServer) { + /* prepare to send back the appropriate response */ + rv = ssl3_RegisterServerHelloExtensionSender(ss, ex_type, + ssl3_SendRenegotiationInfoXtn); + } + return rv; +} + diff --git a/net/third_party/nss/ssl/ssl3prot.h b/net/third_party/nss/ssl/ssl3prot.h index 84d73a9..c82c891 100644 --- a/net/third_party/nss/ssl/ssl3prot.h +++ b/net/third_party/nss/ssl/ssl3prot.h @@ -38,7 +38,7 @@ * the terms of any one of the MPL, the GPL or the LGPL. * * ***** END LICENSE BLOCK ***** */ -/* $Id: ssl3prot.h,v 1.15 2009/11/07 18:23:06 wtc%google.com Exp $ */ +/* $Id: ssl3prot.h,v 1.18 2010/02/03 02:25:35 alexei.volkov.bugs%sun.com Exp $ */ #ifndef __ssl3proto_h_ #define __ssl3proto_h_ @@ -344,20 +344,8 @@ typedef struct { unsigned char *mac; } EncryptedSessionTicket; -/* Supported extensions. */ -/* Update MAX_EXTENSIONS whenever a new extension type is added. */ -typedef enum { - server_name_xtn = 0, -#ifdef NSS_ENABLE_ECC - elliptic_curves_xtn = 10, - ec_point_formats_xtn = 11, -#endif - session_ticket_xtn = 35, - next_proto_neg_xtn = 13172 -} ExtensionType; - -#define MAX_EXTENSIONS 5 - #define TLS_EX_SESS_TICKET_MAC_LENGTH 32 +#define TLS_STE_NO_SERVER_NAME -1 + #endif /* __ssl3proto_h_ */ diff --git a/net/third_party/nss/ssl/sslcon.c b/net/third_party/nss/ssl/sslcon.c index 500b787..c02b315 100644 --- a/net/third_party/nss/ssl/sslcon.c +++ b/net/third_party/nss/ssl/sslcon.c @@ -37,7 +37,7 @@ * the terms of any one of the MPL, the GPL or the LGPL. * * ***** END LICENSE BLOCK ***** */ -/* $Id: sslcon.c,v 1.37 2009/10/16 17:45:35 wtc%google.com Exp $ */ +/* $Id: sslcon.c,v 1.39 2010/02/04 03:08:44 wtc%google.com Exp $ */ #include "nssrenam.h" #include "cert.h" @@ -3007,6 +3007,7 @@ ssl2_BeginClientHandshake(sslSocket *ss) unsigned int i; int sendLen, sidLen = 0; SECStatus rv; + TLSExtensionData *xtnData; PORT_Assert( ss->opt.noLocks || ssl_Have1stHandshakeLock(ss) ); @@ -3151,7 +3152,8 @@ ssl2_BeginClientHandshake(sslSocket *ss) localCipherSpecs = ss->cipherSpecs; localCipherSize = ss->sizeCipherSpecs; - sendLen = SSL_HL_CLIENT_HELLO_HBYTES + localCipherSize + sidLen + + /* Add 3 for SCSV */ + sendLen = SSL_HL_CLIENT_HELLO_HBYTES + localCipherSize + 3 + sidLen + SSL_CHALLENGE_BYTES; /* Generate challenge bytes for server */ @@ -3176,8 +3178,9 @@ ssl2_BeginClientHandshake(sslSocket *ss) msg[1] = MSB(ss->clientHelloVersion); msg[2] = LSB(ss->clientHelloVersion); - msg[3] = MSB(localCipherSize); - msg[4] = LSB(localCipherSize); + /* Add 3 for SCSV */ + msg[3] = MSB(localCipherSize + 3); + msg[4] = LSB(localCipherSize + 3); msg[5] = MSB(sidLen); msg[6] = LSB(sidLen); msg[7] = MSB(SSL_CHALLENGE_BYTES); @@ -3185,6 +3188,16 @@ ssl2_BeginClientHandshake(sslSocket *ss) cp += SSL_HL_CLIENT_HELLO_HBYTES; PORT_Memcpy(cp, localCipherSpecs, localCipherSize); cp += localCipherSize; + /* + * Add SCSV. SSL 2.0 cipher suites are listed before SSL 3.0 cipher + * suites in localCipherSpecs for compatibility with SSL 2.0 servers. + * Since SCSV looks like an SSL 3.0 cipher suite, we can't add it at + * the beginning. + */ + cp[0] = 0x00; + cp[1] = 0x00; + cp[2] = 0xff; + cp += 3; if (sidLen) { PORT_Memcpy(cp, sid->u.ssl2.sessionID, sidLen); cp += sidLen; @@ -3207,6 +3220,14 @@ ssl2_BeginClientHandshake(sslSocket *ss) goto loser; } + /* + * Since we sent the SCSV, pretend we sent empty RI extension. We need + * to record the extension has been advertised after ssl3_InitState has + * been called, which ssl3_StartHandshakeHash took care for us above. + */ + xtnData = &ss->xtnData; + xtnData->advertised[xtnData->numAdvertised++] = ssl_renegotiation_info_xtn; + /* Setup to receive servers hello message */ ssl_GetRecvBufLock(ss); ss->gs.recordLen = 0; diff --git a/net/third_party/nss/ssl/sslerr.h b/net/third_party/nss/ssl/sslerr.h index c132ab9..61b721c 100644 --- a/net/third_party/nss/ssl/sslerr.h +++ b/net/third_party/nss/ssl/sslerr.h @@ -36,7 +36,7 @@ * the terms of any one of the MPL, the GPL or the LGPL. * * ***** END LICENSE BLOCK ***** */ -/* $Id: sslerr.h,v 1.8 2009/11/06 20:11:28 nelson%bolyard.com Exp $ */ +/* $Id: sslerr.h,v 1.10 2010/02/03 03:44:29 wtc%google.com Exp $ */ #ifndef __SSL_ERR_H_ #define __SSL_ERR_H_ @@ -197,6 +197,9 @@ SSL_ERROR_RX_MALFORMED_NEW_SESSION_TICKET = (SSL_ERROR_BASE + 110), SSL_ERROR_DECOMPRESSION_FAILURE = (SSL_ERROR_BASE + 111), SSL_ERROR_RENEGOTIATION_NOT_ALLOWED = (SSL_ERROR_BASE + 112), +SSL_ERROR_UNSAFE_NEGOTIATION = (SSL_ERROR_BASE + 113), + +SSL_ERROR_RX_UNEXPECTED_UNCOMPRESSED_RECORD = (SSL_ERROR_BASE + 114), SSL_ERROR_END_OF_LIST /* let the c compiler determine the value of this. */ } SSLErrorCodes; diff --git a/net/third_party/nss/ssl/sslimpl.h b/net/third_party/nss/ssl/sslimpl.h index 6f2316a..0ec579d 100644 --- a/net/third_party/nss/ssl/sslimpl.h +++ b/net/third_party/nss/ssl/sslimpl.h @@ -39,7 +39,7 @@ * the terms of any one of the MPL, the GPL or the LGPL. * * ***** END LICENSE BLOCK ***** */ -/* $Id: sslimpl.h,v 1.70 2009/11/21 03:40:49 wtc%google.com Exp $ */ +/* $Id: sslimpl.h,v 1.76 2010/02/04 03:08:45 wtc%google.com Exp $ */ #ifndef __sslimpl_h_ #define __sslimpl_h_ @@ -137,7 +137,7 @@ extern int Debug; #endif #define ssl_InMonitor(m) PZ_InMonitor(m) -#define LSB(x) ((unsigned char) (x & 0xff)) +#define LSB(x) ((unsigned char) ((x) & 0xff)) #define MSB(x) ((unsigned char) (((unsigned)(x)) >> 8)) /************************************************************************/ @@ -561,6 +561,9 @@ typedef struct { SECItem msItem; unsigned char key_block[NUM_MIXERS * MD5_LENGTH]; unsigned char raw_master_secret[56]; + SECItem srvVirtName; /* for server: name that was negotiated + * with a client. For client - is + * always set to NULL.*/ } ssl3CipherSpec; typedef enum { never_cached, @@ -656,6 +659,7 @@ struct sslSessionIDStr { * ClientHello message. This field is used by clients. */ NewSessionTicket sessionTicket; + SECItem srvName; } ssl3; } u; }; @@ -730,16 +734,23 @@ typedef struct SessionTicketDataStr SessionTicketData; struct TLSExtensionDataStr { /* registered callbacks that send server hello extensions */ - ssl3HelloExtensionSender serverSenders[MAX_EXTENSIONS]; + ssl3HelloExtensionSender serverSenders[SSL_MAX_EXTENSIONS]; /* Keep track of the extensions that are negotiated. */ PRUint16 numAdvertised; PRUint16 numNegotiated; - PRUint16 advertised[MAX_EXTENSIONS]; - PRUint16 negotiated[MAX_EXTENSIONS]; + PRUint16 advertised[SSL_MAX_EXTENSIONS]; + PRUint16 negotiated[SSL_MAX_EXTENSIONS]; /* SessionTicket Extension related data. */ PRBool ticketTimestampVerified; PRBool emptySessionTicket; + + /* SNI Extension related data + * Names data is not coppied from the input buffer. It can not be + * used outside the scope where input buffer is defined and that + * is beyond ssl3_HandleClientHello function. */ + SECItem *sniNameArr; + PRUint32 sniNameArrSize; }; /* @@ -770,9 +781,16 @@ const ssl3CipherSuiteDef *suite_def; PRBool rehandshake; /* immediately start another handshake * when this one finishes */ PRBool usedStepDownKey; /* we did a server key exchange. */ + PRBool sendingSCSV; /* instead of empty RI */ sslBuffer msgState; /* current state for handshake messages*/ /* protected by recvBufLock */ sslBuffer messages; /* Accumulated handshake messages */ + PRUint16 finishedBytes; /* size of single finished below */ + union { + TLSFinished tFinished[2]; /* client, then server */ + SSL3Hashes sFinished[2]; + SSL3Opaque data[72]; + } finishedMsgs; #ifdef NSS_ENABLE_ECC PRUint32 negotiatedECCurves; /* bit mask */ #endif /* NSS_ENABLE_ECC */ @@ -877,6 +895,7 @@ typedef struct SessionTicketStr { ClientIdentity client_identity; SECItem peer_cert; uint32 timestamp; + SECItem srvName; /* negotiated server name */ } SessionTicket; /* @@ -1022,6 +1041,7 @@ struct sslSocketStr { unsigned long recvdCloseNotify; /* received SSL EOF. */ unsigned long TCPconnected; unsigned long appDataBuffered; + unsigned long peerRequestedProtection; /* from old renegotiation */ /* version of the protocol to use */ SSL3ProtocolVersion version; @@ -1050,6 +1070,8 @@ const unsigned char * preferredCipher; void *authCertificateArg; SSLGetClientAuthData getClientAuthData; void *getClientAuthDataArg; + SSLSNISocketConfig sniSocketConfig; + void *sniSocketConfigArg; SSLBadCertHandler handleBadCert; void *badCertArg; SSLHandshakeCallback handshakeCallback; @@ -1130,6 +1152,7 @@ extern NSSRWLock * ssl_global_data_lock; extern char ssl_debug; extern char ssl_trace; extern FILE * ssl_trace_iob; +extern FILE * ssl_keylog_iob; extern CERTDistNames * ssl3_server_ca_list; extern PRUint32 ssl_sid_timeout; extern PRUint32 ssl3_sid_timeout; @@ -1501,6 +1524,23 @@ extern SECStatus ssl3_ServerHandleNextProtoNegoXtn(sslSocket *ss, */ extern PRInt32 ssl3_SendSessionTicketXtn(sslSocket *ss, PRBool append, PRUint32 maxBytes); + +/* ClientHello and ServerHello extension senders. + * The code is in ssl3ext.c. + */ +extern PRInt32 ssl3_SendServerNameXtn(sslSocket *ss, PRBool append, + PRUint32 maxBytes); + +/* Assigns new cert, cert chain and keys to ss->serverCerts + * struct. If certChain is NULL, tries to find one. Aborts if + * fails to do so. If cert and keyPair are NULL - unconfigures + * sslSocket of kea type.*/ +extern SECStatus ssl_ConfigSecureServer(sslSocket *ss, CERTCertificate *cert, + CERTCertificateList *certChain, + ssl3KeyPair *keyPair, SSLKEAType kea); +/* Return key type for the cert */ +extern SSLKEAType ssl_FindCertKEAType(CERTCertificate * cert); + #ifdef NSS_ENABLE_ECC extern PRInt32 ssl3_SendSupportedCurvesXtn(sslSocket *ss, PRBool append, PRUint32 maxBytes); diff --git a/net/third_party/nss/ssl/sslinfo.c b/net/third_party/nss/ssl/sslinfo.c index baa1ab3..e4ee35f 100644 --- a/net/third_party/nss/ssl/sslinfo.c +++ b/net/third_party/nss/ssl/sslinfo.c @@ -34,7 +34,7 @@ * the terms of any one of the MPL, the GPL or the LGPL. * * ***** END LICENSE BLOCK ***** */ -/* $Id: sslinfo.c,v 1.21 2009/11/09 22:00:18 wtc%google.com Exp $ */ +/* $Id: sslinfo.c,v 1.23 2010/01/15 01:49:33 alexei.volkov.bugs%sun.com Exp $ */ #include "ssl.h" #include "sslimpl.h" #include "sslproto.h" @@ -307,3 +307,43 @@ SSL_IsExportCipherSuite(PRUint16 cipherSuite) } return PR_FALSE; } + +SECItem* +SSL_GetNegotiatedHostInfo(PRFileDesc *fd) +{ + SECItem *sniName = NULL; + sslSocket *ss; + char *name = NULL; + + ss = ssl_FindSocket(fd); + if (!ss) { + SSL_DBG(("%d: SSL[%d]: bad socket in SSL_GetNegotiatedHostInfo", + SSL_GETPID(), fd)); + return NULL; + } + + if (ss->sec.isServer) { + if (ss->version > SSL_LIBRARY_VERSION_3_0 && + ss->ssl3.initialized) { /* TLS */ + SECItem *crsName; + ssl_GetSpecReadLock(ss); /*********************************/ + crsName = &ss->ssl3.crSpec->srvVirtName; + if (crsName->data) { + sniName = SECITEM_DupItem(crsName); + } + ssl_ReleaseSpecReadLock(ss); /*----------------------------*/ + } + return sniName; + } + name = SSL_RevealURL(fd); + if (name) { + sniName = PORT_ZNew(SECItem); + if (!sniName) { + PORT_Free(name); + return NULL; + } + sniName->data = (void*)name; + sniName->len = PORT_Strlen(name); + } + return sniName; +} diff --git a/net/third_party/nss/ssl/sslproto.h b/net/third_party/nss/ssl/sslproto.h index b0b466f..bf7b71b 100644 --- a/net/third_party/nss/ssl/sslproto.h +++ b/net/third_party/nss/ssl/sslproto.h @@ -39,7 +39,7 @@ * the terms of any one of the MPL, the GPL or the LGPL. * * ***** END LICENSE BLOCK ***** */ -/* $Id: sslproto.h,v 1.13 2008/12/17 06:09:19 nelson%bolyard.com Exp $ */ +/* $Id: sslproto.h,v 1.14 2010/01/28 06:19:12 nelson%bolyard.com Exp $ */ #ifndef __sslproto_h_ #define __sslproto_h_ @@ -181,6 +181,15 @@ #define TLS_RSA_WITH_SEED_CBC_SHA 0x0096 +/* TLS "Signalling Cipher Suite Value" (SCSV). May be requested by client. + * Must NEVER be chosen by server. SSL 3.0 server acknowledges by sending + * back an empty Renegotiation Info (RI) server hello extension. + */ +#define TLS_RENEGO_PROTECTION_REQUEST 0x00FF + +/* Cipher Suite Values starting with 0xC000 are defined in informational + * RFCs. + */ #define TLS_ECDH_ECDSA_WITH_NULL_SHA 0xC001 #define TLS_ECDH_ECDSA_WITH_RC4_128_SHA 0xC002 #define TLS_ECDH_ECDSA_WITH_3DES_EDE_CBC_SHA 0xC003 diff --git a/net/third_party/nss/ssl/sslreveal.c b/net/third_party/nss/ssl/sslreveal.c index a981dee..74f8814 100644 --- a/net/third_party/nss/ssl/sslreveal.c +++ b/net/third_party/nss/ssl/sslreveal.c @@ -36,7 +36,7 @@ * the terms of any one of the MPL, the GPL or the LGPL. * * ***** END LICENSE BLOCK ***** */ -/* $Id: sslreveal.c,v 1.4 2004/04/27 23:04:39 gerv%gerv.net Exp $ */ +/* $Id: sslreveal.c,v 1.7 2010/02/04 03:21:11 wtc%google.com Exp $ */ #include "cert.h" #include "ssl.h" @@ -82,7 +82,7 @@ SSL_RevealPinArg(PRFileDesc * fd) /* given PRFileDesc, returns a pointer to the URL associated with the socket - * the caller should free url when done + * the caller should free url when done */ char * SSL_RevealURL(PRFileDesc * fd) @@ -98,3 +98,41 @@ SSL_RevealURL(PRFileDesc * fd) return url; } + +/* given PRFileDesc, returns status information related to extensions + * negotiated with peer during the handshake. + */ + +SECStatus +SSL_HandshakeNegotiatedExtension(PRFileDesc * socket, + SSLExtensionType extId, + PRBool *pYes) +{ + /* some decisions derived from SSL_GetChannelInfo */ + sslSocket * sslsocket = NULL; + SECStatus rv = SECFailure; + + if (!pYes) + return rv; + + sslsocket = ssl_FindSocket(socket); + + /* according to public API SSL_GetChannelInfo, this doesn't need a lock */ + if (sslsocket && sslsocket->opt.useSecurity && sslsocket->firstHsDone) { + if (sslsocket->ssl3.initialized) { /* SSL3 and TLS */ + /* now we know this socket went through ssl3_InitState() and + * ss->xtnData got initialized, which is the only member accessed by + * ssl3_ExtensionNegotiated(); + * Member xtnData appears to get accessed in functions that handle + * the handshake (hello messages and extension sending), + * therefore the handshake lock should be sufficient. + */ + ssl_GetSSL3HandshakeLock(sslsocket); + *pYes = ssl3_ExtensionNegotiated(sslsocket, extId); + ssl_ReleaseSSL3HandshakeLock(sslsocket); + rv = SECSuccess; + } + } + + return rv; +} diff --git a/net/third_party/nss/ssl/sslsecur.c b/net/third_party/nss/ssl/sslsecur.c index c13100a..80c2ba6 100644 --- a/net/third_party/nss/ssl/sslsecur.c +++ b/net/third_party/nss/ssl/sslsecur.c @@ -37,7 +37,7 @@ * the terms of any one of the MPL, the GPL or the LGPL. * * ***** END LICENSE BLOCK ***** */ -/* $Id: sslsecur.c,v 1.42 2008/10/03 19:20:20 wtc%google.com Exp $ */ +/* $Id: sslsecur.c,v 1.43 2010/01/14 22:15:25 alexei.volkov.bugs%sun.com Exp $ */ #include "cert.h" #include "secitem.h" #include "keyhi.h" @@ -672,6 +672,79 @@ static PRStatus serverCAListSetup(void *arg) return PR_FAILURE; } +SECStatus +ssl_ConfigSecureServer(sslSocket *ss, CERTCertificate *cert, + CERTCertificateList *certChain, + ssl3KeyPair *keyPair, SSLKEAType kea) +{ + CERTCertificateList *localCertChain = NULL; + sslServerCerts *sc = ss->serverCerts + kea; + + /* load the server certificate */ + if (sc->serverCert != NULL) { + CERT_DestroyCertificate(sc->serverCert); + sc->serverCert = NULL; + sc->serverKeyBits = 0; + } + /* load the server cert chain */ + if (sc->serverCertChain != NULL) { + CERT_DestroyCertificateList(sc->serverCertChain); + sc->serverCertChain = NULL; + } + if (cert) { + sc->serverCert = CERT_DupCertificate(cert); + /* get the size of the cert's public key, and remember it */ + sc->serverKeyBits = SECKEY_PublicKeyStrengthInBits(keyPair->pubKey); + if (!certChain) { + localCertChain = + CERT_CertChainFromCert(sc->serverCert, certUsageSSLServer, + PR_TRUE); + if (!localCertChain) + goto loser; + } + sc->serverCertChain = (certChain) ? CERT_DupCertList(certChain) : + localCertChain; + if (!sc->serverCertChain) { + goto loser; + } + localCertChain = NULL; /* consumed */ + } + + /* get keyPair */ + if (sc->serverKeyPair != NULL) { + ssl3_FreeKeyPair(sc->serverKeyPair); + sc->serverKeyPair = NULL; + } + if (keyPair) { + SECKEY_CacheStaticFlags(keyPair->privKey); + sc->serverKeyPair = ssl3_GetKeyPairRef(keyPair); + } + if (kea == kt_rsa && cert && sc->serverKeyBits > 512 && + !ss->opt.noStepDown && !ss->stepDownKeyPair) { + if (ssl3_CreateRSAStepDownKeys(ss) != SECSuccess) { + goto loser; + } + } + return SECSuccess; + +loser: + if (localCertChain) { + CERT_DestroyCertificateList(localCertChain); + } + if (sc->serverCert != NULL) { + CERT_DestroyCertificate(sc->serverCert); + sc->serverCert = NULL; + } + if (sc->serverCertChain != NULL) { + CERT_DestroyCertificateList(sc->serverCertChain); + sc->serverCertChain = NULL; + } + if (sc->serverKeyPair != NULL) { + ssl3_FreeKeyPair(sc->serverKeyPair); + sc->serverKeyPair = NULL; + } + return SECFailure; +} /* XXX need to protect the data that gets changed here.!! */ @@ -679,10 +752,10 @@ SECStatus SSL_ConfigSecureServer(PRFileDesc *fd, CERTCertificate *cert, SECKEYPrivateKey *key, SSL3KEAType kea) { - SECStatus rv; sslSocket *ss; - sslServerCerts *sc; - SECKEYPublicKey * pubKey = NULL; + SECKEYPublicKey *pubKey = NULL; + ssl3KeyPair *keyPair = NULL; + SECStatus rv = SECFailure; ss = ssl_FindSocket(fd); if (!ss) { @@ -708,41 +781,13 @@ SSL_ConfigSecureServer(PRFileDesc *fd, CERTCertificate *cert, return SECFailure; } - sc = ss->serverCerts + kea; - /* load the server certificate */ - if (sc->serverCert != NULL) { - CERT_DestroyCertificate(sc->serverCert); - sc->serverCert = NULL; - } if (cert) { - sc->serverCert = CERT_DupCertificate(cert); - if (!sc->serverCert) - goto loser; /* get the size of the cert's public key, and remember it */ pubKey = CERT_ExtractPublicKey(cert); if (!pubKey) - goto loser; - sc->serverKeyBits = SECKEY_PublicKeyStrengthInBits(pubKey); - } - - - /* load the server cert chain */ - if (sc->serverCertChain != NULL) { - CERT_DestroyCertificateList(sc->serverCertChain); - sc->serverCertChain = NULL; - } - if (cert) { - sc->serverCertChain = CERT_CertChainFromCert( - sc->serverCert, certUsageSSLServer, PR_TRUE); - if (sc->serverCertChain == NULL) - goto loser; + return SECFailure; } - /* load the private key */ - if (sc->serverKeyPair != NULL) { - ssl3_FreeKeyPair(sc->serverKeyPair); - sc->serverKeyPair = NULL; - } if (key) { SECKEYPrivateKey * keyCopy = NULL; CK_MECHANISM_TYPE keyMech = CKM_INVALID_MECHANISM; @@ -770,51 +815,34 @@ SSL_ConfigSecureServer(PRFileDesc *fd, CERTCertificate *cert, keyCopy = SECKEY_CopyPrivateKey(key); if (keyCopy == NULL) goto loser; - SECKEY_CacheStaticFlags(keyCopy); - sc->serverKeyPair = ssl3_NewKeyPair(keyCopy, pubKey); - if (sc->serverKeyPair == NULL) { + keyPair = ssl3_NewKeyPair(keyCopy, pubKey); + if (keyPair == NULL) { SECKEY_DestroyPrivateKey(keyCopy); goto loser; } pubKey = NULL; /* adopted by serverKeyPair */ } - - if (kea == kt_rsa && cert && sc->serverKeyBits > 512) { - if (ss->opt.noStepDown) { - /* disable all export ciphersuites */ - } else { - rv = ssl3_CreateRSAStepDownKeys(ss); - if (rv != SECSuccess) { - return SECFailure; /* err set by ssl3_CreateRSAStepDownKeys */ - } - } + if (ssl_ConfigSecureServer(ss, cert, NULL, + keyPair, kea) == SECFailure) { + goto loser; } /* Only do this once because it's global. */ if (PR_SUCCESS == PR_CallOnceWithArg(&setupServerCAListOnce, &serverCAListSetup, (void *)(ss->dbHandle))) { - return SECSuccess; + rv = SECSuccess; } loser: + if (keyPair) { + ssl3_FreeKeyPair(keyPair); + } if (pubKey) { SECKEY_DestroyPublicKey(pubKey); pubKey = NULL; } - if (sc->serverCert != NULL) { - CERT_DestroyCertificate(sc->serverCert); - sc->serverCert = NULL; - } - if (sc->serverCertChain != NULL) { - CERT_DestroyCertificateList(sc->serverCertChain); - sc->serverCertChain = NULL; - } - if (sc->serverKeyPair != NULL) { - ssl3_FreeKeyPair(sc->serverKeyPair); - sc->serverKeyPair = NULL; - } - return SECFailure; + return rv; } /************************************************************************/ @@ -1241,7 +1269,8 @@ SSL_BadCertHook(PRFileDesc *fd, SSLBadCertHandler f, void *arg) /* * Allow the application to pass the url or hostname into the SSL library - * so that we can do some checking on it. + * so that we can do some checking on it. It will be used for the value in + * SNI extension of client hello message. */ SECStatus SSL_SetURL(PRFileDesc *fd, const char *url) @@ -1273,6 +1302,46 @@ SSL_SetURL(PRFileDesc *fd, const char *url) } /* + * Allow the application to pass the set of trust anchors + */ +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; + + if (!certList) { + PORT_SetError(SEC_ERROR_INVALID_ARGS); + return SECFailure; + } + if (!ss) { + SSL_DBG(("%d: SSL[%d]: bad socket in SSL_SetTrustAnchors", + SSL_GETPID(), fd)); + return SECFailure; + } + + names = CERT_DistNamesFromCertList(certList); + if (names == NULL) { + return SECFailure; + } + ssl_Get1stHandshakeLock(ss); + ssl_GetSSL3HandshakeLock(ss); + if (ss->ssl3.ca_list) { + CERT_FreeDistNames(ss->ssl3.ca_list); + } + ss->ssl3.ca_list = names; + ssl_ReleaseSSL3HandshakeLock(ss); + ssl_Release1stHandshakeLock(ss); + + return SECSuccess; +#endif +} + +/* ** Returns Negative number on error, zero or greater on success. ** Returns the amount of data immediately available to be read. */ @@ -1440,3 +1509,22 @@ SSL_RestartHandshakeAfterServerCert(sslSocket *ss) ssl_Release1stHandshakeLock(ss); return rv; } + +/* For more info see ssl.h */ +SECStatus +SSL_SNISocketConfigHook(PRFileDesc *fd, SSLSNISocketConfig func, + void *arg) +{ + sslSocket *ss; + + ss = ssl_FindSocket(fd); + if (!ss) { + SSL_DBG(("%d: SSL[%d]: bad socket in SNISocketConfigHook", + SSL_GETPID(), fd)); + return SECFailure; + } + + ss->sniSocketConfig = func; + ss->sniSocketConfigArg = arg; + return SECSuccess; +} diff --git a/net/third_party/nss/ssl/sslsnce.c b/net/third_party/nss/ssl/sslsnce.c index 115766c..5658dc2 100644 --- a/net/third_party/nss/ssl/sslsnce.c +++ b/net/third_party/nss/ssl/sslsnce.c @@ -36,7 +36,7 @@ * the terms of any one of the MPL, the GPL or the LGPL. * * ***** END LICENSE BLOCK ***** */ -/* $Id: sslsnce.c,v 1.51 2009/11/07 18:23:06 wtc%google.com Exp $ */ +/* $Id: sslsnce.c,v 1.52 2010/01/14 22:15:25 alexei.volkov.bugs%sun.com Exp $ */ /* Note: ssl_FreeSID() in sslnonce.c gets used for both client and server * cache sids! @@ -71,6 +71,8 @@ * encKeyCacheEntry ticketEncKey; // Wrapped in non-bypass mode * encKeyCacheEntry ticketMacKey; // Wrapped in non-bypass mode * PRBool ticketKeysValid; + * sidCacheLock srvNameCacheLock; + * srvNameCacheEntry srvNameData[ numSrvNameCacheEntries ]; * } cacheMemCacheData; */ #include "seccomon.h" @@ -84,6 +86,7 @@ #include "pk11func.h" #include "base64.h" #include "keyhi.h" +#include "blapi.h" #include <stdio.h> @@ -150,10 +153,12 @@ struct sidCacheEntryStr { /* 4 */ PRUint32 masterWrapMech; /* 4 */ SSL3KEAType exchKeyType; /* 4 */ PRInt32 certIndex; -/*116 */} ssl3; +/* 4 */ PRInt32 srvNameIndex; +/* 32 */ PRUint8 srvNameHash[SHA256_LENGTH]; /* SHA256 name hash */ +/*152 */} ssl3; /* force sizeof(sidCacheEntry) to be a multiple of cache line size */ struct { -/*120 */ PRUint8 filler[120]; /* 72+120==196, a multiple of 16 */ +/*152 */ PRUint8 filler[120]; /* 72+152==224, a multiple of 16 */ } forceSize; } u; }; @@ -186,6 +191,18 @@ struct encKeyCacheEntryStr { }; typedef struct encKeyCacheEntryStr encKeyCacheEntry; +#define SSL_MAX_DNS_HOST_NAME 1024 + +struct srvNameCacheEntryStr { + PRUint16 type; /* 2 */ + PRUint16 nameLen; /* 2 */ + PRUint8 name[SSL_MAX_DNS_HOST_NAME + 12]; /* 1034 */ + PRUint8 nameHash[SHA256_LENGTH]; /* 32 */ + /* 1072 */ +}; +typedef struct srvNameCacheEntryStr srvNameCacheEntry; + + struct cacheDescStr { PRUint32 cacheMemSize; @@ -203,6 +220,9 @@ struct cacheDescStr { PRUint32 numKeyCacheEntries; PRUint32 keyCacheSize; + PRUint32 numSrvNameCacheEntries; + PRUint32 srvNameCacheSize; + PRUint32 ssl2Timeout; PRUint32 ssl3Timeout; @@ -218,6 +238,7 @@ struct cacheDescStr { sidCacheLock * sidCacheLocks; sidCacheLock * keyCacheLock; sidCacheLock * certCacheLock; + sidCacheLock * srvNameCacheLock; sidCacheSet * sidCacheSets; sidCacheEntry * sidCacheData; certCacheEntry * certCacheData; @@ -226,6 +247,7 @@ struct cacheDescStr { encKeyCacheEntry * ticketEncKey; encKeyCacheEntry * ticketMacKey; PRUint32 * ticketKeysValid; + srvNameCacheEntry * srvNameCacheData; /* Only the private copies of these pointers are valid */ char * cacheMem; @@ -248,6 +270,7 @@ static PRBool isMultiProcess = PR_FALSE; #define DEF_CERT_CACHE_ENTRIES 250 #define MIN_CERT_CACHE_ENTRIES 125 /* the effective size in old releases. */ #define DEF_KEY_CACHE_ENTRIES 250 +#define DEF_NAME_CACHE_ENTRIES 1000 #define SID_CACHE_ENTRIES_PER_SET 128 #define SID_ALIGNMENT 16 @@ -394,6 +417,59 @@ CacheCert(cacheDesc * cache, CERTCertificate *cert, sidCacheEntry *sce) } +/* Server configuration hash tables need to account the SECITEM.type + * field as well. These functions accomplish that. */ +static PLHashNumber +Get32BitNameHash(const SECItem *name) +{ + PLHashNumber rv = SECITEM_Hash(name); + + PRUint8 *rvc = (PRUint8 *)&rv; + rvc[ name->len % sizeof(rv) ] ^= name->type; + + return rv; +} + +/* Put a name in the cache. Update the cert index in the sce. +*/ +static PRUint32 +CacheSrvName(cacheDesc * cache, SECItem *name, sidCacheEntry *sce) +{ + PRUint32 now; + PRUint32 ndx; + srvNameCacheEntry snce; + + if (!name || name->len <= 0 || + name->len > SSL_MAX_DNS_HOST_NAME) { + PORT_SetError(SEC_ERROR_INVALID_ARGS); + return 0; + } + + snce.type = name->type; + snce.nameLen = name->len; + PORT_Memcpy(snce.name, name->data, snce.nameLen); + SHA256_HashBuf(snce.nameHash, (unsigned char*)name->data, + name->len); + /* get index of the next name */ + ndx = Get32BitNameHash(name); + /* get lock on cert cache */ + now = LockSidCacheLock(cache->srvNameCacheLock, 0); + if (now) { + if (cache->numSrvNameCacheEntries > 0) { + /* Fit the index into array */ + ndx %= cache->numSrvNameCacheEntries; + /* write the entry */ + cache->srvNameCacheData[ndx] = snce; + /* remember where we put it. */ + sce->u.ssl3.srvNameIndex = ndx; + /* Copy hash into sid hash */ + PORT_Memcpy(sce->u.ssl3.srvNameHash, snce.nameHash, SHA256_LENGTH); + } + UnlockSidCacheLock(cache->srvNameCacheLock); + } + return now; +} + /* ** Convert local SID to shared memory one */ @@ -454,6 +530,7 @@ ConvertFromSID(sidCacheEntry *to, sslSessionID *from) to->u.ssl3.exchKeyType = from->u.ssl3.exchKeyType; to->sessionIDLength = from->u.ssl3.sessionIDLength; to->u.ssl3.certIndex = -1; + to->u.ssl3.srvNameIndex = -1; PORT_Memcpy(to->sessionID, from->u.ssl3.sessionID, to->sessionIDLength); @@ -472,7 +549,9 @@ ConvertFromSID(sidCacheEntry *to, sslSessionID *from) ** Caller must hold cache lock when calling this. */ static sslSessionID * -ConvertToSID(sidCacheEntry *from, certCacheEntry *pcce, +ConvertToSID(sidCacheEntry * from, + certCacheEntry * pcce, + srvNameCacheEntry *psnce, CERTCertDBHandle * dbHandle) { sslSessionID *to; @@ -526,6 +605,17 @@ ConvertToSID(sidCacheEntry *from, certCacheEntry *pcce, to->u.ssl3.keys = from->u.ssl3.keys; to->u.ssl3.masterWrapMech = from->u.ssl3.masterWrapMech; to->u.ssl3.exchKeyType = from->u.ssl3.exchKeyType; + if (from->u.ssl3.srvNameIndex != -1 && psnce) { + SECItem name; + SECStatus rv; + name.type = psnce->type; + name.len = psnce->nameLen; + name.data = psnce->name; + rv = SECITEM_CopyItem(NULL, &to->u.ssl3.srvName, &name); + if (rv != SECSuccess) { + goto loser; + } + } PORT_Memcpy(to->u.ssl3.sessionID, from->sessionID, from->sessionIDLength); @@ -582,7 +672,9 @@ ConvertToSID(sidCacheEntry *from, certCacheEntry *pcce, PORT_Free(to->u.ssl2.masterKey.data); if (to->u.ssl2.cipherArg.data) PORT_Free(to->u.ssl2.cipherArg.data); - } + } else { + SECITEM_FreeItem(&to->u.ssl3.srvName, PR_FALSE); + } PORT_Free(to); } return NULL; @@ -682,12 +774,14 @@ ServerSessionIDLookup(const PRIPv6Addr *addr, sslSessionID * sid = 0; sidCacheEntry * psce; certCacheEntry *pcce = 0; + srvNameCacheEntry *psnce = 0; cacheDesc * cache = &globalCache; PRUint32 now; PRUint32 set; PRInt32 cndx; sidCacheEntry sce; certCacheEntry cce; + srvNameCacheEntry snce; set = SIDindex(cache, addr, sessionID, sessionIDLength); now = LockSet(cache, set, 0); @@ -696,36 +790,65 @@ ServerSessionIDLookup(const PRIPv6Addr *addr, psce = FindSID(cache, set, now, addr, sessionID, sessionIDLength); if (psce) { - if (psce->version >= SSL_LIBRARY_VERSION_3_0 && - (cndx = psce->u.ssl3.certIndex) != -1) { - - PRUint32 gotLock = LockSidCacheLock(cache->certCacheLock, now); - if (gotLock) { - pcce = &cache->certCacheData[cndx]; - - /* See if the cert's session ID matches the sce cache. */ - if ((pcce->sessionIDLength == psce->sessionIDLength) && - !PORT_Memcmp(pcce->sessionID, psce->sessionID, - pcce->sessionIDLength)) { - cce = *pcce; - } else { - /* The cert doesen't match the SID cache entry, - ** so invalidate the SID cache entry. - */ - psce->valid = 0; - psce = 0; - pcce = 0; - } - UnlockSidCacheLock(cache->certCacheLock); - } else { - /* what the ??. Didn't get the cert cache lock. - ** Don't invalidate the SID cache entry, but don't find it. - */ - PORT_Assert(!("Didn't get cert Cache Lock!")); - psce = 0; - pcce = 0; - } - } + if (psce->version >= SSL_LIBRARY_VERSION_3_0) { + if ((cndx = psce->u.ssl3.certIndex) != -1) { + + PRUint32 gotLock = LockSidCacheLock(cache->certCacheLock, now); + if (gotLock) { + pcce = &cache->certCacheData[cndx]; + + /* See if the cert's session ID matches the sce cache. */ + if ((pcce->sessionIDLength == psce->sessionIDLength) && + !PORT_Memcmp(pcce->sessionID, psce->sessionID, + pcce->sessionIDLength)) { + cce = *pcce; + } else { + /* The cert doesen't match the SID cache entry, + ** so invalidate the SID cache entry. + */ + psce->valid = 0; + psce = 0; + pcce = 0; + } + UnlockSidCacheLock(cache->certCacheLock); + } else { + /* what the ??. Didn't get the cert cache lock. + ** Don't invalidate the SID cache entry, but don't find it. + */ + PORT_Assert(!("Didn't get cert Cache Lock!")); + psce = 0; + pcce = 0; + } + } + if ((cndx = psce->u.ssl3.srvNameIndex) != -1) { + PRUint32 gotLock = LockSidCacheLock(cache->srvNameCacheLock, + now); + if (gotLock) { + psnce = &cache->srvNameCacheData[cndx]; + + if (!PORT_Memcmp(psnce->nameHash, psce->u.ssl3.srvNameHash, + SHA256_LENGTH)) { + snce = *psnce; + } else { + /* The name doesen't match the SID cache entry, + ** so invalidate the SID cache entry. + */ + psce->valid = 0; + psce = 0; + psnce = 0; + } + UnlockSidCacheLock(cache->srvNameCacheLock); + } else { + /* what the ??. Didn't get the cert cache lock. + ** Don't invalidate the SID cache entry, but don't find it. + */ + PORT_Assert(!("Didn't get name Cache Lock!")); + psce = 0; + psnce = 0; + } + + } + } if (psce) { psce->lastAccessTime = now; sce = *psce; /* grab a copy while holding the lock */ @@ -736,7 +859,7 @@ ServerSessionIDLookup(const PRIPv6Addr *addr, /* sce conains a copy of the cache entry. ** Convert shared memory format to local format */ - sid = ConvertToSID(&sce, pcce ? &cce : 0, dbHandle); + sid = ConvertToSID(&sce, pcce ? &cce : 0, psnce ? &snce : 0, dbHandle); } return sid; } @@ -796,9 +919,14 @@ ServerSessionIDCache(sslSessionID *sid) ConvertFromSID(&sce, sid); - if ((version >= SSL_LIBRARY_VERSION_3_0) && - (sid->peerCert != NULL)) { - now = CacheCert(cache, sid->peerCert, &sce); + if (version >= SSL_LIBRARY_VERSION_3_0) { + SECItem *name = &sid->u.ssl3.srvName; + if (name->len && name->data) { + now = CacheSrvName(cache, name, &sce); + } + if (sid->peerCert != NULL) { + now = CacheCert(cache, sid->peerCert, &sce); + } } set = SIDindex(cache, &sce.addr, sce.sessionID, sce.sessionIDLength); @@ -924,7 +1052,8 @@ CloseCache(cacheDesc *cache) } static SECStatus -InitCache(cacheDesc *cache, int maxCacheEntries, PRUint32 ssl2_timeout, +InitCache(cacheDesc *cache, int maxCacheEntries, int maxCertCacheEntries, + int maxSrvNameCacheEntries, PRUint32 ssl2_timeout, PRUint32 ssl3_timeout, const char *directory, PRBool shared) { ptrdiff_t ptr; @@ -973,6 +1102,11 @@ InitCache(cacheDesc *cache, int maxCacheEntries, PRUint32 ssl2_timeout, cache->numSIDCacheSetsPerLock = SID_HOWMANY(cache->numSIDCacheSets, cache->numSIDCacheLocks); + cache->numCertCacheEntries = (maxCertCacheEntries > 0) ? + maxCertCacheEntries : 0; + cache->numSrvNameCacheEntries = (maxSrvNameCacheEntries > 0) ? + maxSrvNameCacheEntries : 0; + /* compute size of shared memory, and offsets of all pointers */ ptr = 0; cache->cacheMem = (char *)ptr; @@ -981,7 +1115,8 @@ InitCache(cacheDesc *cache, int maxCacheEntries, PRUint32 ssl2_timeout, cache->sidCacheLocks = (sidCacheLock *)ptr; cache->keyCacheLock = cache->sidCacheLocks + cache->numSIDCacheLocks; cache->certCacheLock = cache->keyCacheLock + 1; - ptr = (ptrdiff_t)(cache->certCacheLock + 1); + cache->srvNameCacheLock = cache->certCacheLock + 1; + ptr = (ptrdiff_t)(cache->srvNameCacheLock + 1); ptr = SID_ROUNDUP(ptr, SID_ALIGNMENT); cache->sidCacheSets = (sidCacheSet *)ptr; @@ -996,10 +1131,12 @@ InitCache(cacheDesc *cache, int maxCacheEntries, PRUint32 ssl2_timeout, cache->sidCacheSize = (char *)cache->certCacheData - (char *)cache->sidCacheData; - /* This is really a poor way to computer this! */ - cache->numCertCacheEntries = cache->sidCacheSize / sizeof(certCacheEntry); - if (cache->numCertCacheEntries < MIN_CERT_CACHE_ENTRIES) + if (cache->numCertCacheEntries < MIN_CERT_CACHE_ENTRIES) { + /* This is really a poor way to computer this! */ + cache->numCertCacheEntries = cache->sidCacheSize / sizeof(certCacheEntry); + if (cache->numCertCacheEntries < MIN_CERT_CACHE_ENTRIES) cache->numCertCacheEntries = MIN_CERT_CACHE_ENTRIES; + } ptr = (ptrdiff_t)(cache->certCacheData + cache->numCertCacheEntries); ptr = SID_ROUNDUP(ptr, SID_ALIGNMENT); @@ -1030,6 +1167,15 @@ InitCache(cacheDesc *cache, int maxCacheEntries, PRUint32 ssl2_timeout, ptr = (ptrdiff_t)(cache->ticketKeysValid + 1); ptr = SID_ROUNDUP(ptr, SID_ALIGNMENT); + cache->srvNameCacheData = (srvNameCacheEntry *)ptr; + if (cache->numSrvNameCacheEntries < 0) { + cache->numSrvNameCacheEntries = DEF_NAME_CACHE_ENTRIES; + } + cache->srvNameCacheSize = + cache->numSrvNameCacheEntries * sizeof(srvNameCacheEntry); + ptr = (ptrdiff_t)(cache->srvNameCacheData + cache->numSrvNameCacheEntries); + ptr = SID_ROUNDUP(ptr, SID_ALIGNMENT); + cache->cacheMemSize = ptr; if (ssl2_timeout) { @@ -1113,6 +1259,7 @@ InitCache(cacheDesc *cache, int maxCacheEntries, PRUint32 ssl2_timeout, *(ptrdiff_t *)(&cache->sidCacheLocks) += ptr; *(ptrdiff_t *)(&cache->keyCacheLock ) += ptr; *(ptrdiff_t *)(&cache->certCacheLock) += ptr; + *(ptrdiff_t *)(&cache->srvNameCacheLock) += ptr; *(ptrdiff_t *)(&cache->sidCacheSets ) += ptr; *(ptrdiff_t *)(&cache->sidCacheData ) += ptr; *(ptrdiff_t *)(&cache->certCacheData) += ptr; @@ -1121,11 +1268,12 @@ InitCache(cacheDesc *cache, int maxCacheEntries, PRUint32 ssl2_timeout, *(ptrdiff_t *)(&cache->ticketEncKey ) += ptr; *(ptrdiff_t *)(&cache->ticketMacKey ) += ptr; *(ptrdiff_t *)(&cache->ticketKeysValid) += ptr; + *(ptrdiff_t *)(&cache->srvNameCacheData) += ptr; /* initialize the locks */ init_time = ssl_Time(); pLock = cache->sidCacheLocks; - for (locks_to_initialize = cache->numSIDCacheLocks + 2; + for (locks_to_initialize = cache->numSIDCacheLocks + 3; locks_initialized < locks_to_initialize; ++locks_initialized, ++pLock ) { @@ -1170,23 +1318,28 @@ SSL_SetMaxServerCacheLocks(PRUint32 maxLocks) return SECSuccess; } -SECStatus -SSL_ConfigServerSessionIDCacheInstance( cacheDesc *cache, - int maxCacheEntries, - PRUint32 ssl2_timeout, - PRUint32 ssl3_timeout, - const char * directory, PRBool shared) +static SECStatus +ssl_ConfigServerSessionIDCacheInstanceWithOpt(cacheDesc *cache, + PRUint32 ssl2_timeout, + PRUint32 ssl3_timeout, + const char * directory, + PRBool shared, + int maxCacheEntries, + int maxCertCacheEntries, + int maxSrvNameCacheEntries) { SECStatus rv; - PORT_Assert(sizeof(sidCacheEntry) == 192); + PORT_Assert(sizeof(sidCacheEntry) == 224); PORT_Assert(sizeof(certCacheEntry) == 4096); + PORT_Assert(sizeof(srvNameCacheEntry) == 1072); myPid = SSL_GETPID(); if (!directory) { directory = DEFAULT_CACHE_DIRECTORY; } - rv = InitCache(cache, maxCacheEntries, ssl2_timeout, ssl3_timeout, + rv = InitCache(cache, maxCacheEntries, maxCertCacheEntries, + maxSrvNameCacheEntries, ssl2_timeout, ssl3_timeout, directory, shared); if (rv) { SET_ERROR_CODE @@ -1200,6 +1353,22 @@ SSL_ConfigServerSessionIDCacheInstance( cacheDesc *cache, } SECStatus +SSL_ConfigServerSessionIDCacheInstance( cacheDesc *cache, + int maxCacheEntries, + PRUint32 ssl2_timeout, + PRUint32 ssl3_timeout, + const char * directory, PRBool shared) +{ + return ssl_ConfigServerSessionIDCacheInstanceWithOpt(cache, + ssl2_timeout, + ssl3_timeout, + directory, + shared, + maxCacheEntries, + -1, -1); +} + +SECStatus SSL_ConfigServerSessionIDCache( int maxCacheEntries, PRUint32 ssl2_timeout, PRUint32 ssl3_timeout, @@ -1231,11 +1400,13 @@ SSL_ShutdownServerSessionIDCache(void) /* Use this function, instead of SSL_ConfigServerSessionIDCache, * if the cache will be shared by multiple processes. */ -SECStatus -SSL_ConfigMPServerSIDCache( int maxCacheEntries, - PRUint32 ssl2_timeout, - PRUint32 ssl3_timeout, - const char * directory) +static SECStatus +ssl_ConfigMPServerSIDCacheWithOpt( PRUint32 ssl2_timeout, + PRUint32 ssl3_timeout, + const char * directory, + int maxCacheEntries, + int maxCertCacheEntries, + int maxSrvNameCacheEntries) { char * envValue; char * inhValue; @@ -1248,8 +1419,9 @@ SSL_ConfigMPServerSIDCache( int maxCacheEntries, char fmString[PR_FILEMAP_STRING_BUFSIZE]; isMultiProcess = PR_TRUE; - result = SSL_ConfigServerSessionIDCacheInstance(cache, maxCacheEntries, - ssl2_timeout, ssl3_timeout, directory, PR_TRUE); + result = ssl_ConfigServerSessionIDCacheInstanceWithOpt(cache, + ssl2_timeout, ssl3_timeout, directory, PR_TRUE, + maxCacheEntries, maxCacheEntries, maxSrvNameCacheEntries); if (result != SECSuccess) return result; @@ -1289,6 +1461,44 @@ SSL_ConfigMPServerSIDCache( int maxCacheEntries, return result; } +/* Use this function, instead of SSL_ConfigServerSessionIDCache, + * if the cache will be shared by multiple processes. + */ +SECStatus +SSL_ConfigMPServerSIDCache( int maxCacheEntries, + PRUint32 ssl2_timeout, + PRUint32 ssl3_timeout, + const char * directory) +{ + return ssl_ConfigMPServerSIDCacheWithOpt(ssl2_timeout, + ssl3_timeout, + directory, + maxCacheEntries, + -1, -1); +} + +SECStatus +SSL_ConfigServerSessionIDCacheWithOpt( + PRUint32 ssl2_timeout, + PRUint32 ssl3_timeout, + const char * directory, + int maxCacheEntries, + int maxCertCacheEntries, + int maxSrvNameCacheEntries, + PRBool enableMPCache) +{ + if (!enableMPCache) { + ssl_InitSessionCacheLocks(PR_FALSE); + return ssl_ConfigServerSessionIDCacheInstanceWithOpt(&globalCache, + ssl2_timeout, ssl3_timeout, directory, PR_FALSE, + maxCacheEntries, maxCertCacheEntries, maxSrvNameCacheEntries); + } else { + return ssl_ConfigMPServerSIDCacheWithOpt(ssl2_timeout, ssl3_timeout, + directory, maxCacheEntries, maxCertCacheEntries, + maxSrvNameCacheEntries); + } +} + SECStatus SSL_InheritMPServerSIDCacheInstance(cacheDesc *cache, const char * envString) { @@ -1391,6 +1601,7 @@ SSL_InheritMPServerSIDCacheInstance(cacheDesc *cache, const char * envString) *(ptrdiff_t *)(&cache->sidCacheLocks) += ptr; *(ptrdiff_t *)(&cache->keyCacheLock ) += ptr; *(ptrdiff_t *)(&cache->certCacheLock) += ptr; + *(ptrdiff_t *)(&cache->srvNameCacheLock) += ptr; *(ptrdiff_t *)(&cache->sidCacheSets ) += ptr; *(ptrdiff_t *)(&cache->sidCacheData ) += ptr; *(ptrdiff_t *)(&cache->certCacheData) += ptr; @@ -1399,6 +1610,7 @@ SSL_InheritMPServerSIDCacheInstance(cacheDesc *cache, const char * envString) *(ptrdiff_t *)(&cache->ticketEncKey ) += ptr; *(ptrdiff_t *)(&cache->ticketMacKey ) += ptr; *(ptrdiff_t *)(&cache->ticketKeysValid) += ptr; + *(ptrdiff_t *)(&cache->srvNameCacheData) += ptr; cache->cacheMemMap = my.cacheMemMap; cache->cacheMem = my.cacheMem; @@ -1420,7 +1632,7 @@ SSL_InheritMPServerSIDCacheInstance(cacheDesc *cache, const char * envString) /* note from jpierre : this should be free'd in child processes when ** a function is added to delete the SSL session cache in the future. */ - locks_to_initialize = cache->numSIDCacheLocks + 2; + locks_to_initialize = cache->numSIDCacheLocks + 3; newLocks = PORT_NewArray(sidCacheLock, locks_to_initialize); if (!newLocks) goto loser; @@ -1443,6 +1655,7 @@ SSL_InheritMPServerSIDCacheInstance(cacheDesc *cache, const char * envString) /* also fix the key and cert cache which use the last 2 lock entries */ cache->keyCacheLock = cache->sidCacheLocks + cache->numSIDCacheLocks; cache->certCacheLock = cache->keyCacheLock + 1; + cache->srvNameCacheLock = cache->certCacheLock + 1; #endif PORT_Free(myEnvString); diff --git a/net/third_party/nss/ssl/sslsock.c b/net/third_party/nss/ssl/sslsock.c index 2275800..722fe60 100644 --- a/net/third_party/nss/ssl/sslsock.c +++ b/net/third_party/nss/ssl/sslsock.c @@ -40,7 +40,7 @@ * the terms of any one of the MPL, the GPL or the LGPL. * * ***** END LICENSE BLOCK ***** */ -/* $Id: sslsock.c,v 1.60 2009/11/25 05:24:25 wtc%google.com Exp $ */ +/* $Id: sslsock.c,v 1.64 2010/01/28 06:19:13 nelson%bolyard.com Exp $ */ #include "seccomon.h" #include "cert.h" #include "keyhi.h" @@ -182,7 +182,7 @@ static sslOptions ssl_defaults = { PR_FALSE, /* noLocks */ PR_FALSE, /* enableSessionTickets */ PR_FALSE, /* enableDeflate */ - 0, /* enableRenegotiation (default: never) */ + 2, /* enableRenegotiation (default: requires extension) */ PR_FALSE, /* requireSafeNegotiation */ }; @@ -199,6 +199,7 @@ int ssl_lock_readers = 1; /* default true. */ char ssl_debug; char ssl_trace; FILE * ssl_trace_iob; +FILE * ssl_keylog_iob; char lockStatus[] = "Locks are ENABLED. "; #define LOCKSTATUS_OFFSET 10 /* offset of ENABLED */ @@ -305,7 +306,7 @@ ssl_DupSocket(sslSocket *os) int i; sslServerCerts * oc = os->serverCerts; sslServerCerts * sc = ss->serverCerts; - + for (i=kt_null; i < kt_kea_size; i++, oc++, sc++) { if (oc->serverCert && oc->serverCertChain) { sc->serverCert = CERT_DupCertificate(oc->serverCert); @@ -334,6 +335,8 @@ ssl_DupSocket(sslSocket *os) ss->authCertificateArg = os->authCertificateArg; ss->getClientAuthData = os->getClientAuthData; ss->getClientAuthDataArg = os->getClientAuthDataArg; + ss->sniSocketConfig = os->sniSocketConfig; + ss->sniSocketConfigArg = os->sniSocketConfigArg; ss->handleBadCert = os->handleBadCert; ss->badCertArg = os->badCertArg; ss->handshakeCallback = os->handshakeCallback; @@ -439,6 +442,11 @@ ssl_DestroySocketContents(sslSocket *ss) 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); + ss->xtnData.sniNameArr = NULL; + } } /* @@ -1321,6 +1329,119 @@ SSL_GetNextProto(PRFileDesc *fd, int *state, unsigned char *buf, 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; + sslServerCerts * sc = ss->serverCerts; + + if (model == NULL) { + PR_SetError(SEC_ERROR_INVALID_ARGS, 0); + return NULL; + } + sm = ssl_FindSocket(model); + if (sm == NULL) { + SSL_DBG(("%d: SSL[%d]: bad model socket in ssl_ReconfigFD", + SSL_GETPID(), model)); + return NULL; + } + ss = ssl_FindSocket(fd); + PORT_Assert(ss); + if (ss == NULL) { + PORT_SetError(SEC_ERROR_INVALID_ARGS); + return NULL; + } + + ss->opt = sm->opt; + PORT_Memcpy(ss->cipherSuites, sm->cipherSuites, sizeof sm->cipherSuites); + + if (!ss->opt.useSecurity) { + PORT_SetError(SEC_ERROR_INVALID_ARGS); + return NULL; + } + /* This int should be SSLKEAType, but CC on Irix complains, + * during the for loop. + */ + for (i=kt_null; i < kt_kea_size; i++, mc++, sc++) { + if (mc->serverCert && mc->serverCertChain) { + if (sc->serverCert) { + CERT_DestroyCertificate(sc->serverCert); + } + sc->serverCert = CERT_DupCertificate(mc->serverCert); + if (sc->serverCertChain) { + CERT_DestroyCertificateList(sc->serverCertChain); + } + sc->serverCertChain = CERT_DupCertList(mc->serverCertChain); + if (!sc->serverCertChain) + goto loser; + } + if (mc->serverKeyPair) { + if (sc->serverKeyPair) { + ssl3_FreeKeyPair(sc->serverKeyPair); + } + sc->serverKeyPair = ssl3_GetKeyPairRef(mc->serverKeyPair); + sc->serverKeyBits = mc->serverKeyBits; + } + } + if (sm->stepDownKeyPair) { + if (ss->stepDownKeyPair) { + ssl3_FreeKeyPair(ss->stepDownKeyPair); + } + ss->stepDownKeyPair = ssl3_GetKeyPairRef(sm->stepDownKeyPair); + } + if (sm->ephemeralECDHKeyPair) { + if (ss->ephemeralECDHKeyPair) { + ssl3_FreeKeyPair(ss->ephemeralECDHKeyPair); + } + ss->ephemeralECDHKeyPair = + ssl3_GetKeyPairRef(sm->ephemeralECDHKeyPair); + } + /* copy trust anchor names */ + if (sm->ssl3.ca_list) { + if (ss->ssl3.ca_list) { + CERT_FreeDistNames(ss->ssl3.ca_list); + } + ss->ssl3.ca_list = CERT_DupDistNames(sm->ssl3.ca_list); + if (!ss->ssl3.ca_list) { + goto loser; + } + } + + if (sm->authCertificate) + ss->authCertificate = sm->authCertificate; + if (sm->authCertificateArg) + ss->authCertificateArg = sm->authCertificateArg; + if (sm->getClientAuthData) + ss->getClientAuthData = sm->getClientAuthData; + if (sm->getClientAuthDataArg) + ss->getClientAuthDataArg = sm->getClientAuthDataArg; + if (sm->sniSocketConfig) + ss->sniSocketConfig = sm->sniSocketConfig; + if (sm->sniSocketConfigArg) + ss->sniSocketConfigArg = sm->sniSocketConfigArg; + if (sm->handleBadCert) + ss->handleBadCert = sm->handleBadCert; + if (sm->badCertArg) + ss->badCertArg = sm->badCertArg; + if (sm->handshakeCallback) + ss->handshakeCallback = sm->handshakeCallback; + if (sm->handshakeCallbackData) + ss->handshakeCallbackData = sm->handshakeCallbackData; + if (sm->pkcs11PinArg) + ss->pkcs11PinArg = sm->pkcs11PinArg; + return fd; +loser: + return NULL; +#endif +} + /************************************************************************/ /* The following functions are the TOP LEVEL SSL functions. ** They all get called through the NSPRIOMethods table below. @@ -2223,6 +2344,15 @@ ssl_NewSocket(PRBool makeLocks) ssl_trace = atoi(ev); SSL_TRACE(("SSL: tracing set to %d", ssl_trace)); } + ev = getenv("SSLKEYLOGFILE"); + if (ev && ev[0]) { + ssl_keylog_iob = fopen(ev, "a"); + if (ftell(ssl_keylog_iob) == 0) { + fputs("# pre-master secret log file, generated by NSS\n", + ssl_keylog_iob); + } + SSL_TRACE(("SSL: logging pre-master secrets to %s", ev)); + } #endif /* TRACE */ ev = getenv("SSLDEBUG"); if (ev && ev[0]) { @@ -2247,19 +2377,12 @@ ssl_NewSocket(PRBool makeLocks) if (ev) { if (ev[0] == '1' || LOWER(ev[0]) == 'u') ssl_defaults.enableRenegotiation = SSL_RENEGOTIATE_UNRESTRICTED; -#ifdef LATER - /* When SSL_RENEGOTIATE_REQUIRES_XTN is implemented, it will be - * the default. Until then, NEVER will be the default. - */ else if (ev[0] == '0' || LOWER(ev[0]) == 'n') ssl_defaults.enableRenegotiation = SSL_RENEGOTIATE_NEVER; + else if (ev[0] == '3' || LOWER(ev[0]) == 'c') + ssl_defaults.enableRenegotiation = SSL_RENEGOTIATE_CLIENT_ONLY; else ssl_defaults.enableRenegotiation = SSL_RENEGOTIATE_REQUIRES_XTN; -#else - else - ssl_defaults.enableRenegotiation = SSL_RENEGOTIATE_NEVER; -#endif - SSL_TRACE(("SSL: enableRenegotiation set to %d", ssl_defaults.enableRenegotiation)); } @@ -2309,6 +2432,8 @@ ssl_NewSocket(PRBool makeLocks) /* Provide default implementation of hooks */ ss->authCertificate = SSL_AuthCertificate; ss->authCertificateArg = (void *)ss->dbHandle; + ss->sniSocketConfig = NULL; + ss->sniSocketConfigArg = NULL; ss->getClientAuthData = NULL; ss->handleBadCert = NULL; ss->badCertArg = NULL; diff --git a/net/third_party/nss/ssl/sslt.h b/net/third_party/nss/ssl/sslt.h index 80f1dc2..f6e0b62 100644 --- a/net/third_party/nss/ssl/sslt.h +++ b/net/third_party/nss/ssl/sslt.h @@ -37,7 +37,7 @@ * the terms of any one of the MPL, the GPL or the LGPL. * * ***** END LICENSE BLOCK ***** */ -/* $Id: sslt.h,v 1.13 2009/11/07 18:23:06 wtc%google.com Exp $ */ +/* $Id: sslt.h,v 1.16 2010/02/04 03:21:11 wtc%google.com Exp $ */ #ifndef __sslt_h_ #define __sslt_h_ @@ -189,4 +189,24 @@ typedef struct SSLCipherSuiteInfoStr { } SSLCipherSuiteInfo; +typedef enum { + SSL_sni_host_name = 0, + SSL_sni_type_total +} SSLSniNameType; + +/* Supported extensions. */ +/* Update SSL_MAX_EXTENSIONS whenever a new extension type is added. */ +typedef enum { + ssl_server_name_xtn = 0, +#ifdef NSS_ENABLE_ECC + ssl_elliptic_curves_xtn = 10, + 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 6 + #endif /* __sslt_h_ */ |