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:
bsmith%mozilla.com 2011-10-29 00:29:11 +00:00
parent b585bb9ec9
commit 0601ca68ad
10 changed files with 420 additions and 11 deletions

View File

@ -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.")

View File

@ -164,3 +164,11 @@ NSSSSL_GetVersion;
;+ local:
;+ *;
;+};
;+NSS_3.13.2 { # NSS 3.13.2 release
;+ global:
SSL_SetNextProtoCallback;
SSL_SetNextProtoNego;
SSL_GetNextProto;
;+ local:
;+ *;
;+};

View File

@ -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.

View File

@ -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 */

View File

@ -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

View File

@ -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 {

View File

@ -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 */

View File

@ -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);

View File

@ -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)
{

View File

@ -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_ */