diff options
author | wtc%google.com <devnull@localhost> | 2013-02-05 18:10:46 +0000 |
---|---|---|
committer | wtc%google.com <devnull@localhost> | 2013-02-05 18:10:46 +0000 |
commit | acd57f58f4f76d551ba25e6ad95f823c9c9fb3a9 (patch) | |
tree | 21d136245493d951eb7b1f53f626ee3100359f2a | |
parent | 81fad6d3605d9159d6323e3ad74b9cf0f87f15c3 (diff) | |
download | nss-hg-acd57f58f4f76d551ba25e6ad95f823c9c9fb3a9.tar.gz |
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
23 files changed, 1332 insertions, 89 deletions
diff --git a/security/nss/lib/freebl/blapi.h b/security/nss/lib/freebl/blapi.h index a6e999676..06dd0dfb1 100644 --- a/security/nss/lib/freebl/blapi.h +++ b/security/nss/lib/freebl/blapi.h @@ -875,6 +875,18 @@ 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 * returns size; @@ -1031,6 +1043,18 @@ 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. */ extern void SHA1_TraceState(SHA1Context *cx); @@ -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); diff --git a/security/nss/lib/freebl/hmacct.c b/security/nss/lib/freebl/hmacct.c new file mode 100644 index 000000000..93390eb5e --- /dev/null +++ b/security/nss/lib/freebl/hmacct.c @@ -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 */); +} + diff --git a/security/nss/lib/freebl/hmacct.h b/security/nss/lib/freebl/hmacct.h new file mode 100644 index 000000000..8b0e91c8a --- /dev/null +++ b/security/nss/lib/freebl/hmacct.h @@ -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 diff --git a/security/nss/lib/freebl/ldvector.c b/security/nss/lib/freebl/ldvector.c index 1b51afb22..186ae2f5e 100644 --- a/security/nss/lib/freebl/ldvector.c +++ b/security/nss/lib/freebl/ldvector.c @@ -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 * diff --git a/security/nss/lib/freebl/loader.c b/security/nss/lib/freebl/loader.c index 71daabd1c..ae3025199 100644 --- a/security/nss/lib/freebl/loader.c +++ b/security/nss/lib/freebl/loader.c @@ -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); +} diff --git a/security/nss/lib/freebl/loader.h b/security/nss/lib/freebl/loader.h index d5d80b7b4..4ea2afda7 100644 --- a/security/nss/lib/freebl/loader.h +++ b/security/nss/lib/freebl/loader.h @@ -11,7 +11,7 @@ #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; diff --git a/security/nss/lib/freebl/manifest.mn b/security/nss/lib/freebl/manifest.mn index ea29a8eaa..f7f98c15b 100644 --- a/security/nss/lib/freebl/manifest.mn +++ b/security/nss/lib/freebl/manifest.mn @@ -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 \ diff --git a/security/nss/lib/freebl/md5.c b/security/nss/lib/freebl/md5.c index 705a85735..919ef7fdb 100644 --- a/security/nss/lib/freebl/md5.c +++ b/security/nss/lib/freebl/md5.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) { diff --git a/security/nss/lib/freebl/rawhash.c b/security/nss/lib/freebl/rawhash.c index 253b0fe73..7962b1fff 100644 --- a/security/nss/lib/freebl/rawhash.c +++ b/security/nss/lib/freebl/rawhash.c @@ -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 }, }; diff --git a/security/nss/lib/freebl/sha512.c b/security/nss/lib/freebl/sha512.c index 910241ad6..301656e54 100644 --- a/security/nss/lib/freebl/sha512.c +++ b/security/nss/lib/freebl/sha512.c @@ -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) diff --git a/security/nss/lib/freebl/sha_fast.c b/security/nss/lib/freebl/sha_fast.c index cc7895c4b..6044610ab 100644 --- a/security/nss/lib/freebl/sha_fast.c +++ b/security/nss/lib/freebl/sha_fast.c @@ -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 diff --git a/security/nss/lib/freebl/sha_fast.h b/security/nss/lib/freebl/sha_fast.h index fb490b056..9d47aba42 100644 --- a/security/nss/lib/freebl/sha_fast.h +++ b/security/nss/lib/freebl/sha_fast.h @@ -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 diff --git a/security/nss/lib/nss/nss.def b/security/nss/lib/nss/nss.def index aecd92870..7fbe2ba2a 100644 --- a/security/nss/lib/nss/nss.def +++ b/security/nss/lib/nss/nss.def @@ -1021,3 +1021,9 @@ CERT_CreateOCSPSingleResponseRevoked; ;+ local: ;+ *; ;+}; +;+NSS_3.14.2 { # NSS 3.14.2 release +;+ global: +PK11_SignWithSymKey; +;+ local: +;+ *; +;+}; diff --git a/security/nss/lib/pk11wrap/pk11obj.c b/security/nss/lib/pk11wrap/pk11obj.c index be701d217..4fa5dde98 100644 --- a/security/nss/lib/pk11wrap/pk11obj.c +++ b/security/nss/lib/pk11wrap/pk11obj.c @@ -778,6 +778,51 @@ PK11_Sign(SECKEYPrivateKey *key, SECItem *sig, const SECItem *hash) } /* + * 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 * up with a meaning for rawdecrypt for any other public key operation, diff --git a/security/nss/lib/pk11wrap/pk11pub.h b/security/nss/lib/pk11wrap/pk11pub.h index 314ccba40..f15d6da81 100644 --- a/security/nss/lib/pk11wrap/pk11pub.h +++ b/security/nss/lib/pk11wrap/pk11pub.h @@ -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, diff --git a/security/nss/lib/softoken/manifest.mn b/security/nss/lib/softoken/manifest.mn index eefbb19fc..e36bf6075 100644 --- a/security/nss/lib/softoken/manifest.mn +++ b/security/nss/lib/softoken/manifest.mn @@ -47,6 +47,7 @@ CSRCS = \ rsawrapr.c \ sdb.c \ sftkdb.c \ + sftkhmac.c \ sftkpars.c \ sftkpwd.c \ softkver.c \ diff --git a/security/nss/lib/softoken/pkcs11.c b/security/nss/lib/softoken/pkcs11.c index 226b9c60b..d526b453c 100644 --- a/security/nss/lib/softoken/pkcs11.c +++ b/security/nss/lib/softoken/pkcs11.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]); diff --git a/security/nss/lib/softoken/pkcs11c.c b/security/nss/lib/softoken/pkcs11c.c index dfe12e12b..666fbfcb1 100644 --- a/security/nss/lib/softoken/pkcs11c.c +++ b/security/nss/lib/softoken/pkcs11c.c @@ -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; diff --git a/security/nss/lib/softoken/pkcs11i.h b/security/nss/lib/softoken/pkcs11i.h index 45001b8d0..904a0621a 100644 --- a/security/nss/lib/softoken/pkcs11i.h +++ b/security/nss/lib/softoken/pkcs11i.h @@ -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) */ diff --git a/security/nss/lib/softoken/sftkhmac.c b/security/nss/lib/softoken/sftkhmac.c new file mode 100644 index 000000000..412ee4dc4 --- /dev/null +++ b/security/nss/lib/softoken/sftkhmac.c @@ -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); +} diff --git a/security/nss/lib/ssl/ssl3con.c b/security/nss/lib/ssl/ssl3con.c index 301902876..d5d6ef0f9 100644 --- a/security/nss/lib/ssl/ssl3con.c +++ b/security/nss/lib/ssl/ssl3con.c @@ -1844,7 +1844,6 @@ static const unsigned char mac_pad_2 [60] = { }; /* Called from: ssl3_SendRecord() -** ssl3_HandleRecord() ** Caller must already hold the SpecReadLock. (wish we could assert that!) */ static SECStatus @@ -2026,6 +2025,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; + } + + good &= SECStatusToMask(rv); + + if (hashBytes != (unsigned)crSpec->mac_size || + NSS_SecureMemcmp(givenHash, hash, crSpec->mac_size) != 0) { + /* We're allowed to leak whether or not the MAC check was correct */ + good = 0; } - /* Check the MAC */ - if (hashBytes != (unsigned)crSpec->mac_size || padIsBad || - NSS_SecureMemcmp(plaintext->buf + plaintext->len, hash, - crSpec->mac_size) != 0) { + if (good == 0) { /* must not hold spec lock when calling SSL3_SendAlert. */ ssl_ReleaseSpecReadLock(ss); diff --git a/security/nss/lib/util/hasht.h b/security/nss/lib/util/hasht.h index 484f8442a..6fd12f13a 100644 --- a/security/nss/lib/util/hasht.h +++ b/security/nss/lib/util/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 { diff --git a/security/nss/lib/util/pkcs11n.h b/security/nss/lib/util/pkcs11n.h index 6f89f1531..a6fceec1e 100644 --- a/security/nss/lib/util/pkcs11n.h +++ b/security/nss/lib/util/pkcs11n.h @@ -195,6 +195,9 @@ static const char CKT_CVS_ID[] = "@(#) $RCSfile$ $Revision$ $Date$"; #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 * |