File nss-CC-DH_selftest.patch of Package mozilla-nss.972
# HG changeset patch
# Parent 6dbcd9b97c79050cf36a9eb2adddbf3439b8b870
Diffie-Hellman key exchange selftest for FIPS 140-2
bsc#921783
diff --git a/lib/freebl/blapit.h b/lib/freebl/blapit.h
--- a/lib/freebl/blapit.h
+++ b/lib/freebl/blapit.h
@@ -8,16 +8,20 @@
#ifndef _BLAPIT_H_
#define _BLAPIT_H_
#include "seccomon.h"
#include "prlink.h"
#include "plarena.h"
#include "ecl-exp.h"
+/* special pointer value used as an indicator - ones' complement of zero. On
+ * Linux this should be a kernel space address which shouldn't be used to pass
+ * around user space data */
+#define ZERO_OC_POINTER ((void *)(~0))
/* RC2 operation modes */
#define NSS_RC2 0
#define NSS_RC2_CBC 1
/* RC5 operation modes */
#define NSS_RC5 0
#define NSS_RC5_CBC 1
diff --git a/lib/freebl/dh.c b/lib/freebl/dh.c
--- a/lib/freebl/dh.c
+++ b/lib/freebl/dh.c
@@ -135,73 +135,100 @@ cleanup:
SECStatus
DH_NewKey(DHParams *params, DHPrivateKey **privKey)
{
PLArenaPool *arena;
DHPrivateKey *key;
mp_int g, xa, p, Ya;
mp_err err = MP_OKAY;
SECStatus rv = SECSuccess;
+ PRBool havePrivateValue = PR_FALSE;
+
if (!params || !privKey) {
PORT_SetError(SEC_ERROR_INVALID_ARGS);
return SECFailure;
}
+ /* FIPS selftest has to be a known answer one, namely: generate public
+ * value based on parameters (g, p) and private key and compare it with
+ * precomputed value. Thus a special path is needed that will allow passing
+ * a particular private key value to this function.
+ * Since params is used as an indicator, base (g) and prime (p) already
+ * need to be in privKey alongside privateValue and an initialised arena
+ * from which the public key is going to be allocated.
+ * Note: g, p and private secret don't necessarily need to be allocated
+ * from that arena, as these are left touched on error. */
+ if ((DHParams *)(ZERO_OC_POINTER) == params) {
+ key = *privKey;
+ arena = key->arena;
+ havePrivateValue = PR_TRUE;
+ goto have_privKey;
+ }
arena = PORT_NewArena(NSS_FREEBL_DEFAULT_CHUNKSIZE);
if (!arena) {
PORT_SetError(SEC_ERROR_NO_MEMORY);
return SECFailure;
}
key = (DHPrivateKey *)PORT_ArenaZAlloc(arena, sizeof(DHPrivateKey));
if (!key) {
PORT_SetError(SEC_ERROR_NO_MEMORY);
PORT_FreeArena(arena, PR_TRUE);
return SECFailure;
}
key->arena = arena;
+have_privKey:
MP_DIGITS(&g) = 0;
MP_DIGITS(&xa) = 0;
MP_DIGITS(&p) = 0;
MP_DIGITS(&Ya) = 0;
CHECK_MPI_OK( mp_init(&g) );
CHECK_MPI_OK( mp_init(&xa) );
CHECK_MPI_OK( mp_init(&p) );
CHECK_MPI_OK( mp_init(&Ya) );
/* Set private key's p */
- CHECK_SEC_OK( SECITEM_CopyItem(arena, &key->prime, ¶ms->prime) );
+ if (!havePrivateValue)
+ CHECK_SEC_OK( SECITEM_CopyItem(arena, &key->prime, ¶ms->prime) );
SECITEM_TO_MPINT(key->prime, &p);
/* Set private key's g */
- CHECK_SEC_OK( SECITEM_CopyItem(arena, &key->base, ¶ms->base) );
+ if (!havePrivateValue)
+ CHECK_SEC_OK( SECITEM_CopyItem(arena, &key->base, ¶ms->base) );
SECITEM_TO_MPINT(key->base, &g);
/* Generate private key xa */
- SECITEM_AllocItem(arena, &key->privateValue,
- dh_GetSecretKeyLen(params->prime.len));
- CHECK_SEC_OK( RNG_GenerateGlobalRandomBytes(key->privateValue.data,
- key->privateValue.len));
+ if (!havePrivateValue) {
+ SECITEM_AllocItem(arena, &key->privateValue,
+ dh_GetSecretKeyLen(params->prime.len));
+ CHECK_SEC_OK( RNG_GenerateGlobalRandomBytes(key->privateValue.data,
+ key->privateValue.len));
+ }
SECITEM_TO_MPINT( key->privateValue, &xa );
/* xa < p */
CHECK_MPI_OK( mp_mod(&xa, &p, &xa) );
/* Compute public key Ya = g ** xa mod p */
CHECK_MPI_OK( mp_exptmod(&g, &xa, &p, &Ya) );
MPINT_TO_SECITEM(&Ya, &key->publicValue, key->arena);
- *privKey = key;
+ if (!havePrivateValue)
+ *privKey = key;
cleanup:
mp_clear(&g);
mp_clear(&xa);
mp_clear(&p);
mp_clear(&Ya);
if (err) {
MP_TO_SEC_ERROR(err);
rv = SECFailure;
}
if (rv) {
- SECITEM_ZfreeItem(&key->prime, PR_FALSE);
- SECITEM_ZfreeItem(&key->base, PR_FALSE);
- SECITEM_ZfreeItem(&key->publicValue, PR_FALSE);
- SECITEM_ZfreeItem(&key->privateValue, PR_FALSE);
- PORT_FreeArena(arena, PR_TRUE);
+ if (!havePrivateValue) {
+ SECITEM_ZfreeItem(&key->prime, PR_FALSE);
+ SECITEM_ZfreeItem(&key->base, PR_FALSE);
+ SECITEM_ZfreeItem(&key->publicValue, PR_FALSE);
+ SECITEM_ZfreeItem(&key->privateValue, PR_FALSE);
+ PORT_FreeArena(arena, PR_TRUE);
+ } else {
+ SECITEM_ZfreeItem(&key->publicValue, PR_FALSE);
+ }
}
return rv;
}
SECStatus
DH_Derive(SECItem *publicValue,
SECItem *prime,
SECItem *privateValue,
diff --git a/lib/softoken/fipstest.c b/lib/softoken/fipstest.c
--- a/lib/softoken/fipstest.c
+++ b/lib/softoken/fipstest.c
@@ -8,22 +8,25 @@
#include "softoken.h" /* Required for RC2-ECB, RC2-CBC, RC4, DES-ECB, */
/* DES-CBC, DES3-ECB, DES3-CBC, RSA */
/* and DSA. */
#include "seccomon.h" /* Required for RSA and DSA. */
#include "lowkeyi.h" /* Required for RSA and DSA. */
#include "pkcs11.h" /* Required for PKCS #11. */
#include "secoid.h" /* Required for ECDSA */
#include "secerr.h"
+#include "blapi.h"
#ifndef NSS_DISABLE_ECC
#include "ec.h" /* Required for ECDSA */
#endif
+#include <stdio.h>
+
/* FIPS preprocessor directives for RC2-ECB and RC2-CBC. */
#define FIPS_RC2_KEY_LENGTH 5 /* 40-bits */
#define FIPS_RC2_ENCRYPT_LENGTH 8 /* 64-bits */
#define FIPS_RC2_DECRYPT_LENGTH 8 /* 64-bits */
/* FIPS preprocessor directives for RC4. */
#define FIPS_RC4_KEY_LENGTH 5 /* 40-bits */
@@ -2033,16 +2036,135 @@ sftk_fips_RNG_PowerUpSelfTest( void )
if( ( rng_status != SECSuccess ) ||
( PORT_Memcmp( DSAX, rng_known_DSAX,
(FIPS_DSA_SUBPRIME_LENGTH) ) != 0 ) )
return( CKR_DEVICE_ERROR );
return( CKR_OK );
}
+static CK_RV
+sftk_fips_DH_PowerUpSelfTest( void )
+{
+ static const PRUint8 dh_P[] = {
+ 0xae,0xec,0xee,0x22,0xfa,0x3a,0xa5,0x22,
+ 0xc0,0xde,0x0f,0x09,0x7e,0x17,0xc0,0x05,
+ 0xf9,0xf1,0xe7,0xc6,0x87,0x14,0x6d,0x11,
+ 0xe7,0xae,0xed,0x2f,0x72,0x59,0xc5,0xa9,
+ 0x9b,0xb8,0x02,0xa5,0xf3,0x69,0x70,0xd6,
+ 0xdd,0x90,0xf9,0x19,0x79,0xbe,0x60,0x8f,
+ 0x25,0x92,0x30,0x1c,0x51,0x51,0x38,0x26,
+ 0x82,0x25,0xe6,0xfc,0xed,0x65,0x96,0x8f,
+ 0x57,0xe5,0x53,0x8b,0x38,0x63,0xc7,0xce,
+ 0xbc,0x1b,0x4d,0x18,0x2a,0x5b,0x04,0x3f,
+ 0x6a,0x3c,0x94,0x39,0xae,0x36,0xd6,0x5e,
+ 0x0f,0xa2,0xcc,0xd0,0xd4,0xd5,0xc6,0x1e,
+ 0xf6,0xa0,0xf5,0x89,0x4e,0xb4,0x0b,0xa4,
+ 0xb3,0x2b,0x3d,0xe2,0x4e,0xe1,0x49,0x25,
+ 0x99,0x5f,0x32,0x16,0x33,0x32,0x1b,0x7a,
+ 0xa5,0x5c,0x6b,0x34,0x0d,0x39,0x99,0xdc,
+ 0xf0,0x76,0xe5,0x5a,0xd4,0x71,0x00,0xed,
+ 0x5a,0x73,0xfb,0xc8,0x01,0xad,0x99,0xcf,
+ 0x99,0x52,0x7c,0x9c,0x64,0xc6,0x76,0x40,
+ 0x57,0xaf,0x59,0xd7,0x38,0x0b,0x40,0xde,
+ 0x33,0x0d,0xb8,0x76,0xec,0xa9,0xd8,0x73,
+ 0xf8,0xef,0x26,0x66,0x06,0x27,0xdd,0x7c,
+ 0xa4,0x10,0x9c,0xa6,0xaa,0xf9,0x53,0x62,
+ 0x73,0x1d,0xba,0x1c,0xf1,0x67,0xf4,0x35,
+ 0xed,0x6f,0x37,0x92,0xe8,0x4f,0x6c,0xba,
+ 0x52,0x6e,0xa1,0xed,0xda,0x9f,0x85,0x11,
+ 0x82,0x52,0x62,0x08,0x44,0xf1,0x30,0x03,
+ 0xc3,0x38,0x2c,0x79,0xbd,0xd4,0x43,0x45,
+ 0xee,0x8e,0x50,0xfc,0x29,0x46,0x9a,0xfe,
+ 0x54,0x1a,0x19,0x8f,0x4b,0x84,0x08,0xde,
+ 0x20,0x62,0x73,0xcc,0xdd,0x7e,0xf0,0xef,
+ 0xa2,0xfd,0x86,0x58,0x4b,0xd8,0x37,0xeb};
+
+ static const PRUint8 dh_G[] = {
+ 0x02};
+
+ static const PRUint8 dh_public[] = {
+ 0xa0,0x39,0x11,0x77,0x9a,0xc1,0x30,0x1f,
+ 0xbe,0x48,0xa7,0xaa,0xa0,0x84,0x54,0x64,
+ 0xad,0x1b,0x70,0xfa,0x13,0x55,0x63,0xd2,
+ 0x1f,0x62,0x32,0x93,0x8e,0xc9,0x3e,0x09,
+ 0xa7,0x64,0xe4,0x12,0x6e,0x1b,0xf2,0x92,
+ 0x3b,0xb9,0xcb,0x56,0xea,0x07,0x88,0xb5,
+ 0xa6,0xbc,0x16,0x1f,0x27,0xfe,0xd8,0xaa,
+ 0x40,0xb2,0xb0,0x2d,0x37,0x76,0xa6,0xa4,
+ 0x82,0x2c,0x0e,0x22,0x64,0x9d,0xcb,0xd1,
+ 0x00,0xb7,0x89,0x14,0x72,0x4e,0xbe,0x48,
+ 0x41,0xf8,0xb2,0x51,0x11,0x09,0x4b,0x22,
+ 0x01,0x23,0x39,0x96,0xe0,0x15,0xd7,0x9f,
+ 0x60,0xd1,0xb7,0xae,0xfe,0x5f,0xdb,0xe7,
+ 0x03,0x17,0x97,0xa6,0x16,0x74,0xbd,0x53,
+ 0x81,0x19,0xc5,0x47,0x5e,0xce,0x8d,0xed,
+ 0x45,0x5d,0x3c,0x00,0xa0,0x0a,0x68,0x6a,
+ 0xe0,0x8e,0x06,0x46,0x6f,0xd7,0xf9,0xdf,
+ 0x31,0x7e,0x77,0x44,0x0d,0x98,0xe0,0xca,
+ 0x98,0x09,0x52,0x04,0x90,0xea,0x6d,0xf4,
+ 0x30,0x69,0x8f,0xb1,0x9b,0xc1,0x43,0xdb,
+ 0xd5,0x8d,0xc8,0x8e,0xb6,0x0b,0x05,0xbe,
+ 0x0e,0xc5,0x99,0xc8,0x6e,0x4e,0xf3,0xcb,
+ 0xc3,0x5e,0x9b,0x53,0xf7,0x06,0x1c,0x4f,
+ 0xc7,0xb8,0x6e,0x30,0x18,0xca,0x9b,0xb9,
+ 0xbc,0x5f,0x17,0x72,0x29,0x5a,0xe5,0xd9,
+ 0x96,0xb7,0x0b,0xf3,0x2d,0x8c,0xf1,0xe1,
+ 0x0e,0x0d,0x74,0xd5,0x9d,0xf0,0x06,0xa9,
+ 0xb4,0x95,0x63,0x76,0x46,0x55,0x48,0x82,
+ 0x39,0x90,0xef,0x56,0x75,0x34,0xb8,0x34,
+ 0xc3,0x18,0x6e,0x1e,0xad,0xe3,0x48,0x7e,
+ 0x93,0x2c,0x23,0xe7,0xf8,0x90,0x73,0xb1,
+ 0x77,0x80,0x67,0xa9,0x36,0x9e,0xda,0xd2};
+
+ static const PRUint8 dh_private[] = {
+ 0x0c,0x4b,0x30,0x89,0xd1,0xb8,0x62,0xcb,
+ 0x3c,0x43,0x64,0x91,0xf0,0x91,0x54,0x70,
+ 0xc5,0x27,0x96,0xe3,0xac,0xbe,0xe8,0x00,
+ 0xec,0x55,0xf6,0xcc};
+
+ SECStatus dh_status = SECSuccess;
+
+ DHPrivateKey dh_privkey;
+ DHPrivateKey *dh_privkey_p;
+
+ dh_privkey.prime.len = sizeof(dh_P);
+ dh_privkey.prime.data = dh_P;
+ dh_privkey.base.len = sizeof(dh_G);
+ dh_privkey.base.data = dh_G;
+ dh_privkey.privateValue.len = sizeof(dh_private);
+ dh_privkey.privateValue.data = dh_private;
+ dh_privkey.arena = PORT_NewArena(NSS_FREEBL_DEFAULT_CHUNKSIZE);
+ if (!dh_privkey.arena) {
+ dh_status = SECFailure;
+ goto cleanup;
+ }
+
+ dh_privkey_p = &dh_privkey;
+
+ /* create public key from the private one */
+ dh_status = DH_NewKey((DHParams *)ZERO_OC_POINTER, &dh_privkey_p);
+
+ if( dh_status != SECSuccess )
+ goto cleanup;
+
+ /* compare public keys */
+ if (PORT_Memcmp(dh_public, dh_privkey.publicValue.data, sizeof(dh_public)))
+ dh_status = SECFailure;
+
+cleanup:
+ PORT_FreeArena(dh_privkey.arena, PR_TRUE);
+
+ if( dh_status != SECSuccess )
+ return( CKR_DEVICE_ERROR );
+
+ return( CKR_OK );
+
+}
+
/* FIPS selftests are implemented in library constructors and abort on failure
* - if anybody gets to call this function it means the tests passed and this
* can be a successful no-op
*/
CK_RV
sftk_fipsPowerUpSelfTest( void )
{
return CKR_OK;
@@ -2152,12 +2274,18 @@ FIPS_cryptoSelftestSoftoken( void )
#ifndef NSS_DISABLE_ECC
/* ECDSA Power-Up SelfTest(s). */
rv = sftk_fips_ECDSA_PowerUpSelfTest();
if( rv != CKR_OK )
return rv;
#endif
+ /* DH Power-Up SelfTest(s). */
+ rv = sftk_fips_DH_PowerUpSelfTest();
+
+ if( rv != CKR_OK )
+ return rv;
+
/* Passed Power-Up SelfTest(s). */
return( CKR_OK );
}