Bug 547312: Implement client-side support for NPN; original patch by agl r=wtc; changes by bsmith r=agl
git-svn-id: svn://10.0.0.236/trunk@263024 18797224-902f-48f8-a5cc-f745e15eee43
This commit is contained in:
parent
b585bb9ec9
commit
0601ca68ad
@ -405,3 +405,6 @@ ER3(SSL_ERROR_RX_UNEXPECTED_UNCOMPRESSED_RECORD, (SSL_ERROR_BASE + 114),
|
||||
|
||||
ER3(SSL_ERROR_WEAK_SERVER_EPHEMERAL_DH_KEY, (SSL_ERROR_BASE + 115),
|
||||
"SSL received a weak ephemeral Diffie-Hellman key in Server Key Exchange handshake message.")
|
||||
|
||||
ER3(SSL_ERROR_NEXT_PROTOCOL_DATA_INVALID, (SSL_ERROR_BASE + 116),
|
||||
"SSL received invalid NPN extension data.")
|
||||
|
||||
@ -164,3 +164,11 @@ NSSSSL_GetVersion;
|
||||
;+ local:
|
||||
;+ *;
|
||||
;+};
|
||||
;+NSS_3.13.2 { # NSS 3.13.2 release
|
||||
;+ global:
|
||||
SSL_SetNextProtoCallback;
|
||||
SSL_SetNextProtoNego;
|
||||
SSL_GetNextProto;
|
||||
;+ local:
|
||||
;+ *;
|
||||
;+};
|
||||
|
||||
@ -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.44 2011-10-06 22:42:33 wtc%google.com Exp $ */
|
||||
/* $Id: ssl.h,v 1.45 2011-10-29 00:29:11 bsmith%mozilla.com Exp $ */
|
||||
|
||||
#ifndef __ssl_h_
|
||||
#define __ssl_h_
|
||||
@ -181,6 +181,62 @@ 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);
|
||||
|
||||
/* SSLNextProtoCallback is called during the handshake for the client, when a
|
||||
* Next Protocol Negotiation (NPN) extension has been received from the server.
|
||||
* |protos| and |protosLen| define a buffer which contains the server's
|
||||
* advertisement. This data is guaranteed to be well formed per the NPN spec.
|
||||
* |protoOut| is a buffer provided by the caller, of length 255 (the maximum
|
||||
* allowed by the protocol). On successful return, the protocol to be announced
|
||||
* to the server will be in |protoOut| and its length in |*protoOutLen|.
|
||||
*
|
||||
* The callback must return SECFailure or SECSuccess (not SECWouldBlock).
|
||||
*/
|
||||
typedef SECStatus (PR_CALLBACK *SSLNextProtoCallback)(
|
||||
void *arg,
|
||||
PRFileDesc *fd,
|
||||
const unsigned char* protos,
|
||||
unsigned int protosLen,
|
||||
unsigned char* protoOut,
|
||||
unsigned int* protoOutLen,
|
||||
unsigned int protoMaxOut);
|
||||
|
||||
/* SSL_SetNextProtoCallback sets a callback function to handle Next Protocol
|
||||
* Negotiation. It causes a client to advertise NPN. */
|
||||
SSL_IMPORT SECStatus SSL_SetNextProtoCallback(PRFileDesc *fd,
|
||||
SSLNextProtoCallback callback,
|
||||
void *arg);
|
||||
|
||||
/* SSL_SetNextProtoNego can be used as an alternative to
|
||||
* SSL_SetNextProtoCallback. It also causes a client to advertise NPN and
|
||||
* installs a default callback function which selects the first supported
|
||||
* protocol in server-preference order. If no matching protocol is found it
|
||||
* selects the first supported protocol.
|
||||
*
|
||||
* The supported protocols are specified in |data| in wire-format (8-bit
|
||||
* length-prefixed). For example: "\010http/1.1\006spdy/2". */
|
||||
SSL_IMPORT SECStatus SSL_SetNextProtoNego(PRFileDesc *fd,
|
||||
const unsigned char *data,
|
||||
unsigned int length);
|
||||
|
||||
typedef enum SSLNextProtoState {
|
||||
SSL_NEXT_PROTO_NO_SUPPORT = 0, /* No peer support */
|
||||
SSL_NEXT_PROTO_NEGOTIATED = 1, /* Mutual agreement */
|
||||
SSL_NEXT_PROTO_NO_OVERLAP = 2 /* No protocol overlap found */
|
||||
} SSLNextProtoState;
|
||||
|
||||
/* SSL_GetNextProto can be used in the HandshakeCallback or any time after
|
||||
* a handshake to retrieve the result of the Next Protocol negotiation.
|
||||
*
|
||||
* The length of the negotiated protocol, if any, is written into *bufLen.
|
||||
* If the negotiated protocol is longer than bufLenMax, then SECFailure is
|
||||
* returned. Otherwise, the negotiated protocol, if any, is written into buf,
|
||||
* and SECSuccess is returned. */
|
||||
SSL_IMPORT SECStatus SSL_GetNextProto(PRFileDesc *fd,
|
||||
SSLNextProtoState *state,
|
||||
unsigned char *buf,
|
||||
unsigned int *bufLen,
|
||||
unsigned int bufLenMax);
|
||||
|
||||
/*
|
||||
** Control ciphers that SSL uses. If on is non-zero then the named cipher
|
||||
** is enabled, otherwise it is disabled.
|
||||
|
||||
@ -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.152 2011-10-01 03:59:54 bsmith%mozilla.com Exp $ */
|
||||
/* $Id: ssl3con.c,v 1.153 2011-10-29 00:29:11 bsmith%mozilla.com Exp $ */
|
||||
|
||||
#include "cert.h"
|
||||
#include "ssl.h"
|
||||
@ -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);
|
||||
@ -5788,6 +5789,14 @@ ssl3_HandleServerHelloDone(sslSocket *ss)
|
||||
if (rv != SECSuccess) {
|
||||
goto loser; /* err code was set. */
|
||||
}
|
||||
|
||||
if (!ss->firstHsDone) {
|
||||
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. */
|
||||
@ -8220,6 +8229,40 @@ ssl3_ComputeTLSFinished(ssl3CipherSpec *spec,
|
||||
return rv;
|
||||
}
|
||||
|
||||
/* 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.nextProto.len == 0)
|
||||
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
|
||||
@ -8473,6 +8516,14 @@ ssl3_HandleFinished(sslSocket *ss, SSL3Opaque *b, PRUint32 length,
|
||||
if (doStepUp || ss->writerThread == PR_GetCurrentThread()) {
|
||||
flags = ssl_SEND_FLAG_FORCE_INTO_BUFFER;
|
||||
}
|
||||
|
||||
if (!isServer && !ss->firstHsDone) {
|
||||
rv = ssl3_SendNextProto(ss);
|
||||
if (rv != SECSuccess) {
|
||||
goto xmit_loser; /* err code was set. */
|
||||
}
|
||||
}
|
||||
|
||||
rv = ssl3_SendFinished(ss, flags);
|
||||
if (rv != SECSuccess) {
|
||||
goto xmit_loser; /* err is set. */
|
||||
@ -9540,6 +9591,8 @@ ssl3_DestroySSL3Info(sslSocket *ss)
|
||||
ssl3_DestroyCipherSpec(&ss->ssl3.specs[1], PR_TRUE/*freeSrvName*/);
|
||||
|
||||
ss->ssl3.initialized = PR_FALSE;
|
||||
|
||||
SECITEM_FreeItem(&ss->ssl3.nextProto, PR_FALSE);
|
||||
}
|
||||
|
||||
/* End of ssl3con.c */
|
||||
|
||||
@ -41,7 +41,7 @@
|
||||
* ***** END LICENSE BLOCK ***** */
|
||||
|
||||
/* TLS extension code moved here from ssl3ecc.c */
|
||||
/* $Id: ssl3ext.c,v 1.16 2011-03-24 01:40:14 alexei.volkov.bugs%sun.com Exp $ */
|
||||
/* $Id: ssl3ext.c,v 1.17 2011-10-29 00:29:11 bsmith%mozilla.com Exp $ */
|
||||
|
||||
#include "nssrenam.h"
|
||||
#include "nss.h"
|
||||
@ -78,6 +78,12 @@ static PRInt32 ssl3_SendRenegotiationInfoXtn(sslSocket * ss,
|
||||
PRBool append, PRUint32 maxBytes);
|
||||
static SECStatus ssl3_HandleRenegotiationInfoXtn(sslSocket *ss,
|
||||
PRUint16 ex_type, SECItem *data);
|
||||
static SECStatus ssl3_ClientHandleNextProtoNegoXtn(sslSocket *ss,
|
||||
PRUint16 ex_type, SECItem *data);
|
||||
static SECStatus ssl3_ServerHandleNextProtoNegoXtn(sslSocket *ss,
|
||||
PRUint16 ex_type, SECItem *data);
|
||||
static PRInt32 ssl3_ClientSendNextProtoNegoXtn(sslSocket *ss, PRBool append,
|
||||
PRUint32 maxBytes);
|
||||
|
||||
/*
|
||||
* Write bytes. Using this function means the SECItem structure
|
||||
@ -235,6 +241,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 +252,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 +275,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 } */
|
||||
};
|
||||
|
||||
@ -534,6 +543,123 @@ ssl3_SendSessionTicketXtn(
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* handle an incoming Next Protocol Negotiation extension. */
|
||||
static SECStatus
|
||||
ssl3_ServerHandleNextProtoNegoXtn(sslSocket * ss, PRUint16 ex_type, SECItem *data)
|
||||
{
|
||||
if (ss->firstHsDone || data->len != 0) {
|
||||
/* Clients MUST send an empty NPN extension, if any. */
|
||||
PORT_SetError(SSL_ERROR_NEXT_PROTOCOL_DATA_INVALID);
|
||||
return SECFailure;
|
||||
}
|
||||
|
||||
return SECSuccess;
|
||||
}
|
||||
|
||||
/* ssl3_ValidateNextProtoNego checks that the given block of data is valid: none
|
||||
* of the lengths may be 0 and the sum of the lengths must equal the length of
|
||||
* the block. */
|
||||
SECStatus
|
||||
ssl3_ValidateNextProtoNego(const unsigned char* data, unsigned int length)
|
||||
{
|
||||
unsigned int offset = 0;
|
||||
|
||||
while (offset < length) {
|
||||
unsigned int newOffset = offset + 1 + (unsigned int) data[offset];
|
||||
/* Reject embedded nulls to protect against buggy applications that
|
||||
* store protocol identifiers in null-terminated strings.
|
||||
*/
|
||||
if (newOffset > length || data[offset] == 0) {
|
||||
PORT_SetError(SSL_ERROR_NEXT_PROTOCOL_DATA_INVALID);
|
||||
return SECFailure;
|
||||
}
|
||||
offset = newOffset;
|
||||
}
|
||||
|
||||
if (offset > length) {
|
||||
PORT_SetError(SSL_ERROR_NEXT_PROTOCOL_DATA_INVALID);
|
||||
return SECFailure;
|
||||
}
|
||||
|
||||
return SECSuccess;
|
||||
}
|
||||
|
||||
static SECStatus
|
||||
ssl3_ClientHandleNextProtoNegoXtn(sslSocket *ss, PRUint16 ex_type,
|
||||
SECItem *data)
|
||||
{
|
||||
SECStatus rv;
|
||||
unsigned char resultBuffer[255];
|
||||
unsigned char * newData;
|
||||
SECItem result = { siBuffer, resultBuffer, 0 };
|
||||
|
||||
if (ss->firstHsDone) {
|
||||
PORT_SetError(SSL_ERROR_NEXT_PROTOCOL_DATA_INVALID);
|
||||
return SECFailure;
|
||||
}
|
||||
|
||||
rv = ssl3_ValidateNextProtoNego(data->data, data->len);
|
||||
if (rv != SECSuccess)
|
||||
return rv;
|
||||
|
||||
/* ss->nextProtoCallback cannot normally be NULL if we negotiated the
|
||||
* extension. However, It is possible that an application erroneously
|
||||
* cleared the callback between the time we sent the ClientHello and now.
|
||||
*/
|
||||
PORT_Assert(ss->nextProtoCallback != NULL);
|
||||
if (!ss->nextProtoCallback) {
|
||||
PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
|
||||
return SECFailure;
|
||||
}
|
||||
|
||||
rv = ss->nextProtoCallback(ss->nextProtoArg, ss->fd, data->data, data->len,
|
||||
result.data, &result.len, sizeof resultBuffer);
|
||||
if (rv != SECSuccess)
|
||||
return rv;
|
||||
/* If the callback wrote more than allowed to |result| it has corrupted our
|
||||
* stack. */
|
||||
if (result.len > sizeof result) {
|
||||
PORT_SetError(SEC_ERROR_OUTPUT_LEN);
|
||||
return SECFailure;
|
||||
}
|
||||
|
||||
SECITEM_FreeItem(&ss->ssl3.nextProto, PR_FALSE);
|
||||
return SECITEM_CopyItem(NULL, &ss->ssl3.nextProto, &result);
|
||||
}
|
||||
|
||||
static PRInt32
|
||||
ssl3_ClientSendNextProtoNegoXtn(sslSocket * ss, PRBool append,
|
||||
PRUint32 maxBytes)
|
||||
{
|
||||
PRInt32 extension_length;
|
||||
|
||||
/* Renegotiations do not send this extension. */
|
||||
if (!ss->nextProtoCallback || ss->firstHsDone) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
extension_length = 4;
|
||||
|
||||
if (append && maxBytes >= extension_length) {
|
||||
SECStatus rv;
|
||||
rv = ssl3_AppendHandshakeNumber(ss, ssl_next_proto_neg_xtn, 2);
|
||||
if (rv != SECSuccess)
|
||||
goto loser;
|
||||
rv = ssl3_AppendHandshakeNumber(ss, 0, 2);
|
||||
if (rv != SECSuccess)
|
||||
goto loser;
|
||||
ss->xtnData.advertised[ss->xtnData.numAdvertised++] =
|
||||
ssl_next_proto_neg_xtn;
|
||||
} else if (maxBytes < extension_length) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
return extension_length;
|
||||
|
||||
loser:
|
||||
return -1;
|
||||
}
|
||||
|
||||
/*
|
||||
* NewSessionTicket
|
||||
* Called from ssl3_HandleFinished
|
||||
|
||||
@ -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.19 2010-06-24 09:24:18 nelson%bolyard.com Exp $ */
|
||||
/* $Id: ssl3prot.h,v 1.20 2011-10-29 00:29:11 bsmith%mozilla.com Exp $ */
|
||||
|
||||
#ifndef __ssl3proto_h_
|
||||
#define __ssl3proto_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 {
|
||||
|
||||
@ -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.14 2011-10-05 18:07:18 emaldona%redhat.com Exp $ */
|
||||
/* $Id: sslerr.h,v 1.15 2011-10-29 00:29:11 bsmith%mozilla.com Exp $ */
|
||||
#ifndef __SSL_ERR_H_
|
||||
#define __SSL_ERR_H_
|
||||
|
||||
@ -205,6 +205,8 @@ SSL_ERROR_RX_UNEXPECTED_UNCOMPRESSED_RECORD = (SSL_ERROR_BASE + 114),
|
||||
|
||||
SSL_ERROR_WEAK_SERVER_EPHEMERAL_DH_KEY = (SSL_ERROR_BASE + 115),
|
||||
|
||||
SSL_ERROR_NEXT_PROTOCOL_DATA_INVALID = (SSL_ERROR_BASE + 116),
|
||||
|
||||
SSL_ERROR_END_OF_LIST /* let the c compiler determine the value of this. */
|
||||
} SSLErrorCodes;
|
||||
#endif /* NO_SECURITY_ERROR_ENUM */
|
||||
|
||||
@ -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.84 2011-10-22 16:45:40 emaldona%redhat.com Exp $ */
|
||||
/* $Id: sslimpl.h,v 1.85 2011-10-29 00:29:11 bsmith%mozilla.com Exp $ */
|
||||
|
||||
#ifndef __sslimpl_h_
|
||||
#define __sslimpl_h_
|
||||
@ -313,6 +313,10 @@ typedef struct {
|
||||
#endif /* NSS_ENABLE_ECC */
|
||||
|
||||
typedef struct sslOptionsStr {
|
||||
/* If SSL_SetNextProtoNego has been called, then this contains the
|
||||
* list of supported protocols. */
|
||||
SECItem nextProtoNego;
|
||||
|
||||
unsigned int useSecurity : 1; /* 1 */
|
||||
unsigned int useSocks : 1; /* 2 */
|
||||
unsigned int requestCertificate : 1; /* 3 */
|
||||
@ -828,6 +832,12 @@ 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 negotiated.
|
||||
*/
|
||||
SECItem nextProto;
|
||||
SSLNextProtoState nextProtoState;
|
||||
};
|
||||
|
||||
typedef struct {
|
||||
@ -1059,6 +1069,8 @@ const unsigned char * preferredCipher;
|
||||
SSLHandshakeCallback handshakeCallback;
|
||||
void *handshakeCallbackData;
|
||||
void *pkcs11PinArg;
|
||||
SSLNextProtoCallback nextProtoCallback;
|
||||
void *nextProtoArg;
|
||||
|
||||
PRIntervalTime rTimeout; /* timeout for NSPR I/O */
|
||||
PRIntervalTime wTimeout; /* timeout for NSPR I/O */
|
||||
@ -1569,6 +1581,9 @@ extern PRBool ssl_GetSessionTicketKeysPKCS11(SECKEYPrivateKey *svrPrivKey,
|
||||
#define TLS_EX_SESS_TICKET_LIFETIME_HINT (2 * 24 * 60 * 60) /* 2 days */
|
||||
#define TLS_EX_SESS_TICKET_VERSION (0x0100)
|
||||
|
||||
extern SECStatus ssl3_ValidateNextProtoNego(const unsigned char* data,
|
||||
unsigned int length);
|
||||
|
||||
/* Construct a new NSPR socket for the app to use */
|
||||
extern PRFileDesc *ssl_NewPRSocket(sslSocket *ss, PRFileDesc *fd);
|
||||
extern void ssl_FreePRSocket(PRFileDesc *fd);
|
||||
|
||||
@ -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.75 2011-10-22 16:45:40 emaldona%redhat.com Exp $ */
|
||||
/* $Id: sslsock.c,v 1.76 2011-10-29 00:29:11 bsmith%mozilla.com Exp $ */
|
||||
#include "seccomon.h"
|
||||
#include "cert.h"
|
||||
#include "keyhi.h"
|
||||
@ -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 */
|
||||
@ -440,6 +441,7 @@ ssl_DestroySocketContents(sslSocket *ss)
|
||||
ssl3_FreeKeyPair(ss->ephemeralECDHKeyPair);
|
||||
ss->ephemeralECDHKeyPair = NULL;
|
||||
}
|
||||
SECITEM_FreeItem(&ss->opt.nextProtoNego, PR_FALSE);
|
||||
PORT_Assert(!ss->xtnData.sniNameArr);
|
||||
if (ss->xtnData.sniNameArr) {
|
||||
PORT_Free(ss->xtnData.sniNameArr);
|
||||
@ -1301,6 +1303,148 @@ SSL_ImportFD(PRFileDesc *model, PRFileDesc *fd)
|
||||
return fd;
|
||||
}
|
||||
|
||||
SECStatus
|
||||
SSL_SetNextProtoCallback(PRFileDesc *fd, SSLNextProtoCallback callback,
|
||||
void *arg)
|
||||
{
|
||||
sslSocket *ss = ssl_FindSocket(fd);
|
||||
|
||||
if (!ss) {
|
||||
SSL_DBG(("%d: SSL[%d]: bad socket in SSL_SetNextProtoCallback", SSL_GETPID(),
|
||||
fd));
|
||||
PORT_SetError(SEC_ERROR_INVALID_ARGS);
|
||||
return SECFailure;
|
||||
}
|
||||
|
||||
ssl_GetSSL3HandshakeLock(ss);
|
||||
ss->nextProtoCallback = callback;
|
||||
ss->nextProtoArg = arg;
|
||||
ssl_ReleaseSSL3HandshakeLock(ss);
|
||||
|
||||
return SECSuccess;
|
||||
}
|
||||
|
||||
/* NextProtoStandardCallback is set as an NPN callback for the case when
|
||||
* SSL_SetNextProtoNego is used.
|
||||
*/
|
||||
static SECStatus
|
||||
ssl_NextProtoNegoCallback(void *arg, PRFileDesc *fd,
|
||||
const unsigned char *protos, unsigned int protos_len,
|
||||
unsigned char *protoOut, unsigned int *protoOutLen,
|
||||
unsigned int protoMaxLen)
|
||||
{
|
||||
unsigned int i, j;
|
||||
const unsigned char *result;
|
||||
sslSocket *ss = ssl_FindSocket(fd);
|
||||
|
||||
if (!ss) {
|
||||
SSL_DBG(("%d: SSL[%d]: bad socket in ssl_NextProtoNegoCallback",
|
||||
SSL_GETPID(), fd));
|
||||
PORT_SetError(SEC_ERROR_INVALID_ARGS);
|
||||
return SECFailure;
|
||||
}
|
||||
|
||||
if (protos_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;
|
||||
}
|
||||
|
||||
/* For each protocol in server preference, see if we support it. */
|
||||
for (i = 0; i < protos_len; ) {
|
||||
for (j = 0; j < ss->opt.nextProtoNego.len; ) {
|
||||
if (protos[i] == ss->opt.nextProtoNego.data[j] &&
|
||||
PORT_Memcmp(&protos[i+1], &ss->opt.nextProtoNego.data[j+1],
|
||||
protos[i]) == 0) {
|
||||
/* We found a match. */
|
||||
ss->ssl3.nextProtoState = SSL_NEXT_PROTO_NEGOTIATED;
|
||||
result = &protos[i];
|
||||
goto found;
|
||||
}
|
||||
j += 1 + (unsigned int)ss->opt.nextProtoNego.data[j];
|
||||
}
|
||||
i += 1 + (unsigned int)protos[i];
|
||||
}
|
||||
|
||||
pick_first:
|
||||
ss->ssl3.nextProtoState = SSL_NEXT_PROTO_NO_OVERLAP;
|
||||
result = ss->opt.nextProtoNego.data;
|
||||
|
||||
found:
|
||||
*protoOutLen = result[0];
|
||||
if (protoMaxLen < result[0]) {
|
||||
PORT_SetError(SEC_ERROR_OUTPUT_LEN);
|
||||
return SECFailure;
|
||||
}
|
||||
memcpy(protoOut, result + 1, result[0]);
|
||||
return SECSuccess;
|
||||
}
|
||||
|
||||
SECStatus
|
||||
SSL_SetNextProtoNego(PRFileDesc *fd, const unsigned char *data,
|
||||
unsigned int length)
|
||||
{
|
||||
sslSocket *ss = ssl_FindSocket(fd);
|
||||
SECStatus rv;
|
||||
SECItem dataItem = { siBuffer, (unsigned char *) data, length };
|
||||
|
||||
if (!ss) {
|
||||
SSL_DBG(("%d: SSL[%d]: bad socket in SSL_SetNextProtoNego",
|
||||
SSL_GETPID(), fd));
|
||||
PORT_SetError(SEC_ERROR_INVALID_ARGS);
|
||||
return SECFailure;
|
||||
}
|
||||
|
||||
if (ssl3_ValidateNextProtoNego(data, length) != SECSuccess)
|
||||
return SECFailure;
|
||||
|
||||
ssl_GetSSL3HandshakeLock(ss);
|
||||
SECITEM_FreeItem(&ss->opt.nextProtoNego, PR_FALSE);
|
||||
rv = SECITEM_CopyItem(NULL, &ss->opt.nextProtoNego, &dataItem);
|
||||
ssl_ReleaseSSL3HandshakeLock(ss);
|
||||
|
||||
if (rv != SECSuccess)
|
||||
return rv;
|
||||
|
||||
return SSL_SetNextProtoCallback(fd, ssl_NextProtoNegoCallback, NULL);
|
||||
}
|
||||
|
||||
SECStatus
|
||||
SSL_GetNextProto(PRFileDesc *fd, SSLNextProtoState *state, unsigned char *buf,
|
||||
unsigned int *bufLen, unsigned int bufLenMax)
|
||||
{
|
||||
sslSocket *ss = ssl_FindSocket(fd);
|
||||
|
||||
if (!ss) {
|
||||
SSL_DBG(("%d: SSL[%d]: bad socket in SSL_GetNextProto", SSL_GETPID(),
|
||||
fd));
|
||||
PORT_SetError(SEC_ERROR_INVALID_ARGS);
|
||||
return SECFailure;
|
||||
}
|
||||
|
||||
if (!state || !buf || !bufLen) {
|
||||
PORT_SetError(SEC_ERROR_INVALID_ARGS);
|
||||
return SECFailure;
|
||||
}
|
||||
|
||||
*state = ss->ssl3.nextProtoState;
|
||||
|
||||
if (ss->ssl3.nextProtoState != SSL_NEXT_PROTO_NO_SUPPORT &&
|
||||
ss->ssl3.nextProto.data) {
|
||||
*bufLen = ss->ssl3.nextProto.len;
|
||||
if (*bufLen > bufLenMax) {
|
||||
PORT_SetError(SEC_ERROR_OUTPUT_LEN);
|
||||
*bufLen = 0;
|
||||
return SECFailure;
|
||||
}
|
||||
PORT_Memcpy(buf, ss->ssl3.nextProto.data, ss->ssl3.nextProto.len);
|
||||
} else {
|
||||
*bufLen = 0;
|
||||
}
|
||||
|
||||
return SECSuccess;
|
||||
}
|
||||
|
||||
PRFileDesc *
|
||||
SSL_ReconfigFD(PRFileDesc *model, PRFileDesc *fd)
|
||||
{
|
||||
|
||||
@ -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.16 2010-02-04 03:21:11 wtc%google.com Exp $ */
|
||||
/* $Id: sslt.h,v 1.17 2011-10-29 00:29:11 bsmith%mozilla.com Exp $ */
|
||||
|
||||
#ifndef __sslt_h_
|
||||
#define __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_ */
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user