| 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 46e31c3bfb1dc8ca30c9efd0189bf79527706671..04157701e9028e670098fa47469960ffc05513c9 100644
|
| --- a/net/third_party/nss/ssl/ssl3ext.c
|
| +++ b/net/third_party/nss/ssl/ssl3ext.c
|
| @@ -724,6 +724,7 @@ static PRInt32
|
| ssl3_ClientSendAppProtoXtn(sslSocket * ss, PRBool append, PRUint32 maxBytes)
|
| {
|
| PRInt32 extension_length;
|
| + unsigned char *alpn_protos = NULL;
|
|
|
| /* Renegotiations do not send this extension. */
|
| if (!ss->opt.nextProtoNego.data || ss->firstHsDone) {
|
| @@ -735,15 +736,38 @@ ssl3_ClientSendAppProtoXtn(sslSocket * ss, PRBool append, PRUint32 maxBytes)
|
| ss->opt.nextProtoNego.len;
|
|
|
| if (append && maxBytes >= extension_length) {
|
| + /* NPN requires that the client's fallback protocol is first in the
|
| + * list. However, ALPN sends protocols in preference order. So we
|
| + * allocate a buffer and move the first protocol to the end of the
|
| + * list. */
|
| SECStatus rv;
|
| + const unsigned int len = ss->opt.nextProtoNego.len;
|
| +
|
| + alpn_protos = PORT_Alloc(len);
|
| + if (alpn_protos == NULL) {
|
| + return SECFailure;
|
| + }
|
| + if (len > 0) {
|
| + /* Each protocol string is prefixed with a single byte length. */
|
| + unsigned int i = ss->opt.nextProtoNego.data[0] + 1;
|
| + if (i <= len) {
|
| + memcpy(alpn_protos, &ss->opt.nextProtoNego.data[i], len - i);
|
| + memcpy(alpn_protos + len - i, ss->opt.nextProtoNego.data, i);
|
| + } else {
|
| + /* This seems to be invalid data so we'll send as-is. */
|
| + memcpy(alpn_protos, ss->opt.nextProtoNego.data, len);
|
| + }
|
| + }
|
| +
|
| rv = ssl3_AppendHandshakeNumber(ss, ssl_app_layer_protocol_xtn, 2);
|
| if (rv != SECSuccess)
|
| goto loser;
|
| rv = ssl3_AppendHandshakeNumber(ss, extension_length - 4, 2);
|
| if (rv != SECSuccess)
|
| goto loser;
|
| - rv = ssl3_AppendHandshakeVariable(ss, ss->opt.nextProtoNego.data,
|
| - ss->opt.nextProtoNego.len, 2);
|
| + rv = ssl3_AppendHandshakeVariable(ss, alpn_protos, len, 2);
|
| + PORT_Free(alpn_protos);
|
| + alpn_protos = NULL;
|
| if (rv != SECSuccess)
|
| goto loser;
|
| ss->xtnData.advertised[ss->xtnData.numAdvertised++] =
|
| @@ -755,6 +779,8 @@ ssl3_ClientSendAppProtoXtn(sslSocket * ss, PRBool append, PRUint32 maxBytes)
|
| return extension_length;
|
|
|
| loser:
|
| + if (alpn_protos)
|
| + PORT_Free(alpn_protos);
|
| return -1;
|
| }
|
|
|
|
|