summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--base/nss_init.cc4
-rw-r--r--build/linux/system.gyp3
-rw-r--r--net/base/ssl_config_service.h11
-rw-r--r--net/base/ssl_info.h20
-rw-r--r--net/flip/flip_session.cc11
-rw-r--r--net/socket/ssl_client_socket_nss.cc43
-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
14 files changed, 383 insertions, 7 deletions
diff --git a/base/nss_init.cc b/base/nss_init.cc
index 24e3203..015adae 100644
--- a/base/nss_init.cc
+++ b/base/nss_init.cc
@@ -115,6 +115,7 @@ class NSSInitSingleton {
NSS_SetDomesticPolicy();
+#if defined(USE_SYSTEM_SSL)
// Use late binding to avoid scary but benign warning
// "Symbol `SSL_ImplementedCiphers' has different size in shared object,
// consider re-linking"
@@ -124,6 +125,9 @@ class NSSInitSingleton {
NOTREACHED() << "Can't get list of supported ciphers";
return;
}
+#else
+#define pSSL_ImplementedCiphers SSL_ImplementedCiphers
+#endif
// Explicitly enable exactly those ciphers with keys of at least 80 bits
for (int i = 0; i < SSL_NumImplementedCiphers; i++) {
diff --git a/build/linux/system.gyp b/build/linux/system.gyp
index 09e420a..eb36588 100644
--- a/build/linux/system.gyp
+++ b/build/linux/system.gyp
@@ -89,6 +89,9 @@
'cflags': [
'<!@(<(pkg-config) --cflags nss)',
],
+ 'defines': [
+ 'USE_SYSTEM_SSL',
+ ],
},
'link_settings': {
'ldflags': [
diff --git a/net/base/ssl_config_service.h b/net/base/ssl_config_service.h
index a4d3cb4..45c1fc6 100644
--- a/net/base/ssl_config_service.h
+++ b/net/base/ssl_config_service.h
@@ -18,7 +18,8 @@ struct SSLConfig {
// Default to SSL 2.0 off, SSL 3.0 on, and TLS 1.0 on.
SSLConfig()
: rev_checking_enabled(true), ssl2_enabled(false), ssl3_enabled(true),
- tls1_enabled(true), send_client_cert(false), verify_ev_cert(false) {
+ tls1_enabled(true), send_client_cert(false), verify_ev_cert(false),
+ next_protos("\007http1.1") {
}
bool rev_checking_enabled; // True if server certificate revocation
@@ -57,6 +58,14 @@ struct SSLConfig {
bool verify_ev_cert; // True if we should verify the certificate for EV.
+ // The list of application level protocols supported. If set, this will
+ // enable Next Protocol Negotiation (if supported). This is a list of 8-bit
+ // length prefixed strings. The order of the protocols doesn't matter expect
+ // for one case: if the server supports Next Protocol Negotiation, but there
+ // is no overlap between the server's and client's protocol sets, then the
+ // first protocol in this list will be requested by the client.
+ std::string next_protos;
+
scoped_refptr<X509Certificate> client_cert;
};
diff --git a/net/base/ssl_info.h b/net/base/ssl_info.h
index 203b6de..5b637c7 100644
--- a/net/base/ssl_info.h
+++ b/net/base/ssl_info.h
@@ -5,6 +5,8 @@
#ifndef NET_BASE_SSL_INFO_H_
#define NET_BASE_SSL_INFO_H_
+#include <string>
+
#include "net/base/cert_status_flags.h"
#include "net/base/x509_certificate.h"
@@ -14,12 +16,25 @@ namespace net {
// This is really a struct. All members are public.
class SSLInfo {
public:
- SSLInfo() : cert_status(0), security_bits(-1) { }
+ // Next Protocol Negotiation (NPN) allows a TLS client and server to come to
+ // an agreement about the application level protocol to speak over a
+ // connection. See also the next_protos field in SSLConfig.
+ enum NextProtoStatus {
+ kNextProtoUnsupported = 0, // The server doesn't support NPN.
+ kNextProtoNegotiated = 1, // We agreed on a protocol, see next_proto
+ kNextProtoNoOverlap = 2, // No protocols in common. We requested
+ // |next_proto|.
+ };
+
+ SSLInfo() : cert_status(0), security_bits(-1),
+ next_proto_status(kNextProtoUnsupported) { }
void Reset() {
cert = NULL;
security_bits = -1;
cert_status = 0;
+ next_proto.clear();
+ next_proto_status = kNextProtoUnsupported;
}
bool is_valid() const { return cert != NULL; }
@@ -41,6 +56,9 @@ class SSLInfo {
// 0 means the connection is not encrypted.
// -1 means the security strength is unknown.
int security_bits;
+
+ NextProtoStatus next_proto_status; // One of kNextProto*
+ std::string next_proto; // The negotiated protocol, if any.
};
} // namespace net
diff --git a/net/flip/flip_session.cc b/net/flip/flip_session.cc
index b1fe38c..31fe46a 100644
--- a/net/flip/flip_session.cc
+++ b/net/flip/flip_session.cc
@@ -181,6 +181,17 @@ FlipSession::FlipSession(const std::string& host, HttpNetworkSession* session)
flip_framer_.set_visitor(this);
session_->ssl_config_service()->GetSSLConfig(&ssl_config_);
+
+ // TODO(agl): This is a temporary hack for testing reasons. In the medium
+ // term we'll want to use NPN for all HTTPS connections and use the protocol
+ // suggested.
+ //
+ // In the event that the server supports Next Protocol Negotiation, but
+ // doesn't support either of these protocols, we'll request the first
+ // protocol in the list. Because of that, HTTP is listed first because it's
+ // what we'll actually fallback to in the case that the server doesn't
+ // support SPDY.
+ ssl_config_.next_protos = "\007http1.1\004spdy";
}
FlipSession::~FlipSession() {
diff --git a/net/socket/ssl_client_socket_nss.cc b/net/socket/ssl_client_socket_nss.cc
index 155d3e5..865c6c6 100644
--- a/net/socket/ssl_client_socket_nss.cc
+++ b/net/socket/ssl_client_socket_nss.cc
@@ -317,6 +317,17 @@ int SSLClientSocketNSS::InitializeSSLOptions() {
LOG(INFO) << "SSL_ENABLE_DEFLATE failed. Old system nss?";
#endif
+#ifdef SSL_NEXT_PROTO_NEGOTIATED
+ if (!ssl_config_.next_protos.empty()) {
+ rv = SSL_SetNextProtoNego(
+ nss_fd_,
+ reinterpret_cast<const unsigned char *>(ssl_config_.next_protos.data()),
+ ssl_config_.next_protos.size());
+ if (rv != SECSuccess)
+ LOG(INFO) << "SSL_SetNextProtoNego failed.";
+ }
+#endif
+
rv = SSL_OptionSet(nss_fd_, SSL_HANDSHAKE_AS_CLIENT, PR_TRUE);
if (rv != SECSuccess)
return ERR_UNEXPECTED;
@@ -510,6 +521,38 @@ void SSLClientSocketNSS::GetSSLInfo(SSLInfo* ssl_info) {
ssl_info->cert_status = server_cert_verify_result_.cert_status;
DCHECK(server_cert_ != NULL);
ssl_info->cert = server_cert_;
+
+#ifdef SSL_NEXT_PROTO_NEGOTIATED
+ unsigned char npn_buf[255];
+ unsigned npn_len;
+ int npn_status;
+ SECStatus rv = SSL_GetNextProto(nss_fd_, &npn_status, npn_buf, &npn_len,
+ sizeof(npn_buf));
+ if (rv != SECSuccess) {
+ npn_status = SSL_NEXT_PROTO_NO_SUPPORT;
+ }
+
+ if (npn_status == SSL_NEXT_PROTO_NO_SUPPORT) {
+ ssl_info->next_proto_status = SSLInfo::kNextProtoUnsupported;
+ ssl_info->next_proto.clear();
+ } else {
+ ssl_info->next_proto =
+ std::string(reinterpret_cast<const char *>(npn_buf), npn_len);
+ switch (npn_status) {
+ case SSL_NEXT_PROTO_NEGOTIATED:
+ ssl_info->next_proto_status = SSLInfo::kNextProtoNegotiated;
+ break;
+ case SSL_NEXT_PROTO_NO_OVERLAP:
+ ssl_info->next_proto_status = SSLInfo::kNextProtoNoOverlap;
+ break;
+ default:
+ LOG(ERROR) << "Unknown npn_status: " << npn_status;
+ ssl_info->next_proto_status = SSLInfo::kNextProtoNoOverlap;
+ break;
+ }
+ }
+#endif
+
LeaveFunction("");
}
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.