| Index: net/third_party/nss/patches/cbc.patch
|
| diff --git a/net/third_party/nss/patches/cbc.patch b/net/third_party/nss/patches/cbc.patch
|
| new file mode 100644
|
| index 0000000000000000000000000000000000000000..aa36bcd918eb059bf044aad340a5500583073c99
|
| --- /dev/null
|
| +++ b/net/third_party/nss/patches/cbc.patch
|
| @@ -0,0 +1,511 @@
|
| +diff --git a/mozilla/security/nss/lib/ssl/ssl3con.c b/mozilla/security/nss/lib/ssl/ssl3con.c
|
| +index c3706fe..4247f44 100644
|
| +--- a/mozilla/security/nss/lib/ssl/ssl3con.c
|
| ++++ b/mozilla/security/nss/lib/ssl/ssl3con.c
|
| +@@ -1844,7 +1844,6 @@ static const unsigned char mac_pad_2 [60] = {
|
| + };
|
| +
|
| + /* Called from: ssl3_SendRecord()
|
| +-** ssl3_HandleRecord()
|
| + ** Caller must already hold the SpecReadLock. (wish we could assert that!)
|
| + */
|
| + static SECStatus
|
| +@@ -2026,6 +2025,128 @@ ssl3_ComputeRecordMAC(
|
| + return rv;
|
| + }
|
| +
|
| ++/* This is a bodge to allow this code to be compiled against older NSS headers
|
| ++ * that don't contain the CBC constant-time changes. */
|
| ++#ifndef CKM_NSS_HMAC_CONSTANT_TIME
|
| ++#define CKM_NSS_HMAC_CONSTANT_TIME (CKM_NSS + 19)
|
| ++#define CKM_NSS_SSLV3_MAC_CONSTANT_TIME (CKM_NSS + 20)
|
| ++
|
| ++typedef struct CK_NSS_MACConstantTimeParams {
|
| ++ CK_MECHANISM_TYPE hashAlg; /* in */
|
| ++ CK_ULONG ulBodyTotalLength; /* in */
|
| ++ CK_BYTE * pHeader; /* in */
|
| ++ CK_ULONG ulHeaderLength; /* in */
|
| ++} CK_NSS_MACConstantTimeParams;
|
| ++#endif
|
| ++
|
| ++/* Called from: ssl3_HandleRecord()
|
| ++ * Caller must already hold the SpecReadLock. (wish we could assert that!)
|
| ++ *
|
| ++ * On entry:
|
| ++ * originalLen >= inputLen >= MAC size
|
| ++*/
|
| ++static SECStatus
|
| ++ssl3_ComputeRecordMACConstantTime(
|
| ++ ssl3CipherSpec * spec,
|
| ++ PRBool useServerMacKey,
|
| ++ PRBool isDTLS,
|
| ++ SSL3ContentType type,
|
| ++ SSL3ProtocolVersion version,
|
| ++ SSL3SequenceNumber seq_num,
|
| ++ const SSL3Opaque * input,
|
| ++ int inputLen,
|
| ++ int originalLen,
|
| ++ unsigned char * outbuf,
|
| ++ unsigned int * outLen)
|
| ++{
|
| ++ CK_MECHANISM_TYPE macType;
|
| ++ CK_NSS_MACConstantTimeParams params;
|
| ++ PK11Context * mac_context;
|
| ++ SECItem param;
|
| ++ SECStatus rv;
|
| ++ unsigned char header[13];
|
| ++ PK11SymKey * key;
|
| ++ int recordLength;
|
| ++
|
| ++ PORT_Assert(inputLen >= spec->mac_size);
|
| ++ PORT_Assert(originalLen >= inputLen);
|
| ++
|
| ++ if (spec->bypassCiphers) {
|
| ++ /* This function doesn't support PKCS#11 bypass. We fallback on the
|
| ++ * non-constant time version. */
|
| ++ goto fallback;
|
| ++ }
|
| ++
|
| ++ if (spec->mac_def->mac == mac_null) {
|
| ++ *outLen = 0;
|
| ++ return SECSuccess;
|
| ++ }
|
| ++
|
| ++ header[0] = (unsigned char)(seq_num.high >> 24);
|
| ++ header[1] = (unsigned char)(seq_num.high >> 16);
|
| ++ header[2] = (unsigned char)(seq_num.high >> 8);
|
| ++ header[3] = (unsigned char)(seq_num.high >> 0);
|
| ++ header[4] = (unsigned char)(seq_num.low >> 24);
|
| ++ header[5] = (unsigned char)(seq_num.low >> 16);
|
| ++ header[6] = (unsigned char)(seq_num.low >> 8);
|
| ++ header[7] = (unsigned char)(seq_num.low >> 0);
|
| ++ header[8] = type;
|
| ++
|
| ++ macType = CKM_NSS_HMAC_CONSTANT_TIME;
|
| ++ recordLength = inputLen - spec->mac_size;
|
| ++ if (spec->version <= SSL_LIBRARY_VERSION_3_0) {
|
| ++ macType = CKM_NSS_SSLV3_MAC_CONSTANT_TIME;
|
| ++ header[9] = recordLength >> 8;
|
| ++ header[10] = recordLength;
|
| ++ params.ulHeaderLength = 11;
|
| ++ } else {
|
| ++ header[9] = version >> 8;
|
| ++ header[10] = version;
|
| ++ header[11] = recordLength >> 8;
|
| ++ header[12] = recordLength;
|
| ++ params.ulHeaderLength = 13;
|
| ++ }
|
| ++
|
| ++ params.hashAlg = spec->mac_def->mmech;
|
| ++ params.ulBodyTotalLength = originalLen;
|
| ++ params.pHeader = header;
|
| ++
|
| ++ param.data = (unsigned char*) ¶ms;
|
| ++ param.len = sizeof(params);
|
| ++ param.type = 0;
|
| ++
|
| ++ key = spec->server.write_mac_key;
|
| ++ if (!useServerMacKey) {
|
| ++ key = spec->client.write_mac_key;
|
| ++ }
|
| ++ mac_context = PK11_CreateContextBySymKey(macType, CKA_SIGN, key, ¶m);
|
| ++ if (mac_context == NULL) {
|
| ++ /* Older versions of NSS may not support constant-time MAC. */
|
| ++ goto fallback;
|
| ++ }
|
| ++
|
| ++ rv = PK11_DigestBegin(mac_context);
|
| ++ rv |= PK11_DigestOp(mac_context, input, inputLen);
|
| ++ rv |= PK11_DigestFinal(mac_context, outbuf, outLen, spec->mac_size);
|
| ++ PK11_DestroyContext(mac_context, PR_TRUE);
|
| ++
|
| ++ PORT_Assert(rv != SECSuccess || *outLen == (unsigned)spec->mac_size);
|
| ++
|
| ++ if (rv != SECSuccess) {
|
| ++ rv = SECFailure;
|
| ++ ssl_MapLowLevelError(SSL_ERROR_MAC_COMPUTATION_FAILURE);
|
| ++ }
|
| ++ return rv;
|
| ++
|
| ++fallback:
|
| ++ /* ssl3_ComputeRecordMAC expects the MAC to have been removed from the
|
| ++ * length already. */
|
| ++ inputLen -= spec->mac_size;
|
| ++ return ssl3_ComputeRecordMAC(spec, useServerMacKey, isDTLS, type,
|
| ++ version, seq_num, input, inputLen,
|
| ++ outbuf, outLen);
|
| ++}
|
| ++
|
| + static PRBool
|
| + ssl3_ClientAuthTokenPresent(sslSessionID *sid) {
|
| + PK11SlotInfo *slot = NULL;
|
| +@@ -9530,6 +9651,177 @@ ssl3_HandleHandshake(sslSocket *ss, sslBuffer *origBuf)
|
| + return SECSuccess;
|
| + }
|
| +
|
| ++/* These macros return the given value with the MSB copied to all the other
|
| ++ * bits. They use the fact that arithmetic shift shifts-in the sign bit.
|
| ++ * However, this is not ensured by the C standard so you may need to replace
|
| ++ * them with something else for odd compilers. */
|
| ++#define DUPLICATE_MSB_TO_ALL(x) ( (unsigned)( (int)(x) >> (sizeof(int)*8-1) ) )
|
| ++#define DUPLICATE_MSB_TO_ALL_8(x) ((unsigned char)(DUPLICATE_MSB_TO_ALL(x)))
|
| ++
|
| ++/* SECStatusToMask returns, in constant time, a mask value of all ones if rv ==
|
| ++ * SECSuccess. Otherwise it returns zero. */
|
| ++static unsigned SECStatusToMask(SECStatus rv)
|
| ++{
|
| ++ unsigned int good;
|
| ++ /* rv ^ SECSuccess is zero iff rv == SECSuccess. Subtracting one results in
|
| ++ * the MSB being set to one iff it was zero before. */
|
| ++ good = rv ^ SECSuccess;
|
| ++ good--;
|
| ++ return DUPLICATE_MSB_TO_ALL(good);
|
| ++}
|
| ++
|
| ++/* ssl_ConstantTimeGE returns 0xff if a>=b and 0x00 otherwise. */
|
| ++static unsigned char ssl_ConstantTimeGE(unsigned a, unsigned b)
|
| ++{
|
| ++ a -= b;
|
| ++ return DUPLICATE_MSB_TO_ALL(~a);
|
| ++}
|
| ++
|
| ++/* ssl_ConstantTimeEQ8 returns 0xff if a==b and 0x00 otherwise. */
|
| ++static unsigned char ssl_ConstantTimeEQ8(unsigned char a, unsigned char b)
|
| ++{
|
| ++ unsigned c = a ^ b;
|
| ++ c--;
|
| ++ return DUPLICATE_MSB_TO_ALL_8(c);
|
| ++}
|
| ++
|
| ++static SECStatus ssl_RemoveSSLv3CBCPadding(sslBuffer *plaintext,
|
| ++ unsigned blockSize,
|
| ++ unsigned macSize) {
|
| ++ unsigned int paddingLength, good, t;
|
| ++ const unsigned int overhead = 1 /* padding length byte */ + macSize;
|
| ++
|
| ++ /* These lengths are all public so we can test them in non-constant
|
| ++ * time. */
|
| ++ if (overhead > plaintext->len) {
|
| ++ return SECFailure;
|
| ++ }
|
| ++
|
| ++ paddingLength = plaintext->buf[plaintext->len-1];
|
| ++ /* SSLv3 padding bytes are random and cannot be checked. */
|
| ++ t = plaintext->len;
|
| ++ t -= paddingLength+overhead;
|
| ++ /* If len >= padding_length+overhead then the MSB of t is zero. */
|
| ++ good = DUPLICATE_MSB_TO_ALL(~t);
|
| ++ /* SSLv3 requires that the padding is minimal. */
|
| ++ t = blockSize - (paddingLength+1);
|
| ++ good &= DUPLICATE_MSB_TO_ALL(~t);
|
| ++ plaintext->len -= good & (paddingLength+1);
|
| ++ return (good & SECSuccess) | (~good & SECFailure);
|
| ++}
|
| ++
|
| ++
|
| ++static SECStatus ssl_RemoveTLSCBCPadding(sslBuffer *plaintext,
|
| ++ unsigned macSize) {
|
| ++ unsigned int paddingLength, good, t, toCheck, i;
|
| ++ const unsigned int overhead = 1 /* padding length byte */ + macSize;
|
| ++
|
| ++ /* These lengths are all public so we can test them in non-constant
|
| ++ * time. */
|
| ++ if (overhead > plaintext->len) {
|
| ++ return SECFailure;
|
| ++ }
|
| ++
|
| ++ paddingLength = plaintext->buf[plaintext->len-1];
|
| ++ t = plaintext->len;
|
| ++ t -= paddingLength+overhead;
|
| ++ /* If len >= paddingLength+overhead then the MSB of t is zero. */
|
| ++ good = DUPLICATE_MSB_TO_ALL(~t);
|
| ++
|
| ++ /* The padding consists of a length byte at the end of the record and then
|
| ++ * that many bytes of padding, all with the same value as the length byte.
|
| ++ * Thus, with the length byte included, there are paddingLength+1 bytes of
|
| ++ * padding.
|
| ++ *
|
| ++ * We can't check just |paddingLength+1| bytes because that leaks
|
| ++ * decrypted information. Therefore we always have to check the maximum
|
| ++ * amount of padding possible. (Again, the length of the record is
|
| ++ * public information so we can use it.) */
|
| ++ toCheck = 255; /* maximum amount of padding. */
|
| ++ if (toCheck > plaintext->len-1) {
|
| ++ toCheck = plaintext->len-1;
|
| ++ }
|
| ++
|
| ++ for (i = 0; i < toCheck; i++) {
|
| ++ unsigned int t = paddingLength - i;
|
| ++ /* If i <= paddingLength then the MSB of t is zero and mask is
|
| ++ * 0xff. Otherwise, mask is 0. */
|
| ++ unsigned char mask = DUPLICATE_MSB_TO_ALL(~t);
|
| ++ unsigned char b = plaintext->buf[plaintext->len-1-i];
|
| ++ /* The final |paddingLength+1| bytes should all have the value
|
| ++ * |paddingLength|. Therefore the XOR should be zero. */
|
| ++ good &= ~(mask&(paddingLength ^ b));
|
| ++ }
|
| ++
|
| ++ /* If any of the final |paddingLength+1| bytes had the wrong value,
|
| ++ * one or more of the lower eight bits of |good| will be cleared. We
|
| ++ * AND the bottom 8 bits together and duplicate the result to all the
|
| ++ * bits. */
|
| ++ good &= good >> 4;
|
| ++ good &= good >> 2;
|
| ++ good &= good >> 1;
|
| ++ good <<= sizeof(good)*8-1;
|
| ++ good = DUPLICATE_MSB_TO_ALL(good);
|
| ++
|
| ++ plaintext->len -= good & (paddingLength+1);
|
| ++ return (good & SECSuccess) | (~good & SECFailure);
|
| ++}
|
| ++
|
| ++/* On entry:
|
| ++ * originalLength >= macSize
|
| ++ * macSize <= MAX_MAC_LENGTH
|
| ++ * plaintext->len >= macSize
|
| ++ */
|
| ++static void ssl_CBCExtractMAC(sslBuffer *plaintext,
|
| ++ unsigned int originalLength,
|
| ++ SSL3Opaque* out,
|
| ++ unsigned int macSize) {
|
| ++ unsigned char rotatedMac[MAX_MAC_LENGTH];
|
| ++ /* macEnd is the index of |plaintext->buf| just after the end of the MAC. */
|
| ++ unsigned macEnd = plaintext->len;
|
| ++ unsigned macStart = macEnd - macSize;
|
| ++ /* scanStart contains the number of bytes that we can ignore because
|
| ++ * the MAC's position can only vary by 255 bytes. */
|
| ++ unsigned scanStart = 0;
|
| ++ unsigned i, j, divSpoiler;
|
| ++ unsigned char rotateOffset;
|
| ++
|
| ++ if (originalLength > macSize + 255 + 1)
|
| ++ scanStart = originalLength - (macSize + 255 + 1);
|
| ++
|
| ++ /* divSpoiler contains a multiple of macSize that is used to cause the
|
| ++ * modulo operation to be constant time. Without this, the time varies
|
| ++ * based on the amount of padding when running on Intel chips at least.
|
| ++ *
|
| ++ * The aim of right-shifting macSize is so that the compiler doesn't
|
| ++ * figure out that it can remove divSpoiler as that would require it
|
| ++ * to prove that macSize is always even, which I hope is beyond it. */
|
| ++ divSpoiler = macSize >> 1;
|
| ++ divSpoiler <<= (sizeof(divSpoiler)-1)*8;
|
| ++ rotateOffset = (divSpoiler + macStart - scanStart) % macSize;
|
| ++
|
| ++ memset(rotatedMac, 0, macSize);
|
| ++ for (i = scanStart; i < originalLength;) {
|
| ++ for (j = 0; j < macSize && i < originalLength; i++, j++) {
|
| ++ unsigned char macStarted = ssl_ConstantTimeGE(i, macStart);
|
| ++ unsigned char macEnded = ssl_ConstantTimeGE(i, macEnd);
|
| ++ unsigned char b = 0;
|
| ++ b = plaintext->buf[i];
|
| ++ rotatedMac[j] |= b & macStarted & ~macEnded;
|
| ++ }
|
| ++ }
|
| ++
|
| ++ /* Now rotate the MAC. If we knew that the MAC fit into a CPU cache line we
|
| ++ * could line-align |rotatedMac| and rotate in place. */
|
| ++ memset(out, 0, macSize);
|
| ++ for (i = 0; i < macSize; i++) {
|
| ++ unsigned char offset = (divSpoiler + macSize - rotateOffset + i) % macSize;
|
| ++ for (j = 0; j < macSize; j++) {
|
| ++ out[j] |= rotatedMac[i] & ssl_ConstantTimeEQ8(j, offset);
|
| ++ }
|
| ++ }
|
| ++}
|
| ++
|
| + /* if cText is non-null, then decipher, check MAC, and decompress the
|
| + * SSL record from cText->buf (typically gs->inbuf)
|
| + * into databuf (typically gs->buf), and any previous contents of databuf
|
| +@@ -9559,15 +9851,18 @@ ssl3_HandleRecord(sslSocket *ss, SSL3Ciphertext *cText, sslBuffer *databuf)
|
| + ssl3CipherSpec * crSpec;
|
| + SECStatus rv;
|
| + unsigned int hashBytes = MAX_MAC_LENGTH + 1;
|
| +- unsigned int padding_length;
|
| + PRBool isTLS;
|
| +- PRBool padIsBad = PR_FALSE;
|
| + SSL3ContentType rType;
|
| + SSL3Opaque hash[MAX_MAC_LENGTH];
|
| ++ SSL3Opaque givenHashBuf[MAX_MAC_LENGTH];
|
| ++ SSL3Opaque *givenHash;
|
| + sslBuffer *plaintext;
|
| + sslBuffer temp_buf;
|
| + PRUint64 dtls_seq_num;
|
| + unsigned int ivLen = 0;
|
| ++ unsigned int originalLen = 0;
|
| ++ unsigned int good;
|
| ++ unsigned int minLength;
|
| +
|
| + PORT_Assert( ss->opt.noLocks || ssl_HaveRecvBufLock(ss) );
|
| +
|
| +@@ -9635,6 +9930,30 @@ ssl3_HandleRecord(sslSocket *ss, SSL3Ciphertext *cText, sslBuffer *databuf)
|
| + }
|
| + }
|
| +
|
| ++ good = (unsigned)-1;
|
| ++ minLength = crSpec->mac_size;
|
| ++ if (cipher_def->type == type_block) {
|
| ++ /* CBC records have a padding length byte at the end. */
|
| ++ minLength++;
|
| ++ if (crSpec->version >= SSL_LIBRARY_VERSION_TLS_1_1) {
|
| ++ /* With >= TLS 1.1, CBC records have an explicit IV. */
|
| ++ minLength += cipher_def->iv_size;
|
| ++ }
|
| ++ }
|
| ++
|
| ++ /* We can perform this test in variable time because the record's total
|
| ++ * length and the ciphersuite are both public knowledge. */
|
| ++ if (cText->buf->len < minLength) {
|
| ++ SSL_DBG(("%d: SSL3[%d]: HandleRecord, record too small.",
|
| ++ SSL_GETPID(), ss->fd));
|
| ++ /* must not hold spec lock when calling SSL3_SendAlert. */
|
| ++ ssl_ReleaseSpecReadLock(ss);
|
| ++ SSL3_SendAlert(ss, alert_fatal, bad_record_mac);
|
| ++ /* always log mac error, in case attacker can read server logs. */
|
| ++ PORT_SetError(SSL_ERROR_BAD_MAC_READ);
|
| ++ return SECFailure;
|
| ++ }
|
| ++
|
| + 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
|
| +@@ -9652,16 +9971,6 @@ ssl3_HandleRecord(sslSocket *ss, SSL3Ciphertext *cText, sslBuffer *databuf)
|
| + PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
|
| + return SECFailure;
|
| + }
|
| +- if (ivLen > cText->buf->len) {
|
| +- SSL_DBG(("%d: SSL3[%d]: HandleRecord, IV length check failed",
|
| +- SSL_GETPID(), ss->fd));
|
| +- /* must not hold spec lock when calling SSL3_SendAlert. */
|
| +- ssl_ReleaseSpecReadLock(ss);
|
| +- SSL3_SendAlert(ss, alert_fatal, bad_record_mac);
|
| +- /* always log mac error, in case attacker can read server logs. */
|
| +- PORT_SetError(SSL_ERROR_BAD_MAC_READ);
|
| +- return SECFailure;
|
| +- }
|
| +
|
| + PRINT_BUF(80, (ss, "IV (ciphertext):", cText->buf->buf, ivLen));
|
| +
|
| +@@ -9672,12 +9981,7 @@ ssl3_HandleRecord(sslSocket *ss, SSL3Ciphertext *cText, sslBuffer *databuf)
|
| + rv = crSpec->decode(crSpec->decodeContext, iv, &decoded,
|
| + sizeof(iv), cText->buf->buf, ivLen);
|
| +
|
| +- if (rv != SECSuccess) {
|
| +- /* All decryption failures must be treated like a bad record
|
| +- * MAC; see RFC 5246 (TLS 1.2).
|
| +- */
|
| +- padIsBad = PR_TRUE;
|
| +- }
|
| ++ good &= SECStatusToMask(rv);
|
| + }
|
| +
|
| + /* If we will be decompressing the buffer we need to decrypt somewhere
|
| +@@ -9719,54 +10023,70 @@ ssl3_HandleRecord(sslSocket *ss, SSL3Ciphertext *cText, sslBuffer *databuf)
|
| + rv = crSpec->decode(
|
| + crSpec->decodeContext, plaintext->buf, (int *)&plaintext->len,
|
| + plaintext->space, cText->buf->buf + ivLen, cText->buf->len - ivLen);
|
| ++ good &= SECStatusToMask(rv);
|
| +
|
| + PRINT_BUF(80, (ss, "cleartext:", plaintext->buf, plaintext->len));
|
| +- if (rv != SECSuccess) {
|
| +- /* All decryption failures must be treated like a bad record
|
| +- * MAC; see RFC 5246 (TLS 1.2).
|
| +- */
|
| +- padIsBad = PR_TRUE;
|
| +- }
|
| ++
|
| ++ originalLen = plaintext->len;
|
| +
|
| + /* If it's a block cipher, check and strip the padding. */
|
| +- if (cipher_def->type == type_block && !padIsBad) {
|
| +- PRUint8 * pPaddingLen = plaintext->buf + plaintext->len - 1;
|
| +- padding_length = *pPaddingLen;
|
| +- /* TLS permits padding to exceed the block size, up to 255 bytes. */
|
| +- if (padding_length + 1 + crSpec->mac_size > plaintext->len)
|
| +- padIsBad = PR_TRUE;
|
| +- else {
|
| +- plaintext->len -= padding_length + 1;
|
| +- /* In TLS all padding bytes must be equal to the padding length. */
|
| +- if (isTLS) {
|
| +- PRUint8 *p;
|
| +- for (p = pPaddingLen - padding_length; p < pPaddingLen; ++p) {
|
| +- padIsBad |= *p ^ padding_length;
|
| +- }
|
| +- }
|
| +- }
|
| +- }
|
| ++ if (cipher_def->type == type_block) {
|
| ++ const unsigned int blockSize = cipher_def->iv_size;
|
| ++ const unsigned int macSize = crSpec->mac_size;
|
| +
|
| +- /* Remove the MAC. */
|
| +- if (plaintext->len >= crSpec->mac_size)
|
| +- plaintext->len -= crSpec->mac_size;
|
| +- else
|
| +- padIsBad = PR_TRUE; /* really macIsBad */
|
| ++ if (crSpec->version <= SSL_LIBRARY_VERSION_3_0) {
|
| ++ good &= SECStatusToMask(ssl_RemoveSSLv3CBCPadding(
|
| ++ plaintext, blockSize, macSize));
|
| ++ } else {
|
| ++ good &= SECStatusToMask(ssl_RemoveTLSCBCPadding(
|
| ++ plaintext, macSize));
|
| ++ }
|
| ++ }
|
| +
|
| + /* compute the MAC */
|
| + rType = cText->type;
|
| +- rv = ssl3_ComputeRecordMAC( crSpec, (PRBool)(!ss->sec.isServer),
|
| +- IS_DTLS(ss), rType, cText->version,
|
| +- IS_DTLS(ss) ? cText->seq_num : crSpec->read_seq_num,
|
| +- plaintext->buf, plaintext->len, hash, &hashBytes);
|
| +- if (rv != SECSuccess) {
|
| +- padIsBad = PR_TRUE; /* really macIsBad */
|
| ++ if (cipher_def->type == type_block) {
|
| ++ rv = ssl3_ComputeRecordMACConstantTime(
|
| ++ crSpec, (PRBool)(!ss->sec.isServer),
|
| ++ IS_DTLS(ss), rType, cText->version,
|
| ++ IS_DTLS(ss) ? cText->seq_num : crSpec->read_seq_num,
|
| ++ plaintext->buf, plaintext->len, originalLen,
|
| ++ hash, &hashBytes);
|
| ++
|
| ++ ssl_CBCExtractMAC(plaintext, originalLen, givenHashBuf,
|
| ++ crSpec->mac_size);
|
| ++ givenHash = givenHashBuf;
|
| ++
|
| ++ /* plaintext->len will always have enough space to remove the MAC
|
| ++ * because in ssl_Remove{SSLv3|TLS}CBCPadding we only adjust
|
| ++ * plaintext->len if the result has enough space for the MAC and we
|
| ++ * tested the unadjusted size against minLength, above. */
|
| ++ plaintext->len -= crSpec->mac_size;
|
| ++ } else {
|
| ++ /* This is safe because we checked the minLength above. */
|
| ++ plaintext->len -= crSpec->mac_size;
|
| ++
|
| ++ rv = ssl3_ComputeRecordMAC(
|
| ++ crSpec, (PRBool)(!ss->sec.isServer),
|
| ++ IS_DTLS(ss), rType, cText->version,
|
| ++ IS_DTLS(ss) ? cText->seq_num : crSpec->read_seq_num,
|
| ++ plaintext->buf, plaintext->len,
|
| ++ hash, &hashBytes);
|
| ++
|
| ++ /* We can read the MAC directly from the record because its location is
|
| ++ * public when a stream cipher is used. */
|
| ++ givenHash = plaintext->buf + plaintext->len;
|
| ++ }
|
| ++
|
| ++ good &= SECStatusToMask(rv);
|
| ++
|
| ++ 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 */
|
| ++ good = 0;
|
| + }
|
| +
|
| +- /* Check the MAC */
|
| +- if (hashBytes != (unsigned)crSpec->mac_size || padIsBad ||
|
| +- NSS_SecureMemcmp(plaintext->buf + plaintext->len, hash,
|
| +- crSpec->mac_size) != 0) {
|
| ++ if (good == 0) {
|
| + /* must not hold spec lock when calling SSL3_SendAlert. */
|
| + ssl_ReleaseSpecReadLock(ss);
|
| +
|
|
|