diff --git a/lib/freebl/fipsfreebl.c b/lib/freebl/fipsfreebl.c
--- a/lib/freebl/fipsfreebl.c
+++ b/lib/freebl/fipsfreebl.c
@@ -10,18 +10,20 @@
#ifdef FREEBL_NO_DEPEND
#include "stubs.h"
#endif
#include "blapi.h"
#include "seccomon.h" /* Required for RSA and DSA. */
#include "secerr.h"
#include "prtypes.h"
+#include "secitem.h"
+#include "pkcs11t.h"
-#include "ec.h" /* Required for ECDSA */
+#include "ec.h" /* Required for EC */
/*
* different platforms have different ways of calling and initial entry point
* when the dll/.so is loaded. Most platforms support either a posix pragma
* or the GCC attribute. Some platforms suppor a pre-defined name, and some
* platforms have a link line way of invoking this function.
*/
@@ -283,61 +285,88 @@ freebl_fips_AES_PowerUpSelfTest(int aes_
/* AES-CBC Known Initialization Vector (128-bits). */
static const PRUint8 aes_cbc_known_initialization_vector[] =
{ "SecurityytiruceS" };
/* AES Known Plaintext (128-bits). (blocksize is 128-bits) */
static const PRUint8 aes_known_plaintext[] = { "NetscapeepacsteN" };
+ static const PRUint8 aes_gcm_known_aad[] = { "MozillaallizoM" };
+
/* AES Known Ciphertext (128-bit key). */
static const PRUint8 aes_ecb128_known_ciphertext[] = {
0x3c, 0xa5, 0x96, 0xf3, 0x34, 0x6a, 0x96, 0xc1,
0x03, 0x88, 0x16, 0x7b, 0x20, 0xbf, 0x35, 0x47
};
static const PRUint8 aes_cbc128_known_ciphertext[] = {
0xcf, 0x15, 0x1d, 0x4f, 0x96, 0xe4, 0x4f, 0x63,
0x15, 0x54, 0x14, 0x1d, 0x4e, 0xd8, 0xd5, 0xea
};
+ static const PRUint8 aes_gcm128_known_ciphertext[] = {
+ 0x63, 0xf4, 0x95, 0x28, 0xe6, 0x78, 0xee, 0x6e,
+ 0x4f, 0xe0, 0xfc, 0x8d, 0xd7, 0xa2, 0xb1, 0xff,
+ 0x0c, 0x97, 0x1b, 0x0a, 0xdd, 0x97, 0x75, 0xed,
+ 0x8b, 0xde, 0xbf, 0x16, 0x5e, 0x57, 0x6b, 0x4f
+ };
+
/* AES Known Ciphertext (192-bit key). */
static const PRUint8 aes_ecb192_known_ciphertext[] = {
0xa0, 0x18, 0x62, 0xed, 0x88, 0x19, 0xcb, 0x62,
0x88, 0x1d, 0x4d, 0xfe, 0x84, 0x02, 0x89, 0x0e
};
static const PRUint8 aes_cbc192_known_ciphertext[] = {
0x83, 0xf7, 0xa4, 0x76, 0xd1, 0x6f, 0x07, 0xbe,
0x07, 0xbc, 0x43, 0x2f, 0x6d, 0xad, 0x29, 0xe1
};
+ static const PRUint8 aes_gcm192_known_ciphertext[] = {
+ 0xc1, 0x0b, 0x92, 0x1d, 0x68, 0x21, 0xf4, 0x25,
+ 0x41, 0x61, 0x20, 0x2d, 0x59, 0x7f, 0x53, 0xde,
+ 0x93, 0x39, 0xab, 0x09, 0x76, 0x41, 0x57, 0x2b,
+ 0x90, 0x2e, 0x44, 0xbb, 0x52, 0x03, 0xe9, 0x07
+ };
+
/* AES Known Ciphertext (256-bit key). */
static const PRUint8 aes_ecb256_known_ciphertext[] = {
0xdb, 0xa6, 0x52, 0x01, 0x8a, 0x70, 0xae, 0x66,
0x3a, 0x99, 0xd8, 0x95, 0x7f, 0xfb, 0x01, 0x67
};
static const PRUint8 aes_cbc256_known_ciphertext[] = {
0x37, 0xea, 0x07, 0x06, 0x31, 0x1c, 0x59, 0x27,
0xc5, 0xc5, 0x68, 0x71, 0x6e, 0x34, 0x40, 0x16
};
+ static const PRUint8 aes_gcm256_known_ciphertext[] = {
+ 0x5d, 0x9e, 0xd2, 0xa2, 0x74, 0x9c, 0xd9, 0x1c,
+ 0xd1, 0xc9, 0xee, 0x5d, 0xb6, 0xf2, 0xc9, 0xb6,
+ 0x79, 0x27, 0x53, 0x02, 0xa3, 0xdc, 0x22, 0xce,
+ 0xf4, 0xb0, 0xc1, 0x8c, 0x86, 0x51, 0xf5, 0xa1
+ };
+
const PRUint8 *aes_ecb_known_ciphertext =
(aes_key_size == FIPS_AES_128_KEY_SIZE) ? aes_ecb128_known_ciphertext : (aes_key_size == FIPS_AES_192_KEY_SIZE) ? aes_ecb192_known_ciphertext : aes_ecb256_known_ciphertext;
const PRUint8 *aes_cbc_known_ciphertext =
(aes_key_size == FIPS_AES_128_KEY_SIZE) ? aes_cbc128_known_ciphertext : (aes_key_size == FIPS_AES_192_KEY_SIZE) ? aes_cbc192_known_ciphertext : aes_cbc256_known_ciphertext;
+ const PRUint8 *aes_gcm_known_ciphertext =
+ (aes_key_size == FIPS_AES_128_KEY_SIZE) ? aes_gcm128_known_ciphertext : (aes_key_size == FIPS_AES_192_KEY_SIZE) ? aes_gcm192_known_ciphertext : aes_gcm256_known_ciphertext;
+
/* AES variables. */
- PRUint8 aes_computed_ciphertext[FIPS_AES_ENCRYPT_LENGTH];
- PRUint8 aes_computed_plaintext[FIPS_AES_DECRYPT_LENGTH];
+ PRUint8 aes_computed_ciphertext[FIPS_AES_ENCRYPT_LENGTH * 2];
+ PRUint8 aes_computed_plaintext[FIPS_AES_DECRYPT_LENGTH * 2];
AESContext *aes_context;
unsigned int aes_bytes_encrypted;
unsigned int aes_bytes_decrypted;
+ CK_GCM_PARAMS gcmParams;
SECStatus aes_status;
/*check if aes_key_size is 128, 192, or 256 bits */
if ((aes_key_size != FIPS_AES_128_KEY_SIZE) &&
(aes_key_size != FIPS_AES_192_KEY_SIZE) &&
(aes_key_size != FIPS_AES_256_KEY_SIZE)) {
PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
return (SECFailure);
@@ -450,16 +479,79 @@ freebl_fips_AES_PowerUpSelfTest(int aes_
if ((aes_status != SECSuccess) ||
(aes_bytes_decrypted != FIPS_AES_DECRYPT_LENGTH) ||
(PORT_Memcmp(aes_computed_plaintext, aes_known_plaintext,
FIPS_AES_DECRYPT_LENGTH) != 0)) {
PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
return (SECFailure);
}
+ /******************************************************/
+ /* AES-GCM Single-Round Known Answer Encryption Test. */
+ /******************************************************/
+
+ gcmParams.pIv = (PRUint8 *)aes_cbc_known_initialization_vector;
+ gcmParams.ulIvLen = FIPS_AES_BLOCK_SIZE;
+ gcmParams.pAAD = (PRUint8 *)aes_gcm_known_aad;
+ gcmParams.ulAADLen = sizeof(aes_gcm_known_aad);
+ gcmParams.ulTagBits = FIPS_AES_BLOCK_SIZE * 8;
+ aes_context = AES_CreateContext(aes_known_key,
+ (PRUint8 *)&gcmParams,
+ NSS_AES_GCM, PR_TRUE, aes_key_size,
+ FIPS_AES_BLOCK_SIZE);
+
+ if (aes_context == NULL) {
+ PORT_SetError(SEC_ERROR_NO_MEMORY);
+ return (SECFailure);
+ }
+
+ aes_status = AES_Encrypt(aes_context, aes_computed_ciphertext,
+ &aes_bytes_encrypted, FIPS_AES_ENCRYPT_LENGTH * 2,
+ aes_known_plaintext,
+ FIPS_AES_DECRYPT_LENGTH);
+
+ AES_DestroyContext(aes_context, PR_TRUE);
+
+ if ((aes_status != SECSuccess) ||
+ (aes_bytes_encrypted != FIPS_AES_ENCRYPT_LENGTH * 2) ||
+ (PORT_Memcmp(aes_computed_ciphertext, aes_gcm_known_ciphertext,
+ FIPS_AES_ENCRYPT_LENGTH * 2) != 0)) {
+ PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
+ return (SECFailure);
+ }
+
+ /******************************************************/
+ /* AES-GCM Single-Round Known Answer Decryption Test. */
+ /******************************************************/
+
+ aes_context = AES_CreateContext(aes_known_key,
+ (PRUint8 *)&gcmParams,
+ NSS_AES_GCM, PR_FALSE, aes_key_size,
+ FIPS_AES_BLOCK_SIZE);
+
+ if (aes_context == NULL) {
+ PORT_SetError(SEC_ERROR_NO_MEMORY);
+ return (SECFailure);
+ }
+
+ aes_status = AES_Decrypt(aes_context, aes_computed_plaintext,
+ &aes_bytes_decrypted, FIPS_AES_DECRYPT_LENGTH * 2,
+ aes_gcm_known_ciphertext,
+ FIPS_AES_ENCRYPT_LENGTH * 2);
+
+ AES_DestroyContext(aes_context, PR_TRUE);
+
+ if ((aes_status != SECSuccess) ||
+ (aes_bytes_decrypted != FIPS_AES_DECRYPT_LENGTH) ||
+ (PORT_Memcmp(aes_computed_plaintext, aes_known_plaintext,
+ FIPS_AES_DECRYPT_LENGTH) != 0)) {
+ PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
+ return (SECFailure);
+ }
+
return (SECSuccess);
}
/* Known Hash Message (512-bits). Used for all hashes (incl. SHA-N [N>1]). */
static const PRUint8 known_hash_message[] = {
"The test message for the MD2, MD5, and SHA-1 hashing algorithms."
};
@@ -1089,17 +1181,17 @@ freebl_fips_ECDSA_Test(ECParams *ecparam
0x7b, 0x5a, 0x3b, 0x76, 0x4e, 0x7b, 0x7c, 0xbc,
0xf2, 0x76, 0x1c, 0x1c, 0x7f, 0xc5, 0x53, 0x2f
};
static const PRUint8 msg[] = {
"Firefox and ThunderBird are awesome!"
};
- unsigned char sha1[SHA1_LENGTH]; /* SHA-1 hash (160 bits) */
+ unsigned char sha256[SHA256_LENGTH]; /* SHA-256 hash (256 bits) */
unsigned char sig[2 * MAX_ECKEY_LEN];
SECItem signature, digest;
ECPrivateKey *ecdsa_private_key = NULL;
ECPublicKey ecdsa_public_key;
SECStatus ecdsaStatus = SECSuccess;
/* Generates a new EC key pair. The private key is a supplied
* random value (in seed) and the public key is the result of
@@ -1131,23 +1223,23 @@ freebl_fips_ECDSA_Test(ECParams *ecparam
if (ecdsaStatus != SECSuccess) {
goto loser;
}
/***************************************************/
/* ECDSA Single-Round Known Answer Signature Test. */
/***************************************************/
- ecdsaStatus = SHA1_HashBuf(sha1, msg, sizeof msg);
+ ecdsaStatus = SHA256_HashBuf(sha256, msg, sizeof msg);
if (ecdsaStatus != SECSuccess) {
goto loser;
}
digest.type = siBuffer;
- digest.data = sha1;
- digest.len = SHA1_LENGTH;
+ digest.data = sha256;
+ digest.len = SHA256_LENGTH;
memset(sig, 0, sizeof sig);
signature.type = siBuffer;
signature.data = sig;
signature.len = sizeof sig;
ecdsaStatus = ECDSA_SignDigestWithSeed(ecdsa_private_key, &signature,
&digest, ecdsa_Known_Seed, sizeof ecdsa_Known_Seed);
@@ -1176,20 +1268,93 @@ loser:
if (ecdsaStatus != SECSuccess) {
PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
return (SECFailure);
}
return (SECSuccess);
}
static SECStatus
-freebl_fips_ECDSA_PowerUpSelfTest()
+freebl_fips_ECDH_Test(ECParams *ecparams)
{
- /* ECDSA Known curve nistp256 == ECCCurve_X9_62_PRIME_256V1 params */
+ /* ECDH Known result (reused old CAVS vector) */
+ static const PRUint8 ecdh_known_pub_key_1[] = {
+ EC_POINT_FORM_UNCOMPRESSED,
+ /* pubX */
+ 0x16, 0x81, 0x32, 0x86, 0xc8, 0xe4, 0x3a, 0x1f,
+ 0x5d, 0xe3, 0x06, 0x22, 0x8b, 0x99, 0x14, 0x25,
+ 0xf7, 0x9c, 0x5b, 0x1e, 0x96, 0x84, 0x85, 0x3b,
+ 0x17, 0xfe, 0xf3, 0x1c, 0x0e, 0xed, 0xc4, 0xce,
+ /* pubY */
+ 0x7a, 0x44, 0xfe, 0xbd, 0x91, 0x71, 0x7d, 0x73,
+ 0xd9, 0x45, 0xea, 0xae, 0x66, 0x78, 0xfa, 0x6e,
+ 0x46, 0xcd, 0xfa, 0x95, 0x15, 0x47, 0x62, 0x5d,
+ 0xbb, 0x1b, 0x9f, 0xe6, 0x39, 0xfc, 0xfd, 0x47
+ };
+ static const PRUint8 ecdh_known_priv_key_2[] = {
+ 0xb4, 0x2a, 0xe3, 0x69, 0x19, 0xec, 0xf0, 0x42,
+ 0x6d, 0x45, 0x8c, 0x94, 0x4a, 0x26, 0xa7, 0x5c,
+ 0xea, 0x9d, 0xd9, 0x0f, 0x59, 0xe0, 0x1a, 0x9d,
+ 0x7c, 0xb7, 0x1c, 0x04, 0x53, 0xb8, 0x98, 0x5a
+ };
+ static const PRUint8 ecdh_known_hash_result[] = {
+ 0x16, 0xf3, 0x85, 0xa2, 0x41, 0xf3, 0x7f, 0xc4,
+ 0x0b, 0x56, 0x47, 0xee, 0xa7, 0x74, 0xb9, 0xdb,
+ 0xe1, 0xfa, 0x22, 0xe9, 0x04, 0xf1, 0xb6, 0x12,
+ 0x4b, 0x44, 0x8a, 0xbb, 0xbc, 0x08, 0x2b, 0xa7,
+ };
+
+ SECItem ecdh_priv_2, ecdh_pub_1;
+ SECItem ZZ = { 0, 0, 0 };
+ SECStatus ecdhStatus = SECSuccess;
+ PRUint8 computed_hash_result[HASH_LENGTH_MAX];
+
+ ecdh_priv_2.data = (PRUint8 *)ecdh_known_priv_key_2;
+ ecdh_priv_2.len = sizeof(ecdh_known_priv_key_2);
+ ecdh_pub_1.data = (PRUint8 *)ecdh_known_pub_key_1;
+ ecdh_pub_1.len = sizeof(ecdh_known_pub_key_1);
+
+ /* Generates a new EC key pair. The private key is a supplied
+ * random value (in seed) and the public key is the result of
+ * performing a scalar point multiplication of that value with
+ * the curve's base point.
+ */
+ ecdhStatus = ECDH_Derive(&ecdh_pub_1, ecparams, &ecdh_priv_2, PR_FALSE, &ZZ);
+ if (ecdhStatus != SECSuccess) {
+ goto loser;
+ }
+ ecdhStatus = SHA256_HashBuf(computed_hash_result, ZZ.data, ZZ.len);
+ if (ecdhStatus != SECSuccess) {
+ goto loser;
+ }
+
+ if (PORT_Memcmp(computed_hash_result, ecdh_known_hash_result,
+ sizeof(ecdh_known_hash_result)) != 0) {
+ ecdhStatus = SECFailure;
+ goto loser;
+ }
+
+loser:
+ if (ZZ.data) {
+ SECITEM_FreeItem(&ZZ, PR_FALSE);
+ }
+
+ if (ecdhStatus != SECSuccess) {
+ PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
+ return (SECFailure);
+ }
+ return (SECSuccess);
+}
+
+static SECStatus
+freebl_fips_EC_PowerUpSelfTest()
+{
+
+ /* EC Known curve nistp256 == ECCCurve_X9_62_PRIME_256V1 params */
static const unsigned char p256_prime[] = {
0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF
};
static const unsigned char p256_a[] = {
0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
@@ -1212,17 +1377,17 @@ freebl_fips_ECDSA_PowerUpSelfTest()
static const unsigned char p256_order[] = {
0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
0xFF, 0xFF, 0xFF, 0xBC, 0xE6, 0xFA, 0xAD, 0xA7, 0x17, 0x9E, 0x84, 0xF3, 0xB9,
0xCA, 0xC2, 0xFC, 0x63, 0x25, 0x51
};
static const unsigned char p256_encoding[] = {
0x06, 0x08, 0x2a, 0x86, 0x48, 0xce, 0x3d, 0x03, 0x01, 0x07
};
- static const ECParams ecdsa_known_P256_Params = {
+ static const ECParams ec_known_P256_Params = {
NULL, ec_params_named, /* arena, type */
/* fieldID */
{ 256, ec_field_GFp, /* size and type */
{ { siBuffer, (unsigned char *)p256_prime, sizeof(p256_prime) } }, /* u.prime */
0,
0,
0 },
/* curve */
@@ -1245,34 +1410,39 @@ freebl_fips_ECDSA_PowerUpSelfTest()
{ siBuffer, (unsigned char *)(p256_encoding) + 2, sizeof(p256_encoding) - 2 },
};
static const PRUint8 ecdsa_known_P256_signature[] = {
0x07, 0xb1, 0xcb, 0x57, 0x20, 0xa7, 0x10, 0xd6,
0x9d, 0x37, 0x4b, 0x1c, 0xdc, 0x35, 0x90, 0xff,
0x1a, 0x2d, 0x98, 0x95, 0x1b, 0x2f, 0xeb, 0x7f,
0xbb, 0x81, 0xca, 0xc0, 0x69, 0x75, 0xea, 0xc5,
- 0x59, 0x6a, 0x62, 0x49, 0x3d, 0x50, 0xc9, 0xe1,
- 0x27, 0x3b, 0xff, 0x9b, 0x13, 0x66, 0x67, 0xdd,
- 0x7d, 0xd1, 0x0d, 0x2d, 0x7c, 0x44, 0x04, 0x1b,
- 0x16, 0x21, 0x12, 0xc5, 0xcb, 0xbd, 0x9e, 0x75
+ 0xa7, 0xd2, 0x20, 0xdd, 0x45, 0xf9, 0x2b, 0xdd,
+ 0xda, 0x98, 0x99, 0x5b, 0x1c, 0x02, 0x3a, 0x27,
+ 0x8b, 0x7d, 0xb6, 0xed, 0x0e, 0xe0, 0xa7, 0xac,
+ 0xaa, 0x36, 0x2c, 0xfa, 0x1a, 0xdf, 0x0d, 0xe1,
};
ECParams ecparams;
SECStatus rv;
/* ECDSA GF(p) prime field curve test */
- ecparams = ecdsa_known_P256_Params;
+ ecparams = ec_known_P256_Params;
rv = freebl_fips_ECDSA_Test(&ecparams,
ecdsa_known_P256_signature,
sizeof ecdsa_known_P256_signature);
if (rv != SECSuccess) {
return (SECFailure);
}
+ /* ECDH GF(p) prime field curve test */
+ rv = freebl_fips_ECDH_Test(&ecparams);
+ if (rv != SECSuccess) {
+ return (SECFailure);
+ }
return (SECSuccess);
}
static SECStatus
freebl_fips_DSA_PowerUpSelfTest(void)
{
/* DSA Known P (1024-bits), Q (160-bits), and G (1024-bits) Values. */
@@ -1413,16 +1583,148 @@ freebl_fips_DSA_PowerUpSelfTest(void)
PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
return SECFailure;
}
return (SECSuccess);
}
static SECStatus
+freebl_fips_DH_PowerUpSelfTest(void)
+{
+ /* DH Known P (2048-bits) */
+ static const PRUint8 dh_known_P[] = {
+ 0xc2, 0x79, 0xbb, 0x76, 0x32, 0x0d, 0x43, 0xfd,
+ 0x1b, 0x8c, 0xa2, 0x3c, 0x00, 0xdd, 0x6d, 0xef,
+ 0xf8, 0x1a, 0xd9, 0xc1, 0xa2, 0xf5, 0x73, 0x2b,
+ 0xdb, 0x1a, 0x3e, 0x84, 0x90, 0xeb, 0xe7, 0x8e,
+ 0x5f, 0x5c, 0x6b, 0xb6, 0x61, 0x89, 0xd1, 0x03,
+ 0xb0, 0x5f, 0x91, 0xe4, 0xd2, 0x82, 0x90, 0xfc,
+ 0x3c, 0x49, 0x69, 0x59, 0xc1, 0x51, 0x6a, 0x85,
+ 0x71, 0xe7, 0x5d, 0x72, 0x5a, 0x45, 0xad, 0x01,
+ 0x6f, 0x82, 0xae, 0xec, 0x91, 0x08, 0x2e, 0x7c,
+ 0x64, 0x93, 0x46, 0x1c, 0x68, 0xef, 0xc2, 0x03,
+ 0x28, 0x1d, 0x75, 0x3a, 0xeb, 0x9c, 0x46, 0xf0,
+ 0xc9, 0xdb, 0x99, 0x95, 0x13, 0x66, 0x4d, 0xd5,
+ 0x1a, 0x78, 0x92, 0x51, 0x89, 0x72, 0x28, 0x7f,
+ 0x20, 0x70, 0x41, 0x49, 0xa2, 0x86, 0xe9, 0xf9,
+ 0x78, 0x5f, 0x8d, 0x2e, 0x5d, 0xfa, 0xdb, 0x57,
+ 0xd4, 0x71, 0xdf, 0x66, 0xe3, 0x9e, 0x88, 0x70,
+ 0xa4, 0x21, 0x44, 0x6a, 0xc7, 0xae, 0x30, 0x2c,
+ 0x9c, 0x1f, 0x91, 0x57, 0xc8, 0x24, 0x34, 0x2d,
+ 0x7a, 0x4a, 0x43, 0xc2, 0x5f, 0xab, 0x64, 0x2e,
+ 0xaa, 0x28, 0x32, 0x95, 0x42, 0x7b, 0xa0, 0xcc,
+ 0xdf, 0xfd, 0x22, 0xc8, 0x56, 0x84, 0xc1, 0x62,
+ 0x15, 0xb2, 0x77, 0x86, 0x81, 0xfc, 0xa5, 0x12,
+ 0x3c, 0xca, 0x28, 0x17, 0x8f, 0x03, 0x16, 0x6e,
+ 0xb8, 0x24, 0xfa, 0x1b, 0x15, 0x02, 0xfd, 0x8b,
+ 0xb6, 0x0a, 0x1a, 0xf7, 0x47, 0x41, 0xc5, 0x2b,
+ 0x37, 0x3e, 0xa1, 0xbf, 0x68, 0xda, 0x1c, 0x55,
+ 0x44, 0xc3, 0xee, 0xa1, 0x63, 0x07, 0x11, 0x3b,
+ 0x5f, 0x00, 0x84, 0xb4, 0xc4, 0xe4, 0xa7, 0x97,
+ 0x29, 0xf8, 0xce, 0xab, 0xfc, 0x27, 0x3e, 0x34,
+ 0xe4, 0xc7, 0x81, 0x52, 0x32, 0x0e, 0x27, 0x3c,
+ 0xa6, 0x70, 0x3f, 0x4a, 0x54, 0xda, 0xdd, 0x60,
+ 0x26, 0xb3, 0x6e, 0x45, 0x26, 0x19, 0x41, 0x6f
+ };
+
+ static const PRUint8 dh_known_Y_1[] = {
+ 0xb4, 0xc7, 0x85, 0xba, 0xa6, 0x98, 0xb3, 0x77,
+ 0x41, 0x2b, 0xd9, 0x9a, 0x72, 0x90, 0xa4, 0xac,
+ 0xc4, 0xf7, 0xc2, 0x23, 0x9a, 0x68, 0xe2, 0x7d,
+ 0x3a, 0x54, 0x45, 0x91, 0xc1, 0xd7, 0x8a, 0x17,
+ 0x54, 0xd3, 0x37, 0xaa, 0x0c, 0xcd, 0x0b, 0xe2,
+ 0xf2, 0x34, 0x0f, 0x17, 0xa8, 0x07, 0x88, 0xaf,
+ 0xed, 0xc1, 0x02, 0xd4, 0xdb, 0xdc, 0x0f, 0x22,
+ 0x51, 0x23, 0x40, 0xb9, 0x65, 0x6d, 0x39, 0xf4,
+ 0xe1, 0x8b, 0x57, 0x7d, 0xb6, 0xd3, 0xf2, 0x6b,
+ 0x02, 0xa9, 0x36, 0xf0, 0x0d, 0xe3, 0xdb, 0x9a,
+ 0xbf, 0x20, 0x00, 0x4d, 0xec, 0x6f, 0x68, 0x95,
+ 0xee, 0x59, 0x4e, 0x3c, 0xb6, 0xda, 0x7b, 0x19,
+ 0x08, 0x9a, 0xef, 0x61, 0x43, 0xf5, 0xfb, 0x25,
+ 0x70, 0x19, 0xc1, 0x5f, 0x0e, 0x0f, 0x6a, 0x63,
+ 0x44, 0xe9, 0xcf, 0x33, 0xce, 0x13, 0x4f, 0x34,
+ 0x3c, 0x94, 0x40, 0x8d, 0xf2, 0x65, 0x42, 0xef,
+ 0x70, 0x54, 0xdd, 0x5f, 0xc1, 0xd7, 0x0b, 0xa6,
+ 0x06, 0xd5, 0xa6, 0x47, 0xae, 0x2c, 0x1f, 0x5a,
+ 0xa6, 0xb3, 0xc1, 0x38, 0x3a, 0x3b, 0x60, 0x94,
+ 0xa2, 0x95, 0xab, 0xb2, 0x86, 0x82, 0xc5, 0x3b,
+ 0xb8, 0x6f, 0x3e, 0x55, 0x86, 0x84, 0xe0, 0x00,
+ 0xe5, 0xef, 0xca, 0x5c, 0xec, 0x7e, 0x38, 0x0f,
+ 0x82, 0xa2, 0xb1, 0xee, 0x48, 0x1b, 0x32, 0xbb,
+ 0x5a, 0x33, 0xa5, 0x01, 0xba, 0xca, 0xa6, 0x64,
+ 0x61, 0xb6, 0xe5, 0x5c, 0x0e, 0x5f, 0x2c, 0x66,
+ 0x0d, 0x01, 0x6a, 0x20, 0x04, 0x70, 0x68, 0x82,
+ 0x93, 0x29, 0x15, 0x3b, 0x7a, 0x06, 0xb2, 0x92,
+ 0x61, 0xcd, 0x7e, 0xa4, 0xc1, 0x15, 0x64, 0x3b,
+ 0x3c, 0x51, 0x10, 0x4c, 0x87, 0xa6, 0xaf, 0x07,
+ 0xce, 0x46, 0x82, 0x75, 0xf3, 0x90, 0xf3, 0x21,
+ 0x55, 0x74, 0xc2, 0xe4, 0x96, 0x7d, 0xc3, 0xe6,
+ 0x33, 0xa5, 0xc6, 0x51, 0xef, 0xec, 0x90, 0x08
+ };
+
+ static const PRUint8 dh_known_x_2[] = {
+ 0x9e, 0x9b, 0xc3, 0x25, 0x53, 0xf9, 0xfc, 0x92,
+ 0xb6, 0xae, 0x54, 0x8e, 0x23, 0x4c, 0x94, 0xba,
+ 0x41, 0xe6, 0x29, 0x33, 0xb9, 0xdb, 0xff, 0x6d,
+ 0xa8, 0xb8, 0x48, 0x49, 0x66, 0x11, 0xa6, 0x13
+ };
+
+ static const PRUint8 dh_known_hash_result[] = {
+ 0x93, 0xa2, 0x89, 0x1c, 0x8a, 0xc3, 0x70, 0xbf,
+ 0xa7, 0xdf, 0xb6, 0xd7, 0x82, 0xfb, 0x87, 0x81,
+ 0x09, 0x47, 0xf3, 0x9f, 0x5a, 0xbf, 0x4f, 0x3f,
+ 0x8e, 0x5e, 0x06, 0xca, 0x30, 0xa7, 0xaf, 0x10
+ };
+
+ /* DH variables. */
+ SECStatus dhStatus;
+ SECItem dh_prime;
+ SECItem dh_pub_key_1;
+ SECItem dh_priv_key_2;
+ SECItem ZZ = { 0, 0, 0 };
+ PRUint8 computed_hash_result[HASH_LENGTH_MAX];
+
+ dh_prime.data = (PRUint8 *)dh_known_P;
+ dh_prime.len = sizeof(dh_known_P);
+ dh_pub_key_1.data = (PRUint8 *)dh_known_Y_1;
+ dh_pub_key_1.len = sizeof(dh_known_Y_1);
+ dh_priv_key_2.data = (PRUint8 *)dh_known_x_2;
+ dh_priv_key_2.len = sizeof(dh_known_x_2);
+
+ /* execute the derive */
+ dhStatus = DH_Derive(&dh_pub_key_1, &dh_prime, &dh_priv_key_2, &ZZ, dh_prime.len);
+ if (dhStatus != SECSuccess) {
+ goto loser;
+ }
+
+ dhStatus = SHA256_HashBuf(computed_hash_result, ZZ.data, ZZ.len);
+ if (dhStatus != SECSuccess) {
+ goto loser;
+ }
+
+ if (PORT_Memcmp(computed_hash_result, dh_known_hash_result,
+ sizeof(dh_known_hash_result)) != 0) {
+ dhStatus = SECFailure;
+ goto loser;
+ }
+
+loser:
+ if (ZZ.data) {
+ SECITEM_FreeItem(&ZZ, PR_FALSE);
+ }
+
+ if (dhStatus != SECSuccess) {
+ PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
+ return (SECFailure);
+ }
+ return (SECSuccess);
+}
+
+static SECStatus
freebl_fips_RNG_PowerUpSelfTest(void)
{
static const PRUint8 Q[] = {
0x85, 0x89, 0x9c, 0x77, 0xa3, 0x79, 0xff, 0x1a,
0x86, 0x6f, 0x2f, 0x3e, 0x2e, 0xf9, 0x8c, 0x9c,
0x9d, 0xef, 0xeb, 0xed
};
static const PRUint8 GENX[] = {
@@ -1536,31 +1838,37 @@ freebl_fipsPowerUpSelfTest(unsigned int
/* HMAC SHA-X Power-Up SelfTest(s). */
rv = freebl_fips_HMAC_PowerUpSelfTest();
if (rv != SECSuccess)
return rv;
/* NOTE: RSA can only be tested in full freebl. It requires access to
- * the locking primitives */
+ * the locking primitives */
/* RSA Power-Up SelfTest(s). */
rv = freebl_fips_RSA_PowerUpSelfTest();
if (rv != SECSuccess)
return rv;
/* DSA Power-Up SelfTest(s). */
rv = freebl_fips_DSA_PowerUpSelfTest();
if (rv != SECSuccess)
return rv;
- /* ECDSA Power-Up SelfTest(s). */
- rv = freebl_fips_ECDSA_PowerUpSelfTest();
+ /* DH Power-Up SelfTest(s). */
+ rv = freebl_fips_DH_PowerUpSelfTest();
+
+ if (rv != SECSuccess)
+ return rv;
+
+ /* EC Power-Up SelfTest(s). */
+ rv = freebl_fips_EC_PowerUpSelfTest();
if (rv != SECSuccess)
return rv;
}
/* Passed Power-Up SelfTest(s). */
return (SECSuccess);
}
diff --git a/lib/freebl/intel-gcm-wrap.c b/lib/freebl/intel-gcm-wrap.c
--- a/lib/freebl/intel-gcm-wrap.c
+++ b/lib/freebl/intel-gcm-wrap.c
@@ -138,16 +138,17 @@ intel_AES_GCM_CreateContext(void *contex
loser:
PORT_Free(gcm);
return NULL;
}
void
intel_AES_GCM_DestroyContext(intel_AES_GCMContext *gcm, PRBool freeit)
{
+ PORT_Memset(gcm, 0, sizeof(intel_AES_GCMContext));
if (freeit) {
PORT_Free(gcm);
}
}
SECStatus
intel_AES_GCM_EncryptUpdate(intel_AES_GCMContext *gcm,
unsigned char *outbuf,
diff --git a/lib/freebl/pqg.c b/lib/freebl/pqg.c
--- a/lib/freebl/pqg.c
+++ b/lib/freebl/pqg.c
@@ -486,21 +486,21 @@ cleanup:
** Perform steps from FIPS 186-3, Appendix A.1.2.1 and Appendix C.6
**
** This generates a provable prime from two smaller prime. The resulting
** prime p will have q0 as a multiple of p-1. q0 can be 1.
**
** This implments steps 4 thorough 22 of FIPS 186-3 A.1.2.1 and
** steps 16 through 34 of FIPS 186-2 C.6
*/
-#define MAX_ST_SEED_BITS (HASH_LENGTH_MAX * PR_BITS_PER_BYTE)
static SECStatus
makePrimefromPrimesShaweTaylor(
HASH_HashType hashtype, /* selected Hashing algorithm */
unsigned int length, /* input. Length of prime in bits. */
+ unsigned int seedlen, /* input seed length in bits */
mp_int *c0, /* seed prime */
mp_int *q, /* sub prime, can be 1 */
mp_int *prime, /* output. */
SECItem *prime_seed, /* input/output. */
unsigned int *prime_gen_counter) /* input/output. */
{
mp_int c;
mp_int c0_2;
@@ -552,33 +552,32 @@ makePrimefromPrimesShaweTaylor(
*/
/* Step 4/16 iterations = ceiling(length/outlen)-1 */
iterations = (length + outlen - 1) / outlen; /* NOTE: iterations +1 */
/* Step 5/17 old_counter = prime_gen_counter */
old_counter = *prime_gen_counter;
/*
** Comment: Generate a pseudorandom integer x in the interval
- ** [2**(lenght-1), 2**length].
+ ** [2**(length-1), 2**length].
**
** Step 6/18 x = 0
*/
PORT_Memset(x, 0, sizeof(x));
/*
** Step 7/19 for i = 0 to iterations do
** x = x + (HASH(prime_seed + i) * 2^(i*outlen))
*/
for (i = 0; i < iterations; i++) {
/* is bigger than prime_seed should get to */
CHECK_SEC_OK(addToSeedThenHash(hashtype, prime_seed, i,
- MAX_ST_SEED_BITS, &x[(iterations - i - 1) * hashlen]));
+ seedlen, &x[(iterations - i - 1) * hashlen]));
}
/* Step 8/20 prime_seed = prime_seed + iterations + 1 */
- CHECK_SEC_OK(addToSeed(prime_seed, iterations, MAX_ST_SEED_BITS,
- prime_seed));
+ CHECK_SEC_OK(addToSeed(prime_seed, iterations, seedlen, prime_seed));
/*
** Step 9/21 x = 2 ** (length-1) + x mod 2 ** (length-1)
**
** This step mathematically sets the high bit and clears out
** all the other bits higher than length. 'x' is stored
** in the x array, MSB first. The above formula gives us an 'x'
** which is length bytes long and has the high bit set. We also know
** that length <= iterations*outlen since
@@ -590,17 +589,17 @@ makePrimefromPrimesShaweTaylor(
* multiple of 8,*/
bit = 1 << ((length - 1) & 0x7); /* select the proper bit in the byte */
/* we need to zero out the rest of the bits in the byte above */
mask = (bit - 1);
/* now we set it */
x[offset] = (mask & x[offset]) | bit;
/*
** Comment: Generate a candidate prime c in the interval
- ** [2**(lenght-1), 2**length].
+ ** [2**(length-1), 2**length].
**
** Step 10 t = ceiling(x/(2q(p0)))
** Step 22 t = ceiling(x/(2(c0)))
*/
CHECK_MPI_OK(mp_read_unsigned_octets(&t, &x[offset],
hashlen * iterations - offset)); /* t = x */
CHECK_MPI_OK(mp_mul(c0, q, &c0_2)); /* c0_2 is now c0*q */
CHECK_MPI_OK(mp_add(&c0_2, &c0_2, &c0_2)); /* c0_2 is now 2*q*c0 */
@@ -619,17 +618,17 @@ makePrimefromPrimesShaweTaylor(
step_23:
CHECK_MPI_OK(mp_mul(&t, &c0_2, &c)); /* c = t*2qc0 */
CHECK_MPI_OK(mp_add_d(&c, (mp_digit)1, &c)); /* c= 2tqc0 + 1*/
if (mpl_significant_bits(&c) > length) { /* if c > 2**length */
CHECK_MPI_OK(mp_sub_d(&c0_2, (mp_digit)1, &t)); /* t = 2qc0-1 */
/* t = 2**(length-1) + 2qc0 -1 */
CHECK_MPI_OK(mp_add(&two_length_minus_1, &t, &t));
/* t = floor((2**(length-1)+2qc0 -1)/2qco)
- * = ceil(2**(lenght-2)/2qc0) */
+ * = ceil(2**(length-2)/2qc0) */
CHECK_MPI_OK(mp_div(&t, &c0_2, &t, NULL));
CHECK_MPI_OK(mp_mul(&t, &c0_2, &c));
CHECK_MPI_OK(mp_add_d(&c, (mp_digit)1, &c)); /* c= 2tqc0 + 1*/
}
/* Step 13/25 prime_gen_counter = prime_gen_counter + 1*/
(*prime_gen_counter)++;
/*
** Comment: Test the candidate prime c for primality; first pick an
@@ -640,23 +639,21 @@ step_23:
PORT_Memset(x, 0, sizeof(x)); /* use x for a */
/*
** Step 15/27 for i = 0 to iterations do
** a = a + (HASH(prime_seed + i) * 2^(i*outlen))
**
** NOTE: we reuse the x array for 'a' initially.
*/
for (i = 0; i < iterations; i++) {
- /* MAX_ST_SEED_BITS is bigger than prime_seed should get to */
CHECK_SEC_OK(addToSeedThenHash(hashtype, prime_seed, i,
- MAX_ST_SEED_BITS, &x[(iterations - i - 1) * hashlen]));
+ seedlen, &x[(iterations - i - 1) * hashlen]));
}
/* Step 16/28 prime_seed = prime_seed + iterations + 1 */
- CHECK_SEC_OK(addToSeed(prime_seed, iterations, MAX_ST_SEED_BITS,
- prime_seed));
+ CHECK_SEC_OK(addToSeed(prime_seed, iterations, seedlen, prime_seed));
/* Step 17/29 a = 2 + (a mod (c-3)). */
CHECK_MPI_OK(mp_read_unsigned_octets(&a, x, iterations * hashlen));
CHECK_MPI_OK(mp_sub_d(&c, (mp_digit)3, &z)); /* z = c -3 */
CHECK_MPI_OK(mp_mod(&a, &z, &a)); /* a = a mod c -3 */
CHECK_MPI_OK(mp_add_d(&a, (mp_digit)2, &a)); /* a = 2 + a mod c -3 */
/*
** Step 18 z = a**(2tq) mod p.
** Step 30 z = a**(2t) mod c.
@@ -737,16 +734,17 @@ makePrimefromSeedShaweTaylor(
{
mp_int c;
mp_int c0;
mp_int one;
SECStatus rv = SECFailure;
int hashlen = HASH_ResultLen(hashtype);
int outlen = hashlen * PR_BITS_PER_BYTE;
int offset;
+ int seedlen = input_seed->len * 8; /*seedlen is in bits */
unsigned char bit, mask;
unsigned char x[HASH_LENGTH_MAX * 2];
mp_digit dummy;
mp_err err = MP_OKAY;
int i;
MP_DIGITS(&c) = 0;
MP_DIGITS(&c0) = 0;
@@ -770,30 +768,29 @@ makePrimefromSeedShaweTaylor(
*/
rv = makePrimefromSeedShaweTaylor(hashtype, (length + 1) / 2 + 1,
input_seed, &c0, prime_seed, prime_gen_counter);
/* Step 15 if FAILURE is returned, return (FAILURE, 0, 0, 0). */
if (rv != SECSuccess) {
goto cleanup;
}
/* Steps 16-34 */
- rv = makePrimefromPrimesShaweTaylor(hashtype, length, &c0, &one,
+ rv = makePrimefromPrimesShaweTaylor(hashtype, length, seedlen, &c0, &one,
prime, prime_seed, prime_gen_counter);
goto cleanup; /* we're done, one way or the other */
}
/* Step 3 prime_seed = input_seed */
CHECK_SEC_OK(SECITEM_CopyItem(NULL, prime_seed, input_seed));
/* Step 4 prime_gen_count = 0 */
*prime_gen_counter = 0;
step_5:
/* Step 5 c = Hash(prime_seed) xor Hash(prime_seed+1). */
CHECK_SEC_OK(HASH_HashBuf(hashtype, x, prime_seed->data, prime_seed->len));
- CHECK_SEC_OK(addToSeedThenHash(hashtype, prime_seed, 1,
- MAX_ST_SEED_BITS, &x[hashlen]));
+ CHECK_SEC_OK(addToSeedThenHash(hashtype, prime_seed, 1, seedlen, &x[hashlen]));
for (i = 0; i < hashlen; i++) {
x[i] = x[i] ^ x[i + hashlen];
}
/* Step 6 c = 2**length-1 + c mod 2**length-1 */
/* This step mathematically sets the high bit and clears out
** all the other bits higher than length. Right now c is stored
** in the x array, MSB first. The above formula gives us a c which
** is length bytes long and has the high bit set. We also know that
@@ -812,17 +809,17 @@ step_5:
/* Step 7 c = c*floor(c/2) + 1 */
/* set the low bit. much easier to find (the end of the array) */
x[hashlen - 1] |= 1;
/* now that we've set our bits, we can create our candidate "c" */
CHECK_MPI_OK(mp_read_unsigned_octets(&c, &x[offset], hashlen - offset));
/* Step 8 prime_gen_counter = prime_gen_counter + 1 */
(*prime_gen_counter)++;
/* Step 9 prime_seed = prime_seed + 2 */
- CHECK_SEC_OK(addToSeed(prime_seed, 2, MAX_ST_SEED_BITS, prime_seed));
+ CHECK_SEC_OK(addToSeed(prime_seed, 2, seedlen, prime_seed));
/* Step 10 Perform deterministic primality test on c. For example, since
** c is small, it's primality can be tested by trial division, See
** See Appendic C.7.
**
** We in fact test with trial division. mpi has a built int trial divider
** that divides all divisors up to 2^16.
*/
if (prime_tab[prime_tab_size - 1] < 0xFFF1) {
@@ -885,17 +882,18 @@ findQfromSeed(
unsigned int L, /* input. Length of p in bits. */
unsigned int N, /* input. Length of q in bits. */
unsigned int g, /* input. Length of seed in bits. */
const SECItem *seed, /* input. */
mp_int *Q, /* input. */
mp_int *Q_, /* output. */
unsigned int *qseed_len, /* output */
HASH_HashType *hashtypePtr, /* output. Hash uses */
- pqgGenType *typePtr) /* output. Generation Type used */
+ pqgGenType *typePtr, /* output. Generation Type used */
+ unsigned int *qgen_counter) /* output. q_counter */
{
HASH_HashType hashtype;
SECItem firstseed = { 0, 0, 0 };
SECItem qseed = { 0, 0, 0 };
SECStatus rv;
*qseed_len = 0; /* only set if FIPS186_3_ST_TYPE */
@@ -959,16 +957,17 @@ findQfromSeed(
* accident, someone has been tweeking with the seeds, just
* fail a this point. */
SECITEM_FreeItem(&qseed, PR_FALSE);
return SECFailure;
}
*qseed_len = qseed.len;
*hashtypePtr = hashtype;
*typePtr = FIPS186_3_ST_TYPE;
+ *qgen_counter = count;
SECITEM_FreeItem(&qseed, PR_FALSE);
return SECSuccess;
}
SECITEM_FreeItem(&qseed, PR_FALSE);
}
/* no hash algorithms found which match seed to Q, fail */
return SECFailure;
}
@@ -1383,29 +1382,33 @@ step_5:
CHECK_SEC_OK(makePrimefromSeedShaweTaylor(hashtype, N, &firstseed, &Q,
&qseed, &qgen_counter));
/* Step 3. Use floor(L/2+1) and qseed to generate random prime p0
* using Appendix C.6 */
pgen_counter = 0;
CHECK_SEC_OK(makePrimefromSeedShaweTaylor(hashtype, (L + 1) / 2 + 1,
&qseed, &p0, &pseed, &pgen_counter));
/* Steps 4-22 FIPS 186-3 appendix A.1.2.1.2 */
- CHECK_SEC_OK(makePrimefromPrimesShaweTaylor(hashtype, L,
+ CHECK_SEC_OK(makePrimefromPrimesShaweTaylor(hashtype, L, seedBytes * 8,
&p0, &Q, &P, &pseed, &pgen_counter));
/* combine all the seeds */
- seed->len = firstseed.len + qseed.len + pseed.len;
+ if ((qseed.len > firstseed.len) || (pseed.len > firstseed.len)) {
+ PORT_SetError(SEC_ERROR_LIBRARY_FAILURE); /* shouldn't happen */
+ goto cleanup;
+ }
+ seed->len = firstseed.len * 3; /*handle leading zeros in pseed and qseed*/
seed->data = PORT_ArenaZAlloc(verify->arena, seed->len);
if (seed->data == NULL) {
goto cleanup;
}
PORT_Memcpy(seed->data, firstseed.data, firstseed.len);
- PORT_Memcpy(seed->data + firstseed.len, pseed.data, pseed.len);
- PORT_Memcpy(seed->data + firstseed.len + pseed.len, qseed.data, qseed.len);
- counter = 0; /* (qgen_counter << 16) | pgen_counter; */
+ PORT_Memcpy(seed->data + 2 * firstseed.len - pseed.len, pseed.data, pseed.len);
+ PORT_Memcpy(seed->data + 3 * firstseed.len - qseed.len, qseed.data, qseed.len);
+ counter = (qgen_counter << 16) | pgen_counter;
/* we've generated both P and Q now, skip to generating G */
goto generate_G;
}
/* ******************************************************************
** Step 8. (Step 4 in 186-1)
** "Use a robust primality testing algorithm to test whether q is prime."
**
@@ -1615,16 +1618,17 @@ PQG_VerifyParams(const PQGParams *params
{
SECStatus rv = SECSuccess;
unsigned int g, n, L, N, offset, outlen;
mp_int p0, P, Q, G, P_, Q_, G_, r, h;
mp_err err = MP_OKAY;
int j;
unsigned int counter_max = 0; /* handle legacy L < 1024 */
unsigned int qseed_len;
+ unsigned int qgen_counter_ = 0;
SECItem pseed_ = { 0, 0, 0 };
HASH_HashType hashtype;
pqgGenType type;
#define CHECKPARAM(cond) \
if (!(cond)) { \
*result = SECFailure; \
goto cleanup; \
@@ -1694,77 +1698,104 @@ PQG_VerifyParams(const PQGParams *params
CHECKPARAM(mp_cmp_d(&r, 1) == 0);
/* 5. Q is prime */
CHECKPARAM(mpp_pprime(&Q, prime_testcount_q(L, N)) == MP_YES);
/* 6. P is prime */
CHECKPARAM(mpp_pprime(&P, prime_testcount_p(L, N)) == MP_YES);
/* Steps 7-12 are done only if the optional PQGVerify is supplied. */
/* continue processing P */
/* 7. counter < 4*L */
- CHECKPARAM((vfy->counter == -1) || (vfy->counter < counter_max));
/* 8. g >= N and g < 2*L (g is length of seed in bits) */
- g = vfy->seed.len * 8;
- CHECKPARAM(g >= N && g < counter_max / 2);
+ /* step 7 and 8 are delayed until we determine which type of generation
+ * was used */
/* 9. Q generated from SEED matches Q in PQGParams. */
/* This function checks all possible hash and generation types to
* find a Q_ which matches Q. */
+ g = vfy->seed.len * 8;
CHECKPARAM(findQfromSeed(L, N, g, &vfy->seed, &Q, &Q_, &qseed_len,
- &hashtype, &type) == SECSuccess);
+ &hashtype, &type, &qgen_counter_) == SECSuccess);
CHECKPARAM(mp_cmp(&Q, &Q_) == 0);
+ /* now we can do steps 7 & 8*/
+ if ((type == FIPS186_1_TYPE) || (type == FIPS186_3_TYPE)) {
+ CHECKPARAM((vfy->counter == -1) || (vfy->counter < counter_max));
+ CHECKPARAM(g >= N && g < counter_max / 2);
+ }
if (type == FIPS186_3_ST_TYPE) {
SECItem qseed = { 0, 0, 0 };
SECItem pseed = { 0, 0, 0 };
unsigned int first_seed_len;
- unsigned int pgen_counter = 0;
+ unsigned int pgen_counter_ = 0;
+ unsigned int qgen_counter = (vfy->counter >> 16) & 0xffff;
+ unsigned int pgen_counter = (vfy->counter) & 0xffff;
/* extract pseed and qseed from domain_parameter_seed, which is
* first_seed || pseed || qseed. qseed is first_seed + small_integer
- * pseed is qseed + small_integer. This means most of the time
+ * mod the length of first_seed. pseed is qseed + small_integer mod
+ * the length of first_seed. This means most of the time
* first_seed.len == qseed.len == pseed.len. Rarely qseed.len and/or
- * pseed.len will be one greater than first_seed.len, so we can
- * depend on the fact that
- * first_seed.len = floor(domain_parameter_seed.len/3).
- * findQfromSeed returned qseed.len, so we can calculate pseed.len as
- * pseed.len = domain_parameter_seed.len - first_seed.len - qseed.len
- * this is probably over kill, since 99.999% of the time they will all
- * be equal.
- *
- * With the lengths, we can now find the offsets;
+ * pseed.len will be smaller because mpi clamps them. pqgGen
+ * automatically adds the zero pad back though, so we can depend
+ * domain_parameter_seed.len to be a multiple of three. We only have
+ * to deal with the fact that the returned seeds from our functions
+ * could be shorter.
+ * first_seed.len = domain_parameter_seed.len/3
+ * We can now find the offsets;
* first_seed.data = domain_parameter_seed.data + 0
* pseed.data = domain_parameter_seed.data + first_seed.len
* qseed.data = domain_parameter_seed.data
* + domain_paramter_seed.len - qseed.len
- *
+ * We deal with pseed possibly having zero pad in the pseed check later.
*/
first_seed_len = vfy->seed.len / 3;
CHECKPARAM(qseed_len < vfy->seed.len);
CHECKPARAM(first_seed_len * 8 > N - 1);
- CHECKPARAM(first_seed_len + qseed_len < vfy->seed.len);
+ CHECKPARAM(first_seed_len * 8 < counter_max / 2);
+ CHECKPARAM(first_seed_len >= qseed_len);
qseed.len = qseed_len;
qseed.data = vfy->seed.data + vfy->seed.len - qseed.len;
- pseed.len = vfy->seed.len - (first_seed_len + qseed_len);
+ pseed.len = first_seed_len;
pseed.data = vfy->seed.data + first_seed_len;
/*
* now complete FIPS 186-3 A.1.2.1.2. Step 1 was completed
* above in our initial checks, Step 2 was completed by
* findQfromSeed */
/* Step 3 (status, c0, prime_seed, prime_gen_counter) =
** (ST_Random_Prime((ceil(length/2)+1, input_seed)
*/
CHECK_SEC_OK(makePrimefromSeedShaweTaylor(hashtype, (L + 1) / 2 + 1,
- &qseed, &p0, &pseed_, &pgen_counter));
+ &qseed, &p0, &pseed_, &pgen_counter_));
/* Steps 4-22 FIPS 186-3 appendix A.1.2.1.2 */
- CHECK_SEC_OK(makePrimefromPrimesShaweTaylor(hashtype, L,
- &p0, &Q_, &P_, &pseed_, &pgen_counter));
+ CHECK_SEC_OK(makePrimefromPrimesShaweTaylor(hashtype, L, first_seed_len * 8,
+ &p0, &Q_, &P_, &pseed_, &pgen_counter_));
CHECKPARAM(mp_cmp(&P, &P_) == 0);
/* make sure pseed wasn't tampered with (since it is part of
* calculating G) */
+ if (pseed.len > pseed_.len) {
+ /* handle the case of zero pad for pseed */
+ int extra = pseed.len - pseed_.len;
+ int i;
+ for (i = 0; i < extra; i++) {
+ if (pseed.data[i] != 0) {
+ *result = SECFailure;
+ goto cleanup;
+ }
+ }
+ pseed.data += extra;
+ pseed.len -= extra;
+ /* the rest is handled in the normal compare below */
+ }
CHECKPARAM(SECITEM_CompareItem(&pseed, &pseed_) == SECEqual);
+ if (vfy->counter != -1) {
+ CHECKPARAM(pgen_counter < counter_max);
+ CHECKPARAM(qgen_counter < counter_max);
+ CHECKPARAM((pgen_counter_ == pgen_counter));
+ CHECKPARAM((qgen_counter_ == qgen_counter));
+ }
} else if (vfy->counter == -1) {
/* If counter is set to -1, we are really only verifying G, skip
* the remainder of the checks for P */
CHECKPARAM(type != FIPS186_1_TYPE); /* we only do this for DSA2 */
} else {
/* 10. P generated from (L, counter, g, SEED, Q) matches P
* in PQGParams. */
outlen = HASH_ResultLen(hashtype) * PR_BITS_PER_BYTE;
diff --git a/lib/freebl/rijndael.c b/lib/freebl/rijndael.c
--- a/lib/freebl/rijndael.c
+++ b/lib/freebl/rijndael.c
@@ -1027,23 +1027,25 @@ AES_CreateContext(const unsigned char *k
* AES_DestroyContext
*
* Zero an AES cipher context. If freeit is true, also free the pointer
* to the context.
*/
void
AES_DestroyContext(AESContext *cx, PRBool freeit)
{
+ void *mem = cx->mem;
if (cx->worker_cx && cx->destroy) {
(*cx->destroy)(cx->worker_cx, PR_TRUE);
cx->worker_cx = NULL;
cx->destroy = NULL;
}
+ PORT_Memset(cx, 0, sizeof(AESContext));
if (freeit) {
- PORT_Free(cx->mem);
+ PORT_Free(mem);
}
}
/*
* AES_Encrypt
*
* Encrypt an arbitrary-length buffer. The output buffer must already be
* allocated to at least inputLen.
diff --git a/lib/softoken/pkcs11c.c b/lib/softoken/pkcs11c.c
--- a/lib/softoken/pkcs11c.c
+++ b/lib/softoken/pkcs11c.c
@@ -4708,16 +4708,24 @@ sftk_PairwiseConsistencyCheck(CK_SESSION
pairwise_digest_length,
signature,
&signature_length);
if (crv != CKR_OK) {
PORT_Free(signature);
return crv;
}
+ /* detect trivial signing transforms */
+ if (signature_length >= pairwise_digest_length) {
+ if (PORT_Memcmp(known_digest, signature + (signature_length - pairwise_digest_length), pairwise_digest_length) == 0) {
+ PORT_Free(signature);
+ return CKR_DEVICE_ERROR;
+ }
+ }
+
/* Verify the known hash using the public key. */
crv = NSC_VerifyInit(hSession, &mech, publicKey->handle);
if (crv != CKR_OK) {
PORT_Free(signature);
return crv;
}
crv = NSC_Verify(hSession,
@@ -7543,40 +7551,55 @@ NSC_DeriveKey(CK_SESSION_HANDLE hSession
SHA512_HashBuf(key_block, (const unsigned char *)att->attrib.pValue,
att->attrib.ulValueLen);
crv = sftk_forceAttribute(key, CKA_VALUE, key_block, keySize);
break;
case CKM_DH_PKCS_DERIVE: {
SECItem derived, dhPublic;
- SECItem dhPrime, dhValue;
+ SECItem dhPrime, dhSubPrime, dhValue;
/* sourceKey - values for the local existing low key */
/* get prime and value attributes */
crv = sftk_Attribute2SecItem(NULL, &dhPrime, sourceKey, CKA_PRIME);
- if (crv != SECSuccess)
+ if (crv != CKR_OK)
break;
crv = sftk_Attribute2SecItem(NULL, &dhValue, sourceKey, CKA_VALUE);
- if (crv != SECSuccess) {
+ if (crv != CKR_OK) {
PORT_Free(dhPrime.data);
break;
}
dhPublic.data = pMechanism->pParameter;
dhPublic.len = pMechanism->ulParameterLen;
+ /* if the caller bothered to provide Q, use Q to validate.
+ * the public key */
+ crv = sftk_Attribute2SecItem(NULL, &dhSubPrime, sourceKey, CKA_SUBPRIME);
+ if (crv == CKR_OK) {
+ rv = KEA_Verify(&dhPublic, &dhPrime, &dhSubPrime);
+ PORT_Free(dhSubPrime.data);
+ if (rv != SECSuccess) {
+ crv = CKR_ARGUMENTS_BAD;
+ PORT_Free(dhPrime.data);
+ PORT_Free(dhValue.data);
+ break;
+ }
+ }
+
/* calculate private value - oct */
rv = DH_Derive(&dhPublic, &dhPrime, &dhValue, &derived, keySize);
PORT_Free(dhPrime.data);
PORT_Free(dhValue.data);
if (rv == SECSuccess) {
sftk_forceAttribute(key, CKA_VALUE, derived.data, derived.len);
PORT_ZFree(derived.data, derived.len);
+ crv = CKR_OK;
} else
crv = CKR_HOST_MEMORY;
break;
}
case CKM_ECDH1_DERIVE:
case CKM_ECDH1_COFACTOR_DERIVE: {