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:
wtc%google.com 2013-02-05 18:10:46 +00:00
parent 15e5148cca
commit f7ff05a366
23 changed files with 1340 additions and 97 deletions

View File

@ -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);

View 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 */);
}

View 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

View File

@ -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 *

View File

@ -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);
}

View File

@ -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;

View File

@ -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 \

View File

@ -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)
{

View File

@ -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
},
};

View File

@ -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)

View File

@ -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

View File

@ -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

View File

@ -1021,3 +1021,9 @@ CERT_CreateOCSPSingleResponseRevoked;
;+ local:
;+ *;
;+};
;+NSS_3.14.2 { # NSS 3.14.2 release
;+ global:
PK11_SignWithSymKey;
;+ local:
;+ *;
;+};

View File

@ -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

View File

@ -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,

View File

@ -47,6 +47,7 @@ CSRCS = \
rsawrapr.c \
sdb.c \
sftkdb.c \
sftkhmac.c \
sftkpars.c \
sftkpwd.c \
softkver.c \

View File

@ -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]);

View File

@ -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;

View File

@ -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)
*/

View 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);
}

View File

@ -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*) &params;
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, &param, &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);

View File

@ -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 {

View File

@ -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
*