Bug 822365: Make CBC decoding constant time. This patch makes the decoding
of SSLv3 and TLS CBC records constant time. Without this, a timing side channel can be used to build a padding oracle and mount Vaudenay's attack. The patch is contributed by Adam Langley <agl@chromium.org>. r=rrelyea,ryan.sleevi. Modified Files: lib/freebl/blapi.h lib/freebl/ldvector.c lib/freebl/loader.c lib/freebl/loader.h lib/freebl/manifest.mn lib/freebl/md5.c lib/freebl/rawhash.c lib/freebl/sha512.c lib/freebl/sha_fast.c lib/freebl/sha_fast.h lib/nss/nss.def lib/pk11wrap/pk11obj.c lib/pk11wrap/pk11pub.h lib/softoken/manifest.mn lib/softoken/pkcs11.c lib/softoken/pkcs11c.c lib/softoken/pkcs11i.h lib/ssl/ssl3con.c lib/util/hasht.h lib/util/pkcs11n.h Added Files: lib/freebl/hmacct.c lib/freebl/hmacct.h lib/softoken/sftkhmac.c git-svn-id: svn://10.0.0.236/trunk@264692 18797224-902f-48f8-a5cc-f745e15eee43
This commit is contained in:
parent
15e5148cca
commit
f7ff05a366
@ -4,7 +4,7 @@
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
/* $Id: blapi.h,v 1.49 2012-10-11 00:10:26 rrelyea%redhat.com Exp $ */
|
||||
/* $Id: blapi.h,v 1.50 2013-02-05 18:10:42 wtc%google.com Exp $ */
|
||||
|
||||
#ifndef _BLAPI_H_
|
||||
#define _BLAPI_H_
|
||||
@ -874,6 +874,18 @@ extern void MD5_Update(MD5Context *cx,
|
||||
extern void MD5_End(MD5Context *cx, unsigned char *digest,
|
||||
unsigned int *digestLen, unsigned int maxDigestLen);
|
||||
|
||||
/*
|
||||
** Export the raw state of the MD5 hash without appending the standard padding
|
||||
** and length bytes. Produce the digested results in "digest"
|
||||
** "cx" the context
|
||||
** "digest" where the 16 bytes of digest data are stored
|
||||
** "digestLen" where the digest length (16) is stored (optional)
|
||||
** "maxDigestLen" the maximum amount of data that can ever be
|
||||
** stored in "digest"
|
||||
*/
|
||||
extern void MD5_EndRaw(MD5Context *cx, unsigned char *digest,
|
||||
unsigned int *digestLen, unsigned int maxDigestLen);
|
||||
|
||||
/*
|
||||
* Return the the size of a buffer needed to flatten the MD5 Context into
|
||||
* "cx" the context
|
||||
@ -1030,6 +1042,18 @@ extern void SHA1_Update(SHA1Context *cx, const unsigned char *input,
|
||||
extern void SHA1_End(SHA1Context *cx, unsigned char *digest,
|
||||
unsigned int *digestLen, unsigned int maxDigestLen);
|
||||
|
||||
/*
|
||||
** Export the current state of the SHA-1 hash without appending the standard
|
||||
** padding and length. Produce the digested results in "digest"
|
||||
** "cx" the context
|
||||
** "digest" where the 16 bytes of digest data are stored
|
||||
** "digestLen" where the digest length (20) is stored (optional)
|
||||
** "maxDigestLen" the maximum amount of data that can ever be
|
||||
** stored in "digest"
|
||||
*/
|
||||
extern void SHA1_EndRaw(SHA1Context *cx, unsigned char *digest,
|
||||
unsigned int *digestLen, unsigned int maxDigestLen);
|
||||
|
||||
/*
|
||||
** trace the intermediate state info of the SHA1 hash.
|
||||
*/
|
||||
@ -1068,6 +1092,8 @@ extern void SHA224_Update(SHA224Context *cx, const unsigned char *input,
|
||||
unsigned int inputLen);
|
||||
extern void SHA224_End(SHA224Context *cx, unsigned char *digest,
|
||||
unsigned int *digestLen, unsigned int maxDigestLen);
|
||||
extern void SHA224_EndRaw(SHA224Context *cx, unsigned char *digest,
|
||||
unsigned int *digestLen, unsigned int maxDigestLen);
|
||||
extern SECStatus SHA224_HashBuf(unsigned char *dest, const unsigned char *src,
|
||||
uint32 src_length);
|
||||
extern SECStatus SHA224_Hash(unsigned char *dest, const char *src);
|
||||
@ -1086,6 +1112,8 @@ extern void SHA256_Update(SHA256Context *cx, const unsigned char *input,
|
||||
unsigned int inputLen);
|
||||
extern void SHA256_End(SHA256Context *cx, unsigned char *digest,
|
||||
unsigned int *digestLen, unsigned int maxDigestLen);
|
||||
extern void SHA256_EndRaw(SHA256Context *cx, unsigned char *digest,
|
||||
unsigned int *digestLen, unsigned int maxDigestLen);
|
||||
extern SECStatus SHA256_HashBuf(unsigned char *dest, const unsigned char *src,
|
||||
uint32 src_length);
|
||||
extern SECStatus SHA256_Hash(unsigned char *dest, const char *src);
|
||||
@ -1102,6 +1130,8 @@ extern void SHA512_DestroyContext(SHA512Context *cx, PRBool freeit);
|
||||
extern void SHA512_Begin(SHA512Context *cx);
|
||||
extern void SHA512_Update(SHA512Context *cx, const unsigned char *input,
|
||||
unsigned int inputLen);
|
||||
extern void SHA512_EndRaw(SHA512Context *cx, unsigned char *digest,
|
||||
unsigned int *digestLen, unsigned int maxDigestLen);
|
||||
extern void SHA512_End(SHA512Context *cx, unsigned char *digest,
|
||||
unsigned int *digestLen, unsigned int maxDigestLen);
|
||||
extern SECStatus SHA512_HashBuf(unsigned char *dest, const unsigned char *src,
|
||||
@ -1122,6 +1152,8 @@ extern void SHA384_Update(SHA384Context *cx, const unsigned char *input,
|
||||
unsigned int inputLen);
|
||||
extern void SHA384_End(SHA384Context *cx, unsigned char *digest,
|
||||
unsigned int *digestLen, unsigned int maxDigestLen);
|
||||
extern void SHA384_EndRaw(SHA384Context *cx, unsigned char *digest,
|
||||
unsigned int *digestLen, unsigned int maxDigestLen);
|
||||
extern SECStatus SHA384_HashBuf(unsigned char *dest, const unsigned char *src,
|
||||
uint32 src_length);
|
||||
extern SECStatus SHA384_Hash(unsigned char *dest, const char *src);
|
||||
|
||||
317
mozilla/security/nss/lib/freebl/hmacct.c
Normal file
317
mozilla/security/nss/lib/freebl/hmacct.c
Normal file
@ -0,0 +1,317 @@
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#ifdef FREEBL_NO_DEPEND
|
||||
#include "stubs.h"
|
||||
#endif
|
||||
|
||||
#include "secport.h"
|
||||
#include "hasht.h"
|
||||
#include "blapit.h"
|
||||
#include "hmacct.h"
|
||||
#include "secerr.h"
|
||||
|
||||
/* MAX_HASH_BIT_COUNT_BYTES is the maximum number of bytes in the hash's length
|
||||
* field. (SHA-384/512 have 128-bit length.) */
|
||||
#define MAX_HASH_BIT_COUNT_BYTES 16
|
||||
|
||||
/* Some utility functions are needed:
|
||||
*
|
||||
* These macros return the given value with the MSB copied to all the other
|
||||
* bits. They use the fact that an 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 on odd CPUs.
|
||||
*
|
||||
* Note: the argument to these macros must be an unsigned int.
|
||||
* */
|
||||
#define DUPLICATE_MSB_TO_ALL(x) ( (unsigned int)( (int)(x) >> (sizeof(int)*8-1) ) )
|
||||
#define DUPLICATE_MSB_TO_ALL_8(x) ( (unsigned char)(DUPLICATE_MSB_TO_ALL(x)) )
|
||||
|
||||
/* constantTimeGE returns 0xff if a>=b and 0x00 otherwise, where a, b <
|
||||
* MAX_UINT/2. */
|
||||
static unsigned char constantTimeGE(unsigned int a, unsigned int b) {
|
||||
a -= b;
|
||||
return DUPLICATE_MSB_TO_ALL(~a);
|
||||
}
|
||||
|
||||
/* constantTimeEQ8 returns 0xff if a==b and 0x00 otherwise. */
|
||||
static unsigned char constantTimeEQ8(unsigned char a, unsigned char b) {
|
||||
unsigned int c = a ^ b;
|
||||
c--;
|
||||
return DUPLICATE_MSB_TO_ALL_8(c);
|
||||
}
|
||||
|
||||
/* mac performs a constant time SSLv3/TLS MAC of |dataLen| bytes of |data|,
|
||||
* where |dataLen| includes both the authenticated bytes and the MAC tag from
|
||||
* the sender. |dataLen| must be >= the length of the MAC tag.
|
||||
*
|
||||
* |dataTotalLen| is >= |dataLen| and also accounts for any padding bytes
|
||||
* that may follow the sender's MAC. (Only a single block of padding my follow
|
||||
* in SSLv3, or up to 255 bytes in TLS.)
|
||||
*
|
||||
* Since the results of decryption are secret information (otherwise a
|
||||
* padding-oracle is created), this function is constant-time with respect to
|
||||
* |dataLen|.
|
||||
*
|
||||
* |header| contains either the 13-byte TLS header (containing the sequence
|
||||
* number, record type etc), or it contains the SSLv3 header with the SSLv3
|
||||
* padding bytes etc. */
|
||||
static SECStatus mac(
|
||||
unsigned char *mdOut,
|
||||
unsigned int *mdOutLen,
|
||||
unsigned int mdOutMax,
|
||||
const SECHashObject *hashObj,
|
||||
const unsigned char *macSecret,
|
||||
unsigned int macSecretLen,
|
||||
const unsigned char *header,
|
||||
unsigned int headerLen,
|
||||
const unsigned char *data,
|
||||
unsigned int dataLen,
|
||||
unsigned int dataTotalLen,
|
||||
unsigned char isSSLv3) {
|
||||
|
||||
void *mdState = hashObj->create();
|
||||
const unsigned int mdSize = hashObj->length;
|
||||
const unsigned int mdBlockSize = hashObj->blocklength;
|
||||
/* mdLengthSize is the number of bytes in the length field that terminates
|
||||
* the hash.
|
||||
*
|
||||
* This assumes that hash functions with a 64 byte block size use a 64-bit
|
||||
* length, and otherwise they use a 128-bit length. This is true of {MD5,
|
||||
* SHA*} (which are all of the hash functions specified for use with TLS
|
||||
* today). */
|
||||
const unsigned int mdLengthSize = mdBlockSize == 64 ? 8 : 16;
|
||||
|
||||
const unsigned int sslv3PadLen = hashObj->type == HASH_AlgMD5 ? 48 : 40;
|
||||
|
||||
/* varianceBlocks is the number of blocks of the hash that we have to
|
||||
* calculate in constant time because they could be altered by the
|
||||
* padding value.
|
||||
*
|
||||
* In SSLv3, the padding must be minimal so the end of the plaintext
|
||||
* varies by, at most, 15+20 = 35 bytes. (We conservatively assume that
|
||||
* the MAC size varies from 0..20 bytes.) In case the 9 bytes of hash
|
||||
* termination (0x80 + 64-bit length) don't fit in the final block, we
|
||||
* say that the final two blocks can vary based on the padding.
|
||||
*
|
||||
* TLSv1 has MACs up to 48 bytes long (SHA-384) and the padding is not
|
||||
* required to be minimal. Therefore we say that the final six blocks
|
||||
* can vary based on the padding.
|
||||
*
|
||||
* Later in the function, if the message is short and there obviously
|
||||
* cannot be this many blocks then varianceBlocks can be reduced. */
|
||||
unsigned int varianceBlocks = isSSLv3 ? 2 : 6;
|
||||
/* From now on we're dealing with the MAC, which conceptually has 13
|
||||
* bytes of `header' before the start of the data (TLS) or 71/75 bytes
|
||||
* (SSLv3) */
|
||||
const unsigned int len = dataTotalLen + headerLen;
|
||||
/* maxMACBytes contains the maximum bytes of bytes in the MAC, including
|
||||
* |header|, assuming that there's no padding. */
|
||||
const unsigned int maxMACBytes = len - mdSize - 1;
|
||||
/* numBlocks is the maximum number of hash blocks. */
|
||||
const unsigned int numBlocks =
|
||||
(maxMACBytes + 1 + mdLengthSize + mdBlockSize - 1) / mdBlockSize;
|
||||
/* macEndOffset is the index just past the end of the data to be
|
||||
* MACed. */
|
||||
const unsigned int macEndOffset = dataLen + headerLen - mdSize;
|
||||
/* c is the index of the 0x80 byte in the final hash block that
|
||||
* contains application data. */
|
||||
const unsigned int c = macEndOffset % mdBlockSize;
|
||||
/* indexA is the hash block number that contains the 0x80 terminating
|
||||
* value. */
|
||||
const unsigned int indexA = macEndOffset / mdBlockSize;
|
||||
/* indexB is the hash block number that contains the 64-bit hash
|
||||
* length, in bits. */
|
||||
const unsigned int indexB = (macEndOffset + mdLengthSize) / mdBlockSize;
|
||||
/* bits is the hash-length in bits. It includes the additional hash
|
||||
* block for the masked HMAC key, or whole of |header| in the case of
|
||||
* SSLv3. */
|
||||
unsigned int bits;
|
||||
/* In order to calculate the MAC in constant time we have to handle
|
||||
* the final blocks specially because the padding value could cause the
|
||||
* end to appear somewhere in the final |varianceBlocks| blocks and we
|
||||
* can't leak where. However, |numStartingBlocks| worth of data can
|
||||
* be hashed right away because no padding value can affect whether
|
||||
* they are plaintext. */
|
||||
unsigned int numStartingBlocks = 0;
|
||||
/* k is the starting byte offset into the conceptual header||data where
|
||||
* we start processing. */
|
||||
unsigned int k = 0;
|
||||
unsigned char lengthBytes[MAX_HASH_BIT_COUNT_BYTES];
|
||||
/* hmacPad is the masked HMAC key. */
|
||||
unsigned char hmacPad[HASH_BLOCK_LENGTH_MAX];
|
||||
unsigned char firstBlock[HASH_BLOCK_LENGTH_MAX];
|
||||
unsigned char macOut[HASH_LENGTH_MAX];
|
||||
unsigned i, j;
|
||||
|
||||
/* For SSLv3, if we're going to have any starting blocks then we need
|
||||
* at least two because the header is larger than a single block. */
|
||||
if (numBlocks > varianceBlocks + (isSSLv3 ? 1 : 0)) {
|
||||
numStartingBlocks = numBlocks - varianceBlocks;
|
||||
k = mdBlockSize*numStartingBlocks;
|
||||
}
|
||||
|
||||
bits = 8*macEndOffset;
|
||||
hashObj->begin(mdState);
|
||||
if (!isSSLv3) {
|
||||
/* Compute the initial HMAC block. For SSLv3, the padding and
|
||||
* secret bytes are included in |header| because they take more
|
||||
* than a single block. */
|
||||
bits += 8*mdBlockSize;
|
||||
memset(hmacPad, 0, mdBlockSize);
|
||||
PORT_Assert(macSecretLen <= sizeof(hmacPad));
|
||||
memcpy(hmacPad, macSecret, macSecretLen);
|
||||
for (i = 0; i < mdBlockSize; i++)
|
||||
hmacPad[i] ^= 0x36;
|
||||
hashObj->update(mdState, hmacPad, mdBlockSize);
|
||||
}
|
||||
|
||||
j = 0;
|
||||
memset(lengthBytes, 0, sizeof(lengthBytes));
|
||||
if (mdLengthSize == 16) {
|
||||
j = 8;
|
||||
}
|
||||
for (i = 0; i < 4; i++) {
|
||||
lengthBytes[4+i+j] = bits >> (8*(7-i));
|
||||
}
|
||||
|
||||
if (k > 0) {
|
||||
if (isSSLv3) {
|
||||
/* The SSLv3 header is larger than a single block.
|
||||
* overhang is the number of bytes beyond a single
|
||||
* block that the header consumes: either 7 bytes
|
||||
* (SHA1) or 11 bytes (MD5). */
|
||||
const unsigned int overhang = headerLen-mdBlockSize;
|
||||
hashObj->update(mdState, header, mdBlockSize);
|
||||
memcpy(firstBlock, header + mdBlockSize, overhang);
|
||||
memcpy(firstBlock + overhang, data, mdBlockSize-overhang);
|
||||
hashObj->update(mdState, firstBlock, mdBlockSize);
|
||||
for (i = 1; i < k/mdBlockSize - 1; i++) {
|
||||
hashObj->update(mdState, data + mdBlockSize*i - overhang, mdBlockSize);
|
||||
}
|
||||
} else {
|
||||
/* k is a multiple of mdBlockSize. */
|
||||
memcpy(firstBlock, header, 13);
|
||||
memcpy(firstBlock+13, data, mdBlockSize-13);
|
||||
hashObj->update(mdState, firstBlock, mdBlockSize);
|
||||
for (i = 1; i < k/mdBlockSize; i++) {
|
||||
hashObj->update(mdState, data + mdBlockSize*i - 13, mdBlockSize);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
memset(macOut, 0, sizeof(macOut));
|
||||
|
||||
/* We now process the final hash blocks. For each block, we construct
|
||||
* it in constant time. If i == indexA then we'll include the 0x80
|
||||
* bytes and zero pad etc. For each block we selectively copy it, in
|
||||
* constant time, to |macOut|. */
|
||||
for (i = numStartingBlocks; i <= numStartingBlocks+varianceBlocks; i++) {
|
||||
unsigned char block[HASH_BLOCK_LENGTH_MAX];
|
||||
unsigned char isBlockA = constantTimeEQ8(i, indexA);
|
||||
unsigned char isBlockB = constantTimeEQ8(i, indexB);
|
||||
for (j = 0; j < mdBlockSize; j++) {
|
||||
unsigned char b = 0;
|
||||
if (k < headerLen) {
|
||||
b = header[k];
|
||||
} else if (k < dataTotalLen + headerLen) {
|
||||
b = data[k-headerLen];
|
||||
}
|
||||
k++;
|
||||
|
||||
unsigned char isPastC = isBlockA & constantTimeGE(j, c);
|
||||
unsigned char isPastCPlus1 = isBlockA & constantTimeGE(j, c+1);
|
||||
/* If this is the block containing the end of the
|
||||
* application data, and we are at the offset for the
|
||||
* 0x80 value, then overwrite b with 0x80. */
|
||||
b = (b&~isPastC) | (0x80&isPastC);
|
||||
/* If this the the block containing the end of the
|
||||
* application data and we're past the 0x80 value then
|
||||
* just write zero. */
|
||||
b = b&~isPastCPlus1;
|
||||
/* If this is indexB (the final block), but not
|
||||
* indexA (the end of the data), then the 64-bit
|
||||
* length didn't fit into indexA and we're having to
|
||||
* add an extra block of zeros. */
|
||||
b &= ~isBlockB | isBlockA;
|
||||
|
||||
/* The final bytes of one of the blocks contains the length. */
|
||||
if (j >= mdBlockSize - mdLengthSize) {
|
||||
/* If this is indexB, write a length byte. */
|
||||
b = (b&~isBlockB) | (isBlockB&lengthBytes[j-(mdBlockSize-mdLengthSize)]);
|
||||
}
|
||||
block[j] = b;
|
||||
}
|
||||
|
||||
hashObj->update(mdState, block, mdBlockSize);
|
||||
hashObj->end_raw(mdState, block, NULL, mdSize);
|
||||
/* If this is indexB, copy the hash value to |macOut|. */
|
||||
for (j = 0; j < mdSize; j++) {
|
||||
macOut[j] |= block[j]&isBlockB;
|
||||
}
|
||||
}
|
||||
|
||||
hashObj->begin(mdState);
|
||||
|
||||
if (isSSLv3) {
|
||||
/* We repurpose |hmacPad| to contain the SSLv3 pad2 block. */
|
||||
for (i = 0; i < sslv3PadLen; i++)
|
||||
hmacPad[i] = 0x5c;
|
||||
|
||||
hashObj->update(mdState, macSecret, macSecretLen);
|
||||
hashObj->update(mdState, hmacPad, sslv3PadLen);
|
||||
hashObj->update(mdState, macOut, mdSize);
|
||||
} else {
|
||||
/* Complete the HMAC in the standard manner. */
|
||||
for (i = 0; i < mdBlockSize; i++)
|
||||
hmacPad[i] ^= 0x6a;
|
||||
|
||||
hashObj->update(mdState, hmacPad, mdBlockSize);
|
||||
hashObj->update(mdState, macOut, mdSize);
|
||||
}
|
||||
|
||||
hashObj->end(mdState, mdOut, mdOutLen, mdOutMax);
|
||||
hashObj->destroy(mdState, PR_TRUE);
|
||||
|
||||
return SECSuccess;
|
||||
}
|
||||
|
||||
SECStatus HMAC_ConstantTime(
|
||||
unsigned char *result,
|
||||
unsigned int *resultLen,
|
||||
unsigned int maxResultLen,
|
||||
const SECHashObject *hashObj,
|
||||
const unsigned char *secret,
|
||||
unsigned int secretLen,
|
||||
const unsigned char *header,
|
||||
unsigned int headerLen,
|
||||
const unsigned char *body,
|
||||
unsigned int bodyLen,
|
||||
unsigned int bodyTotalLen) {
|
||||
if (hashObj->end_raw == NULL)
|
||||
return SECFailure;
|
||||
return mac(result, resultLen, maxResultLen, hashObj, secret, secretLen,
|
||||
header, headerLen, body, bodyLen, bodyTotalLen,
|
||||
0 /* not SSLv3 */);
|
||||
}
|
||||
|
||||
SECStatus SSLv3_MAC_ConstantTime(
|
||||
unsigned char *result,
|
||||
unsigned int *resultLen,
|
||||
unsigned int maxResultLen,
|
||||
const SECHashObject *hashObj,
|
||||
const unsigned char *secret,
|
||||
unsigned int secretLen,
|
||||
const unsigned char *header,
|
||||
unsigned int headerLen,
|
||||
const unsigned char *body,
|
||||
unsigned int bodyLen,
|
||||
unsigned int bodyTotalLen) {
|
||||
if (hashObj->end_raw == NULL)
|
||||
return SECFailure;
|
||||
return mac(result, resultLen, maxResultLen, hashObj, secret, secretLen,
|
||||
header, headerLen, body, bodyLen, bodyTotalLen,
|
||||
1 /* SSLv3 */);
|
||||
}
|
||||
|
||||
38
mozilla/security/nss/lib/freebl/hmacct.h
Normal file
38
mozilla/security/nss/lib/freebl/hmacct.h
Normal file
@ -0,0 +1,38 @@
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#ifndef _ALGHMACCT_H_
|
||||
#define _ALGHMACCT_H_
|
||||
|
||||
SEC_BEGIN_PROTOS
|
||||
|
||||
extern SECStatus HMAC_ConstantTime(
|
||||
unsigned char *result,
|
||||
unsigned int *resultLen,
|
||||
unsigned int maxResultLen,
|
||||
const SECHashObject *hashObj,
|
||||
const unsigned char *secret,
|
||||
unsigned int secretLen,
|
||||
const unsigned char *header,
|
||||
unsigned int headerLen,
|
||||
const unsigned char *body,
|
||||
unsigned int bodyLen,
|
||||
unsigned int bodyTotalLen);
|
||||
|
||||
extern SECStatus SSLv3_MAC_ConstantTime(
|
||||
unsigned char *result,
|
||||
unsigned int *resultLen,
|
||||
unsigned int maxResultLen,
|
||||
const SECHashObject *hashObj,
|
||||
const unsigned char *secret,
|
||||
unsigned int secretLen,
|
||||
const unsigned char *header,
|
||||
unsigned int headerLen,
|
||||
const unsigned char *body,
|
||||
unsigned int bodyLen,
|
||||
unsigned int bodyTotalLen);
|
||||
|
||||
SEC_END_PROTOS
|
||||
|
||||
#endif
|
||||
@ -4,7 +4,7 @@
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
/* $Id: ldvector.c,v 1.32 2012-06-28 17:55:05 rrelyea%redhat.com Exp $ */
|
||||
/* $Id: ldvector.c,v 1.33 2013-02-05 18:10:42 wtc%google.com Exp $ */
|
||||
|
||||
#ifdef FREEBL_NO_DEPEND
|
||||
extern int FREEBL_InitStubs(void);
|
||||
@ -12,6 +12,7 @@ extern int FREEBL_InitStubs(void);
|
||||
|
||||
#include "loader.h"
|
||||
#include "alghmac.h"
|
||||
#include "hmacct.h"
|
||||
|
||||
|
||||
static const struct FREEBLVectorStr vector =
|
||||
@ -258,9 +259,14 @@ static const struct FREEBLVectorStr vector =
|
||||
/* End of Version 3.013 */
|
||||
|
||||
PQG_ParamGenV2,
|
||||
PRNGTEST_RunHealthTests
|
||||
PRNGTEST_RunHealthTests,
|
||||
|
||||
/* End of Version 3.014 */
|
||||
|
||||
HMAC_ConstantTime,
|
||||
SSLv3_MAC_ConstantTime
|
||||
|
||||
/* End of Version 3.015 */
|
||||
};
|
||||
|
||||
const FREEBLVector *
|
||||
|
||||
@ -4,7 +4,7 @@
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
/* $Id: loader.c,v 1.58 2012-12-13 22:47:15 wtc%google.com Exp $ */
|
||||
/* $Id: loader.c,v 1.59 2013-02-05 18:10:42 wtc%google.com Exp $ */
|
||||
|
||||
#include "loader.h"
|
||||
#include "prmem.h"
|
||||
@ -1858,3 +1858,47 @@ PRNGTEST_RunHealthTests(void)
|
||||
return SECFailure;
|
||||
return vector->p_PRNGTEST_RunHealthTests();
|
||||
}
|
||||
|
||||
SECStatus SSLv3_MAC_ConstantTime(
|
||||
unsigned char *result,
|
||||
unsigned int *resultLen,
|
||||
unsigned int maxResultLen,
|
||||
const SECHashObject *hashObj,
|
||||
const unsigned char *secret,
|
||||
unsigned int secretLen,
|
||||
const unsigned char *header,
|
||||
unsigned int headerLen,
|
||||
const unsigned char *body,
|
||||
unsigned int bodyLen,
|
||||
unsigned int bodyTotalLen) {
|
||||
if (!vector && PR_SUCCESS != freebl_RunLoaderOnce())
|
||||
return SECFailure;
|
||||
return (vector->p_SSLv3_MAC_ConstantTime)(
|
||||
result, resultLen, maxResultLen,
|
||||
hashObj,
|
||||
secret, secretLen,
|
||||
header, headerLen,
|
||||
body, bodyLen, bodyTotalLen);
|
||||
}
|
||||
|
||||
SECStatus HMAC_ConstantTime(
|
||||
unsigned char *result,
|
||||
unsigned int *resultLen,
|
||||
unsigned int maxResultLen,
|
||||
const SECHashObject *hashObj,
|
||||
const unsigned char *secret,
|
||||
unsigned int secretLen,
|
||||
const unsigned char *header,
|
||||
unsigned int headerLen,
|
||||
const unsigned char *body,
|
||||
unsigned int bodyLen,
|
||||
unsigned int bodyTotalLen) {
|
||||
if (!vector && PR_SUCCESS != freebl_RunLoaderOnce())
|
||||
return SECFailure;
|
||||
return (vector->p_HMAC_ConstantTime)(
|
||||
result, resultLen, maxResultLen,
|
||||
hashObj,
|
||||
secret, secretLen,
|
||||
header, headerLen,
|
||||
body, bodyLen, bodyTotalLen);
|
||||
}
|
||||
|
||||
@ -4,14 +4,14 @@
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
/* $Id: loader.h,v 1.38 2012-06-28 17:55:05 rrelyea%redhat.com Exp $ */
|
||||
/* $Id: loader.h,v 1.39 2013-02-05 18:10:42 wtc%google.com Exp $ */
|
||||
|
||||
#ifndef _LOADER_H_
|
||||
#define _LOADER_H_ 1
|
||||
|
||||
#include "blapi.h"
|
||||
|
||||
#define FREEBL_VERSION 0x030E
|
||||
#define FREEBL_VERSION 0x030F
|
||||
|
||||
struct FREEBLVectorStr {
|
||||
|
||||
@ -569,7 +569,35 @@ struct FREEBLVectorStr {
|
||||
SECStatus (*p_PRNGTEST_RunHealthTests)(void);
|
||||
|
||||
/* Version 3.014 came to here */
|
||||
};
|
||||
|
||||
SECStatus (* p_HMAC_ConstantTime)(
|
||||
unsigned char *result,
|
||||
unsigned int *resultLen,
|
||||
unsigned int maxResultLen,
|
||||
const SECHashObject *hashObj,
|
||||
const unsigned char *secret,
|
||||
unsigned int secretLen,
|
||||
const unsigned char *header,
|
||||
unsigned int headerLen,
|
||||
const unsigned char *body,
|
||||
unsigned int bodyLen,
|
||||
unsigned int bodyTotalLen);
|
||||
|
||||
SECStatus (* p_SSLv3_MAC_ConstantTime)(
|
||||
unsigned char *result,
|
||||
unsigned int *resultLen,
|
||||
unsigned int maxResultLen,
|
||||
const SECHashObject *hashObj,
|
||||
const unsigned char *secret,
|
||||
unsigned int secretLen,
|
||||
const unsigned char *header,
|
||||
unsigned int headerLen,
|
||||
const unsigned char *body,
|
||||
unsigned int bodyLen,
|
||||
unsigned int bodyTotalLen);
|
||||
|
||||
/* Version 3.015 came to here */
|
||||
};
|
||||
|
||||
typedef struct FREEBLVectorStr FREEBLVector;
|
||||
|
||||
|
||||
@ -56,6 +56,7 @@ EXPORTS = \
|
||||
PRIVATE_EXPORTS = \
|
||||
alghmac.h \
|
||||
blapi.h \
|
||||
hmacct.h \
|
||||
secmpi.h \
|
||||
secrng.h \
|
||||
ec.h \
|
||||
@ -102,6 +103,7 @@ CSRCS = \
|
||||
cts.c \
|
||||
ctr.c \
|
||||
gcm.c \
|
||||
hmacct.c \
|
||||
rijndael.c \
|
||||
aeskeywrap.c \
|
||||
camellia.c \
|
||||
|
||||
@ -523,7 +523,8 @@ MD5_End(MD5Context *cx, unsigned char *digest,
|
||||
md5_compress(cx, cx->u.w);
|
||||
|
||||
/* Copy the resulting values out of the chain variables into return buf. */
|
||||
*digestLen = MD5_HASH_LEN;
|
||||
if (digestLen)
|
||||
*digestLen = MD5_HASH_LEN;
|
||||
#ifndef IS_LITTLE_ENDIAN
|
||||
cx->cv[0] = lendian(cx->cv[0]);
|
||||
cx->cv[1] = lendian(cx->cv[1]);
|
||||
@ -533,6 +534,29 @@ MD5_End(MD5Context *cx, unsigned char *digest,
|
||||
memcpy(digest, cx->cv, MD5_HASH_LEN);
|
||||
}
|
||||
|
||||
void
|
||||
MD5_EndRaw(MD5Context *cx, unsigned char *digest,
|
||||
unsigned int *digestLen, unsigned int maxDigestLen)
|
||||
{
|
||||
PRUint32 cv[4];
|
||||
|
||||
if (maxDigestLen < MD5_HASH_LEN) {
|
||||
PORT_SetError(SEC_ERROR_INVALID_ARGS);
|
||||
return;
|
||||
}
|
||||
|
||||
memcpy(cv, cx->cv, sizeof(cv));
|
||||
#ifndef IS_LITTLE_ENDIAN
|
||||
cv[0] = lendian(cv[0]);
|
||||
cv[1] = lendian(cv[1]);
|
||||
cv[2] = lendian(cv[2]);
|
||||
cv[3] = lendian(cv[3]);
|
||||
#endif
|
||||
memcpy(digest, cv, MD5_HASH_LEN);
|
||||
if (digestLen)
|
||||
*digestLen = MD5_HASH_LEN;
|
||||
}
|
||||
|
||||
unsigned int
|
||||
MD5_FlattenSize(MD5Context *cx)
|
||||
{
|
||||
|
||||
@ -58,7 +58,9 @@ const SECHashObject SECRawHashObjects[] = {
|
||||
(void (*)(void *, unsigned char *, unsigned int *,
|
||||
unsigned int)) null_hash_end,
|
||||
0,
|
||||
HASH_AlgNULL
|
||||
HASH_AlgNULL,
|
||||
(void (*)(void *, unsigned char *, unsigned int *,
|
||||
unsigned int)) null_hash_end
|
||||
},
|
||||
{ MD2_LENGTH,
|
||||
(void * (*)(void)) MD2_NewContext,
|
||||
@ -68,7 +70,8 @@ const SECHashObject SECRawHashObjects[] = {
|
||||
(void (*)(void *, const unsigned char *, unsigned int)) MD2_Update,
|
||||
(void (*)(void *, unsigned char *, unsigned int *, unsigned int)) MD2_End,
|
||||
MD2_BLOCK_LENGTH,
|
||||
HASH_AlgMD2
|
||||
HASH_AlgMD2,
|
||||
NULL /* end_raw */
|
||||
},
|
||||
{ MD5_LENGTH,
|
||||
(void * (*)(void)) MD5_NewContext,
|
||||
@ -78,7 +81,8 @@ const SECHashObject SECRawHashObjects[] = {
|
||||
(void (*)(void *, const unsigned char *, unsigned int)) MD5_Update,
|
||||
(void (*)(void *, unsigned char *, unsigned int *, unsigned int)) MD5_End,
|
||||
MD5_BLOCK_LENGTH,
|
||||
HASH_AlgMD5
|
||||
HASH_AlgMD5,
|
||||
(void (*)(void *, unsigned char *, unsigned int *, unsigned int)) MD5_EndRaw
|
||||
},
|
||||
{ SHA1_LENGTH,
|
||||
(void * (*)(void)) SHA1_NewContext,
|
||||
@ -88,7 +92,9 @@ const SECHashObject SECRawHashObjects[] = {
|
||||
(void (*)(void *, const unsigned char *, unsigned int)) SHA1_Update,
|
||||
(void (*)(void *, unsigned char *, unsigned int *, unsigned int)) SHA1_End,
|
||||
SHA1_BLOCK_LENGTH,
|
||||
HASH_AlgSHA1
|
||||
HASH_AlgSHA1,
|
||||
(void (*)(void *, unsigned char *, unsigned int *, unsigned int))
|
||||
SHA1_EndRaw
|
||||
},
|
||||
{ SHA256_LENGTH,
|
||||
(void * (*)(void)) SHA256_NewContext,
|
||||
@ -99,7 +105,9 @@ const SECHashObject SECRawHashObjects[] = {
|
||||
(void (*)(void *, unsigned char *, unsigned int *,
|
||||
unsigned int)) SHA256_End,
|
||||
SHA256_BLOCK_LENGTH,
|
||||
HASH_AlgSHA256
|
||||
HASH_AlgSHA256,
|
||||
(void (*)(void *, unsigned char *, unsigned int *,
|
||||
unsigned int)) SHA256_EndRaw
|
||||
},
|
||||
{ SHA384_LENGTH,
|
||||
(void * (*)(void)) SHA384_NewContext,
|
||||
@ -110,7 +118,9 @@ const SECHashObject SECRawHashObjects[] = {
|
||||
(void (*)(void *, unsigned char *, unsigned int *,
|
||||
unsigned int)) SHA384_End,
|
||||
SHA384_BLOCK_LENGTH,
|
||||
HASH_AlgSHA384
|
||||
HASH_AlgSHA384,
|
||||
(void (*)(void *, unsigned char *, unsigned int *,
|
||||
unsigned int)) SHA384_EndRaw
|
||||
},
|
||||
{ SHA512_LENGTH,
|
||||
(void * (*)(void)) SHA512_NewContext,
|
||||
@ -121,7 +131,9 @@ const SECHashObject SECRawHashObjects[] = {
|
||||
(void (*)(void *, unsigned char *, unsigned int *,
|
||||
unsigned int)) SHA512_End,
|
||||
SHA512_BLOCK_LENGTH,
|
||||
HASH_AlgSHA512
|
||||
HASH_AlgSHA512,
|
||||
(void (*)(void *, unsigned char *, unsigned int *,
|
||||
unsigned int)) SHA512_EndRaw
|
||||
},
|
||||
{ SHA224_LENGTH,
|
||||
(void * (*)(void)) SHA224_NewContext,
|
||||
@ -132,7 +144,9 @@ const SECHashObject SECRawHashObjects[] = {
|
||||
(void (*)(void *, unsigned char *, unsigned int *,
|
||||
unsigned int)) SHA224_End,
|
||||
SHA224_BLOCK_LENGTH,
|
||||
HASH_AlgSHA224
|
||||
HASH_AlgSHA224,
|
||||
(void (*)(void *, unsigned char *, unsigned int *,
|
||||
unsigned int)) SHA224_EndRaw
|
||||
},
|
||||
};
|
||||
|
||||
|
||||
@ -4,7 +4,7 @@
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
/* $Id: sha512.c,v 1.21 2012-07-27 20:00:39 wtc%google.com Exp $ */
|
||||
/* $Id: sha512.c,v 1.22 2013-02-05 18:10:42 wtc%google.com Exp $ */
|
||||
|
||||
#ifdef FREEBL_NO_DEPEND
|
||||
#include "stubs.h"
|
||||
@ -462,6 +462,32 @@ SHA256_End(SHA256Context *ctx, unsigned char *digest,
|
||||
*digestLen = padLen;
|
||||
}
|
||||
|
||||
void
|
||||
SHA256_EndRaw(SHA256Context *ctx, unsigned char *digest,
|
||||
unsigned int *digestLen, unsigned int maxDigestLen)
|
||||
{
|
||||
PRUint32 h[8];
|
||||
unsigned int len;
|
||||
|
||||
memcpy(&h, ctx->h, sizeof(h));
|
||||
|
||||
#if defined(IS_LITTLE_ENDIAN)
|
||||
BYTESWAP4(h[0]);
|
||||
BYTESWAP4(h[1]);
|
||||
BYTESWAP4(h[2]);
|
||||
BYTESWAP4(h[3]);
|
||||
BYTESWAP4(h[4]);
|
||||
BYTESWAP4(h[5]);
|
||||
BYTESWAP4(h[6]);
|
||||
BYTESWAP4(h[7]);
|
||||
#endif
|
||||
|
||||
len = PR_MIN(SHA256_LENGTH, maxDigestLen);
|
||||
memcpy(digest, h, len);
|
||||
if (digestLen)
|
||||
*digestLen = len;
|
||||
}
|
||||
|
||||
SECStatus
|
||||
SHA256_HashBuf(unsigned char *dest, const unsigned char *src,
|
||||
uint32 src_length)
|
||||
@ -556,6 +582,14 @@ SHA224_End(SHA256Context *ctx, unsigned char *digest,
|
||||
SHA256_End(ctx, digest, digestLen, maxLen);
|
||||
}
|
||||
|
||||
void
|
||||
SHA224_EndRaw(SHA256Context *ctx, unsigned char *digest,
|
||||
unsigned int *digestLen, unsigned int maxDigestLen)
|
||||
{
|
||||
unsigned int maxLen = SHA_MIN(maxDigestLen, SHA224_LENGTH);
|
||||
SHA256_EndRaw(ctx, digest, digestLen, maxLen);
|
||||
}
|
||||
|
||||
SECStatus
|
||||
SHA224_HashBuf(unsigned char *dest, const unsigned char *src,
|
||||
uint32 src_length)
|
||||
@ -1228,6 +1262,31 @@ SHA512_End(SHA512Context *ctx, unsigned char *digest,
|
||||
*digestLen = padLen;
|
||||
}
|
||||
|
||||
void
|
||||
SHA512_EndRaw(SHA512Context *ctx, unsigned char *digest,
|
||||
unsigned int *digestLen, unsigned int maxDigestLen)
|
||||
{
|
||||
PRUint64 h[8];
|
||||
unsigned int len;
|
||||
|
||||
memcpy(h, ctx->h, sizeof(h));
|
||||
|
||||
#if defined(IS_LITTLE_ENDIAN)
|
||||
BYTESWAP8(h[0]);
|
||||
BYTESWAP8(h[1]);
|
||||
BYTESWAP8(h[2]);
|
||||
BYTESWAP8(h[3]);
|
||||
BYTESWAP8(h[4]);
|
||||
BYTESWAP8(h[5]);
|
||||
BYTESWAP8(h[6]);
|
||||
BYTESWAP8(h[7]);
|
||||
#endif
|
||||
len = PR_MIN(SHA512_LENGTH, maxDigestLen);
|
||||
memcpy(digest, h, len);
|
||||
if (digestLen)
|
||||
*digestLen = len;
|
||||
}
|
||||
|
||||
SECStatus
|
||||
SHA512_HashBuf(unsigned char *dest, const unsigned char *src,
|
||||
uint32 src_length)
|
||||
@ -1336,6 +1395,14 @@ SHA384_End(SHA384Context *ctx, unsigned char *digest,
|
||||
SHA512_End(ctx, digest, digestLen, maxLen);
|
||||
}
|
||||
|
||||
void
|
||||
SHA384_EndRaw(SHA384Context *ctx, unsigned char *digest,
|
||||
unsigned int *digestLen, unsigned int maxDigestLen)
|
||||
{
|
||||
unsigned int maxLen = SHA_MIN(maxDigestLen, SHA384_LENGTH);
|
||||
SHA512_EndRaw(ctx, digest, digestLen, maxLen);
|
||||
}
|
||||
|
||||
SECStatus
|
||||
SHA384_HashBuf(unsigned char *dest, const unsigned char *src,
|
||||
uint32 src_length)
|
||||
|
||||
@ -148,6 +148,7 @@ SHA1_End(SHA1Context *ctx, unsigned char *hashout,
|
||||
{
|
||||
register PRUint64 size;
|
||||
register PRUint32 lenB;
|
||||
PRUint32 tmpbuf[5];
|
||||
|
||||
static const unsigned char bulk_pad[64] = { 0x80,0,0,0,0,0,0,0,0,0,
|
||||
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
|
||||
@ -174,8 +175,21 @@ SHA1_End(SHA1Context *ctx, unsigned char *hashout,
|
||||
* Output hash
|
||||
*/
|
||||
SHA_STORE_RESULT;
|
||||
*pDigestLen = SHA1_LENGTH;
|
||||
if (pDigestLen) {
|
||||
*pDigestLen = SHA1_LENGTH;
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
SHA1_EndRaw(SHA1Context *ctx, unsigned char *hashout,
|
||||
unsigned int *pDigestLen, unsigned int maxDigestLen)
|
||||
{
|
||||
PRUint32 tmpbuf[5];
|
||||
PORT_Assert (maxDigestLen >= SHA1_LENGTH);
|
||||
|
||||
SHA_STORE_RESULT;
|
||||
if (pDigestLen)
|
||||
*pDigestLen = SHA1_LENGTH;
|
||||
}
|
||||
|
||||
#undef B
|
||||
|
||||
@ -147,12 +147,12 @@ static __inline__ PRUint32 swap4b(PRUint32 value)
|
||||
SHA_STORE(3); \
|
||||
SHA_STORE(4); \
|
||||
} else { \
|
||||
ctx->u.w[0] = SHA_HTONL(ctx->H[0]); \
|
||||
ctx->u.w[1] = SHA_HTONL(ctx->H[1]); \
|
||||
ctx->u.w[2] = SHA_HTONL(ctx->H[2]); \
|
||||
ctx->u.w[3] = SHA_HTONL(ctx->H[3]); \
|
||||
ctx->u.w[4] = SHA_HTONL(ctx->H[4]); \
|
||||
memcpy(hashout, ctx->u.w, SHA1_LENGTH); \
|
||||
tmpbuf[0] = SHA_HTONL(ctx->H[0]); \
|
||||
tmpbuf[1] = SHA_HTONL(ctx->H[1]); \
|
||||
tmpbuf[2] = SHA_HTONL(ctx->H[2]); \
|
||||
tmpbuf[3] = SHA_HTONL(ctx->H[3]); \
|
||||
tmpbuf[4] = SHA_HTONL(ctx->H[4]); \
|
||||
memcpy(hashout, tmpbuf, SHA1_LENGTH); \
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
@ -1021,3 +1021,9 @@ CERT_CreateOCSPSingleResponseRevoked;
|
||||
;+ local:
|
||||
;+ *;
|
||||
;+};
|
||||
;+NSS_3.14.2 { # NSS 3.14.2 release
|
||||
;+ global:
|
||||
PK11_SignWithSymKey;
|
||||
;+ local:
|
||||
;+ *;
|
||||
;+};
|
||||
|
||||
@ -777,6 +777,51 @@ PK11_Sign(SECKEYPrivateKey *key, SECItem *sig, const SECItem *hash)
|
||||
return SECSuccess;
|
||||
}
|
||||
|
||||
/*
|
||||
* sign data with a MAC key.
|
||||
*/
|
||||
SECStatus
|
||||
PK11_SignWithSymKey(PK11SymKey *symKey, CK_MECHANISM_TYPE mechanism,
|
||||
SECItem *param, SECItem *sig, const SECItem *data)
|
||||
{
|
||||
PK11SlotInfo *slot = symKey->slot;
|
||||
CK_MECHANISM mech = {0, NULL, 0 };
|
||||
PRBool owner = PR_TRUE;
|
||||
CK_SESSION_HANDLE session;
|
||||
PRBool haslock = PR_FALSE;
|
||||
CK_ULONG len;
|
||||
CK_RV crv;
|
||||
|
||||
mech.mechanism = mechanism;
|
||||
if (param) {
|
||||
mech.pParameter = param->data;
|
||||
mech.ulParameterLen = param->len;
|
||||
}
|
||||
|
||||
session = pk11_GetNewSession(slot,&owner);
|
||||
haslock = (!owner || !(slot->isThreadSafe));
|
||||
if (haslock) PK11_EnterSlotMonitor(slot);
|
||||
crv = PK11_GETTAB(slot)->C_SignInit(session,&mech,symKey->objectID);
|
||||
if (crv != CKR_OK) {
|
||||
if (haslock) PK11_ExitSlotMonitor(slot);
|
||||
pk11_CloseSession(slot,session,owner);
|
||||
PORT_SetError( PK11_MapError(crv) );
|
||||
return SECFailure;
|
||||
}
|
||||
|
||||
len = sig->len;
|
||||
crv = PK11_GETTAB(slot)->C_Sign(session,data->data,
|
||||
data->len, sig->data, &len);
|
||||
if (haslock) PK11_ExitSlotMonitor(slot);
|
||||
pk11_CloseSession(slot,session,owner);
|
||||
sig->len = len;
|
||||
if (crv != CKR_OK) {
|
||||
PORT_SetError( PK11_MapError(crv) );
|
||||
return SECFailure;
|
||||
}
|
||||
return SECSuccess;
|
||||
}
|
||||
|
||||
/*
|
||||
* Now SSL 2.0 uses raw RSA stuff. These next to functions *must* use
|
||||
* RSA keys, or they'll fail. We do the checks up front. If anyone comes
|
||||
|
||||
@ -660,6 +660,8 @@ int PK11_SignatureLen(SECKEYPrivateKey *key);
|
||||
PK11SlotInfo * PK11_GetSlotFromPrivateKey(SECKEYPrivateKey *key);
|
||||
SECStatus PK11_Sign(SECKEYPrivateKey *key, SECItem *sig,
|
||||
const SECItem *hash);
|
||||
SECStatus PK11_SignWithSymKey(PK11SymKey *symKey, CK_MECHANISM_TYPE mechanism,
|
||||
SECItem *param, SECItem *sig, const SECItem *data);
|
||||
SECStatus PK11_VerifyRecover(SECKEYPublicKey *key, const SECItem *sig,
|
||||
SECItem *dsig, void * wincx);
|
||||
SECStatus PK11_Verify(SECKEYPublicKey *key, const SECItem *sig,
|
||||
|
||||
@ -47,6 +47,7 @@ CSRCS = \
|
||||
rsawrapr.c \
|
||||
sdb.c \
|
||||
sftkdb.c \
|
||||
sftkhmac.c \
|
||||
sftkpars.c \
|
||||
sftkpwd.c \
|
||||
softkver.c \
|
||||
|
||||
@ -488,7 +488,10 @@ static const struct mechanismList mechanisms[] = {
|
||||
{CKM_NSS_JPAKE_FINAL_SHA1, {0, 0, CKF_DERIVE}, PR_TRUE},
|
||||
{CKM_NSS_JPAKE_FINAL_SHA256, {0, 0, CKF_DERIVE}, PR_TRUE},
|
||||
{CKM_NSS_JPAKE_FINAL_SHA384, {0, 0, CKF_DERIVE}, PR_TRUE},
|
||||
{CKM_NSS_JPAKE_FINAL_SHA512, {0, 0, CKF_DERIVE}, PR_TRUE}
|
||||
{CKM_NSS_JPAKE_FINAL_SHA512, {0, 0, CKF_DERIVE}, PR_TRUE},
|
||||
/* -------------------- Constant Time TLS MACs ----------------------- */
|
||||
{CKM_NSS_HMAC_CONSTANT_TIME, {0, 0, CKF_DIGEST}, PR_TRUE},
|
||||
{CKM_NSS_SSLV3_MAC_CONSTANT_TIME, {0, 0, CKF_DIGEST}, PR_TRUE}
|
||||
};
|
||||
static const CK_ULONG mechanismCount = sizeof(mechanisms)/sizeof(mechanisms[0]);
|
||||
|
||||
|
||||
@ -1529,17 +1529,23 @@ DOSUB(SHA256)
|
||||
DOSUB(SHA384)
|
||||
DOSUB(SHA512)
|
||||
|
||||
/*
|
||||
* HMAC General copies only a portion of the result. This update routine likes
|
||||
* the final HMAC output with the signature.
|
||||
*/
|
||||
static SECStatus
|
||||
sftk_HMACCopy(CK_ULONG *copyLen,unsigned char *sig,unsigned int *sigLen,
|
||||
unsigned int maxLen,unsigned char *hash, unsigned int hashLen)
|
||||
{
|
||||
if (maxLen < *copyLen) return SECFailure;
|
||||
PORT_Memcpy(sig,hash,*copyLen);
|
||||
*sigLen = *copyLen;
|
||||
SECStatus sftk_SignCopy(
|
||||
CK_ULONG *copyLen,
|
||||
void *out, unsigned int *outLength,
|
||||
unsigned int maxLength,
|
||||
const unsigned char *hashResult,
|
||||
unsigned int hashResultLength) {
|
||||
unsigned int toCopy = *copyLen;
|
||||
if (toCopy > maxLength) {
|
||||
toCopy = maxLength;
|
||||
}
|
||||
if (toCopy > hashResultLength) {
|
||||
toCopy = hashResultLength;
|
||||
}
|
||||
memcpy(out, hashResult, toCopy);
|
||||
if (outLength) {
|
||||
*outLength = toCopy;
|
||||
}
|
||||
return SECSuccess;
|
||||
}
|
||||
|
||||
@ -1595,7 +1601,7 @@ sftk_doHMACInit(SFTKSessionContext *context,HASH_HashType hash,
|
||||
*intpointer = mac_size;
|
||||
context->cipherInfo = (void *) intpointer;
|
||||
context->destroy = (SFTKDestroy) sftk_Space;
|
||||
context->update = (SFTKCipher) sftk_HMACCopy;
|
||||
context->update = (SFTKCipher) sftk_SignCopy;
|
||||
context->verify = (SFTKVerify) sftk_HMACCmp;
|
||||
context->maxLen = hashObj->length;
|
||||
HMAC_Begin(HMACcontext);
|
||||
@ -2241,6 +2247,65 @@ finish_rsa:
|
||||
case CKM_TLS_PRF_GENERAL:
|
||||
crv = sftk_TLSPRFInit(context, key, key_type);
|
||||
break;
|
||||
|
||||
case CKM_NSS_HMAC_CONSTANT_TIME: {
|
||||
sftk_MACConstantTimeCtx *ctx = sftk_HMACConstantTime_New(pMechanism,key);
|
||||
int *intpointer;
|
||||
|
||||
if (ctx == NULL) {
|
||||
crv = CKR_ARGUMENTS_BAD;
|
||||
break;
|
||||
}
|
||||
intpointer = PORT_Alloc(sizeof(int));
|
||||
if (intpointer == NULL) {
|
||||
crv = CKR_HOST_MEMORY;
|
||||
break;
|
||||
}
|
||||
*intpointer = ctx->hash->length;
|
||||
|
||||
context->cipherInfo = intpointer;
|
||||
context->hashInfo = (void *) ctx;
|
||||
context->currentMech = pMechanism->mechanism;
|
||||
context->hashUpdate = sftk_HMACConstantTime_Update;
|
||||
context->hashdestroy = sftk_MACConstantTime_DestroyContext;
|
||||
context->end = sftk_MACConstantTime_EndHash;
|
||||
context->update = sftk_SignCopy;
|
||||
context->destroy = sftk_Space;
|
||||
context->maxLen = 64;
|
||||
context->multi = PR_TRUE;
|
||||
if (ctx == NULL)
|
||||
crv = CKR_ARGUMENTS_BAD;
|
||||
break;
|
||||
}
|
||||
|
||||
case CKM_NSS_SSLV3_MAC_CONSTANT_TIME: {
|
||||
sftk_MACConstantTimeCtx *ctx = sftk_SSLv3MACConstantTime_New(pMechanism,key);
|
||||
int *intpointer;
|
||||
|
||||
if (ctx == NULL) {
|
||||
crv = CKR_ARGUMENTS_BAD;
|
||||
break;
|
||||
}
|
||||
intpointer = PORT_Alloc(sizeof(int));
|
||||
if (intpointer == NULL) {
|
||||
crv = CKR_HOST_MEMORY;
|
||||
break;
|
||||
}
|
||||
*intpointer = ctx->hash->length;
|
||||
|
||||
context->cipherInfo = intpointer;
|
||||
context->hashInfo = (void *) ctx;
|
||||
context->currentMech = pMechanism->mechanism;
|
||||
context->hashUpdate = sftk_SSLv3MACConstantTime_Update;
|
||||
context->hashdestroy = sftk_MACConstantTime_DestroyContext;
|
||||
context->end = sftk_MACConstantTime_EndHash;
|
||||
context->update = sftk_SignCopy;
|
||||
context->destroy = sftk_Space;
|
||||
context->maxLen = 64;
|
||||
context->multi = PR_TRUE;
|
||||
break;
|
||||
}
|
||||
|
||||
default:
|
||||
crv = CKR_MECHANISM_INVALID;
|
||||
break;
|
||||
|
||||
@ -708,6 +708,28 @@ CK_RV jpake_Final(HASH_HashType hashType,
|
||||
const CK_NSS_JPAKEFinalParams * params,
|
||||
SFTKObject * sourceKey, SFTKObject * key);
|
||||
|
||||
/* Constant time MAC functions (hmacct.c) */
|
||||
|
||||
struct sftk_MACConstantTimeCtxStr {
|
||||
const SECHashObject *hash;
|
||||
unsigned char mac[64];
|
||||
unsigned char secret[64];
|
||||
unsigned int headerLength;
|
||||
unsigned int secretLength;
|
||||
unsigned int totalLength;
|
||||
unsigned char header[75];
|
||||
};
|
||||
typedef struct sftk_MACConstantTimeCtxStr sftk_MACConstantTimeCtx;
|
||||
sftk_MACConstantTimeCtx* sftk_HMACConstantTime_New(
|
||||
CK_MECHANISM_PTR mech, SFTKObject *key);
|
||||
sftk_MACConstantTimeCtx* sftk_SSLv3MACConstantTime_New(
|
||||
CK_MECHANISM_PTR mech, SFTKObject *key);
|
||||
void sftk_HMACConstantTime_Update(void *pctx, void *data, unsigned int len);
|
||||
void sftk_SSLv3MACConstantTime_Update(void *pctx, void *data, unsigned int len);
|
||||
void sftk_MACConstantTime_EndHash(
|
||||
void *pctx, void *out, unsigned int *outLength, unsigned int maxLength);
|
||||
void sftk_MACConstantTime_DestroyContext(void *pctx, PRBool);
|
||||
|
||||
/****************************************
|
||||
* implement TLS Pseudo Random Function (PRF)
|
||||
*/
|
||||
|
||||
175
mozilla/security/nss/lib/softoken/sftkhmac.c
Normal file
175
mozilla/security/nss/lib/softoken/sftkhmac.c
Normal file
@ -0,0 +1,175 @@
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#include "seccomon.h"
|
||||
#include "secerr.h"
|
||||
#include "blapi.h"
|
||||
#include "pkcs11i.h"
|
||||
#include "softoken.h"
|
||||
#include "hmacct.h"
|
||||
|
||||
/* mechanismToHash converts a PKCS#11 hash mechanism into a freebl hash type. */
|
||||
static HASH_HashType mechanismToHash(CK_MECHANISM_TYPE mech) {
|
||||
switch (mech) {
|
||||
case CKM_MD5:
|
||||
case CKM_MD5_HMAC:
|
||||
case CKM_SSL3_MD5_MAC:
|
||||
return HASH_AlgMD5;
|
||||
case CKM_SHA_1:
|
||||
case CKM_SHA_1_HMAC:
|
||||
case CKM_SSL3_SHA1_MAC:
|
||||
return HASH_AlgSHA1;
|
||||
case CKM_SHA224:
|
||||
return HASH_AlgSHA224;
|
||||
case CKM_SHA256:
|
||||
return HASH_AlgSHA256;
|
||||
case CKM_SHA384:
|
||||
return HASH_AlgSHA384;
|
||||
case CKM_SHA512:
|
||||
return HASH_AlgSHA512;
|
||||
}
|
||||
return HASH_AlgNULL;
|
||||
}
|
||||
|
||||
static sftk_MACConstantTimeCtx* SetupMAC(CK_MECHANISM_PTR mech,
|
||||
SFTKObject *key) {
|
||||
CK_NSS_MACConstantTimeParams* params =
|
||||
(CK_NSS_MACConstantTimeParams*) mech->pParameter;
|
||||
sftk_MACConstantTimeCtx* ctx;
|
||||
HASH_HashType alg;
|
||||
SFTKAttribute *keyval;
|
||||
unsigned char secret[sizeof(ctx->secret)];
|
||||
unsigned int secretLength;
|
||||
|
||||
if (mech->ulParameterLen != sizeof(CK_NSS_MACConstantTimeParams)) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
alg = mechanismToHash(params->hashAlg);
|
||||
if (alg == HASH_AlgNULL) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
keyval = sftk_FindAttribute(key,CKA_VALUE);
|
||||
if (keyval == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
secretLength = keyval->attrib.ulValueLen;
|
||||
if (secretLength > sizeof(secret)) {
|
||||
sftk_FreeAttribute(keyval);
|
||||
return NULL;
|
||||
}
|
||||
memcpy(secret, keyval->attrib.pValue, secretLength);
|
||||
sftk_FreeAttribute(keyval);
|
||||
|
||||
ctx = PORT_Alloc(sizeof(sftk_MACConstantTimeCtx));
|
||||
if (!ctx) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
memcpy(ctx->secret, secret, secretLength);
|
||||
ctx->secretLength = secretLength;
|
||||
ctx->hash = HASH_GetRawHashObject(alg);
|
||||
ctx->totalLength = params->ulBodyTotalLength;
|
||||
|
||||
return ctx;
|
||||
}
|
||||
|
||||
sftk_MACConstantTimeCtx* sftk_HMACConstantTime_New(CK_MECHANISM_PTR mech,
|
||||
SFTKObject *key) {
|
||||
CK_NSS_MACConstantTimeParams* params =
|
||||
(CK_NSS_MACConstantTimeParams*) mech->pParameter;
|
||||
sftk_MACConstantTimeCtx* ctx;
|
||||
|
||||
if (params->ulHeaderLength > sizeof(ctx->header)) {
|
||||
return NULL;
|
||||
}
|
||||
ctx = SetupMAC(mech, key);
|
||||
if (!ctx) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
ctx->headerLength = params->ulHeaderLength;
|
||||
memcpy(ctx->header, params->pHeader, params->ulHeaderLength);
|
||||
return ctx;
|
||||
}
|
||||
|
||||
sftk_MACConstantTimeCtx* sftk_SSLv3MACConstantTime_New(CK_MECHANISM_PTR mech,
|
||||
SFTKObject *key) {
|
||||
CK_NSS_MACConstantTimeParams* params =
|
||||
(CK_NSS_MACConstantTimeParams*) mech->pParameter;
|
||||
unsigned int padLength = 40, j;
|
||||
|
||||
sftk_MACConstantTimeCtx* ctx = SetupMAC(mech, key);
|
||||
if (!ctx) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (params->hashAlg == CKM_MD5) {
|
||||
padLength = 48;
|
||||
}
|
||||
|
||||
ctx->headerLength =
|
||||
ctx->secretLength +
|
||||
padLength +
|
||||
params->ulHeaderLength;
|
||||
|
||||
if (ctx->headerLength > sizeof(ctx->header)) {
|
||||
goto loser;
|
||||
}
|
||||
|
||||
j = 0;
|
||||
memcpy(&ctx->header[j], ctx->secret, ctx->secretLength);
|
||||
j += ctx->secretLength;
|
||||
memset(&ctx->header[j], 0x36, padLength);
|
||||
j += padLength;
|
||||
memcpy(&ctx->header[j], params->pHeader, params->ulHeaderLength);
|
||||
|
||||
return ctx;
|
||||
|
||||
loser:
|
||||
PORT_Free(ctx);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void sftk_HMACConstantTime_Update(void *pctx, void *data, unsigned int len) {
|
||||
sftk_MACConstantTimeCtx* ctx = (sftk_MACConstantTimeCtx*) pctx;
|
||||
SECStatus rv = HMAC_ConstantTime(
|
||||
ctx->mac, NULL, sizeof(ctx->mac),
|
||||
ctx->hash,
|
||||
ctx->secret, ctx->secretLength,
|
||||
ctx->header, ctx->headerLength,
|
||||
data, len,
|
||||
ctx->totalLength);
|
||||
PORT_Assert(rv == SECSuccess);
|
||||
}
|
||||
|
||||
void sftk_SSLv3MACConstantTime_Update(void *pctx, void *data, unsigned int len) {
|
||||
sftk_MACConstantTimeCtx* ctx = (sftk_MACConstantTimeCtx*) pctx;
|
||||
SECStatus rv = SSLv3_MAC_ConstantTime(
|
||||
ctx->mac, NULL, sizeof(ctx->mac),
|
||||
ctx->hash,
|
||||
ctx->secret, ctx->secretLength,
|
||||
ctx->header, ctx->headerLength,
|
||||
data, len,
|
||||
ctx->totalLength);
|
||||
PORT_Assert(rv == SECSuccess);
|
||||
}
|
||||
|
||||
void sftk_MACConstantTime_EndHash(void *pctx, void *out, unsigned int *outLength,
|
||||
unsigned int maxLength) {
|
||||
const sftk_MACConstantTimeCtx* ctx = (sftk_MACConstantTimeCtx*) pctx;
|
||||
unsigned int toCopy = ctx->hash->length;
|
||||
if (toCopy > maxLength) {
|
||||
toCopy = maxLength;
|
||||
}
|
||||
memcpy(out, ctx->mac, toCopy);
|
||||
if (outLength) {
|
||||
*outLength = toCopy;
|
||||
}
|
||||
}
|
||||
|
||||
void sftk_MACConstantTime_DestroyContext(void *pctx, PRBool free) {
|
||||
PORT_Free(pctx);
|
||||
}
|
||||
@ -5,7 +5,7 @@
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
/* $Id: ssl3con.c,v 1.197 2013-01-18 19:31:42 bsmith%mozilla.com Exp $ */
|
||||
/* $Id: ssl3con.c,v 1.198 2013-02-05 18:10:45 wtc%google.com Exp $ */
|
||||
|
||||
/* TODO(ekr): Implement HelloVerifyRequest on server side. OK for now. */
|
||||
|
||||
@ -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,135 @@ ssl3_ComputeRecordMAC(
|
||||
return rv;
|
||||
}
|
||||
|
||||
/* 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, inputItem, outputItem;
|
||||
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->cipher_def->cipher == cipher_rc2_40) {
|
||||
/* This function doesn't work for SSL3_RSA_EXPORT_WITH_RC2_CBC_40_MD5.
|
||||
* 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 {
|
||||
if (isDTLS) {
|
||||
SSL3ProtocolVersion dtls_version;
|
||||
|
||||
dtls_version = dtls_TLSVersionToDTLSVersion(version);
|
||||
header[9] = dtls_version >> 8;
|
||||
header[10] = dtls_version;
|
||||
} 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;
|
||||
|
||||
inputItem.data = (unsigned char *) input;
|
||||
inputItem.len = inputLen;
|
||||
inputItem.type = 0;
|
||||
|
||||
outputItem.data = outbuf;
|
||||
outputItem.len = *outLen;
|
||||
outputItem.type = 0;
|
||||
|
||||
key = spec->server.write_mac_key;
|
||||
if (!useServerMacKey) {
|
||||
key = spec->client.write_mac_key;
|
||||
}
|
||||
|
||||
rv = PK11_SignWithSymKey(key, macType, ¶m, &outputItem, &inputItem);
|
||||
if (rv != SECSuccess) {
|
||||
if (PORT_GetError() == SEC_ERROR_INVALID_ALGORITHM) {
|
||||
goto fallback;
|
||||
}
|
||||
|
||||
*outLen = 0;
|
||||
rv = SECFailure;
|
||||
ssl_MapLowLevelError(SSL_ERROR_MAC_COMPUTATION_FAILURE);
|
||||
return rv;
|
||||
}
|
||||
|
||||
PORT_Assert(outputItem.len == (unsigned)spec->mac_size);
|
||||
*outLen = outputItem.len;
|
||||
|
||||
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;
|
||||
@ -9534,6 +9662,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
|
||||
@ -9563,15 +9862,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) );
|
||||
|
||||
@ -9639,6 +9941,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
|
||||
@ -9656,16 +9982,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));
|
||||
|
||||
@ -9676,12 +9992,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
|
||||
@ -9723,54 +10034,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;
|
||||
}
|
||||
|
||||
/* Check the MAC */
|
||||
if (hashBytes != (unsigned)crSpec->mac_size || padIsBad ||
|
||||
NSS_SecureMemcmp(plaintext->buf + plaintext->len, hash,
|
||||
crSpec->mac_size) != 0) {
|
||||
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;
|
||||
}
|
||||
|
||||
if (good == 0) {
|
||||
/* must not hold spec lock when calling SSL3_SendAlert. */
|
||||
ssl_ReleaseSpecReadLock(ss);
|
||||
|
||||
|
||||
@ -1,7 +1,7 @@
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
/* $Id: hasht.h,v 1.10 2012-06-26 22:27:33 rrelyea%redhat.com Exp $ */
|
||||
/* $Id: hasht.h,v 1.11 2013-02-05 18:10:46 wtc%google.com Exp $ */
|
||||
|
||||
#ifndef _HASHT_H_
|
||||
#define _HASHT_H_
|
||||
@ -51,6 +51,7 @@ struct SECHashObjectStr {
|
||||
void (*end)(void *, unsigned char *, unsigned int *, unsigned int);
|
||||
unsigned int blocklength; /* hash input block size (in bytes) */
|
||||
HASH_HashType type;
|
||||
void (*end_raw)(void *, unsigned char *, unsigned int *, unsigned int);
|
||||
};
|
||||
|
||||
struct HASHContextStr {
|
||||
|
||||
@ -6,7 +6,7 @@
|
||||
#define _PKCS11N_H_
|
||||
|
||||
#ifdef DEBUG
|
||||
static const char CKT_CVS_ID[] = "@(#) $RCSfile: pkcs11n.h,v $ $Revision: 1.28 $ $Date: 2012-04-25 14:50:16 $";
|
||||
static const char CKT_CVS_ID[] = "@(#) $RCSfile: pkcs11n.h,v $ $Revision: 1.29 $ $Date: 2013-02-05 18:10:46 $";
|
||||
#endif /* DEBUG */
|
||||
|
||||
/*
|
||||
@ -195,6 +195,9 @@ static const char CKT_CVS_ID[] = "@(#) $RCSfile: pkcs11n.h,v $ $Revision: 1.28 $
|
||||
#define CKM_NSS_JPAKE_FINAL_SHA384 (CKM_NSS + 17)
|
||||
#define CKM_NSS_JPAKE_FINAL_SHA512 (CKM_NSS + 18)
|
||||
|
||||
#define CKM_NSS_HMAC_CONSTANT_TIME (CKM_NSS + 19)
|
||||
#define CKM_NSS_SSLV3_MAC_CONSTANT_TIME (CKM_NSS + 20)
|
||||
|
||||
/*
|
||||
* HISTORICAL:
|
||||
* Do not attempt to use these. They are only used by NETSCAPE's internal
|
||||
@ -240,6 +243,13 @@ typedef struct CK_NSS_JPAKEFinalParams {
|
||||
CK_NSS_JPAKEPublicValue B; /* in */
|
||||
} CK_NSS_JPAKEFinalParams;
|
||||
|
||||
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;
|
||||
|
||||
/*
|
||||
* NSS-defined return values
|
||||
*
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user