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 9214a2e6b3bdc2e923d0beba0245b6ba71bf5838..eb3fb70f2805c444317ee87ee55760b36fa31660 100644 |
--- a/net/third_party/nss/ssl/ssl3ext.c |
+++ b/net/third_party/nss/ssl/ssl3ext.c |
@@ -101,6 +101,12 @@ static PRInt32 ssl3_ClientSendDraftVersionXtn(sslSocket *ss, PRBool append, |
PRUint32 maxBytes); |
static SECStatus ssl3_ServerHandleDraftVersionXtn(sslSocket *ss, PRUint16 ex_type, |
SECItem *data); |
+static PRInt32 ssl3_SendExtendedMasterSecretXtn(sslSocket *ss, PRBool append, |
+ PRUint32 maxBytes); |
+static SECStatus ssl3_HandleExtendedMasterSecretXtn(sslSocket *ss, |
+ PRUint16 ex_type, |
+ SECItem *data); |
+ |
/* |
* Write bytes. Using this function means the SECItem structure |
@@ -266,6 +272,7 @@ static const ssl3HelloExtensionHandler clientHelloHandlers[] = { |
{ ssl_cert_status_xtn, &ssl3_ServerHandleStatusRequestXtn }, |
{ ssl_signature_algorithms_xtn, &ssl3_ServerHandleSigAlgsXtn }, |
{ ssl_tls13_draft_version_xtn, &ssl3_ServerHandleDraftVersionXtn }, |
+ { ssl_extended_master_secret_xtn, &ssl3_HandleExtendedMasterSecretXtn }, |
{ -1, NULL } |
}; |
@@ -281,6 +288,7 @@ static const ssl3HelloExtensionHandler serverHelloHandlersTLS[] = { |
{ ssl_use_srtp_xtn, &ssl3_ClientHandleUseSRTPXtn }, |
{ ssl_channel_id_xtn, &ssl3_ClientHandleChannelIDXtn }, |
{ ssl_cert_status_xtn, &ssl3_ClientHandleStatusRequestXtn }, |
+ { ssl_extended_master_secret_xtn, &ssl3_HandleExtendedMasterSecretXtn }, |
{ ssl_signed_certificate_timestamp_xtn, |
&ssl3_ClientHandleSignedCertTimestampXtn }, |
{ -1, NULL } |
@@ -319,6 +327,7 @@ ssl3HelloExtensionSender clientHelloSendersTLS[SSL_MAX_EXTENSIONS] = { |
* extension. */ |
{ ssl_signature_algorithms_xtn, &ssl3_ClientSendSigAlgsXtn }, |
{ ssl_tls13_draft_version_xtn, &ssl3_ClientSendDraftVersionXtn }, |
+ { ssl_extended_master_secret_xtn, &ssl3_SendExtendedMasterSecretXtn}, |
/* any extra entries will appear as { 0, NULL } */ |
}; |
@@ -331,7 +340,7 @@ ssl3HelloExtensionSender clientHelloSendersSSL3[SSL_MAX_EXTENSIONS] = { |
static PRBool |
arrayContainsExtension(const PRUint16 *array, PRUint32 len, PRUint16 ex_type) |
{ |
- int i; |
+ unsigned int i; |
for (i = 0; i < len; i++) { |
if (ex_type == array[i]) |
return PR_TRUE; |
@@ -433,12 +442,12 @@ ssl3_HandleServerNameXtn(sslSocket * ss, PRUint16 ex_type, SECItem *data) |
} |
/* length of server_name_list */ |
listLenBytes = ssl3_ConsumeHandshakeNumber(ss, 2, &data->data, &data->len); |
- if (listLenBytes < 0 || listLenBytes != data->len) { |
- (void)ssl3_DecodeError(ss); |
+ if (listLenBytes < 0) { |
return SECFailure; |
} |
- if (listLenBytes == 0) { |
- return SECSuccess; /* ignore an empty extension */ |
+ if (listLenBytes == 0 || listLenBytes != data->len) { |
+ (void)ssl3_DecodeError(ss); |
+ return SECFailure; |
} |
ldata = *data; |
/* Calculate the size of the array.*/ |
@@ -463,15 +472,12 @@ ssl3_HandleServerNameXtn(sslSocket * ss, PRUint16 ex_type, SECItem *data) |
} |
listCount += 1; |
} |
- if (!listCount) { |
- return SECFailure; /* nothing we can act on */ |
- } |
names = PORT_ZNewArray(SECItem, listCount); |
if (!names) { |
return SECFailure; |
} |
for (i = 0;i < listCount;i++) { |
- int j; |
+ unsigned int j; |
PRInt32 type; |
SECStatus rv; |
PRBool nametypePresent = PR_FALSE; |
@@ -559,7 +565,11 @@ ssl3_SendSessionTicketXtn( |
} |
} |
- if (append && maxBytes >= extension_length) { |
+ if (maxBytes < (PRUint32)extension_length) { |
+ PORT_Assert(0); |
+ return 0; |
+ } |
+ if (append) { |
SECStatus rv; |
/* extension_type */ |
rv = ssl3_AppendHandshakeNumber(ss, ssl_session_ticket_xtn, 2); |
@@ -582,9 +592,6 @@ ssl3_SendSessionTicketXtn( |
xtnData->advertised[xtnData->numAdvertised++] = |
ssl_session_ticket_xtn; |
} |
- } else if (maxBytes < extension_length) { |
- PORT_Assert(0); |
- return 0; |
} |
return extension_length; |
@@ -645,12 +652,17 @@ ssl3_SelectAppProtocol(sslSocket *ss, PRUint16 ex_type, SECItem *data) |
rv = ssl3_ValidateNextProtoNego(data->data, data->len); |
if (rv != SECSuccess) { |
- PORT_SetError(SSL_ERROR_NEXT_PROTOCOL_DATA_INVALID); |
(void)SSL3_SendAlert(ss, alert_fatal, decode_error); |
+ PORT_SetError(SSL_ERROR_NEXT_PROTOCOL_DATA_INVALID); |
return rv; |
} |
PORT_Assert(ss->nextProtoCallback); |
+ /* For ALPN, the cipher suite isn't selected yet. Note that extensions |
+ * sometimes affect what cipher suite is selected, e.g., for ECC. */ |
+ PORT_Assert((ss->ssl3.hs.preliminaryInfo & |
+ ssl_preinfo_all & ~ssl_preinfo_cipher_suite) == |
+ (ssl_preinfo_all & ~ssl_preinfo_cipher_suite)); |
rv = ss->nextProtoCallback(ss->nextProtoArg, ss->fd, data->data, data->len, |
result.data, &result.len, sizeof(resultBuffer)); |
if (rv != SECSuccess) { |
@@ -673,8 +685,8 @@ ssl3_SelectAppProtocol(sslSocket *ss, PRUint16 ex_type, SECItem *data) |
ss->ssl3.nextProtoState != SSL_NEXT_PROTO_NEGOTIATED) { |
/* The callback might say OK, but then it picks a default value - one |
* that was not listed. That's OK for NPN, but not ALPN. */ |
- PORT_SetError(SSL_ERROR_NEXT_PROTOCOL_NO_PROTOCOL); |
(void)SSL3_SendAlert(ss, alert_fatal, no_application_protocol); |
+ PORT_SetError(SSL_ERROR_NEXT_PROTOCOL_NO_PROTOCOL); |
return SECFailure; |
} |
@@ -693,8 +705,8 @@ ssl3_ServerHandleAppProtoXtn(sslSocket *ss, PRUint16 ex_type, SECItem *data) |
* 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); |
(void)SSL3_SendAlert(ss, alert_fatal, illegal_parameter); |
+ PORT_SetError(SSL_ERROR_NEXT_PROTOCOL_DATA_INVALID); |
return SECFailure; |
} |
@@ -721,8 +733,8 @@ ssl3_ServerHandleAppProtoXtn(sslSocket *ss, PRUint16 ex_type, SECItem *data) |
rv = ssl3_RegisterServerHelloExtensionSender( |
ss, ex_type, ssl3_ServerSendAppProtoXtn); |
if (rv != SECSuccess) { |
- PORT_SetError(SEC_ERROR_LIBRARY_FAILURE); |
(void)SSL3_SendAlert(ss, alert_fatal, internal_error); |
+ PORT_SetError(SEC_ERROR_LIBRARY_FAILURE); |
return rv; |
} |
} |
@@ -742,8 +754,8 @@ ssl3_ClientHandleNextProtoNegoXtn(sslSocket *ss, PRUint16 ex_type, |
* we've negotiated NPN then we're required to send the NPN handshake |
* message. Thus, these two extensions cannot both be negotiated on the |
* same connection. */ |
- PORT_SetError(SSL_ERROR_BAD_SERVER); |
(void)SSL3_SendAlert(ss, alert_fatal, illegal_parameter); |
+ PORT_SetError(SSL_ERROR_BAD_SERVER); |
return SECFailure; |
} |
@@ -753,8 +765,8 @@ ssl3_ClientHandleNextProtoNegoXtn(sslSocket *ss, PRUint16 ex_type, |
* we sent the ClientHello and now. */ |
if (!ss->nextProtoCallback) { |
PORT_Assert(0); |
- PORT_SetError(SSL_ERROR_NEXT_PROTOCOL_NO_CALLBACK); |
(void)SSL3_SendAlert(ss, alert_fatal, internal_error); |
+ PORT_SetError(SSL_ERROR_NEXT_PROTOCOL_NO_CALLBACK); |
return SECFailure; |
} |
@@ -778,16 +790,16 @@ ssl3_ClientHandleAppProtoXtn(sslSocket *ss, PRUint16 ex_type, SECItem *data) |
* uint8 len; // where len >= 1 |
* uint8 protocol_name[len]; */ |
if (data->len < 4 || data->len > 2 + 1 + 255) { |
- PORT_SetError(SSL_ERROR_NEXT_PROTOCOL_DATA_INVALID); |
(void)SSL3_SendAlert(ss, alert_fatal, decode_error); |
+ PORT_SetError(SSL_ERROR_NEXT_PROTOCOL_DATA_INVALID); |
return SECFailure; |
} |
list_len = ssl3_ConsumeHandshakeNumber(ss, 2, &data->data, &data->len); |
/* The list has to be the entire extension. */ |
if (list_len != data->len) { |
- PORT_SetError(SSL_ERROR_NEXT_PROTOCOL_DATA_INVALID); |
(void)SSL3_SendAlert(ss, alert_fatal, decode_error); |
+ PORT_SetError(SSL_ERROR_NEXT_PROTOCOL_DATA_INVALID); |
return SECFailure; |
} |
@@ -795,8 +807,8 @@ ssl3_ClientHandleAppProtoXtn(sslSocket *ss, PRUint16 ex_type, SECItem *data) |
&data->data, &data->len); |
/* The list must have exactly one value. */ |
if (rv != SECSuccess || data->len != 0) { |
- PORT_SetError(SSL_ERROR_NEXT_PROTOCOL_DATA_INVALID); |
(void)SSL3_SendAlert(ss, alert_fatal, decode_error); |
+ PORT_SetError(SSL_ERROR_NEXT_PROTOCOL_DATA_INVALID); |
return SECFailure; |
} |
@@ -819,7 +831,10 @@ ssl3_ClientSendNextProtoNegoXtn(sslSocket * ss, PRBool append, |
extension_length = 4; |
- if (append && maxBytes >= extension_length) { |
+ if (maxBytes < (PRUint32)extension_length) { |
+ return 0; |
+ } |
+ if (append) { |
SECStatus rv; |
rv = ssl3_AppendHandshakeNumber(ss, ssl_next_proto_nego_xtn, 2); |
if (rv != SECSuccess) |
@@ -829,8 +844,6 @@ ssl3_ClientSendNextProtoNegoXtn(sslSocket * ss, PRBool append, |
goto loser; |
ss->xtnData.advertised[ss->xtnData.numAdvertised++] = |
ssl_next_proto_nego_xtn; |
- } else if (maxBytes < extension_length) { |
- return 0; |
} |
return extension_length; |
@@ -854,7 +867,10 @@ ssl3_ClientSendAppProtoXtn(sslSocket * ss, PRBool append, PRUint32 maxBytes) |
2 /* protocol name list length */ + |
ss->opt.nextProtoNego.len; |
- if (append && maxBytes >= extension_length) { |
+ if (maxBytes < (PRUint32)extension_length) { |
+ return 0; |
+ } |
+ if (append) { |
/* 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 |
@@ -894,8 +910,6 @@ ssl3_ClientSendAppProtoXtn(sslSocket * ss, PRBool append, PRUint32 maxBytes) |
} |
ss->xtnData.advertised[ss->xtnData.numAdvertised++] = |
ssl_app_layer_protocol_xtn; |
- } else if (maxBytes < extension_length) { |
- return 0; |
} |
return extension_length; |
@@ -923,7 +937,10 @@ ssl3_ServerSendAppProtoXtn(sslSocket * ss, PRBool append, PRUint32 maxBytes) |
2 /* protocol name list */ + 1 /* name length */ + |
ss->ssl3.nextProto.len; |
- if (append && maxBytes >= extension_length) { |
+ if (maxBytes < (PRUint32)extension_length) { |
+ return 0; |
+ } |
+ if (append) { |
SECStatus rv; |
rv = ssl3_AppendHandshakeNumber(ss, ssl_app_layer_protocol_xtn, 2); |
if (rv != SECSuccess) { |
@@ -942,8 +959,6 @@ ssl3_ServerSendAppProtoXtn(sslSocket * ss, PRBool append, PRUint32 maxBytes) |
if (rv != SECSuccess) { |
return -1; |
} |
- } else if (maxBytes < extension_length) { |
- return 0; |
} |
return extension_length; |
@@ -1045,7 +1060,10 @@ ssl3_ServerSendStatusRequestXtn( |
return 0; |
extension_length = 2 + 2; |
- if (append && maxBytes >= extension_length) { |
+ if (maxBytes < (PRUint32)extension_length) { |
+ return 0; |
+ } |
+ if (append) { |
/* extension_type */ |
rv = ssl3_AppendHandshakeNumber(ss, ssl_cert_status_xtn, 2); |
if (rv != SECSuccess) |
@@ -1078,7 +1096,11 @@ ssl3_ClientSendStatusRequestXtn(sslSocket * ss, PRBool append, |
*/ |
extension_length = 9; |
- if (append && maxBytes >= extension_length) { |
+ if (maxBytes < (PRUint32)extension_length) { |
+ PORT_Assert(0); |
+ return 0; |
+ } |
+ if (append) { |
SECStatus rv; |
TLSExtensionData *xtnData; |
@@ -1106,9 +1128,6 @@ ssl3_ClientSendStatusRequestXtn(sslSocket * ss, PRBool append, |
xtnData = &ss->xtnData; |
xtnData->advertised[xtnData->numAdvertised++] = ssl_cert_status_xtn; |
- } else if (maxBytes < extension_length) { |
- PORT_Assert(0); |
- return 0; |
} |
return extension_length; |
} |
@@ -1120,7 +1139,7 @@ ssl3_ClientSendStatusRequestXtn(sslSocket * ss, PRBool append, |
SECStatus |
ssl3_SendNewSessionTicket(sslSocket *ss) |
{ |
- int i; |
+ PRUint32 i; |
SECStatus rv; |
NewSessionTicket ticket; |
SECItem plaintext; |
@@ -1152,7 +1171,7 @@ ssl3_SendNewSessionTicket(sslSocket *ss) |
CK_MECHANISM_TYPE cipherMech = CKM_AES_CBC; |
PK11Context *aes_ctx_pkcs11; |
CK_MECHANISM_TYPE macMech = CKM_SHA256_HMAC; |
- PK11Context *hmac_ctx_pkcs11; |
+ PK11Context *hmac_ctx_pkcs11 = NULL; |
unsigned char computed_mac[TLS_EX_SESS_TICKET_MAC_LENGTH]; |
unsigned int computed_mac_length; |
unsigned char iv[AES_BLOCK_SIZE]; |
@@ -1200,7 +1219,8 @@ ssl3_SendNewSessionTicket(sslSocket *ss) |
sslSessionID sid; |
PORT_Memset(&sid, 0, sizeof(sslSessionID)); |
- if (ss->ssl3.hs.kea_def->kea == kea_ecdhe_rsa) { |
+ if (ss->ssl3.hs.kea_def->kea == kea_ecdhe_rsa || |
+ ss->ssl3.hs.kea_def->kea == kea_dhe_rsa) { |
effectiveExchKeyType = kt_rsa; |
} else { |
effectiveExchKeyType = ss->ssl3.hs.kea_def->exchKeyType; |
@@ -1243,6 +1263,7 @@ ssl3_SendNewSessionTicket(sslSocket *ss) |
+ cert_length /* cert */ |
+ 1 /* server name type */ |
+ srvNameLen /* name len + length field */ |
+ + 1 /* extendedMasterSecretUsed */ |
+ sizeof(ticket.ticket_lifetime_hint); |
padding_length = AES_BLOCK_SIZE - |
(ciphertext_length % AES_BLOCK_SIZE); |
@@ -1341,6 +1362,11 @@ ssl3_SendNewSessionTicket(sslSocket *ss) |
if (rv != SECSuccess) goto loser; |
} |
+ /* extendedMasterSecretUsed */ |
+ rv = ssl3_AppendNumberToItem( |
+ &plaintext, ss->sec.ci.sid->u.ssl3.keys.extendedMasterSecretUsed, 1); |
+ if (rv != SECSuccess) goto loser; |
+ |
PORT_Assert(plaintext.len == padding_length); |
for (i = 0; i < padding_length; i++) |
plaintext.data[i] = (unsigned char)padding_length; |
@@ -1410,14 +1436,18 @@ ssl3_SendNewSessionTicket(sslSocket *ss) |
goto loser; |
rv = PK11_DigestBegin(hmac_ctx_pkcs11); |
+ if (rv != SECSuccess) goto loser; |
rv = PK11_DigestOp(hmac_ctx_pkcs11, key_name, |
SESS_TICKET_KEY_NAME_LEN); |
+ if (rv != SECSuccess) goto loser; |
rv = PK11_DigestOp(hmac_ctx_pkcs11, iv, sizeof(iv)); |
+ if (rv != SECSuccess) goto loser; |
rv = PK11_DigestOp(hmac_ctx_pkcs11, (unsigned char *)length_buf, 2); |
+ if (rv != SECSuccess) goto loser; |
rv = PK11_DigestOp(hmac_ctx_pkcs11, ciphertext.data, ciphertext.len); |
+ if (rv != SECSuccess) goto loser; |
rv = PK11_DigestFinal(hmac_ctx_pkcs11, computed_mac, |
&computed_mac_length, sizeof(computed_mac)); |
- PK11_DestroyContext(hmac_ctx_pkcs11, PR_TRUE); |
if (rv != SECSuccess) goto loser; |
} |
@@ -1446,6 +1476,8 @@ ssl3_SendNewSessionTicket(sslSocket *ss) |
if (rv != SECSuccess) goto loser; |
loser: |
+ if (hmac_ctx_pkcs11) |
+ PK11_DestroyContext(hmac_ctx_pkcs11, PR_TRUE); |
if (plaintext_item.data) |
SECITEM_FreeItem(&plaintext_item, PR_FALSE); |
if (ciphertext.data) |
@@ -1495,7 +1527,7 @@ ssl3_ServerHandleSessionTicketXtn(sslSocket *ss, PRUint16 ex_type, |
if (data->len == 0) { |
ss->xtnData.emptySessionTicket = PR_TRUE; |
} else { |
- int i; |
+ PRUint32 i; |
SECItem extension_data; |
EncryptedSessionTicket enc_session_ticket; |
unsigned char computed_mac[TLS_EX_SESS_TICKET_MAC_LENGTH]; |
@@ -1698,9 +1730,10 @@ ssl3_ServerHandleSessionTicketXtn(sslSocket *ss, PRUint16 ex_type, |
goto loser; |
} |
- /* Read ticket_version (which is ignored for now.) */ |
+ /* Read ticket_version and reject if the version is wrong */ |
temp = ssl3_ConsumeHandshakeNumber(ss, 2, &buffer, &buffer_len); |
- if (temp < 0) goto no_ticket; |
+ if (temp != TLS_EX_SESS_TICKET_VERSION) goto no_ticket; |
+ |
parsed_session_ticket->ticket_version = (SSL3ProtocolVersion)temp; |
/* Read SSLVersion. */ |
@@ -1801,6 +1834,13 @@ ssl3_ServerHandleSessionTicketXtn(sslSocket *ss, PRUint16 ex_type, |
parsed_session_ticket->srvName.type = nameType; |
} |
+ /* Read extendedMasterSecretUsed */ |
+ temp = ssl3_ConsumeHandshakeNumber(ss, 1, &buffer, &buffer_len); |
+ if (temp < 0) |
+ goto no_ticket; |
+ PORT_Assert(temp == PR_TRUE || temp == PR_FALSE); |
+ parsed_session_ticket->extendedMasterSecretUsed = (PRBool)temp; |
+ |
/* Done parsing. Check that all bytes have been consumed. */ |
if (buffer_len != padding_length) |
goto no_ticket; |
@@ -1847,6 +1887,8 @@ ssl3_ServerHandleSessionTicketXtn(sslSocket *ss, PRUint16 ex_type, |
parsed_session_ticket->ms_is_wrapped; |
sid->u.ssl3.masterValid = PR_TRUE; |
sid->u.ssl3.keys.resumable = PR_TRUE; |
+ sid->u.ssl3.keys.extendedMasterSecretUsed = parsed_session_ticket-> |
+ extendedMasterSecretUsed; |
/* Copy over client cert from session ticket if there is one. */ |
if (parsed_session_ticket->peer_cert.data != NULL) { |
@@ -2085,7 +2127,10 @@ ssl3_SendRenegotiationInfoXtn( |
(ss->sec.isServer ? ss->ssl3.hs.finishedBytes * 2 |
: ss->ssl3.hs.finishedBytes); |
needed = 5 + len; |
- if (append && maxBytes >= needed) { |
+ if (maxBytes < (PRUint32)needed) { |
+ return 0; |
+ } |
+ if (append) { |
SECStatus rv; |
/* extension_type */ |
rv = ssl3_AppendHandshakeNumber(ss, ssl_renegotiation_info_xtn, 2); |
@@ -2138,8 +2183,8 @@ ssl3_HandleRenegotiationInfoXtn(sslSocket *ss, PRUint16 ex_type, SECItem *data) |
} |
if (len && NSS_SecureMemcmp(ss->ssl3.hs.finishedMsgs.data, |
data->data + 1, len)) { |
- PORT_SetError(SSL_ERROR_BAD_HANDSHAKE_HASH_VALUE); |
(void)SSL3_SendAlert(ss, alert_fatal, handshake_failure); |
+ PORT_SetError(SSL_ERROR_BAD_HANDSHAKE_HASH_VALUE); |
return SECFailure; |
} |
/* remember that we got this extension and it was correct. */ |
@@ -2263,8 +2308,8 @@ ssl3_ClientHandleUseSRTPXtn(sslSocket * ss, PRUint16 ex_type, SECItem *data) |
} |
if (!found) { |
- PORT_SetError(SSL_ERROR_RX_MALFORMED_SERVER_HELLO); |
(void)SSL3_SendAlert(ss, alert_fatal, illegal_parameter); |
+ PORT_SetError(SSL_ERROR_RX_MALFORMED_SERVER_HELLO); |
return SECFailure; |
} |
@@ -2277,8 +2322,8 @@ ssl3_ClientHandleUseSRTPXtn(sslSocket * ss, PRUint16 ex_type, SECItem *data) |
/* We didn't offer an MKI, so this must be 0 length */ |
if (litem.len != 0) { |
- PORT_SetError(SSL_ERROR_RX_MALFORMED_SERVER_HELLO); |
(void)SSL3_SendAlert(ss, alert_fatal, illegal_parameter); |
+ PORT_SetError(SSL_ERROR_RX_MALFORMED_SERVER_HELLO); |
return SECFailure; |
} |
@@ -2374,7 +2419,7 @@ ssl3_ServerHandleSigAlgsXtn(sslSocket * ss, PRUint16 ex_type, SECItem *data) |
SECStatus rv; |
SECItem algorithms; |
const unsigned char *b; |
- unsigned int numAlgorithms, i, j; |
+ unsigned int numAlgorithms, i; |
/* Ignore this extension if we aren't doing TLS 1.2 or greater. */ |
if (ss->version < SSL_LIBRARY_VERSION_TLS_1_2) { |
@@ -2388,8 +2433,8 @@ ssl3_ServerHandleSigAlgsXtn(sslSocket * ss, PRUint16 ex_type, SECItem *data) |
} |
/* Trailing data, empty value, or odd-length value is invalid. */ |
if (data->len != 0 || algorithms.len == 0 || (algorithms.len & 1) != 0) { |
- PORT_SetError(SSL_ERROR_RX_MALFORMED_CLIENT_HELLO); |
(void)SSL3_SendAlert(ss, alert_fatal, decode_error); |
+ PORT_SetError(SSL_ERROR_RX_MALFORMED_CLIENT_HELLO); |
return SECFailure; |
} |
@@ -2401,30 +2446,24 @@ ssl3_ServerHandleSigAlgsXtn(sslSocket * ss, PRUint16 ex_type, SECItem *data) |
} |
ss->ssl3.hs.clientSigAndHash = |
- PORT_NewArray(SSL3SignatureAndHashAlgorithm, numAlgorithms); |
+ PORT_NewArray(SSLSignatureAndHashAlg, numAlgorithms); |
if (!ss->ssl3.hs.clientSigAndHash) { |
- PORT_SetError(SSL_ERROR_RX_MALFORMED_CLIENT_HELLO); |
(void)SSL3_SendAlert(ss, alert_fatal, internal_error); |
+ PORT_SetError(SSL_ERROR_RX_MALFORMED_CLIENT_HELLO); |
return SECFailure; |
} |
ss->ssl3.hs.numClientSigAndHash = 0; |
b = algorithms.data; |
- for (i = j = 0; i < numAlgorithms; i++) { |
- unsigned char tls_hash = *(b++); |
- unsigned char tls_sig = *(b++); |
- SECOidTag hash = ssl3_TLSHashAlgorithmToOID(tls_hash); |
- |
- if (hash == SEC_OID_UNKNOWN) { |
- /* We ignore formats that we don't understand. */ |
- continue; |
+ ss->ssl3.hs.numClientSigAndHash = 0; |
+ for (i = 0; i < numAlgorithms; i++) { |
+ SSLSignatureAndHashAlg *sigAndHash = |
+ &ss->ssl3.hs.clientSigAndHash[ss->ssl3.hs.numClientSigAndHash]; |
+ sigAndHash->hashAlg = (SSLHashType)*(b++); |
+ sigAndHash->sigAlg = (SSLSignType)*(b++); |
+ if (ssl3_IsSupportedSignatureAlgorithm(sigAndHash)) { |
+ ++ss->ssl3.hs.numClientSigAndHash; |
} |
- /* tls_sig support will be checked later in |
- * ssl3_PickSignatureHashAlgorithm. */ |
- ss->ssl3.hs.clientSigAndHash[j].hashAlg = hash; |
- ss->ssl3.hs.clientSigAndHash[j].sigAlg = tls_sig; |
- ++j; |
- ++ss->ssl3.hs.numClientSigAndHash; |
} |
if (!ss->ssl3.hs.numClientSigAndHash) { |
@@ -2442,60 +2481,60 @@ ssl3_ServerHandleSigAlgsXtn(sslSocket * ss, PRUint16 ex_type, SECItem *data) |
/* ssl3_ClientSendSigAlgsXtn sends the signature_algorithm extension for TLS |
* 1.2 ClientHellos. */ |
static PRInt32 |
-ssl3_ClientSendSigAlgsXtn(sslSocket * ss, PRBool append, PRUint32 maxBytes) |
+ssl3_ClientSendSigAlgsXtn(sslSocket *ss, PRBool append, PRUint32 maxBytes) |
{ |
- static const unsigned char signatureAlgorithms[] = { |
- /* This block is the contents of our signature_algorithms extension, in |
- * wire format. See |
- * https://tools.ietf.org/html/rfc5246#section-7.4.1.4.1 */ |
- tls_hash_sha256, tls_sig_rsa, |
- tls_hash_sha384, tls_sig_rsa, |
- tls_hash_sha512, tls_sig_rsa, |
- tls_hash_sha1, tls_sig_rsa, |
-#ifndef NSS_DISABLE_ECC |
- tls_hash_sha256, tls_sig_ecdsa, |
- tls_hash_sha384, tls_sig_ecdsa, |
- tls_hash_sha512, tls_sig_ecdsa, |
- tls_hash_sha1, tls_sig_ecdsa, |
-#endif |
- tls_hash_sha256, tls_sig_dsa, |
- tls_hash_sha1, tls_sig_dsa, |
- }; |
PRInt32 extension_length; |
+ unsigned int i; |
+ PRInt32 pos=0; |
+ PRUint32 policy; |
+ PRUint8 buf[MAX_SIGNATURE_ALGORITHMS * 2]; |
if (ss->version < SSL_LIBRARY_VERSION_TLS_1_2) { |
return 0; |
} |
+ for (i=0; i < ss->ssl3.signatureAlgorithmCount; i++) { |
+ SECOidTag hashOID = ssl3_TLSHashAlgorithmToOID( |
+ ss->ssl3.signatureAlgorithms[i].hashAlg); |
+ if ((NSS_GetAlgorithmPolicy(hashOID, & policy) != SECSuccess) || |
+ (policy & NSS_USE_ALG_IN_SSL_KX)) { |
+ buf[pos++] = ss->ssl3.signatureAlgorithms[i].hashAlg; |
+ buf[pos++] = ss->ssl3.signatureAlgorithms[i].sigAlg; |
+ } |
+ } |
+ |
extension_length = |
2 /* extension type */ + |
2 /* extension length */ + |
2 /* supported_signature_algorithms length */ + |
- sizeof(signatureAlgorithms); |
+ pos; |
+ |
+ if (maxBytes < extension_length) { |
+ PORT_Assert(0); |
+ return 0; |
+ } |
- if (append && maxBytes >= extension_length) { |
+ if (append) { |
SECStatus rv; |
rv = ssl3_AppendHandshakeNumber(ss, ssl_signature_algorithms_xtn, 2); |
- if (rv != SECSuccess) |
- goto loser; |
+ if (rv != SECSuccess) { |
+ return -1; |
+ } |
rv = ssl3_AppendHandshakeNumber(ss, extension_length - 4, 2); |
- if (rv != SECSuccess) |
- goto loser; |
- rv = ssl3_AppendHandshakeVariable(ss, signatureAlgorithms, |
- sizeof(signatureAlgorithms), 2); |
- if (rv != SECSuccess) |
- goto loser; |
+ if (rv != SECSuccess) { |
+ return -1; |
+ } |
+ |
+ rv = ssl3_AppendHandshakeVariable(ss, buf, extension_length - 6, 2); |
+ if (rv != SECSuccess) { |
+ return -1; |
+ } |
+ |
ss->xtnData.advertised[ss->xtnData.numAdvertised++] = |
ssl_signature_algorithms_xtn; |
- } else if (maxBytes < extension_length) { |
- PORT_Assert(0); |
- return 0; |
} |
return extension_length; |
- |
-loser: |
- return -1; |
} |
unsigned int |
@@ -2565,7 +2604,11 @@ ssl3_ClientSendDraftVersionXtn(sslSocket * ss, PRBool append, PRUint32 maxBytes) |
} |
extension_length = 6; /* Type + length + number */ |
- if (append && maxBytes >= extension_length) { |
+ if (maxBytes < (PRUint32)extension_length) { |
+ PORT_Assert(0); |
+ return 0; |
+ } |
+ if (append) { |
SECStatus rv; |
rv = ssl3_AppendHandshakeNumber(ss, ssl_tls13_draft_version_xtn, 2); |
if (rv != SECSuccess) |
@@ -2578,9 +2621,6 @@ ssl3_ClientSendDraftVersionXtn(sslSocket * ss, PRBool append, PRUint32 maxBytes) |
goto loser; |
ss->xtnData.advertised[ss->xtnData.numAdvertised++] = |
ssl_tls13_draft_version_xtn; |
- } else if (maxBytes < extension_length) { |
- PORT_Assert(0); |
- return 0; |
} |
return extension_length; |
@@ -2633,6 +2673,51 @@ ssl3_ServerHandleDraftVersionXtn(sslSocket * ss, PRUint16 ex_type, |
return SECSuccess; |
} |
+static PRInt32 |
+ssl3_SendExtendedMasterSecretXtn(sslSocket * ss, PRBool append, |
+ PRUint32 maxBytes) |
+{ |
+ PRInt32 extension_length; |
+ |
+ if (!ss->opt.enableExtendedMS) { |
+ return 0; |
+ } |
+ |
+#ifndef NO_PKCS11_BYPASS |
+ /* Extended MS can only be used w/o bypass mode */ |
+ if (ss->opt.bypassPKCS11) { |
+ PORT_Assert(0); |
+ PORT_SetError(PR_NOT_IMPLEMENTED_ERROR); |
+ return -1; |
+ } |
+#endif |
+ |
+ /* Always send the extension in this function, since the |
+ * client always sends it and this function is only called on |
+ * the server if we negotiated the extension. */ |
+ extension_length = 4; /* Type + length (0) */ |
+ if (maxBytes < extension_length) { |
+ PORT_Assert(0); |
+ return 0; |
+ } |
+ |
+ if (append) { |
+ SECStatus rv; |
+ rv = ssl3_AppendHandshakeNumber(ss, ssl_extended_master_secret_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_extended_master_secret_xtn; |
+ } |
+ |
+ return extension_length; |
+loser: |
+ return -1; |
+} |
+ |
/* ssl3_ClientSendSignedCertTimestampXtn sends the signed_certificate_timestamp |
* extension for TLS ClientHellos. */ |
static PRInt32 |
@@ -2646,7 +2731,12 @@ ssl3_ClientSendSignedCertTimestampXtn(sslSocket *ss, PRBool append, |
if (!ss->opt.enableSignedCertTimestamps) |
return 0; |
- if (append && maxBytes >= extension_length) { |
+ if (maxBytes < extension_length) { |
+ PORT_Assert(0); |
+ return 0; |
+ } |
+ |
+ if (append) { |
SECStatus rv; |
/* extension_type */ |
rv = ssl3_AppendHandshakeNumber(ss, |
@@ -2660,9 +2750,6 @@ ssl3_ClientSendSignedCertTimestampXtn(sslSocket *ss, PRBool append, |
goto loser; |
ss->xtnData.advertised[ss->xtnData.numAdvertised++] = |
ssl_signed_certificate_timestamp_xtn; |
- } else if (maxBytes < extension_length) { |
- PORT_Assert(0); |
- return 0; |
} |
return extension_length; |
@@ -2671,6 +2758,46 @@ loser: |
} |
static SECStatus |
+ssl3_HandleExtendedMasterSecretXtn(sslSocket * ss, PRUint16 ex_type, |
+ SECItem *data) |
+{ |
+ if (ss->version < SSL_LIBRARY_VERSION_TLS_1_0) { |
+ return SECSuccess; |
+ } |
+ |
+ if (!ss->opt.enableExtendedMS) { |
+ return SECSuccess; |
+ } |
+ |
+#ifndef NO_PKCS11_BYPASS |
+ /* Extended MS can only be used w/o bypass mode */ |
+ if (ss->opt.bypassPKCS11) { |
+ PORT_Assert(0); |
+ PORT_SetError(PR_NOT_IMPLEMENTED_ERROR); |
+ return SECFailure; |
+ } |
+#endif |
+ |
+ if (data->len != 0) { |
+ SSL_TRC(30, ("%d: SSL3[%d]: Bogus extended master secret extension", |
+ SSL_GETPID(), ss->fd)); |
+ return SECFailure; |
+ } |
+ |
+ SSL_DBG(("%d: SSL[%d]: Negotiated extended master secret extension.", |
+ SSL_GETPID(), ss->fd)); |
+ |
+ /* Keep track of negotiated extensions. */ |
+ ss->xtnData.negotiated[ss->xtnData.numNegotiated++] = ex_type; |
+ |
+ if (ss->sec.isServer) { |
+ return ssl3_RegisterServerHelloExtensionSender( |
+ ss, ex_type, ssl3_SendExtendedMasterSecretXtn); |
+ } |
+ return SECSuccess; |
+} |
+ |
+static SECStatus |
ssl3_ClientHandleSignedCertTimestampXtn(sslSocket *ss, PRUint16 ex_type, |
SECItem *data) |
{ |