summaryrefslogtreecommitdiffstats
path: root/net/third_party
diff options
context:
space:
mode:
authoragl@chromium.org <agl@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2009-11-30 20:40:53 +0000
committeragl@chromium.org <agl@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2009-11-30 20:40:53 +0000
commit644bdcae0edf0cfa3ac9644edf3b52a0d3162489 (patch)
tree64b3ab5519929c10d59e3b58f4415ffdafcde2c8 /net/third_party
parent48f619d8bd9a264f14ce4b62a935e05df015432b (diff)
downloadchromium_src-644bdcae0edf0cfa3ac9644edf3b52a0d3162489.zip
chromium_src-644bdcae0edf0cfa3ac9644edf3b52a0d3162489.tar.gz
chromium_src-644bdcae0edf0cfa3ac9644edf3b52a0d3162489.tar.bz2
Linux: add next-protocol-negotiation to libssl.
This is an experimental, client only implementation of next-protocol-negotiation: http://www.imperialviolet.org/binary/draft-agl-tls-nextprotoneg-00.html This only affects the internal copy of libssl and is only active when built with use_system_ssl=0, which is not currently the default. git-svn-id: svn://svn.chromium.org/chrome/trunk/src@33327 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'net/third_party')
-rw-r--r--net/third_party/nss/README.google5
-rw-r--r--net/third_party/nss/ssl/ssl.def7
-rw-r--r--net/third_party/nss/ssl/ssl.h12
-rw-r--r--net/third_party/nss/ssl/ssl3con.c46
-rw-r--r--net/third_party/nss/ssl/ssl3ext.c122
-rw-r--r--net/third_party/nss/ssl/ssl3prot.h8
-rw-r--r--net/third_party/nss/ssl/sslimpl.h24
-rw-r--r--net/third_party/nss/ssl/sslsock.c74
8 files changed, 293 insertions, 5 deletions
diff --git a/net/third_party/nss/README.google b/net/third_party/nss/README.google
index b0d60f5..63f0bb4 100644
--- a/net/third_party/nss/README.google
+++ b/net/third_party/nss/README.google
@@ -3,7 +3,10 @@ This directory includes a copy of NSS's libssl from the CVS repo at:
The snapshot was taken at Thu Nov 12 17:19:36 PST 2009.
-There are no local patches.
+Patches:
+
+ * Next protocol negotiation support.
+ http://codereview.chromium.org/415005
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/ssl/ssl.def b/net/third_party/nss/ssl/ssl.def
index e4d4d1d..6a11804 100644
--- a/net/third_party/nss/ssl/ssl.def
+++ b/net/third_party/nss/ssl/ssl.def
@@ -139,3 +139,10 @@ SSL_CanBypass;
;+ local:
;+*;
;+};
+;+NSS_CHROMIUM { # Chromium experimental
+;+ global:
+SSL_GetNextProto;
+SSL_SetNextProtoNego;
+;+ local:
+;+*;
+;+};
diff --git a/net/third_party/nss/ssl/ssl.h b/net/third_party/nss/ssl/ssl.h
index 7540796..b3be5fc 100644
--- a/net/third_party/nss/ssl/ssl.h
+++ b/net/third_party/nss/ssl/ssl.h
@@ -135,6 +135,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/net/third_party/nss/ssl/ssl3con.c b/net/third_party/nss/ssl/ssl3con.c
index ff93bf4..f908382 100644
--- a/net/third_party/nss/ssl/ssl3con.c
+++ b/net/third_party/nss/ssl/ssl3con.c
@@ -85,6 +85,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);
@@ -5619,6 +5620,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. */
@@ -7797,6 +7804,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
*/
@@ -9072,6 +9113,11 @@ ssl3_DestroySSL3Info(sslSocket *ss)
ssl3_DestroyCipherSpec(&ss->ssl3.specs[1]);
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/net/third_party/nss/ssl/ssl3ext.c b/net/third_party/nss/ssl/ssl3ext.c
index 21bb818..0365d5a 100644
--- a/net/third_party/nss/ssl/ssl3ext.c
+++ b/net/third_party/nss/ssl/ssl3ext.c
@@ -229,6 +229,7 @@ static const ssl3HelloExtensionHandler clientHelloHandlers[] = {
{ ec_point_formats_xtn, &ssl3_HandleSupportedPointFormatsXtn },
#endif
{ session_ticket_xtn, &ssl3_ServerHandleSessionTicketXtn },
+ { next_proto_neg_xtn, &ssl3_ServerHandleNextProtoNegoXtn },
{ -1, NULL }
};
@@ -236,6 +237,7 @@ 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 },
{ -1, NULL }
};
@@ -254,7 +256,8 @@ ssl3HelloExtensionSender clientHelloSenders[MAX_EXTENSIONS] = {
{ -1, NULL },
{ -1, NULL },
#endif
- { session_ticket_xtn, ssl3_SendSessionTicketXtn }
+ { session_ticket_xtn, ssl3_SendSessionTicketXtn },
+ { next_proto_neg_xtn, ssl3_ClientSendNextProtoNegoXtn }
};
static PRBool
@@ -412,6 +415,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 += 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 += ss->opt.nextProtoNego.data[j] + 1;
+ }
+
+ i += 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, 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++] = 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/net/third_party/nss/ssl/ssl3prot.h b/net/third_party/nss/ssl/ssl3prot.h
index 139af0d..84d73a9 100644
--- a/net/third_party/nss/ssl/ssl3prot.h
+++ b/net/third_party/nss/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 {
@@ -351,10 +352,11 @@ typedef enum {
elliptic_curves_xtn = 10,
ec_point_formats_xtn = 11,
#endif
- session_ticket_xtn = 35
+ session_ticket_xtn = 35,
+ next_proto_neg_xtn = 13172
} ExtensionType;
-#define MAX_EXTENSIONS 4
+#define MAX_EXTENSIONS 5
#define TLS_EX_SESS_TICKET_MAC_LENGTH 32
diff --git a/net/third_party/nss/ssl/sslimpl.h b/net/third_party/nss/ssl/sslimpl.h
index 0b69910..0a7fbcf 100644
--- a/net/third_party/nss/ssl/sslimpl.h
+++ b/net/third_party/nss/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 */
@@ -770,6 +775,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;
@@ -811,6 +817,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 {
@@ -1471,8 +1487,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
@@ -1486,6 +1506,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/net/third_party/nss/ssl/sslsock.c b/net/third_party/nss/ssl/sslsock.c
index c173086..d0a70e5 100644
--- a/net/third_party/nss/ssl/sslsock.c
+++ b/net/third_party/nss/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 */
@@ -434,6 +435,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;
+ }
}
/*
@@ -1247,6 +1252,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;
+}
+
/************************************************************************/
/* The following functions are the TOP LEVEL SSL functions.
** They all get called through the NSPRIOMethods table below.