| 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 523e49a275308777ace1607a41393437e6e6eacb..f6530fe7960d3a1e4e83349a869ddbaefc13824d 100644
|
| --- a/net/third_party/nss/ssl/ssl3ext.c
|
| +++ b/net/third_party/nss/ssl/ssl3ext.c
|
| @@ -56,10 +56,14 @@ static SECStatus ssl3_ClientHandleAppProtoXtn(sslSocket *ss,
|
| PRUint16 ex_type, SECItem *data);
|
| static SECStatus ssl3_ServerHandleNextProtoNegoXtn(sslSocket *ss,
|
| PRUint16 ex_type, SECItem *data);
|
| +static SECStatus ssl3_ServerHandleAppProtoXtn(sslSocket *ss, PRUint16 ex_type,
|
| + SECItem *data);
|
| +static PRInt32 ssl3_ClientSendNextProtoNegoXtn(sslSocket *ss, PRBool append,
|
| + PRUint32 maxBytes);
|
| static PRInt32 ssl3_ClientSendAppProtoXtn(sslSocket *ss, PRBool append,
|
| PRUint32 maxBytes);
|
| -static PRInt32 ssl3_ClientSendNextProtoNegoXtn(sslSocket *ss, PRBool append,
|
| - PRUint32 maxBytes);
|
| +static PRInt32 ssl3_ServerSendAppProtoXtn(sslSocket *ss, PRBool append,
|
| + PRUint32 maxBytes);
|
| static PRInt32 ssl3_SendUseSRTPXtn(sslSocket *ss, PRBool append,
|
| PRUint32 maxBytes);
|
| static SECStatus ssl3_HandleUseSRTPXtn(sslSocket * ss, PRUint16 ex_type,
|
| @@ -247,6 +251,7 @@ static const ssl3HelloExtensionHandler clientHelloHandlers[] = {
|
| { ssl_session_ticket_xtn, &ssl3_ServerHandleSessionTicketXtn },
|
| { ssl_renegotiation_info_xtn, &ssl3_HandleRenegotiationInfoXtn },
|
| { ssl_next_proto_nego_xtn, &ssl3_ServerHandleNextProtoNegoXtn },
|
| + { ssl_app_layer_protocol_xtn, &ssl3_ServerHandleAppProtoXtn },
|
| { ssl_use_srtp_xtn, &ssl3_HandleUseSRTPXtn },
|
| { ssl_cert_status_xtn, &ssl3_ServerHandleStatusRequestXtn },
|
| { ssl_signature_algorithms_xtn, &ssl3_ServerHandleSigAlgsXtn },
|
| @@ -578,7 +583,8 @@ ssl3_SendSessionTicketXtn(
|
|
|
| /* handle an incoming Next Protocol Negotiation extension. */
|
| static SECStatus
|
| -ssl3_ServerHandleNextProtoNegoXtn(sslSocket * ss, PRUint16 ex_type, SECItem *data)
|
| +ssl3_ServerHandleNextProtoNegoXtn(sslSocket * ss, PRUint16 ex_type,
|
| + SECItem *data)
|
| {
|
| if (ss->firstHsDone || data->len != 0) {
|
| /* Clients MUST send an empty NPN extension, if any. */
|
| @@ -623,14 +629,93 @@ ssl3_ValidateNextProtoNego(const unsigned char* data, unsigned int length)
|
| return SECSuccess;
|
| }
|
|
|
| +/* protocol selection handler for ALPN (server side) and NPN (client side) */
|
| static SECStatus
|
| -ssl3_ClientHandleNextProtoNegoXtn(sslSocket *ss, PRUint16 ex_type,
|
| - SECItem *data)
|
| +ssl3_SelectAppProtocol(sslSocket *ss, PRUint16 ex_type, SECItem *data)
|
| {
|
| SECStatus rv;
|
| unsigned char resultBuffer[255];
|
| SECItem result = { siBuffer, resultBuffer, 0 };
|
|
|
| + rv = ssl3_ValidateNextProtoNego(data->data, data->len);
|
| + if (rv != SECSuccess)
|
| + return rv;
|
| +
|
| + PORT_Assert(ss->nextProtoCallback);
|
| + 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 resultBuffer) {
|
| + PORT_SetError(SEC_ERROR_OUTPUT_LEN);
|
| + return SECFailure;
|
| + }
|
| +
|
| + if (ex_type == ssl_app_layer_protocol_xtn &&
|
| + ss->ssl3.nextProtoState != SSL_NEXT_PROTO_NEGOTIATED) {
|
| + /* The callback might say OK, but then it's picked a default.
|
| + * That's OK for NPN, but not ALPN. */
|
| + SECITEM_FreeItem(&ss->ssl3.nextProto, PR_FALSE);
|
| + PORT_SetError(SSL_ERROR_NEXT_PROTOCOL_NO_PROTOCOL);
|
| + (void)SSL3_SendAlert(ss, alert_fatal, no_application_protocol);
|
| + return SECFailure;
|
| + }
|
| +
|
| + ss->xtnData.negotiated[ss->xtnData.numNegotiated++] = ex_type;
|
| +
|
| + SECITEM_FreeItem(&ss->ssl3.nextProto, PR_FALSE);
|
| + return SECITEM_CopyItem(NULL, &ss->ssl3.nextProto, &result);
|
| +}
|
| +
|
| +/* handle an incoming ALPN extension at the server */
|
| +static SECStatus
|
| +ssl3_ServerHandleAppProtoXtn(sslSocket *ss, PRUint16 ex_type, SECItem *data)
|
| +{
|
| + int count;
|
| + SECStatus rv;
|
| +
|
| + /* We expressly don't want to allow ALPN on renegotiation,
|
| + * despite it being permitted by the spec. */
|
| + if (ss->firstHsDone || data->len == 0) {
|
| + /* Clients MUST send a non-empty ALPN extension. */
|
| + PORT_SetError(SSL_ERROR_NEXT_PROTOCOL_DATA_INVALID);
|
| + return SECFailure;
|
| + }
|
| +
|
| + /* unlike NPN, ALPN has extra redundant length information so that
|
| + * the extension is the same in both ClientHello and ServerHello */
|
| + count = ssl3_ConsumeHandshakeNumber(ss, 2, &data->data, &data->len);
|
| + if (count < 0) {
|
| + return SECFailure; /* fatal alert was sent */
|
| + }
|
| + if (count != data->len) {
|
| + return ssl3_DecodeError(ss);
|
| + }
|
| +
|
| + if (!ss->nextProtoCallback) {
|
| + /* we're not configured for it */
|
| + return SECSuccess;
|
| + }
|
| +
|
| + rv = ssl3_SelectAppProtocol(ss, ex_type, data);
|
| + if (rv != SECSuccess) {
|
| + return rv;
|
| + }
|
| +
|
| + /* prepare to send back a response, if we negotiated */
|
| + if (ss->ssl3.nextProtoState == SSL_NEXT_PROTO_NEGOTIATED) {
|
| + return ssl3_RegisterServerHelloExtensionSender(
|
| + ss, ex_type, ssl3_ServerSendAppProtoXtn);
|
| + }
|
| + return SECSuccess;
|
| +}
|
| +
|
| +static SECStatus
|
| +ssl3_ClientHandleNextProtoNegoXtn(sslSocket *ss, PRUint16 ex_type,
|
| + SECItem *data)
|
| +{
|
| PORT_Assert(!ss->firstHsDone);
|
|
|
| if (ssl3_ExtensionNegotiated(ss, ssl_app_layer_protocol_xtn)) {
|
| @@ -643,37 +728,16 @@ ssl3_ClientHandleNextProtoNegoXtn(sslSocket *ss, PRUint16 ex_type,
|
| 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);
|
| + /* We should only get this call if we sent the extension, so
|
| + * ss->nextProtoCallback needs to be non-NULL. However, it is possible
|
| + * that an application erroneously cleared the callback between the time
|
| + * we sent the ClientHello and now. */
|
| if (!ss->nextProtoCallback) {
|
| - /* XXX Use a better error code. This is an application error, not an
|
| - * NSS bug. */
|
| - PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
|
| + PORT_SetError(SSL_ERROR_NEXT_PROTOCOL_NO_CALLBACK);
|
| 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 resultBuffer) {
|
| - PORT_SetError(SEC_ERROR_OUTPUT_LEN);
|
| - return SECFailure;
|
| - }
|
| -
|
| - ss->xtnData.negotiated[ss->xtnData.numNegotiated++] = ex_type;
|
| -
|
| - SECITEM_FreeItem(&ss->ssl3.nextProto, PR_FALSE);
|
| - return SECITEM_CopyItem(NULL, &ss->ssl3.nextProto, &result);
|
| + return ssl3_SelectAppProtocol(ss, ex_type, data);
|
| }
|
|
|
| static SECStatus
|
| @@ -814,6 +878,47 @@ loser:
|
| return -1;
|
| }
|
|
|
| +static PRInt32
|
| +ssl3_ServerSendAppProtoXtn(sslSocket * ss, PRBool append, PRUint32 maxBytes)
|
| +{
|
| + PRInt32 extension_length;
|
| +
|
| + PORT_Assert(ss->opt.enableALPN);
|
| + PORT_Assert(ss->ssl3.nextProto.data);
|
| + PORT_Assert(ss->ssl3.nextProto.len > 0);
|
| + PORT_Assert(ss->ssl3.nextProtoState == SSL_NEXT_PROTO_NEGOTIATED);
|
| + PORT_Assert(!ss->firstHsDone);
|
| +
|
| + extension_length = 2 /* extension type */ + 2 /* extension length */ +
|
| + 2 /* protocol name list */ + 1 /* name length */ +
|
| + ss->ssl3.nextProto.len;
|
| +
|
| + if (append && maxBytes >= extension_length) {
|
| + SECStatus rv;
|
| + rv = ssl3_AppendHandshakeNumber(ss, ssl_app_layer_protocol_xtn, 2);
|
| + if (rv != SECSuccess) {
|
| + return -1;
|
| + }
|
| + rv = ssl3_AppendHandshakeNumber(ss, extension_length - 4, 2);
|
| + if (rv != SECSuccess) {
|
| + return -1;
|
| + }
|
| + rv = ssl3_AppendHandshakeNumber(ss, ss->ssl3.nextProto.len + 1, 2);
|
| + if (rv != SECSuccess) {
|
| + return -1;
|
| + }
|
| + rv = ssl3_AppendHandshakeVariable(ss, ss->ssl3.nextProto.data,
|
| + ss->ssl3.nextProto.len, 1);
|
| + if (rv != SECSuccess) {
|
| + return -1;
|
| + }
|
| + } else if (maxBytes < extension_length) {
|
| + return 0;
|
| + }
|
| +
|
| + return extension_length;
|
| +}
|
| +
|
| static SECStatus
|
| ssl3_ClientHandleChannelIDXtn(sslSocket *ss, PRUint16 ex_type,
|
| SECItem *data)
|
|
|