Index: net/third_party/nss/ssl/ssl3con.c |
=================================================================== |
--- net/third_party/nss/ssl/ssl3con.c (revision 252347) |
+++ net/third_party/nss/ssl/ssl3con.c (working copy) |
@@ -1384,6 +1384,7 @@ |
ssl3_CleanupKeyMaterial(&spec->client); |
ssl3_CleanupKeyMaterial(&spec->server); |
spec->bypassCiphers = PR_FALSE; |
+ spec->encryptThenMAC = PR_FALSE; |
spec->destroy=NULL; |
spec->destroyCompressContext = NULL; |
spec->destroyDecompressContext = NULL; |
@@ -1469,6 +1470,9 @@ |
pwSpec->compressContext = NULL; |
pwSpec->decompressContext = NULL; |
+ pwSpec->encryptThenMAC = |
+ ssl3_ExtensionNegotiated(ss, ssl_encrypt_then_mac_xtn); |
+ |
ssl_ReleaseSpecWriteLock(ss); /*******************************/ |
return SECSuccess; |
} |
@@ -2732,20 +2736,26 @@ |
return SECFailure; |
} |
} else { |
- /* |
- * Add the MAC |
- */ |
- rv = ssl3_ComputeRecordMAC(cwSpec, isServer, |
- pseudoHeader, pseudoHeaderLen, pIn, contentLen, |
- wrBuf->buf + headerLen + ivLen + contentLen, &macLen); |
- if (rv != SECSuccess) { |
- ssl_MapLowLevelError(SSL_ERROR_MAC_COMPUTATION_FAILURE); |
- return SECFailure; |
+ if (!cwSpec->encryptThenMAC) { |
+ /* |
+ * Add the MAC |
+ */ |
+ rv = ssl3_ComputeRecordMAC(cwSpec, isServer, |
+ pseudoHeader, pseudoHeaderLen, pIn, contentLen, |
+ wrBuf->buf + headerLen + ivLen + contentLen, &macLen); |
+ if (rv != SECSuccess) { |
+ ssl_MapLowLevelError(SSL_ERROR_MAC_COMPUTATION_FAILURE); |
+ return SECFailure; |
+ } |
+ p1Len = contentLen; |
+ p2Len = macLen; |
+ fragLen = contentLen + macLen; /* needs to be encrypted */ |
+ PORT_Assert(fragLen <= MAX_FRAGMENT_LENGTH + 1024); |
+ } else { |
+ p1Len = contentLen; |
+ p2Len = 0; |
+ fragLen = contentLen; /* needs to be encrypted */ |
} |
- p1Len = contentLen; |
- p2Len = macLen; |
- fragLen = contentLen + macLen; /* needs to be encrypted */ |
- PORT_Assert(fragLen <= MAX_FRAGMENT_LENGTH + 1024); |
/* |
* Pad the text (if we're doing a block cipher) |
@@ -2813,6 +2823,29 @@ |
} |
cipherBytes += cipherBytesPart2; |
} |
+ |
+ if (cwSpec->encryptThenMAC) { |
+ /* |
+ * Add the MAC |
+ */ |
+ pseudoHeaderLen = ssl3_BuildRecordPseudoHeader( |
+ pseudoHeader, cwSpec->write_seq_num, type, |
+ cwSpec->version >= SSL_LIBRARY_VERSION_TLS_1_0, cwSpec->version, |
+ isDTLS, cipherBytes /* + crSpec->mac_size */); |
+ PORT_Assert(pseudoHeaderLen <= sizeof(pseudoHeader)); |
+ |
+ rv = ssl3_ComputeRecordMAC(cwSpec, isServer, |
+ pseudoHeader, pseudoHeaderLen, |
+ wrBuf->buf + headerLen, cipherBytes, |
+ wrBuf->buf + headerLen + cipherBytes, &macLen); |
+ if (rv != SECSuccess) { |
+ ssl_MapLowLevelError(SSL_ERROR_MAC_COMPUTATION_FAILURE); |
+ return SECFailure; |
+ } |
+ PORT_Assert(macLen == cwSpec->mac_size); |
+ cipherBytes += macLen; |
+ PORT_Assert(cipherBytes <= MAX_FRAGMENT_LENGTH + 1024); |
+ } |
} |
PORT_Assert(cipherBytes <= MAX_FRAGMENT_LENGTH + 1024); |
@@ -9079,7 +9112,7 @@ |
extensions_len -= 2; |
rv = ssl3_AppendHandshakeNumber(ss, extensions_len, 2); |
if (rv != SECSuccess) |
- return rv; /* err set by ssl3_SetupPendingCipherSpec */ |
+ return rv; /* err set by AppendHandshake. */ |
sent_len = ssl3_CallHelloExtensionSenders(ss, PR_TRUE, extensions_len, |
&ss->xtnData.serverSenders[0]); |
PORT_Assert(sent_len == extensions_len); |
@@ -11921,6 +11954,7 @@ |
rType = content_handshake; |
goto process_it; |
} |
+ rType = cText->type; |
ssl_GetSpecReadLock(ss); /******************************************/ |
@@ -11979,6 +12013,31 @@ |
goto decrypt_loser; |
} |
+ if (crSpec->encryptThenMAC) { |
+ /* compute the MAC */ |
+ headerLen = ssl3_BuildRecordPseudoHeader( |
+ header, IS_DTLS(ss) ? cText->seq_num : crSpec->read_seq_num, |
+ rType, isTLS, cText->version, IS_DTLS(ss), |
+ cText->buf->len - crSpec->mac_size); |
+ PORT_Assert(headerLen <= sizeof(header)); |
+ /* This is safe because we checked the minLength above. */ |
+ cText->buf->len -= crSpec->mac_size; |
+ |
+ rv = ssl3_ComputeRecordMAC( |
+ crSpec, (PRBool)(!ss->sec.isServer), header, headerLen, |
+ cText->buf->buf, cText->buf->len, hash, &hashBytes); |
+ |
+ /* We can read the MAC directly from the record because its location |
+ * is public when a stream cipher is used. */ |
+ givenHash = cText->buf->buf + cText->buf->len; |
+ |
+ if (hashBytes != (unsigned)crSpec->mac_size || |
+ NSS_SecureMemcmp(givenHash, hash, crSpec->mac_size) != 0) { |
+ /* We're allowed to leak whether or not the MAC check was correct */ |
+ goto decrypt_loser; |
+ } |
+ } |
+ |
if (cipher_def->type == type_block && |
crSpec->version >= SSL_LIBRARY_VERSION_TLS_1_1) { |
/* Consume the per-record explicit IV. RFC 4346 Section 6.2.3.2 states |
@@ -12044,7 +12103,6 @@ |
return SECFailure; |
} |
- rType = cText->type; |
if (cipher_def->type == type_aead) { |
/* XXX For many AEAD ciphers, the plaintext is shorter than the |
* ciphertext by a fixed byte count, but it is not true in general. |
@@ -12090,7 +12148,8 @@ |
/* If it's a block cipher, check and strip the padding. */ |
if (cipher_def->type == type_block) { |
const unsigned int blockSize = cipher_def->block_size; |
- const unsigned int macSize = crSpec->mac_size; |
+ const unsigned int macSize = |
+ crSpec->encryptThenMAC ? 0 : crSpec->mac_size; |
if (!isTLS) { |
good &= SECStatusToMask(ssl_RemoveSSLv3CBCPadding( |
@@ -12101,6 +12160,7 @@ |
} |
} |
+ if (!crSpec->encryptThenMAC) { |
/* compute the MAC */ |
headerLen = ssl3_BuildRecordPseudoHeader( |
header, IS_DTLS(ss) ? cText->seq_num : crSpec->read_seq_num, |
@@ -12142,6 +12202,7 @@ |
/* We're allowed to leak whether or not the MAC check was correct */ |
good = 0; |
} |
+ } |
} |
if (good == 0) { |
@@ -12317,6 +12378,7 @@ |
spec->mac_size = 0; |
spec->master_secret = NULL; |
spec->bypassCiphers = PR_FALSE; |
+ spec->encryptThenMAC = PR_FALSE; |
spec->msItem.data = NULL; |
spec->msItem.len = 0; |