| Index: net/third_party/nss/ssl/ssl3ext.c
|
| diff --git a/net/third_party/nss/ssl/ssl3ext.c b/net/third_party/nss/ssl/ssl3ext.c
|
| index 21bb818598cdc55c84f34e1aa7a3b58e1967a4e1..0365d5aa8457c5b224e25babe19335155a77940f 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
|
|
|