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 e54b4fd4c00707fe9f21218378b0fe5e3e0c3e4d..0c6b8e6e7fc4fe88685785eb6b78881e8e501553 100644 |
--- a/net/third_party/nss/ssl/ssl3ext.c |
+++ b/net/third_party/nss/ssl/ssl3ext.c |
@@ -554,12 +554,11 @@ ssl3_ServerHandleNextProtoNegoXtn(sslSocket * ss, PRUint16 ex_type, SECItem *dat |
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 |
+ * 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 short length) |
@@ -568,63 +567,46 @@ ssl3_ValidateNextProtoNego(const unsigned char* data, unsigned short length) |
while (offset < length) { |
if (data[offset] == 0) { |
+ PORT_SetError(SSL_ERROR_NEXT_PROTOCOL_DATA_INVALID); |
return SECFailure; |
} |
offset += (unsigned int)data[offset] + 1; |
} |
- if (offset > length) |
+ if (offset > length) { |
+ PORT_SetError(SSL_ERROR_NEXT_PROTOCOL_DATA_INVALID); |
return SECFailure; |
+ } |
return SECSuccess; |
} |
SECStatus |
ssl3_ClientHandleNextProtoNegoXtn(sslSocket *ss, PRUint16 ex_type, |
- SECItem *data) |
+ 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; |
- } |
+ unsigned char result[255]; |
+ unsigned int result_len; |
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 += (unsigned int)ss->opt.nextProtoNego.data[j] + 1; |
- } |
- |
- i += (unsigned int)data->data[i] + 1; |
- } |
- |
- pick_first: |
- ss->ssl3.nextProtoState = SSL_NEXT_PROTO_NO_OVERLAP; |
- result = ss->opt.nextProtoNego.data; |
+ rv = ss->nextProtoCallback(ss->nextProtoArg, ss->fd, |
+ data->data, data->len, |
+ result, &result_len); |
+ if (rv != SECSuccess) |
+ return rv; |
+ // If the callback wrote more than allowed to |result| it has corrupted our |
+ // stack. |
+ PORT_Assert(result_len <= sizeof(result)); |
- 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]; |
+ ss->ssl3.nextProto.data = PORT_Alloc(result_len); |
+ PORT_Memcpy(ss->ssl3.nextProto.data, result, result_len); |
+ ss->ssl3.nextProto.len = result_len; |
return SECSuccess; |
} |
@@ -636,7 +618,7 @@ ssl3_ClientSendNextProtoNegoXtn(sslSocket * ss, |
PRInt32 extension_length; |
/* Renegotiations do not send this extension. */ |
- if (ss->opt.nextProtoNego.len == 0 || ss->firstHsDone) { |
+ if (!ss->nextProtoCallback || ss->firstHsDone) { |
return 0; |
} |