1149 lines
46 KiB
Diff
1149 lines
46 KiB
Diff
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: {
|