diff --git a/CHANGELOG.md b/CHANGELOG.md index 0e67f18..348af95 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,9 @@ +# Version 102.0 + +- Breaking change to Asymmetric key generation and import handling, sanitizing flags required for FIPS +- Trim symbols exposed in SymCrypt module to those specified in symcrypt.h +- Introduce logic enabling FIPS per-key tests to be deferred to before first use, rather than at generation time + # Version 101.3 - Fix for OpenEnclave binary to workaround clang bug diff --git a/inc/symcrypt.h b/inc/symcrypt.h index b7b8d76..fa83fea 100644 --- a/inc/symcrypt.h +++ b/inc/symcrypt.h @@ -370,7 +370,7 @@ SymCryptStoreMsbFirstUint64( SIZE_T cbDst ); // -// Functions to retreive the bitsize/bytesize of UINT32/UINT64 values +// Functions to retrieve the bitsize/bytesize of UINT32/UINT64 values // Note: the bitsize/bytesize of the value 0 is defined as 0. // Some data formats don't allow empty encodings, so the caller // should ensure they handle the 0-case properly. @@ -5123,86 +5123,41 @@ SymCryptEckeyCopy( //===================================================== -// On-demand self-test flags +// Flags for asymmetric key generation and import -// These flags can be passed in at key generation or import time to indicate that the -// corresponding pairwise consistency test should be run. Running these tests is required -// to be compliant with FIPS 140-3, but because they are computationally expensive, we do not -// run them at module start-up. It is the caller's responsibility to pass in the appropriate flag -// at key generation or import time. -// -// Why are these flags algorithm specific? Because SymCrypt does not distinguish between ECC keys -// used for ECDSA vs. ECC keys used for ECDH, or DL keys used for DSA vs. DL keys used for DH, the -// caller must use the appropriate flag to indicate what the key will be used for and therefore -// which selftest needs to be run. -// -// Note that per FIPS requirements, testing each imported key is not required, but the appropriate -// algorithm test must be run once before an algorithm can be used. Therefore, the key import -// test will be run at most one time per algorithm. SymCrypt handles this internally. For key -// generation, however, each generated key must be tested, so the key generation test will be run -// once per key generated. -#define SYMCRYPT_FLAG_ECKEY_SELFTEST_ECDSA (0x100) -#define SYMCRYPT_FLAG_ECKEY_SELFTEST_ECDH (0x200) +// These flags are introduced primarily for FIPS purposes. For FIPS 140-3 rather than expose to the +// caller the specifics of what tests will be run with various algorithms, we are sanitizing flags +// provided on asymmetric key generation and import to enable the caller to indicate their intent, +// and for SymCrypt to perform the required testing. +// Below we define the flags that can be passed and when a caller should set them. +// The specifics of what tests will be run are likely to change over time, as FIPS requirements and +// our understanding of how best to implement them, change over time. Callers should not rely on +// specific behavior. -#define SYMCRYPT_FLAG_DLKEY_SELFTEST_DSA (0x100) -#define SYMCRYPT_FLAG_DLKEY_SELFTEST_DH (0x200) -#define SYMCRYPT_FLAG_RSAKEY_SELFTEST (0x100) +// Validation required by FIPS is enabled by default. This flag enables a caller to opt out of this +// validation. +#define SYMCRYPT_FLAG_KEY_NO_FIPS (0x100) -//===================================================== -// Generic key validation flags -// Currently only apply to DH, DSA, ECDH, and ECDSA. +// When opting out of FIPS, SymCrypt may still perform some sanity checks on key import +// In very performance sensitive situations where a caller strongly trusts the values it is passing +// to SymCrypt and does not care about FIPS (or can statically prove properties about the imported +// keys), a caller may specify SYMCRYPT_FLAG_KEY_MINIMAL_VALIDATION in addition to +// SYMCRYPT_FLAG_KEY_NO_FIPS to skip costly checks +#define SYMCRYPT_FLAG_KEY_MINIMAL_VALIDATION (0x200) -// SYMCRYPT_FLAG_KEY_MINIMAL_VALIDATION: When set in a SetValue call, minimize costly validation. -// Only to be used in very performance sensitive situations where the caller strongly trusts the values -// it is passing to SymCrypt -// Cannot be specified with SYMCRYPT_FLAG_KEY_RANGE_VALIDATION or SYMCRYPT_FLAG_KEY_RANGE_AND_PUBLIC_KEY_ORDER_VALIDATION -#define SYMCRYPT_FLAG_KEY_MINIMAL_VALIDATION (0x10) +// Callers must specify what algorithm(s) a given asymmetric key will be used for. +// This information will be tracked by SymCrypt, and attempting to use the key in an algorithm it +// was not generated or imported for will result in failure. +// If no algorithm is specified then the key generation or import function will fail. +#define SYMCRYPT_FLAG_DLKEY_DSA (0x1000) +#define SYMCRYPT_FLAG_DLKEY_DH (0x2000) -// Maintain old ECC specific flag for backwards compatibility -#define SYMCRYPT_FLAG_ECC_NO_VALIDATION SYMCRYPT_FLAG_KEY_MINIMAL_VALIDATION - -// SYMCRYPT_FLAG_KEY_RANGE_VALIDATION: When set in a SetValue call, ensure that: -// Generated or imported Private key: -// For DH/DSA: -// Check private key is in the range: [1, q-1] -// If Dlgroup is a named safe-prime group, nBitsPriv is specified either using a default -// value or using SymCryptDlkeySetPrivateKeyLength, such that 2s <= nBitsPriv <= nBitsOfQ. -// In this case, we enforce that the private key is in the reduced range [1, min(2^nBitsPriv, q)-1] -// (s is the maximum security strength for a named safe-prime group as specified in SP800-56arev3) -// If q is not known, this will cause SYMCRYPT_INVALID_ARGUMENT -// For ECDH/ECDSA: -// For Curves with Canonical Private key format: Private key is in range [1, GOrd-1] -// Currently only Short-Weierstrass curves use the SYMCRYPT_ECKEY_PRIVATE_FORMAT_CANONICAL format -// For other Curves: Private key is non-zero -// Generated or imported Public key: -// For DH/DSA: Public key in range [2, p-2] -// For ECDH/ECDSA: -// Public key is nonzero, has coordinates in the underlying field -// and for non-Montgomery Curves: Public key is on the curve -// Cannot be specified with SYMCRYPT_FLAG_KEY_MINIMAL_VALIDATION or SYMCRYPT_FLAG_KEY_RANGE_AND_PUBLIC_KEY_ORDER_VALIDATION -#define SYMCRYPT_FLAG_KEY_RANGE_VALIDATION (0x20) - -// SYMCRYPT_FLAG_KEY_RANGE_AND_PUBLIC_KEY_ORDER_VALIDATION: When set in a SetValue, Generate, or SetRandom call, ensure that: -// Range validation ensured as for SYMCRYPT_FLAG_KEY_RANGE_VALIDATION -// In the case of generation of a Private key this is done by construction -// and -// Generated or imported Public key is in a subgroup of the correct order. i.e.: -// For DH/DSA: Verify that (Public key)^Q == 1 mod P -// If Q is not known, this will cause SYMCRYPT_INVALID_ARGUMENT -// For ECDH/ECDSA: Verify that GOrd*(Public key) == O -// Cannot be specified with SYMCRYPT_FLAG_KEY_MINIMAL_VALIDATION or SYMCRYPT_FLAG_KEY_RANGE_VALIDATION -#define SYMCRYPT_FLAG_KEY_RANGE_AND_PUBLIC_KEY_ORDER_VALIDATION (0x30) - -// SYMCRYPT_FLAG_KEY_KEYPAIR_REGENERATION_VALIDATION: When set in a SetValue call, ensure that: -// If a Public and Private key are imported: -// Use the imported Private key to generate a Public key, and check the generated Public key is equal -// to the imported Public key -#define SYMCRYPT_FLAG_KEY_KEYPAIR_REGENERATION_VALIDATION (0x40) - -// Maintain old DL specific flag for backwards compatibility -#define SYMCRYPT_FLAG_DLKEY_VERIFY SYMCRYPT_FLAG_KEY_KEYPAIR_REGENERATION_VALIDATION +#define SYMCRYPT_FLAG_ECKEY_ECDSA (0x1000) +#define SYMCRYPT_FLAG_ECKEY_ECDH (0x2000) +#define SYMCRYPT_FLAG_RSAKEY_SIGN (0x1000) +#define SYMCRYPT_FLAG_RSAKEY_ENCRYPT (0x2000) //===================================================== // RSA key operations @@ -5291,11 +5246,14 @@ SymCryptRsakeyGenerate( // // Allowed flags: // -// - SYMCRYPT_FLAG_RSAKEY_SELFTEST -// Perform a pairwise consistency test on the generated key. -// This flag must be set for callers who require compliance with FIPS 140-3. Any failure -// in the selftest will cause a fatal error, as it indicates that the module cannot operate -// in a FIPS-compliant mode. +// - SYMCRYPT_FLAG_KEY_NO_FIPS +// Opt-out of performing validation required for FIPS +// +// - At least one of the flags indicating what the Rsakey is to be used for must be specified: +// SYMCRYPT_FLAG_RSAKEY_SIGN +// SYMCRYPT_FLAG_RSAKEY_ENCRYPT + +// Described in more detail in the "Flags for asymmetric key generation and import" section above // SYMCRYPT_ERROR @@ -5323,11 +5281,17 @@ SymCryptRsakeySetValue( // // Allowed flags: // -// - SYMCRYPT_FLAG_RSAKEY_SELFTEST -// Perform an RSA algorithm test, if not already been done. -// This flag must be set for callers who require compliance with FIPS 140-3. Any failure -// in the selftest will cause a fatal error, as it indicates that the module cannot operate -// in a FIPS-compliant mode. +// - SYMCRYPT_FLAG_KEY_NO_FIPS +// Opt-out of performing validation required for FIPS +// +// - SYMCRYPT_FLAG_KEY_MINIMAL_VALIDATION +// Opt-out of performing almost all validation - must be specified with SYMCRYPT_FLAG_KEY_NO_FIPS +// +// - At least one of the flags indicating what the Rsakey is to be used for must be specified: +// SYMCRYPT_FLAG_RSAKEY_SIGN +// SYMCRYPT_FLAG_RSAKEY_ENCRYPT +// +// Described in more detail in the "Flags for asymmetric key generation and import" section above // // Remarks: // - Modulus and all primes are stored in the same format specified by numFormat. @@ -5403,6 +5367,20 @@ SymCryptRsakeyGetCrtValue( // - Currently, the only acceptable value of nCrtExponent is 2 or 0. // pbCrtCoefficient, pbPrivateExponent can be NULL; +SYMCRYPT_ERROR +SYMCRYPT_CALL +SymCryptRsakeyExtendKeyUsage( + _Inout_ PSYMCRYPT_RSAKEY pkRsakey, + UINT32 flags ); +// +// Enable an existing key which has been generated or imported to be used in specified algorithms. +// Some callers may not know at key generation or import time what algorithms a key will be used for +// and this API allows the key to be extended for use in additional algorithms. Use of this API may +// not be compliant with FIPS 140-3 +// +// - flags must be some bitwise OR of the following flags: +// SYMCRYPT_FLAG_RSAKEY_SIGN +// SYMCRYPT_FLAG_RSAKEY_ENCRYPT #define SYMCRYPT_DLGROUP_FIPS_LATEST (SYMCRYPT_DLGROUP_FIPS_186_3) @@ -5652,32 +5630,22 @@ SymCryptDlkeyGenerate( _Inout_ PSYMCRYPT_DLKEY pkDlkey ); // // Allowed flags: -// - SYMCRYPT_FLAG_KEY_RANGE_AND_PUBLIC_KEY_ORDER_VALIDATION -// Described in the key validation flag definitions above. Intended use is to allow additional -// (expensive) checks required by FIPS (SP800-56arev3) to be performed for compliance. -// Provided the Dlgroup is well formed, and the prime Q is known, generated keypairs will always -// pass these checks, so it is not recommended to set this flag unless required, as it makes the -// operation slower without affecting the results. -// // - SYMCRYPT_FLAG_DLKEY_GEN_MODP // When set, generate a private key between 1 and P-2. // When Q is known, this overrides the default behavior of generating a private key between 1 and Q-1, // or 1 and min(2^nBitsPriv-1, Q-1) for named safe-prime groups // When Q is not known, this does not affect the behavior // -// - SYMCRYPT_FLAG_DLKEY_SELFTEST_DSA -// Perform a DSA pairwise consistency test on the generated key. For keys which will be used with -// DSA, this flag must be set for callers who require compliance with FIPS 140-3. Any failure -// in the selftest will cause a fatal error, as it indicates that the module cannot operate -// in a FIPS-compliant mode. +// - SYMCRYPT_FLAG_KEY_NO_FIPS +// Opt-out of performing validation required for FIPS // -// - SYMCRYPT_FLAG_DLKEY_SELFTEST_DH -// Equivalent to SYMCRYPT_FLAG_DLKEY_SELFTEST_DSA, but for keys which will be used with DH. +// - At least one of the flags indicating what the Dlkey is to be used for must be specified: +// SYMCRYPT_FLAG_DLKEY_DSA +// SYMCRYPT_FLAG_DLKEY_DH // // Note: -// If SYMCRYPT_FLAG_DLKEY_GEN_MODP is specified in conjuction with -// SYMCRYPT_FLAG_KEY_RANGE_AND_PUBLIC_KEY_ORDER_VALIDATION a SYMCRYPT_INVALID_ARGUMENT error will be -// returned, as Private key range validation requires the default generation behavior +// If SYMCRYPT_FLAG_DLKEY_GEN_MODP is specified then SYMCRYPT_FLAG_KEY_NO_FIPS must also be +// specified to avoid SYMCRYPT_INVALID_ARGUMENT, as FIPS requires the default generation behavior // SYMCRYPT_ERROR @@ -5695,21 +5663,17 @@ SymCryptDlkeySetValue( // // Allowed flags: // -// - SYMCRYPT_FLAG_DLKEY_SELFTEST_DSA -// Perform a DSA algorithm test, if not already done. For keys which will be used with -// DSA, this flag must be set for callers who require compliance with FIPS 140-3. Any failure -// in the selftest will cause a fatal error, as it indicates that the module cannot operate -// in a FIPS-compliant mode. +// - SYMCRYPT_FLAG_KEY_NO_FIPS +// Opt-out of performing validation required for FIPS // -// - SYMCRYPT_FLAG_DLKEY_SELFTEST_DH -// Equivalent to SYMCRYPT_FLAG_DLKEY_SELFTEST_DSA, but for keys which will be used with DH. +// - SYMCRYPT_FLAG_KEY_MINIMAL_VALIDATION +// Opt-out of performing almost all validation - must be specified with SYMCRYPT_FLAG_KEY_NO_FIPS // -// - Optionally, at most 1 of -// SYMCRYPT_FLAG_KEY_MINIMAL_VALIDATION, -// SYMCRYPT_FLAG_KEY_RANGE_VALIDATION, and -// SYMCRYPT_FLAG_KEY_RANGE_AND_PUBLIC_KEY_ORDER_VALIDATION -// - and optionally SYMCRYPT_FLAG_KEY_KEYPAIR_REGENERATION_VALIDATION -// Described in the key validation flag definitions above. +// - At least one of the flags indicating what the Dlkey is to be used for must be specified: +// SYMCRYPT_FLAG_DLKEY_DSA +// SYMCRYPT_FLAG_DLKEY_DH +// +// Described in more detail in the "Flags for asymmetric key generation and import" section above // SYMCRYPT_ERROR @@ -5729,6 +5693,21 @@ SymCryptDlkeyGetValue( // allocated by the caller. // +SYMCRYPT_ERROR +SYMCRYPT_CALL +SymCryptDlkeyExtendKeyUsage( + _Inout_ PSYMCRYPT_DLKEY pkDlkey, + UINT32 flags ); +// +// Enable an existing key which has been generated or imported to be used in specified algorithms. +// Some callers may not know at key generation or import time what algorithms a key will be used for +// and this API allows the key to be extended for use in additional algorithms. Use of this API may +// not be compliant with FIPS 140-3 +// +// - flags must be some bitwise OR of the following flags: +// SYMCRYPT_FLAG_DLKEY_DSA +// SYMCRYPT_FLAG_DLKEY_DH + //===================================================== // Elliptic curve operations and supported curves // @@ -5903,28 +5882,23 @@ SymCryptEckeySetValue( // // At least one of the public and private keys must be provided. // -// If both are provided, then they should match. They are required to match when -// SYMCRYPT_FLAG_KEY_KEYPAIR_REGENERATION_VALIDATION is specified. +// If both are provided, then they must match. // // The algorithm always sets the corresponding public key // // Allowed flags: // -// - SYMCRYPT_FLAG_ECKEY_SELFTEST_ECDSA -// Perform an ECDSA algorithm test, if not already done. For keys which will be used with -// ECDSA, this flag must be set for callers who require compliance with FIPS 140-3. Any failure -// in the selftest will cause a fatal error, as it indicates that the module cannot operate -// in a FIPS-compliant mode. +// - SYMCRYPT_FLAG_KEY_NO_FIPS +// Opt-out of performing validation required for FIPS // -// - SYMCRYPT_FLAG_ECKEY_SELFTEST_ECDH -// Equivalent to SYMCRYPT_FLAG_ECKEY_SELFTEST_ECDSA, but for keys which will be used with ECDH. +// - SYMCRYPT_FLAG_KEY_MINIMAL_VALIDATION +// Opt-out of performing almost all validation - must be specified with SYMCRYPT_FLAG_KEY_NO_FIPS // -// - Optionally, at most 1 of -// SYMCRYPT_FLAG_KEY_MINIMAL_VALIDATION, -// SYMCRYPT_FLAG_KEY_RANGE_VALIDATION, and -// SYMCRYPT_FLAG_KEY_RANGE_AND_PUBLIC_KEY_ORDER_VALIDATION -// - and optionally SYMCRYPT_FLAG_KEY_KEYPAIR_REGENERATION_VALIDATION -// Described in the key validation flag definitions above. +// - At least one of the flags indicating what the Eckey is to be used for must be specified: +// SYMCRYPT_FLAG_ECKEY_ECDSA +// SYMCRYPT_FLAG_ECKEY_ECDH +// +// Described in more detail in the "Flags for asymmetric key generation and import" section above // SYMCRYPT_ERROR @@ -5944,21 +5918,14 @@ SymCryptEckeySetRandom( // // Allowed flags: // -// - SYMCRYPT_FLAG_ECKEY_SELFTEST_ECDSA -// Perform an ECDSA pairwise consistency test on the generated key. For keys which will be used with -// ECDSA, this flag must be set for callers who require compliance with FIPS 140-3. Any failure -// in the selftest will cause a fatal error, as it indicates that the module cannot operate -// in a FIPS-compliant mode. +// - SYMCRYPT_FLAG_KEY_NO_FIPS +// Opt-out of performing validation required for FIPS // -// - SYMCRYPT_FLAG_ECKEY_SELFTEST_ECDH -// Equivalent to SYMCRYPT_FLAG_ECKEY_SELFTEST_ECDSA, but for keys which will be used with ECDH. -// -// - SYMCRYPT_FLAG_KEY_RANGE_AND_PUBLIC_KEY_ORDER_VALIDATION -// Described in the key validation flag definitions above. Intended use is to allow additional -// (expensive) checks required by FIPS (SP800-56arev3) to be performed for compliance. -// Provided the Ecurve is well formed, generated keypairs will always pass these checks, so it is -// not recommended to set this flag unless required, as it makes the operation slower without -// affecting the results. +// - At least one of the flags indicating what the Eckey is to be used for must be specified: +// SYMCRYPT_FLAG_ECKEY_ECDSA +// SYMCRYPT_FLAG_ECKEY_ECDH + +// Described in more detail in the "Flags for asymmetric key generation and import" section above // SYMCRYPT_ERROR @@ -5979,11 +5946,10 @@ SymCryptEckeyGetValue( // allocated by the caller. // // If (pbPrivateKey != NULL), then the function will return the private key in pbPrivateKey -// in the format specified by the numFormat parameter **as long as** the following two +// in the format specified by the numFormat parameter **as long as** the following three // requirements are satisfied: // 1. cbPrivateKey >= SymCryptEckeyGetSizeofPrivateKey( pEckey ) // 2. pEckey contains a private key part (If this fails the function returns SYMCRYPT_INVALID_BLOB) -// If (pbPrivateKey == NULL) and (cbPrivateKey != 0), then it returns SYMCRYPT_INVALID_ARGUMENT. // If (pbPrivateKey == NULL) and (cbPrivateKey == 0), then these parameters are ignored // and no private key is returned. // @@ -5991,7 +5957,6 @@ SymCryptEckeyGetValue( // in the format specified by the numFormat and the ecPointFormat parameters // **as long as** the following requirement is satisfied: // 1. cbPublicKey >= SymCryptEckeyGetSizeofPublicKey( pEckey, ecPointFormat ) -// If (pbPublicKey == NULL) and (cbPublicKey != 0), then it returns SYMCRYPT_INVALID_ARGUMENT. // If (pbPublicKey == NULL) and (cbPublicKey == 0), then these parameters are ignored // and no public key is returned. // @@ -5999,6 +5964,21 @@ SymCryptEckeyGetValue( // - None. // +SYMCRYPT_ERROR +SYMCRYPT_CALL +SymCryptEckeyExtendKeyUsage( + _Inout_ PSYMCRYPT_ECKEY pEckey, + UINT32 flags ); +// +// Enable an existing key which has been generated or imported to be used in specified algorithms. +// Some callers may not know at key generation or import time what algorithms a key will be used for +// and this API allows the key to be extended for use in additional algorithms. Use of this API may +// not be compliant with FIPS 140-3 +// +// - flags must be some bitwise OR of the following flags: +// SYMCRYPT_FLAG_ECKEY_ECDSA +// SYMCRYPT_FLAG_ECKEY_ECDH + /************************ * Crypto algorithm API * ************************/ @@ -6343,23 +6323,15 @@ SymCryptRsaPssVerify( // None // -VOID -SYMCRYPT_CALL -SymCryptRsaSignVerifyTest( PCSYMCRYPT_RSAKEY pkRsakey ); -// -// FIPS self-test for RSA sign/verify. If the self-test fails, SymCryptFatal will be called to -// fastfail. Rather than calling this function directly, the caller can pass -// SYMCRYPT_FLAG_RSAKEY_SELFTEST into SymCryptRsakeyGenerate/SymCryptRsakeySetValue. -// - VOID SYMCRYPT_CALL SymCryptRsaSelftest( ); // -// Wrapper which calls SymCryptRsaSignVerifyTest with a hard-coded key. Used to satisfy the FIPS -// test-before-use requirement in the case that no keys are generated. Rather than calling this -// function directly, the caller can pass SYMCRYPT_FLAG_RSAKEY_SELFTEST into -// SymCryptRsakeyGenerate/SymCryptRsakeySetValue. +// FIPS self-test for RSA sign/verify. This function uses a hardcoded key to perform the self-test +// without having to generate a key. If the self-test fails, SymCryptFatal will be called to +// fastfail. +// The self-test will automatically be performed before first operational use of RSA if using a key +// with FIPS validation, so most callers should never use this function. // @@ -6408,22 +6380,15 @@ SymCryptDsaVerify( // None // -VOID -SYMCRYPT_CALL -SymCryptDsaSignVerifyTest( PCSYMCRYPT_DLKEY pkDlkey ); -// -// FIPS self-test for DSA sign/verify. If the self-test fails, SymCryptFatal will be called to -// fastfail. Rather than calling this function directly, the caller can pass -// SYMCRYPT_FLAG_DLKEY_SELFTEST_DSA into SymCryptDlkeyGenerate/SymCryptDlkeySetValue. -// - VOID SYMCRYPT_CALL SymCryptDsaSelftest( ); // -// Wrapper which calls SymCryptDsaSignVerifyTest with a hard-coded key. Used to satisfy the FIPS -// test-before-use requirement. Rather than calling this function directly, the caller can pass -// SYMCRYPT_FLAG_DLKEY_SELFTEST_DSA into SymCryptDlkeyGenerate/SymCryptDlkeySetValue. +// FIPS self-test for DSA sign/verify. This function uses a hardcoded key to perform the self-test +// without having to generate a key. If the self-test fails, SymCryptFatal will be called to +// fastfail. +// The self-test will automatically be performed before first operational use of DSA if using a key +// with FIPS validation, so most callers should never use this function. // // @@ -6449,24 +6414,15 @@ SymCryptDhSecretAgreement( // - None // -VOID -SYMCRYPT_CALL -SymCryptDhSecretAgreementPairwiseConsistencyTest( PCSYMCRYPT_DLKEY pkKey1 ); -// -// FIPS self-test for DH secret agreement. If the self-test fails, SymCryptFatal will be called to -// fastfail. Rather than calling this function directly, the caller can pass -// SYMCRYPT_FLAG_DLKEY_SELFTEST_DH into SymCryptDlkeyGenerate/SymCryptDlkeySetValue. -// - VOID SYMCRYPT_CALL SymCryptDhSecretAgreementSelftest(); // -// FIPS self-test for DH secret agreement. Unlike the above function, this function uses two -// hardcoded keys and a precalculated known answer to perform the selftest without having to -// generate a key. If the self-test fails, SymCryptFatal will be called to fastfail. Rather than -// calling this function directly, the caller can pass -// SYMCRYPT_FLAG_DLKEY_SELFTEST_DH into SymCryptDlkeyGenerate/SymCryptDlkeySetValue. +// FIPS self-test for DH secret agreement. This function uses two hardcoded keys and a precalculated +// known answer to perform the self-test without having to generate a key. If the self-test fails, +// SymCryptFatal will be called to fastfail. +// The self-test will automatically be performed before first operational use of DH if using keys +// with FIPS validation, so most callers should never use this function. // // @@ -6522,22 +6478,15 @@ SymCryptEcDsaVerify( // SYMCRYPT_FLAG_ECDSA_NO_TRUNCATION: If set then the hash value will // not be truncated. - -VOID -SYMCRYPT_CALL -SymCryptEcDsaSignVerifyTest( PCSYMCRYPT_ECKEY pkEckey ); -// -// FIPS self-test for ECDSA sign/verify. If the self-test fails, SymCryptFatal will be called to -// fastfail. Rather than calling this function directly, the caller can pass -// SYMCRYPT_FLAG_ECKEY_SELFTEST_ECDSA into SymCryptDlkeyGenerate/SymCryptDlkeySetValue. - VOID SYMCRYPT_CALL SymCryptEcDsaSelftest( ); // -// Wrapper which calls SymCryptEcDsaSignVerifyTest with a hard-coded key. Used to satisfy the FIPS -// test-before-use requirement. Rather than calling this function directly, the caller can pass -// SYMCRYPT_FLAG_ECKEY_SELFTEST_ECDSA into SymCryptDlkeyGenerate/SymCryptDlkeySetValue. +// FIPS self-test for ECDSA sign/verify. This function uses a hardcoded key to perform the self-test +// without having to generate a key. If the self-test fails, SymCryptFatal will be called to +// fastfail. +// The self-test will automatically be performed before first operational use of ECDSA if using a +// key with FIPS validation, so most callers should never use this function. // // @@ -6562,24 +6511,15 @@ SymCryptEcDhSecretAgreement( // - None // -VOID -SYMCRYPT_CALL -SymCryptEcDhSecretAgreementPairwiseConsistencyTest( PCSYMCRYPT_ECKEY pkKey1 ); -// -// FIPS self-test for ECDH secret agreement. If the self-test fails, SymCryptFatal will be called -// to fastfail. Rather than calling this function directly, the caller can pass -// SYMCRYPT_FLAG_ECKEY_SELFTEST_ECDH into SymCryptEckeySetRandom/SymCryptEckeySetValue. -// - VOID SYMCRYPT_CALL SymCryptEcDhSecretAgreementSelftest( ); // -// FIPS self-test for ECDH secret agreement. Unlike the above function, this function uses two -// hardcoded keys and a precalculated known answer to perform the selftest without having to -// generate a key. If the self-test fails, SymCryptFatal will be called to fastfail. Rather than -// calling this function directly, the caller can pass -// SYMCRYPT_FLAG_ECKEY_SELFTEST_ECDH into SymCryptEckeySetRandom/SymCryptEckeySetValue. +// FIPS self-test for ECDH secret agreement. This function uses two hardcoded keys and a +// precalculated known answer to perform the self-test without having to generate a key. If the +// self-test fails, SymCryptFatal will be called to fastfail. +// The self-test will automatically be performed before first operational use of ECDH if using keys +// with FIPS validation, so most callers should never use this function. // // diff --git a/inc/symcrypt_internal.h b/inc/symcrypt_internal.h index b532363..d1ee8ef 100644 --- a/inc/symcrypt_internal.h +++ b/inc/symcrypt_internal.h @@ -2070,6 +2070,11 @@ SYMCRYPT_ASYM_ALIGN_STRUCT _SYMCRYPT_MODELEMENT { // the RSA modulus and each prime. typedef SYMCRYPT_ASYM_ALIGN_STRUCT _SYMCRYPT_RSAKEY { + UINT32 fAlgorithmInfo; // Tracks which algorithms the key can be used in + // Also tracks which per-key selftests have been performed on this key + // A bitwise OR of SYMCRYPT_FLAG_KEY_*, SYMCRYPT_FLAG_RSAKEY_*, and + // SYMCRYPT_SELFTEST_KEY_* values + UINT32 cbTotalSize; // Total size of the rsa key BOOLEAN hasPrivateKey; // Set to true if there is private key information set @@ -2219,12 +2224,17 @@ typedef const SYMCRYPT_DLGROUP * PCSYMCRYPT_DLGROUP; // DLKEY type // typedef SYMCRYPT_ASYM_ALIGN_STRUCT _SYMCRYPT_DLKEY { - PCSYMCRYPT_DLGROUP pDlgroup; // Handle to the group which created the key + UINT32 fAlgorithmInfo; // Tracks which algorithms the key can be used in + // Also tracks which per-key selftests have been performed on this key + // A bitwise OR of SYMCRYPT_FLAG_KEY_*, SYMCRYPT_FLAG_DLKEY_*, and + // SYMCRYPT_SELFTEST_KEY_* values BOOLEAN fHasPrivateKey; // Set to true if there is a private key set BOOLEAN fPrivateModQ; // Set to true if the private key is at most Q-1, otherwise it is at most P-2 UINT32 nBitsPriv; // Number of bits used in private keys + PCSYMCRYPT_DLGROUP pDlgroup; // Handle to the group which created the key + PBYTE pbPrivate; // SYMCRYPT_ASYM_ALIGN'ed buffer that points to the memory allocated for the private key PSYMCRYPT_MODELEMENT pePublicKey; // Public key (modelement modulo P) @@ -2380,11 +2390,15 @@ typedef SYMCRYPT_ASYM_ALIGN_STRUCT _SYMCRYPT_ECPOINT { typedef const SYMCRYPT_ECPOINT * PCSYMCRYPT_ECPOINT; typedef SYMCRYPT_ASYM_ALIGN_STRUCT _SYMCRYPT_ECKEY { - BOOLEAN hasPrivateKey; // Set to true if there is a private key set - PCSYMCRYPT_ECURVE pCurve; // Handle to the curve which created the key + UINT32 fAlgorithmInfo; // Tracks which algorithms the key can be used in + // Also tracks which per-key selftests have been performed on this key + // A bitwise OR of SYMCRYPT_FLAG_KEY_*, SYMCRYPT_FLAG_ECKEY_*, and + // SYMCRYPT_SELFTEST_KEY_* values + BOOLEAN hasPrivateKey; // Set to true if there is a private key set + PCSYMCRYPT_ECURVE pCurve; // Handle to the curve which created the key - PSYMCRYPT_ECPOINT poPublicKey; // Public key (ECPOINT) - PSYMCRYPT_INT piPrivateKey; // Private key + PSYMCRYPT_ECPOINT poPublicKey; // Public key (ECPOINT) + PSYMCRYPT_INT piPrivateKey; // Private key SYMCRYPT_MAGIC_FIELD @@ -2766,17 +2780,46 @@ SymCryptWipeKnownSize(_Out_writes_bytes_(cbData) PVOID pbData, SIZE_T cbData) #define SYMCRYPT_FIPS_ASSERT(x) { if(!(x)){ SymCryptFatal('FIPS'); } } -// Flags for on-demand selftests. When an on-demand selftest succeeds, the corresponding flag +// Flags for FIPS on-demand selftests. When an on-demand selftest succeeds, the corresponding flag // will be set in g_SymCryptFipsSelftestsPerformed. Other selftests are performed automatically // when the module is loaded, so they don't have a corresponding flag. -typedef enum { - SYMCRYPT_SELFTEST_NONE = 0x0, - SYMCRYPT_SELFTEST_STARTUP = 0x1, - SYMCRYPT_SELFTEST_DSA = 0x2, - SYMCRYPT_SELFTEST_ECDSA = 0x4, - SYMCRYPT_SELFTEST_RSA = 0x8, - SYMCRYPT_SELFTEST_DH_SECRET_AGREEMENT = 0x10, - SYMCRYPT_SELFTEST_ECDH_SECRET_AGREEMENT = 0x20 -} SYMCRYPT_FIPS_SELFTEST; +typedef enum _SYMCRYPT_SELFTEST_ALGORITHM { + SYMCRYPT_SELFTEST_ALGORITHM_NONE = 0x0, + SYMCRYPT_SELFTEST_ALGORITHM_STARTUP = 0x1, + SYMCRYPT_SELFTEST_ALGORITHM_DSA = 0x2, + SYMCRYPT_SELFTEST_ALGORITHM_ECDSA = 0x4, + SYMCRYPT_SELFTEST_ALGORITHM_RSA = 0x8, + SYMCRYPT_SELFTEST_ALGORITHM_DH = 0x10, + SYMCRYPT_SELFTEST_ALGORITHM_ECDH = 0x20, +} SYMCRYPT_SELFTEST_ALGORITHM; -extern SYMCRYPT_FIPS_SELFTEST g_SymCryptFipsSelftestsPerformed; \ No newline at end of file +// Takes values which are some bitwise OR combination of SYMCRYPT_SELFTEST_ALGORITHM values +// Specified as UINT32 as we will update with 32 bit atomics, and compilers may choose to make enum +// types smaller than 32 bits. +extern UINT32 g_SymCryptFipsSelftestsPerformed; + +// Flags for per-key selftests. +// When an asymmetric key is generated or imported, and SYMCRYPT_FLAG_KEY_NO_FIPS is not specified, +// some selftests must be performed on the key, before its operational use in an algorithm, to +// comply with FIPS. +// The algorithms the key may be used in will be tracked in the key's fAlgorithmInfo field, as a +// bitwise OR of SYMCRYPT_FLAG__ (e.g. SYMCRYPT_FLAG_DLKEY_DH). +// This field will also track which per-key selftests have been run on the key using the below flags +// We want to track which selftests have been run independently of which algorithms the key may be +// used in as in some scenarios at key generation / import time we may not know what algorithm the +// key will actually be used in. Tracking the run per-key selftests in fAlgorithmInfo allows us to +// defer running expensive tests until we know they are required (e.g. if we generate an Eckey which +// may be used in ECDH or ECDSA, and only use it for ECDH, the ECDSA PCT is deferred until we first +// attempt to use the key in ECDSA, or export the private key). + +// Dlkey selftest flags +// DSA Pairwise Consistency Test to be run generated keys +#define SYMCRYPT_SELFTEST_KEY_DSA (0x1) + +// Eckey selftest flags +// ECDSA Pairwise Consistency Test to be run generated keys +#define SYMCRYPT_SELFTEST_KEY_ECDSA (0x1) + +// Rsakey selftest flags +// RSA Pairwise Consistency Test to be run generated keys +#define SYMCRYPT_SELFTEST_KEY_RSA_SIGN (0x1) diff --git a/inc/symcrypt_internal_shared.inc b/inc/symcrypt_internal_shared.inc index b7fd2e9..ae5bd23 100644 --- a/inc/symcrypt_internal_shared.inc +++ b/inc/symcrypt_internal_shared.inc @@ -22,8 +22,8 @@ // The API numbering starts at 100 to avoid number conficts with the old system. // -#define SYMCRYPT_CODE_VERSION_API 101 -#define SYMCRYPT_CODE_VERSION_MINOR 3 +#define SYMCRYPT_CODE_VERSION_API 102 +#define SYMCRYPT_CODE_VERSION_MINOR 0 #define SYMCRYPT_CODE_VERSION_PATCH 0 #if defined(DBG) diff --git a/lib/dh.c b/lib/dh.c index 2e55d3c..a6c7cd7 100644 --- a/lib/dh.c +++ b/lib/dh.c @@ -105,6 +105,14 @@ SymCryptDhSecretAgreement( UINT32 nBitsOfExp = 0; + // Make sure that the keys may be used in DH + if ( ((pkPrivate->fAlgorithmInfo & SYMCRYPT_FLAG_DLKEY_DH) == 0) || + ((pkPublic->fAlgorithmInfo & SYMCRYPT_FLAG_DLKEY_DH) == 0) ) + { + scError = SYMCRYPT_INVALID_ARGUMENT; + goto cleanup; + } + // Make sure we only specify the correct flags and that // there is a private key if ( (flags != 0) || (!pkPrivate->fHasPrivateKey) ) diff --git a/lib/dlkey.c b/lib/dlkey.c index d5395e4..b28861e 100644 --- a/lib/dlkey.c +++ b/lib/dlkey.c @@ -65,6 +65,7 @@ SymCryptDlkeyCreate( pkRes = (PSYMCRYPT_DLKEY) pbBuffer; // DLKEY parameters + pkRes->fAlgorithmInfo = 0; pkRes->pDlgroup = pDlgroup; pkRes->fHasPrivateKey = FALSE; pkRes->fPrivateModQ = FALSE; // This will be properly set during generate or setvalue @@ -116,6 +117,7 @@ SymCryptDlkeyCopy( // if( pkSrc != pkDst ) { + pkDst->fAlgorithmInfo = pkSrc->fAlgorithmInfo; pkDst->fHasPrivateKey = pkSrc->fHasPrivateKey; pkDst->fPrivateModQ = pkSrc->fPrivateModQ; pkDst->nBitsPriv = pkSrc->nBitsPriv; @@ -197,6 +199,8 @@ SymCryptDlkeyHasPrivateKey( _In_ PCSYMCRYPT_DLKEY pkDlkey ) return pkDlkey->fHasPrivateKey; } +#define SYMCRYPT_FLAG_DLKEY_PUBLIC_KEY_ORDER_VALIDATION (0x1) + SYMCRYPT_ERROR SYMCRYPT_CALL SymCryptDlkeyPerformPublicKeyValidation( @@ -239,7 +243,7 @@ SymCryptDlkeyPerformPublicKeyValidation( } // Perform validation that Public key is in a subgroup of order Q. - if ( (flags & SYMCRYPT_FLAG_KEY_VALIDATION_MASK) == SYMCRYPT_FLAG_KEY_RANGE_AND_PUBLIC_KEY_ORDER_VALIDATION ) + if ( (flags & SYMCRYPT_FLAG_DLKEY_PUBLIC_KEY_ORDER_VALIDATION) != 0 ) { peTmpPublicKeyExpQ = SymCryptModElementCreate( pbScratch, cbModElement, pDlgroup->pmP); pbScratch += cbModElement; @@ -302,22 +306,24 @@ SymCryptDlkeyGenerate( BYTE privMask; UINT32 cntr; + // Ensure caller has specified what algorithm(s) the key will be used with + UINT32 algorithmFlags = SYMCRYPT_FLAG_DLKEY_DSA | SYMCRYPT_FLAG_DLKEY_DH; // Make sure only allowed flags are specified - UINT32 allowedFlags = SYMCRYPT_FLAG_DLKEY_GEN_MODP | - SYMCRYPT_FLAG_KEY_RANGE_AND_PUBLIC_KEY_ORDER_VALIDATION | - SYMCRYPT_FLAG_DLKEY_SELFTEST_DSA | - SYMCRYPT_FLAG_DLKEY_SELFTEST_DH; + UINT32 allowedFlags = SYMCRYPT_FLAG_DLKEY_GEN_MODP | SYMCRYPT_FLAG_KEY_NO_FIPS | algorithmFlags; - if ( ( flags & ~allowedFlags ) != 0 ) + if ( ( ( flags & ~allowedFlags ) != 0 ) || + ( ( flags & algorithmFlags ) == 0 ) ) { scError = SYMCRYPT_INVALID_ARGUMENT; goto cleanup; } - // If any bits of SYMCRYPT_FLAG_KEY_VALIDATION_MASK are set, all bits of - // SYMCRYPT_FLAG_KEY_RANGE_AND_PUBLIC_KEY_ORDER_VALIDATION must be set - if ( ( flags & SYMCRYPT_FLAG_KEY_VALIDATION_MASK ) != 0 && - ( flags & SYMCRYPT_FLAG_KEY_VALIDATION_MASK ) != SYMCRYPT_FLAG_KEY_RANGE_AND_PUBLIC_KEY_ORDER_VALIDATION ) + // Extra sanity checks when running with FIPS + // Either Dlgroup is named SafePrime group and key is for DH, + // or Dlgroup is not named SafePrime group and key is for DSA + if ( ( ( flags & SYMCRYPT_FLAG_KEY_NO_FIPS ) == 0 ) && + ( (pDlgroup->isSafePrimeGroup && (flags & SYMCRYPT_FLAG_DLKEY_DSA)) || + (!(pDlgroup->isSafePrimeGroup) && (flags & SYMCRYPT_FLAG_DLKEY_DH)) ) ) { scError = SYMCRYPT_INVALID_ARGUMENT; goto cleanup; @@ -345,7 +351,7 @@ SymCryptDlkeyGenerate( { // We perform Private key range validation by construction // The Private key is constructed in the range [1,min(2^nBitsPriv,Q)-1] precisely when pkDlkey->fPrivateModQ - if ( (flags & SYMCRYPT_FLAG_KEY_VALIDATION_MASK) == SYMCRYPT_FLAG_KEY_RANGE_AND_PUBLIC_KEY_ORDER_VALIDATION ) + if ( (flags & SYMCRYPT_FLAG_KEY_NO_FIPS) == 0 ) { scError = SYMCRYPT_INVALID_ARGUMENT; goto cleanup; @@ -447,14 +453,13 @@ SymCryptDlkeyGenerate( cbScratch ); // Perform range validation on generated Public key. - if ( (flags & SYMCRYPT_FLAG_KEY_VALIDATION_MASK) == SYMCRYPT_FLAG_KEY_RANGE_AND_PUBLIC_KEY_ORDER_VALIDATION ) + if ( (flags & SYMCRYPT_FLAG_KEY_NO_FIPS) == 0 ) { // Perform Public key validation. - // Always perform range validation - // May also perform validation that Public key is in subgroup of order Q, depending on flags + // Always perform range validation, and validation that Public key is in subgroup of order Q scError = SymCryptDlkeyPerformPublicKeyValidation( pkDlkey, - flags, + SYMCRYPT_FLAG_DLKEY_PUBLIC_KEY_ORDER_VALIDATION, pbScratch, cbScratch ); if ( scError != SYMCRYPT_NO_ERROR ) @@ -466,17 +471,28 @@ SymCryptDlkeyGenerate( // Set the fHasPrivateKey flag pkDlkey->fHasPrivateKey = TRUE; - if( ( flags & SYMCRYPT_FLAG_DLKEY_SELFTEST_DSA ) != 0 ) + pkDlkey->fAlgorithmInfo = flags; // We want to track all of the flags in the Dlkey + + if ( (flags & SYMCRYPT_FLAG_KEY_NO_FIPS) == 0 ) { - SYMCRYPT_RUN_KEYGEN_PCT( SymCryptDsaSignVerifyTest, pkDlkey, SYMCRYPT_SELFTEST_DSA ); - } - - if( ( flags & SYMCRYPT_FLAG_DLKEY_SELFTEST_DH ) != 0 ) - { - SYMCRYPT_RUN_KEYGEN_PCT( - SymCryptDhSecretAgreementPairwiseConsistencyTest, - pkDlkey, - SYMCRYPT_SELFTEST_DH_SECRET_AGREEMENT ); + if( ( flags & SYMCRYPT_FLAG_DLKEY_DSA ) != 0 ) + { + // Run PCT eagerly as the key can only be used for DSA - there is no value in deferring + SYMCRYPT_RUN_KEYGEN_PCT( + SymCryptDsaSignVerifyTest, + pkDlkey, + SYMCRYPT_SELFTEST_ALGORITHM_DSA, + SYMCRYPT_SELFTEST_KEY_DSA ); + } + + if( ( flags & SYMCRYPT_FLAG_DLKEY_DH ) != 0 ) + { + // No additional per-key tests to perform before first use. + // Just ensure we have run the algorithm selftest at least once. + SYMCRYPT_RUN_SELFTEST_ONCE( + SymCryptDhSecretAgreementSelftest, + SYMCRYPT_SELFTEST_ALGORITHM_DH ); + } } cleanup: @@ -512,8 +528,7 @@ SymCryptDlkeySetValue( PSYMCRYPT_MODELEMENT peTmp = NULL; UINT32 cbModElement = SymCryptSizeofModElementFromModulus( pDlgroup->pmP ); - - BOOLEAN performRangeValidation = FALSE; + UINT32 fValidatePublicKeyOrder = SYMCRYPT_FLAG_DLKEY_PUBLIC_KEY_ORDER_VALIDATION; if ( ((pbPrivateKey==NULL) && (cbPrivateKey!=0)) || ((pbPublicKey==NULL) && (cbPublicKey!=0)) || @@ -523,22 +538,41 @@ SymCryptDlkeySetValue( goto cleanup; } - // Ensure only allowed flags are specified - UINT32 allowedFlags = SYMCRYPT_FLAG_KEY_MINIMAL_VALIDATION | - SYMCRYPT_FLAG_KEY_RANGE_VALIDATION | - SYMCRYPT_FLAG_KEY_RANGE_AND_PUBLIC_KEY_ORDER_VALIDATION | - SYMCRYPT_FLAG_KEY_KEYPAIR_REGENERATION_VALIDATION | - SYMCRYPT_FLAG_DLKEY_SELFTEST_DSA | - SYMCRYPT_FLAG_DLKEY_SELFTEST_DH; + // Ensure caller has specified what algorithm(s) the key will be used with + UINT32 algorithmFlags = SYMCRYPT_FLAG_DLKEY_DSA | SYMCRYPT_FLAG_DLKEY_DH; + // Make sure only allowed flags are specified + UINT32 allowedFlags = SYMCRYPT_FLAG_KEY_NO_FIPS | SYMCRYPT_FLAG_KEY_MINIMAL_VALIDATION | algorithmFlags; - if ( ( flags & ~allowedFlags ) != 0 ) + if ( ( ( flags & ~allowedFlags ) != 0 ) || + ( ( flags & algorithmFlags ) == 0 ) ) { scError = SYMCRYPT_INVALID_ARGUMENT; goto cleanup; } - performRangeValidation = ((flags & SYMCRYPT_FLAG_KEY_VALIDATION_MASK) == SYMCRYPT_FLAG_KEY_RANGE_VALIDATION) || - ((flags & SYMCRYPT_FLAG_KEY_VALIDATION_MASK) == SYMCRYPT_FLAG_KEY_RANGE_AND_PUBLIC_KEY_ORDER_VALIDATION); + // Extra sanity checks when running with FIPS + // Either Dlgroup is named SafePrime group and key is for DH, + // or Dlgroup is not named SafePrime group and key is for DSA + if ( ( ( flags & SYMCRYPT_FLAG_KEY_NO_FIPS ) == 0 ) && + ( (pDlgroup->isSafePrimeGroup && (flags & SYMCRYPT_FLAG_DLKEY_DSA)) || + (!(pDlgroup->isSafePrimeGroup) && (flags & SYMCRYPT_FLAG_DLKEY_DH)) ) ) + { + scError = SYMCRYPT_INVALID_ARGUMENT; + goto cleanup; + } + + // Check that minimal validation flag only specified with no fips + if ( ( ( flags & SYMCRYPT_FLAG_KEY_NO_FIPS ) == 0 ) && + ( ( flags & SYMCRYPT_FLAG_KEY_MINIMAL_VALIDATION ) != 0 ) ) + { + scError = SYMCRYPT_INVALID_ARGUMENT; + goto cleanup; + } + + if ( ( flags & SYMCRYPT_FLAG_KEY_NO_FIPS ) != 0 ) + { + fValidatePublicKeyOrder = 0; + } // // From symcrypt_internal.h we have: @@ -562,10 +596,13 @@ SymCryptDlkeySetValue( // If the group does not have a Q assume that the imported key is modulo P as // it wouldn't help us assume otherwise (the bitsize of the private key should be kept // secret from SC attacks). + // If the private key has had some non-default value set for nBitsPriv then the caller + // has explicitly opted in to more stringent range checking. // pkDlkey->fPrivateModQ = ( (pDlgroup->fHasPrimeQ) && ((cbPrivateKey < pDlgroup->cbPrimeQ) || - ((cbPrivateKey == pDlgroup->cbPrimeQ) && (pDlgroup->cbPrimeQ < pDlgroup->cbPrimeP))) ); + ((cbPrivateKey == pDlgroup->cbPrimeQ) && (pDlgroup->cbPrimeQ < pDlgroup->cbPrimeP)) || + (pkDlkey->nBitsPriv != pDlgroup->nDefaultBitsPriv)) ); if ( pkDlkey->fPrivateModQ ) { @@ -596,17 +633,21 @@ SymCryptDlkeySetValue( } // Perform range validation on imported Private key. - if ( performRangeValidation ) + if ( ( flags & SYMCRYPT_FLAG_KEY_MINIMAL_VALIDATION ) == 0 ) { - // Ensure that Q is specified in the Dlgroup - if ( !pDlgroup->fHasPrimeQ ) + // Check if Private key is 0 + if ( SymCryptIntIsEqualUint32( pkDlkey->piPrivateKey, 0 ) ) { scError = SYMCRYPT_INVALID_ARGUMENT; goto cleanup; } + } - // Check if Private key is 0 - if ( SymCryptIntIsEqualUint32( pkDlkey->piPrivateKey, 0 ) ) + // Continue range validation on imported Private key. + if ( ( flags & SYMCRYPT_FLAG_KEY_NO_FIPS ) == 0 ) + { + // Ensure that Q is specified in the Dlgroup + if ( !pDlgroup->fHasPrimeQ ) { scError = SYMCRYPT_INVALID_ARGUMENT; goto cleanup; @@ -643,14 +684,14 @@ SymCryptDlkeySetValue( } // Perform range validation on imported Public key. - if ( performRangeValidation ) + if ( (flags & SYMCRYPT_FLAG_KEY_MINIMAL_VALIDATION) == 0 ) { // Perform Public key validation. // Always perform range validation // May also perform validation that Public key is in subgroup of order Q, depending on flags scError = SymCryptDlkeyPerformPublicKeyValidation( pkDlkey, - flags, + fValidatePublicKeyOrder, pbScratch, cbScratch ); if ( scError != SYMCRYPT_NO_ERROR ) @@ -663,7 +704,7 @@ SymCryptDlkeySetValue( // Calculating the public key if no key was provided // or if needed for keypair regeneration validation if ( (pbPublicKey==NULL) || - ( ( (flags & SYMCRYPT_FLAG_KEY_KEYPAIR_REGENERATION_VALIDATION) != 0 ) && + ( ( ( flags & SYMCRYPT_FLAG_KEY_NO_FIPS ) == 0 ) && (pbPrivateKey!=NULL) && (pbPublicKey!=NULL) ) ) { // Calculate the public key from the private key @@ -699,14 +740,14 @@ SymCryptDlkeySetValue( goto cleanup; } } - else if ( performRangeValidation ) + else if ( ( flags & SYMCRYPT_FLAG_KEY_MINIMAL_VALIDATION ) == 0 ) { // Perform Public key validation on generated public key. // Always perform range validation // May also perform validation that Public key is in subgroup of order Q, depending on flags scError = SymCryptDlkeyPerformPublicKeyValidation( pkDlkey, - flags, + fValidatePublicKeyOrder, pbScratch, cbScratch ); if ( scError != SYMCRYPT_NO_ERROR ) @@ -716,16 +757,30 @@ SymCryptDlkeySetValue( } } - if( ( flags & SYMCRYPT_FLAG_DLKEY_SELFTEST_DSA ) != 0 ) + pkDlkey->fAlgorithmInfo = flags; // We want to track all of the flags in the Dlkey + + if ( (flags & SYMCRYPT_FLAG_KEY_NO_FIPS) == 0 ) { - SYMCRYPT_RUN_SELFTEST_ONCE( SymCryptDsaSelftest, SYMCRYPT_SELFTEST_DSA ); - } - - if( ( flags & SYMCRYPT_FLAG_DLKEY_SELFTEST_DH ) != 0 ) - { - SYMCRYPT_RUN_SELFTEST_ONCE( - SymCryptDhSecretAgreementSelftest, - SYMCRYPT_SELFTEST_DH_SECRET_AGREEMENT ); + if( ( flags & SYMCRYPT_FLAG_DLKEY_DSA ) != 0 ) + { + // Ensure DSA algorithm selftest is run before first use of DSA algorithm + SYMCRYPT_RUN_SELFTEST_ONCE( + SymCryptDsaSelftest, + SYMCRYPT_SELFTEST_ALGORITHM_DSA ); + + if( pkDlkey->fHasPrivateKey ) + { + // We do not need to run a DSA PCT on import, indicate that the test has been run + pkDlkey->fAlgorithmInfo |= SYMCRYPT_SELFTEST_KEY_DSA; + } + } + + if( ( flags & SYMCRYPT_FLAG_DLKEY_DH ) != 0 ) + { + SYMCRYPT_RUN_SELFTEST_ONCE( + SymCryptDhSecretAgreementSelftest, + SYMCRYPT_SELFTEST_ALGORITHM_DH ); + } } cleanup: @@ -813,3 +868,27 @@ cleanup: } return scError; } + +SYMCRYPT_ERROR +SYMCRYPT_CALL +SymCryptDlkeyExtendKeyUsage( + _Inout_ PSYMCRYPT_DLKEY pkDlkey, + UINT32 flags ) +{ + SYMCRYPT_ERROR scError = SYMCRYPT_NO_ERROR; + + // Ensure caller has specified what algorithm(s) the key will be used with + UINT32 algorithmFlags = SYMCRYPT_FLAG_DLKEY_DSA | SYMCRYPT_FLAG_DLKEY_DH; + + if ( ( ( flags & ~algorithmFlags ) != 0 ) || + ( ( flags & algorithmFlags ) == 0) ) + { + scError = SYMCRYPT_INVALID_ARGUMENT; + goto cleanup; + } + + pkDlkey->fAlgorithmInfo |= flags; + +cleanup: + return scError; +} diff --git a/lib/dsa.c b/lib/dsa.c index 4137a9b..3a31b35 100644 --- a/lib/dsa.c +++ b/lib/dsa.c @@ -102,6 +102,13 @@ SymCryptDsaSignEx( UNREFERENCED_PARAMETER( flags ); + // Make sure that the key may be used in DSA + if ( ((pKey->fAlgorithmInfo & SYMCRYPT_FLAG_DLKEY_DSA) == 0) ) + { + scError = SYMCRYPT_INVALID_ARGUMENT; + goto cleanup; + } + // Make sure that the group and the key have all the // information for dsa, i.e. prime q and private key // modulo q, and we are not using a named DH safe-prime @@ -422,6 +429,13 @@ SymCryptDsaVerify( UNREFERENCED_PARAMETER( flags ); + // Make sure that the key may be used in DSA + if ( ((pKey->fAlgorithmInfo & SYMCRYPT_FLAG_DLKEY_DSA) == 0) ) + { + scError = SYMCRYPT_INVALID_ARGUMENT; + goto cleanup; + } + // Make sure that the group has a prime q, and we are not using a named DH safe-prime group if (!pDlgroup->fHasPrimeQ || pDlgroup->isSafePrimeGroup) { diff --git a/lib/ec_dh.c b/lib/ec_dh.c index 019af06..ec8d8c9 100644 --- a/lib/ec_dh.c +++ b/lib/ec_dh.c @@ -32,6 +32,14 @@ SymCryptEcDhSecretAgreement( UINT32 cbQ = 0; UINT32 cbX = 0; + // Make sure that the keys may be used in ECDH + if ( ((pkPrivate->fAlgorithmInfo & SYMCRYPT_FLAG_ECKEY_ECDH) == 0) || + ((pkPublic->fAlgorithmInfo & SYMCRYPT_FLAG_ECKEY_ECDH) == 0) ) + { + scError = SYMCRYPT_INVALID_ARGUMENT; + goto cleanup; + } + // Make sure we only specify the correct flags if (flags != 0) { diff --git a/lib/ec_dsa.c b/lib/ec_dsa.c index b7a96ee..7fe75a2 100644 --- a/lib/ec_dsa.c +++ b/lib/ec_dsa.c @@ -180,6 +180,13 @@ SymCryptEcDsaSignEx( UINT32 cbRs = 0; UINT32 cbX = 0; + // Make sure that the key may be used in ECDSA + if ( ((pKey->fAlgorithmInfo & SYMCRYPT_FLAG_ECKEY_ECDSA) == 0) ) + { + scError = SYMCRYPT_INVALID_ARGUMENT; + goto cleanup; + } + // Make sure that only the correct flags are set if ( (flags & ~SYMCRYPT_FLAG_ECDSA_NO_TRUNCATION) != 0 ) { @@ -389,6 +396,13 @@ SymCryptEcDsaSign( _Out_writes_bytes_( cbSignature ) PBYTE pbSignature, SIZE_T cbSignature ) { + // If the key was generated and a PCT has not yet been performed - perform PCT before first use + SYMCRYPT_RUN_KEYGEN_PCT( + SymCryptEcDsaSignVerifyTest, + pKey, + SYMCRYPT_SELFTEST_ALGORITHM_ECDSA, + SYMCRYPT_SELFTEST_KEY_ECDSA ); + return SymCryptEcDsaSignEx( pKey, pbHashValue, cbHashValue, NULL, format, flags, pbSignature, cbSignature ); } @@ -436,6 +450,13 @@ SymCryptEcDsaVerify( UINT32 cbRs = 0; UINT32 cbX = 0; + // Make sure that the key may be used in ECDSA + if ( ((pKey->fAlgorithmInfo & SYMCRYPT_FLAG_ECKEY_ECDSA) == 0) ) + { + scError = SYMCRYPT_INVALID_ARGUMENT; + goto cleanup; + } + // Make sure that only the correct flags are set if ( (flags & ~SYMCRYPT_FLAG_ECDSA_NO_TRUNCATION) != 0 ) { diff --git a/lib/eckey.c b/lib/eckey.c index ddaef74..24d00c2 100644 --- a/lib/eckey.c +++ b/lib/eckey.c @@ -79,6 +79,7 @@ SymCryptEckeyCreate( pkObj = (PSYMCRYPT_ECKEY) pbBuffer; + pkObj->fAlgorithmInfo = 0; pkObj->hasPrivateKey = FALSE; pkObj->pCurve = pCurve; @@ -118,6 +119,9 @@ SymCryptEckeyCopy( // if( pkSrc != pkDst ) { + // Copy the fAlgorithmInfo flags + pkDst->fAlgorithmInfo = pkSrc->fAlgorithmInfo; + // Copy the hasPrivateKey flag pkDst->hasPrivateKey = pkSrc->hasPrivateKey; @@ -160,6 +164,8 @@ SymCryptEckeyHasPrivateKey( _In_ PCSYMCRYPT_ECKEY pkEckey ) return pkEckey->hasPrivateKey; } +#define SYMCRYPT_FLAG_ECKEY_PUBLIC_KEY_ORDER_VALIDATION (0x1) + SYMCRYPT_ERROR SYMCRYPT_CALL SymCryptEckeyPerformPublicKeyValidation( @@ -200,7 +206,7 @@ SymCryptEckeyPerformPublicKeyValidation( } // Perform validation that Public key is in a subgroup of order GOrd. - if ( (flags & SYMCRYPT_FLAG_KEY_VALIDATION_MASK) == SYMCRYPT_FLAG_KEY_RANGE_AND_PUBLIC_KEY_ORDER_VALIDATION ) + if ( (flags & SYMCRYPT_FLAG_ECKEY_PUBLIC_KEY_ORDER_VALIDATION) != 0 ) { if ( SymCryptIntIsEqualUint32( pCurve->H, 1 ) ) { @@ -273,27 +279,35 @@ SymCryptEckeySetValue( UINT32 privateKeyDigits = SymCryptEcurveDigitsofScalarMultiplier(pCurve); - BOOLEAN performRangeValidation = FALSE; + UINT32 fValidatePublicKeyOrder = SYMCRYPT_FLAG_ECKEY_PUBLIC_KEY_ORDER_VALIDATION; SYMCRYPT_ASSERT( (cbPrivateKey==0) || (cbPrivateKey == SymCryptEcurveSizeofScalarMultiplier( pEckey->pCurve )) ); SYMCRYPT_ASSERT( (cbPublicKey==0) || (cbPublicKey == SymCryptEckeySizeofPublicKey( pEckey, ecPointFormat)) ); - // Ensure only allowed flags are specified - UINT32 allowedFlags = SYMCRYPT_FLAG_KEY_MINIMAL_VALIDATION | - SYMCRYPT_FLAG_KEY_RANGE_VALIDATION | - SYMCRYPT_FLAG_KEY_RANGE_AND_PUBLIC_KEY_ORDER_VALIDATION | - SYMCRYPT_FLAG_KEY_KEYPAIR_REGENERATION_VALIDATION | - SYMCRYPT_FLAG_ECKEY_SELFTEST_ECDSA | - SYMCRYPT_FLAG_ECKEY_SELFTEST_ECDH; + // Ensure caller has specified what algorithm(s) the key will be used with + UINT32 algorithmFlags = SYMCRYPT_FLAG_ECKEY_ECDSA | SYMCRYPT_FLAG_ECKEY_ECDH; + // Make sure only allowed flags are specified + UINT32 allowedFlags = SYMCRYPT_FLAG_KEY_NO_FIPS | SYMCRYPT_FLAG_KEY_MINIMAL_VALIDATION | algorithmFlags; - if ( ( flags & ~allowedFlags ) != 0 ) + if ( ( ( flags & ~allowedFlags ) != 0 ) || + ( ( flags & algorithmFlags ) == 0 ) ) { scError = SYMCRYPT_INVALID_ARGUMENT; goto cleanup; } - performRangeValidation = ((flags & SYMCRYPT_FLAG_KEY_VALIDATION_MASK) == SYMCRYPT_FLAG_KEY_RANGE_VALIDATION) || - ((flags & SYMCRYPT_FLAG_KEY_VALIDATION_MASK) == SYMCRYPT_FLAG_KEY_RANGE_AND_PUBLIC_KEY_ORDER_VALIDATION); + // Check that minimal validation flag only specified with no fips + if ( ( ( flags & SYMCRYPT_FLAG_KEY_NO_FIPS ) == 0 ) && + ( ( flags & SYMCRYPT_FLAG_KEY_MINIMAL_VALIDATION ) != 0 ) ) + { + scError = SYMCRYPT_INVALID_ARGUMENT; + goto cleanup; + } + + if ( ( flags & SYMCRYPT_FLAG_KEY_NO_FIPS ) != 0 ) + { + fValidatePublicKeyOrder = 0; + } if ( ( ( cbPrivateKey == 0 ) && ( cbPublicKey == 0 ) ) || ( ( cbPrivateKey != 0 ) && ( cbPrivateKey != SymCryptEcurveSizeofScalarMultiplier( pEckey->pCurve ) ) ) || @@ -344,11 +358,10 @@ SymCryptEckeySetValue( } // Validation steps - if ( !((flags & SYMCRYPT_FLAG_KEY_VALIDATION_MASK) == SYMCRYPT_FLAG_KEY_MINIMAL_VALIDATION) ) + if ( ( flags & SYMCRYPT_FLAG_KEY_MINIMAL_VALIDATION ) == 0 ) { // Perform range validation on imported Private key if it is in canonical format - if ( performRangeValidation && - (pCurve->PrivateKeyDefaultFormat == SYMCRYPT_ECKEY_PRIVATE_FORMAT_CANONICAL) ) + if ( pCurve->PrivateKeyDefaultFormat == SYMCRYPT_ECKEY_PRIVATE_FORMAT_CANONICAL ) { // Check if Private key is greater than or equal to GOrd if ( !SymCryptIntIsLessThan( piTmpInteger, SymCryptIntFromModulus( pCurve->GOrd ) ) ) @@ -415,7 +428,7 @@ SymCryptEckeySetValue( pbScratchInternal, cbScratchInternal ); - if ( !((flags & SYMCRYPT_FLAG_KEY_VALIDATION_MASK) == SYMCRYPT_FLAG_KEY_MINIMAL_VALIDATION) ) + if ( ( flags & SYMCRYPT_FLAG_KEY_MINIMAL_VALIDATION ) == 0 ) { // Check if Private key is 0 after dividing it by the subgroup order // Other part of range validation @@ -450,11 +463,11 @@ SymCryptEckeySetValue( } // Perform Public key validation on imported Public key. - if ( !((flags & SYMCRYPT_FLAG_KEY_VALIDATION_MASK) == SYMCRYPT_FLAG_KEY_MINIMAL_VALIDATION) ) + if ( ( flags & SYMCRYPT_FLAG_KEY_MINIMAL_VALIDATION ) == 0 ) { scError = SymCryptEckeyPerformPublicKeyValidation( pEckey, - flags, + fValidatePublicKeyOrder, pbScratch, cbScratch ); if ( scError != SYMCRYPT_NO_ERROR ) @@ -467,7 +480,7 @@ SymCryptEckeySetValue( // Calculating the public key if no key was provided // or if needed for keypair regeneration validation if ( (pbPublicKey==NULL) || - ( ( (flags & SYMCRYPT_FLAG_KEY_KEYPAIR_REGENERATION_VALIDATION) != 0 ) && + ( ( ( flags & SYMCRYPT_FLAG_KEY_NO_FIPS ) == 0 ) && (pbPrivateKey!=NULL) && (pbPublicKey!=NULL) ) ) { // Calculate the public key from the private key @@ -510,12 +523,12 @@ SymCryptEckeySetValue( goto cleanup; } } - else if ( !((flags & SYMCRYPT_FLAG_KEY_VALIDATION_MASK) == SYMCRYPT_FLAG_KEY_MINIMAL_VALIDATION) ) + else if ( ( flags & SYMCRYPT_FLAG_KEY_MINIMAL_VALIDATION ) == 0 ) { // Perform Public key validation on generated Public key. scError = SymCryptEckeyPerformPublicKeyValidation( pEckey, - flags, + fValidatePublicKeyOrder, pbScratch, cbScratch ); if ( scError != SYMCRYPT_NO_ERROR ) @@ -525,16 +538,30 @@ SymCryptEckeySetValue( } } - if ( ( flags & SYMCRYPT_FLAG_ECKEY_SELFTEST_ECDSA ) != 0 ) - { - SYMCRYPT_RUN_SELFTEST_ONCE( SymCryptEcDsaSelftest, SYMCRYPT_SELFTEST_ECDSA ); - } + pEckey->fAlgorithmInfo = flags; // We want to track all of the flags in the Eckey - if ( ( flags & SYMCRYPT_FLAG_ECKEY_SELFTEST_ECDH ) != 0 ) + if ( ( flags & SYMCRYPT_FLAG_KEY_NO_FIPS ) == 0 ) { - SYMCRYPT_RUN_SELFTEST_ONCE( - SymCryptEcDhSecretAgreementSelftest, - SYMCRYPT_SELFTEST_ECDH_SECRET_AGREEMENT); + if ( ( flags & SYMCRYPT_FLAG_ECKEY_ECDSA ) != 0 ) + { + // Ensure ECDSA algorithm selftest is run before first use of ECDSA algorithm + SYMCRYPT_RUN_SELFTEST_ONCE( + SymCryptEcDsaSelftest, + SYMCRYPT_SELFTEST_ALGORITHM_ECDSA ); + + if( pEckey->hasPrivateKey ) + { + // We do not need to run an ECDSA PCT on import, indicate that the test has been run + pEckey->fAlgorithmInfo |= SYMCRYPT_SELFTEST_KEY_ECDSA; + } + } + + if ( ( flags & SYMCRYPT_FLAG_ECKEY_ECDH ) != 0 ) + { + SYMCRYPT_RUN_SELFTEST_ONCE( + SymCryptEcDhSecretAgreementSelftest, + SYMCRYPT_SELFTEST_ALGORITHM_ECDH ); + } } cleanup: @@ -628,6 +655,18 @@ SymCryptEckeyGetValue( goto cleanup; } + // If this keypair may be used in ECDSA, and does not have the no FIPS flag, run the PCT if + // it has not already been run + if ( ((pEckey->fAlgorithmInfo & SYMCRYPT_FLAG_ECKEY_ECDSA) != 0) && + ((pEckey->fAlgorithmInfo & SYMCRYPT_FLAG_KEY_NO_FIPS) == 0) ) + { + SYMCRYPT_RUN_KEYGEN_PCT( + SymCryptEcDsaSignVerifyTest, + pEckey, + SYMCRYPT_SELFTEST_ALGORITHM_ECDSA, + SYMCRYPT_SELFTEST_KEY_ECDSA ); + } + // Copy the key into the temporary integer SymCryptIntCopy( pEckey->piPrivateKey, piTmpInteger ); @@ -711,20 +750,13 @@ SymCryptEckeySetRandom( UINT32 highBitRestrictionPosition = pCurve->HighBitRestrictionPosition; - // Ensure only allowed flags are specified - UINT32 allowedFlags = SYMCRYPT_FLAG_KEY_RANGE_AND_PUBLIC_KEY_ORDER_VALIDATION | - SYMCRYPT_FLAG_ECKEY_SELFTEST_ECDSA | - SYMCRYPT_FLAG_ECKEY_SELFTEST_ECDH; - if ( ( flags & ~allowedFlags ) != 0) - { - scError = SYMCRYPT_INVALID_ARGUMENT; - goto cleanup; - } + // Ensure caller has specified what algorithm(s) the key will be used with + UINT32 algorithmFlags = SYMCRYPT_FLAG_ECKEY_ECDSA | SYMCRYPT_FLAG_ECKEY_ECDH; + // Make sure only allowed flags are specified + UINT32 allowedFlags = SYMCRYPT_FLAG_KEY_NO_FIPS | algorithmFlags; - // If any bits of SYMCRYPT_FLAG_KEY_VALIDATION_MASK are set, all bits of - // SYMCRYPT_FLAG_KEY_RANGE_AND_PUBLIC_KEY_ORDER_VALIDATION must be set - if ( ( flags & SYMCRYPT_FLAG_KEY_VALIDATION_MASK ) != 0 && - ( flags & SYMCRYPT_FLAG_KEY_VALIDATION_MASK ) != SYMCRYPT_FLAG_KEY_RANGE_AND_PUBLIC_KEY_ORDER_VALIDATION ) + if ( ( ( flags & ~allowedFlags ) != 0 ) || + ( ( flags & algorithmFlags ) == 0 ) ) { scError = SYMCRYPT_INVALID_ARGUMENT; goto cleanup; @@ -855,14 +887,13 @@ SymCryptEckeySetRandom( } // Perform range and public key order validation on generated Public key. - if ( (flags & SYMCRYPT_FLAG_KEY_VALIDATION_MASK) == SYMCRYPT_FLAG_KEY_RANGE_AND_PUBLIC_KEY_ORDER_VALIDATION ) + if ( (flags & SYMCRYPT_FLAG_KEY_NO_FIPS) == 0 ) { // Perform Public key validation. - // Always perform range validation - // May also perform validation that Public key is in subgroup of order GOrd, depending on flags + // Always perform range validation and validation that Public key is in subgroup of order GOrd scError = SymCryptEckeyPerformPublicKeyValidation( pEckey, - flags, + SYMCRYPT_FLAG_ECKEY_PUBLIC_KEY_ORDER_VALIDATION, pbScratch, cbScratch ); if ( scError != SYMCRYPT_NO_ERROR ) @@ -871,21 +902,25 @@ SymCryptEckeySetRandom( } } - if( ( flags & SYMCRYPT_FLAG_ECKEY_SELFTEST_ECDSA ) != 0 ) - { - SYMCRYPT_RUN_KEYGEN_PCT( SymCryptEcDsaSignVerifyTest, pEckey, SYMCRYPT_SELFTEST_ECDSA ); - } - - if( ( flags & SYMCRYPT_FLAG_ECKEY_SELFTEST_ECDH ) != 0 ) - { - SYMCRYPT_RUN_KEYGEN_PCT( - SymCryptEcDhSecretAgreementPairwiseConsistencyTest, - pEckey, - SYMCRYPT_SELFTEST_ECDH_SECRET_AGREEMENT ); - } - pEckey->hasPrivateKey = TRUE; + pEckey->fAlgorithmInfo = flags; // We want to track all of the flags in the Eckey + + if ( (flags & SYMCRYPT_FLAG_KEY_NO_FIPS) == 0 ) + { + // We defer the ECDSA PCT to before first use of the Eckey in EcDsaSign, or first time + // private key is exported - whichever comes first. + + if( ( flags & SYMCRYPT_FLAG_ECKEY_ECDH ) != 0 ) + { + // No additional per-key tests to perform before first use. + // Just ensure we have run the algorithm selftest at least once. + SYMCRYPT_RUN_SELFTEST_ONCE( + SymCryptEcDhSecretAgreementSelftest, + SYMCRYPT_SELFTEST_ALGORITHM_ECDH ); + } + } + cleanup: if ( pbScratch != NULL ) @@ -896,3 +931,27 @@ cleanup: return scError; } + +SYMCRYPT_ERROR +SYMCRYPT_CALL +SymCryptEckeyExtendKeyUsage( + _Inout_ PSYMCRYPT_ECKEY pEckey, + UINT32 flags ) +{ + SYMCRYPT_ERROR scError = SYMCRYPT_NO_ERROR; + + // Ensure caller has specified what algorithm(s) the key will be used with + UINT32 algorithmFlags = SYMCRYPT_FLAG_ECKEY_ECDSA | SYMCRYPT_FLAG_ECKEY_ECDH; + + if ( ( ( flags & ~algorithmFlags ) != 0 ) || + ( ( flags & algorithmFlags ) == 0) ) + { + scError = SYMCRYPT_INVALID_ARGUMENT; + goto cleanup; + } + + pEckey->fAlgorithmInfo |= flags; + +cleanup: + return scError; +} diff --git a/lib/fips_selftest.c b/lib/fips_selftest.c index ff93e5b..cfb1b44 100644 --- a/lib/fips_selftest.c +++ b/lib/fips_selftest.c @@ -6,7 +6,8 @@ #include "precomp.h" -SYMCRYPT_FIPS_SELFTEST g_SymCryptFipsSelftestsPerformed = SYMCRYPT_SELFTEST_NONE; +// Takes values which are some bitwise OR combination of SYMCRYPT_SELFTEST_ALGORITHM values +UINT32 g_SymCryptFipsSelftestsPerformed = SYMCRYPT_SELFTEST_ALGORITHM_NONE; // // Convenience structs for selftest data @@ -479,101 +480,6 @@ const BYTE rgbSha256Hash[] = 0xb4, 0x10, 0xff, 0x61, 0xf2, 0x00, 0x15, 0xad }; -VOID -SYMCRYPT_CALL -SymCryptDhSecretAgreementPairwiseConsistencyTest( PCSYMCRYPT_DLKEY pkKey1 ) -{ - SYMCRYPT_ERROR scError = SYMCRYPT_NO_ERROR; - - PSYMCRYPT_DLGROUP pKnownDlgroup = NULL; - PSYMCRYPT_DLKEY pkKey2 = NULL; - - PBYTE pbSecret1 = NULL; - PBYTE pbSecret2 = NULL; - ULONG cbSecret = SymCryptDlkeySizeofPublicKey( pkKey1 ); - - pbSecret1 = SymCryptCallbackAlloc( cbSecret ); - SYMCRYPT_FIPS_ASSERT( pbSecret1 != NULL ); - - pbSecret2 = SymCryptCallbackAlloc( cbSecret ); - SYMCRYPT_FIPS_ASSERT( pbSecret2 != NULL ); - - pKnownDlgroup = SymCryptDlgroupAllocate( - SymCryptDlgroupDhSafePrimeParamsModp2048->nBitsOfP, - 0 ); - SYMCRYPT_FIPS_ASSERT( pKnownDlgroup != NULL ); - - scError = SymCryptDlgroupSetValue( - SymCryptDlgroupDhSafePrimeParamsModp2048->pcbPrimeP, - SymCryptDlgroupDhSafePrimeParamsModp2048->nBitsOfP / 8, - NULL, // pbPrimeQ - 0, // cbPrimeQ - (PBYTE) &dhGenerator, - sizeof(dhGenerator), - SYMCRYPT_NUMBER_FORMAT_MSB_FIRST, - NULL, // pHashAlgorithm - NULL, // pbSeed - 0, // cbSeed - 0, // genCounter - SYMCRYPT_DLGROUP_FIPS_NONE, - pKnownDlgroup); - SYMCRYPT_FIPS_ASSERT( scError == SYMCRYPT_NO_ERROR ); - - if( SymCryptDlgroupIsSame( pKnownDlgroup, pkKey1->pDlgroup ) ) - { - pkKey2 = SymCryptDlkeyAllocate( pKnownDlgroup ); - SYMCRYPT_FIPS_ASSERT( pkKey2 != NULL ); - - scError = SymCryptDlkeySetValue( - dhKey2.private, - sizeof(dhKey2.private), - dhKey2.public, - sizeof(dhKey2.public), - SYMCRYPT_NUMBER_FORMAT_MSB_FIRST, - 0, // flags - pkKey2 ); - SYMCRYPT_FIPS_ASSERT( scError == SYMCRYPT_NO_ERROR ); - } - else - { - pkKey2 = SymCryptDlkeyAllocate( pkKey1->pDlgroup ); - SYMCRYPT_FIPS_ASSERT( pkKey2 != NULL ); - - scError = SymCryptDlkeyGenerate(0, pkKey2 ); - SYMCRYPT_FIPS_ASSERT( scError == SYMCRYPT_NO_ERROR ); - } - - // Calculate secret using private key 1 and public key 2 - scError = SymCryptDhSecretAgreement( - pkKey1, - pkKey2, - SYMCRYPT_NUMBER_FORMAT_MSB_FIRST, - 0, // flags - pbSecret1, - cbSecret ); - SYMCRYPT_FIPS_ASSERT( scError == SYMCRYPT_NO_ERROR ); - - // Calculate secret using private key 2 and public key 1 - scError = SymCryptDhSecretAgreement( - pkKey2, - pkKey1, - SYMCRYPT_NUMBER_FORMAT_MSB_FIRST, - 0, // flags - pbSecret2, - cbSecret ); - SYMCRYPT_FIPS_ASSERT( scError == SYMCRYPT_NO_ERROR ); - - SYMCRYPT_FIPS_ASSERT( memcmp( pbSecret1, pbSecret2, cbSecret ) == 0 ); - - SymCryptWipe( pbSecret2, cbSecret ); - SymCryptWipe( pbSecret1, cbSecret ); - - // No need to check for NULL values as allocation errors in this function are fatal - SymCryptCallbackFree( pbSecret2 ); - SymCryptCallbackFree( pbSecret1 ); - SymCryptDlkeyFree( pkKey2 ); - SymCryptDlgroupFree( pKnownDlgroup ); -} VOID SYMCRYPT_CALL @@ -617,7 +523,7 @@ SymCryptDhSecretAgreementSelftest() dhKey1.public, sizeof(dhKey1.public), SYMCRYPT_NUMBER_FORMAT_MSB_FIRST, - 0, // flags + SYMCRYPT_FLAG_DLKEY_DH | SYMCRYPT_FLAG_KEY_NO_FIPS, // flags pkKey1 ); SYMCRYPT_FIPS_ASSERT( scError == SYMCRYPT_NO_ERROR ); @@ -630,7 +536,7 @@ SymCryptDhSecretAgreementSelftest() dhKey2.public, sizeof(dhKey2.public), SYMCRYPT_NUMBER_FORMAT_MSB_FIRST, - 0, // flags + SYMCRYPT_FLAG_DLKEY_DH | SYMCRYPT_FLAG_KEY_NO_FIPS, // flags pkKey2 ); SYMCRYPT_FIPS_ASSERT( scError == SYMCRYPT_NO_ERROR ); @@ -653,200 +559,6 @@ SymCryptDhSecretAgreementSelftest() SymCryptDlgroupFree( pDlgroup ); } -// For performance we always generate a known-good key for performing PCTs. -// To avoid excessive overhead, for short-weierstrass curves we generate the key, -// private = GOrd - 1, public = -G. This is guaranteed to fulfill the validity requirements: -// a) private key is in range [1, GOrd -1] -// b) public key is non-zero, and is on the curve -// c) public key has order GOrd -// d) private key * G == (GOrd - 1) * G == (GOrd * G) - (1 * G) == 0 - G == -G == public key -VOID -SYMCRYPT_CALL -SymCryptDeriveEcDhTestKeyFromShortWeierstrassCurve( - PCSYMCRYPT_ECURVE pCurve, - _Out_ PSYMCRYPT_ECKEY* pkKey ) -{ - SYMCRYPT_ERROR scError = SYMCRYPT_NO_ERROR; - - PSYMCRYPT_ECPOINT poNegativeG = NULL; - PSYMCRYPT_INT piGOrdMinus1 = NULL; - - SIZE_T cbGOrdMinus1 = 0; - PBYTE pbGOrdMinus1 = NULL; - - SIZE_T cbNegativeG = 0; - PBYTE pbNegativeG = NULL; - - *pkKey = SymCryptEckeyAllocate( pCurve ); - SYMCRYPT_FIPS_ASSERT( *pkKey != NULL ); - - SIZE_T cbScratch = SYMCRYPT_MAX( - SYMCRYPT_SCRATCH_BYTES_FOR_COMMON_ECURVE_OPERATIONS( pCurve ), - SYMCRYPT_SCRATCH_BYTES_FOR_GETSET_VALUE_ECURVE_OPERATIONS( pCurve ) ); - PBYTE pbScratch = SymCryptCallbackAlloc( cbScratch ); - SYMCRYPT_FIPS_ASSERT( pbScratch != NULL ); - - poNegativeG = SymCryptEcpointAllocate( pCurve ); - SYMCRYPT_FIPS_ASSERT( poNegativeG != NULL ); - - piGOrdMinus1 = SymCryptIntAllocate( pCurve->GOrdDigits ); - SYMCRYPT_FIPS_ASSERT( piGOrdMinus1 != NULL ); - - // Get our public key, (GOrd - 1) - { - SymCryptIntSubUint32( - SymCryptIntFromModulus( pCurve->GOrd ), - 1, - piGOrdMinus1 ); - - cbGOrdMinus1 = SYMCRYPT_BYTES_FROM_BITS( SymCryptIntBitsizeOfValue( piGOrdMinus1 ) ); - pbGOrdMinus1 = SymCryptCallbackAlloc( cbGOrdMinus1 ); - SYMCRYPT_FIPS_ASSERT( pbGOrdMinus1 != NULL ); - - scError = SymCryptIntGetValue( - piGOrdMinus1, - pbGOrdMinus1, - cbGOrdMinus1, - SYMCRYPT_NUMBER_FORMAT_MSB_FIRST ); - SYMCRYPT_FIPS_ASSERT( scError == SYMCRYPT_NO_ERROR ); - } - - // Get our private key, -G, by negating the curve parameter G - { - SymCryptEcpointCopy( pCurve, pCurve->G, poNegativeG ); - SymCryptEcpointNegate( pCurve, poNegativeG, 0xffffffff, pbScratch, cbScratch ); - - cbNegativeG = 2 * SymCryptEcurveSizeofFieldElement( pCurve ); - pbNegativeG = SymCryptCallbackAlloc( cbNegativeG ); - - scError = SymCryptEcpointGetValue( - pCurve, - poNegativeG, - SYMCRYPT_NUMBER_FORMAT_MSB_FIRST, - SYMCRYPT_ECPOINT_FORMAT_XY, - pbNegativeG, - cbNegativeG, - SYMCRYPT_FLAG_DATA_PUBLIC, - pbScratch, - cbScratch ); - SYMCRYPT_FIPS_ASSERT( scError == SYMCRYPT_NO_ERROR ); - } - - scError = SymCryptEckeySetValue( - pbGOrdMinus1, - cbGOrdMinus1, - pbNegativeG, - cbNegativeG, - SYMCRYPT_NUMBER_FORMAT_MSB_FIRST, - SYMCRYPT_ECPOINT_FORMAT_XY, - 0, // flags - *pkKey ); - SYMCRYPT_FIPS_ASSERT( scError == SYMCRYPT_NO_ERROR ); - - // No need to test for NULL because all errors are fatal - SymCryptWipe( pbNegativeG, cbNegativeG ); - SymCryptCallbackFree( pbNegativeG ); - - SymCryptWipe( pbGOrdMinus1, cbGOrdMinus1 ); - SymCryptCallbackFree( pbGOrdMinus1 ); - - SymCryptIntFree( piGOrdMinus1 ); - SymCryptEcpointFree( pCurve, poNegativeG ); - - SymCryptWipe( pbScratch, cbScratch ); - SymCryptCallbackFree( pbScratch ); -} - -VOID -SYMCRYPT_CALL -SymCryptEcDhSecretAgreementPairwiseConsistencyTest( PCSYMCRYPT_ECKEY pkKey1 ) -{ - SYMCRYPT_ERROR scError = SYMCRYPT_NO_ERROR; - - PSYMCRYPT_ECURVE pKnownCurve = NULL; - PSYMCRYPT_ECKEY pkKey2 = NULL; - - PBYTE pbSecret1 = NULL; - PBYTE pbSecret2 = NULL; - ULONG cbSecret = SymCryptEcurveSizeofFieldElement( pkKey1->pCurve ); - - pbSecret1 = SymCryptCallbackAlloc( cbSecret ); - SYMCRYPT_FIPS_ASSERT( pbSecret1 != NULL ); - - pbSecret2 = SymCryptCallbackAlloc( cbSecret ); - SYMCRYPT_FIPS_ASSERT( pbSecret2 != NULL ); - - pKnownCurve = SymCryptEcurveAllocate( SymCryptEcurveParamsNistP256, 0 ); - SYMCRYPT_FIPS_ASSERT( pKnownCurve != NULL ); - - if( SymCryptEcurveIsSame( pKnownCurve, pkKey1->pCurve ) ) - { - // If this key uses the same curve as our hard-coded key, we can just import that - pkKey2 = SymCryptEckeyAllocate( pKnownCurve ); - SYMCRYPT_FIPS_ASSERT( pkKey2 != NULL ); - - scError = SymCryptEckeySetValue( - eckey2.d, - sizeof(eckey2.d), - eckey2.Qxy, - sizeof(eckey2.Qxy), - SYMCRYPT_NUMBER_FORMAT_MSB_FIRST, - SYMCRYPT_ECPOINT_FORMAT_XY, - 0, // flags - pkKey2); - SYMCRYPT_FIPS_ASSERT( scError == SYMCRYPT_NO_ERROR ); - } - else if( pkKey1->pCurve->type == SYMCRYPT_ECURVE_TYPE_SHORT_WEIERSTRASS && - SymCryptIntIsEqualUint32(pkKey1->pCurve->H, 1) ) - { - // For short Weierstrass curves with cofactor == 1, we can do efficient derivation - // of a test key from the curve parameters - SymCryptDeriveEcDhTestKeyFromShortWeierstrassCurve( pkKey1->pCurve, &pkKey2 ); - } - else - { - // Otherwise, we have to generate a key - pkKey2 = SymCryptEckeyAllocate( pkKey1->pCurve ); - SYMCRYPT_FIPS_ASSERT( pkKey2 != NULL ); - - scError = SymCryptEckeySetRandom( - SYMCRYPT_FLAG_KEY_RANGE_AND_PUBLIC_KEY_ORDER_VALIDATION, - pkKey2 ); - SYMCRYPT_FIPS_ASSERT( scError == SYMCRYPT_NO_ERROR ); - } - - // Calculate secret using private key 1 and public key 2 - scError = SymCryptEcDhSecretAgreement( - pkKey1, - pkKey2, - SYMCRYPT_NUMBER_FORMAT_MSB_FIRST, - 0, - pbSecret1, - cbSecret); - SYMCRYPT_FIPS_ASSERT( scError == SYMCRYPT_NO_ERROR ); - - // Calculate secret using private key 2 and public key 1 - scError = SymCryptEcDhSecretAgreement( - pkKey2, - pkKey1, - SYMCRYPT_NUMBER_FORMAT_MSB_FIRST, - 0, - pbSecret2, - cbSecret); - SYMCRYPT_FIPS_ASSERT( scError == SYMCRYPT_NO_ERROR ); - - SYMCRYPT_FIPS_ASSERT( memcmp( pbSecret1, pbSecret2, cbSecret ) == 0); - - SymCryptWipe( pbSecret2, cbSecret ); - SymCryptWipe( pbSecret1, cbSecret ); - - // No need to check for NULL values as allocation errors in this function are fatal - SymCryptCallbackFree( pbSecret2 ); - SymCryptCallbackFree( pbSecret1 ); - SymCryptEckeyFree( pkKey2 ); - SymCryptEcurveFree( pKnownCurve ); -} - VOID SYMCRYPT_CALL SymCryptEcDhSecretAgreementSelftest( ) @@ -872,7 +584,7 @@ SymCryptEcDhSecretAgreementSelftest( ) sizeof(eckey1.Qxy), SYMCRYPT_NUMBER_FORMAT_MSB_FIRST, SYMCRYPT_ECPOINT_FORMAT_XY, - 0, // flags + SYMCRYPT_FLAG_ECKEY_ECDH | SYMCRYPT_FLAG_KEY_NO_FIPS, // flags pkKey1); SYMCRYPT_FIPS_ASSERT( scError == SYMCRYPT_NO_ERROR ); @@ -886,7 +598,7 @@ SymCryptEcDhSecretAgreementSelftest( ) sizeof(eckey2.Qxy), SYMCRYPT_NUMBER_FORMAT_MSB_FIRST, SYMCRYPT_ECPOINT_FORMAT_XY, - 0, // flags + SYMCRYPT_FLAG_ECKEY_ECDH | SYMCRYPT_FLAG_KEY_NO_FIPS, // flags pkKey2); SYMCRYPT_FIPS_ASSERT( scError == SYMCRYPT_NO_ERROR ); @@ -980,7 +692,7 @@ SymCryptDsaSelftest( ) dsaKey.public, sizeof(dsaKey.public), SYMCRYPT_NUMBER_FORMAT_MSB_FIRST, - 0, // flags + SYMCRYPT_FLAG_DLKEY_DSA | SYMCRYPT_FLAG_KEY_NO_FIPS, // flags pkDlkey ); SYMCRYPT_FIPS_ASSERT( scError == SYMCRYPT_NO_ERROR ); @@ -1000,10 +712,12 @@ SymCryptEcDsaSignVerifyTest( PCSYMCRYPT_ECKEY pkEckey ) PBYTE pbSignature = SymCryptCallbackAlloc( cbSignature ); SYMCRYPT_FIPS_ASSERT( pbSignature != NULL ); - scError = SymCryptEcDsaSign( + // Use SymCryptEcDsaSignEx to avoid infinite recursion in the PCT + scError = SymCryptEcDsaSignEx( pkEckey, rgbSha256Hash, sizeof(rgbSha256Hash), + NULL, SYMCRYPT_NUMBER_FORMAT_MSB_FIRST, 0, pbSignature, @@ -1046,7 +760,7 @@ SymCryptEcDsaSelftest( ) sizeof(eckey1.Qxy), SYMCRYPT_NUMBER_FORMAT_MSB_FIRST, SYMCRYPT_ECPOINT_FORMAT_XY, - 0, // flags + SYMCRYPT_FLAG_ECKEY_ECDSA | SYMCRYPT_FLAG_KEY_NO_FIPS, // flags pkEckey); SYMCRYPT_FIPS_ASSERT( scError == SYMCRYPT_NO_ERROR ); @@ -1124,7 +838,7 @@ SymCryptRsaSelftest( ) cbPrimes, sizeof(cbPrimes) / sizeof(cbPrimes[0]), SYMCRYPT_NUMBER_FORMAT_MSB_FIRST, - 0, + SYMCRYPT_FLAG_RSAKEY_SIGN | SYMCRYPT_FLAG_KEY_NO_FIPS, pkRsakey ); SYMCRYPT_FIPS_ASSERT( scError == SYMCRYPT_NO_ERROR ); diff --git a/lib/rsa_enc.c b/lib/rsa_enc.c index b7503e1..78b2df8 100644 --- a/lib/rsa_enc.c +++ b/lib/rsa_enc.c @@ -521,6 +521,13 @@ SymCryptRsaRawEncrypt( PBYTE pbScratch = NULL; UINT32 cbScratch = 0; + // Make sure that the key may be used in Encrypt/Decrypt + if ( (pkRsakey->fAlgorithmInfo & SYMCRYPT_FLAG_RSAKEY_ENCRYPT) == 0 ) + { + scError = SYMCRYPT_INVALID_ARGUMENT; + goto cleanup; + } + cbScratch = SymCryptRsaCoreEncScratchSpace( pkRsakey ); pbScratch = (PBYTE)SymCryptCallbackAlloc( cbScratch ); @@ -564,6 +571,13 @@ SymCryptRsaRawDecrypt( PBYTE pbScratch = NULL; UINT32 cbScratch = 0; + // Make sure that the key may be used in Encrypt/Decrypt + if ( (pkRsakey->fAlgorithmInfo & SYMCRYPT_FLAG_RSAKEY_ENCRYPT) == 0 ) + { + scError = SYMCRYPT_INVALID_ARGUMENT; + goto cleanup; + } + // Make sure that the key has a private key if (!pkRsakey->hasPrivateKey) { @@ -634,6 +648,13 @@ SymCryptRsaPkcs1Encrypt( UNREFERENCED_PARAMETER( flags ); + // Make sure that the key may be used in Encrypt/Decrypt + if ( (pkRsakey->fAlgorithmInfo & SYMCRYPT_FLAG_RSAKEY_ENCRYPT) == 0 ) + { + scError = SYMCRYPT_INVALID_ARGUMENT; + goto cleanup; + } + *pcbDst = cbTmp; // Check if only *pcbDst is needed @@ -720,6 +741,13 @@ SymCryptRsaPkcs1Decrypt( SIZE_T cbModulus = SymCryptRsakeySizeofModulus(pkRsakey); SIZE_T cbTmp = SymCryptRoundUpPow2Sizet( cbModulus ); // tmp buffer needs to be a power of 2 + // Make sure that the key may be used in Encrypt/Decrypt + if ( (pkRsakey->fAlgorithmInfo & SYMCRYPT_FLAG_RSAKEY_ENCRYPT) == 0 ) + { + scError = SYMCRYPT_INVALID_ARGUMENT; + goto cleanup; + } + // Make sure that the key has a private key if (!pkRsakey->hasPrivateKey) { @@ -825,6 +853,13 @@ SymCryptRsaOaepEncrypt( UNREFERENCED_PARAMETER( flags ); + // Make sure that the key may be used in Encrypt/Decrypt + if ( (pkRsakey->fAlgorithmInfo & SYMCRYPT_FLAG_RSAKEY_ENCRYPT) == 0 ) + { + scError = SYMCRYPT_INVALID_ARGUMENT; + goto cleanup; + } + *pcbDst = cbTmp; // Check if only *pcbDst is needed @@ -923,6 +958,13 @@ SymCryptRsaOaepDecrypt( UNREFERENCED_PARAMETER( flags ); + // Make sure that the key may be used in Encrypt/Decrypt + if ( (pkRsakey->fAlgorithmInfo & SYMCRYPT_FLAG_RSAKEY_ENCRYPT) == 0 ) + { + scError = SYMCRYPT_INVALID_ARGUMENT; + goto cleanup; + } + if (cbSrc > cbTmp) { scError = SYMCRYPT_INVALID_ARGUMENT; @@ -1054,6 +1096,13 @@ SymCryptRsaPkcs1Sign( pbOID = pHashOIDs ? pHashOIDs->pbOID : NULL; cbOID = pHashOIDs ? pHashOIDs->cbOID : 0; + // Make sure that the key may be used in Sign/Verify + if ( (pkRsakey->fAlgorithmInfo & SYMCRYPT_FLAG_RSAKEY_SIGN) == 0 ) + { + scError = SYMCRYPT_INVALID_ARGUMENT; + goto cleanup; + } + // Make sure that the key has a private key if (!pkRsakey->hasPrivateKey) { @@ -1166,6 +1215,13 @@ SymCryptRsaPkcs1Verify( PBYTE pbTmp = NULL; SIZE_T cbTmp = SymCryptRsakeySizeofModulus(pkRsakey); + // Make sure that the key may be used in Sign/Verify + if ( (pkRsakey->fAlgorithmInfo & SYMCRYPT_FLAG_RSAKEY_SIGN) == 0 ) + { + scError = SYMCRYPT_INVALID_ARGUMENT; + goto cleanup; + } + if (cbSignature > cbTmp) { scError = SYMCRYPT_INVALID_ARGUMENT; @@ -1258,6 +1314,13 @@ SymCryptRsaPssSign( PBYTE pbTmp = NULL; SIZE_T cbTmp = SymCryptRsakeySizeofModulus(pkRsakey); + // Make sure that the key may be used in Sign/Verify + if ( (pkRsakey->fAlgorithmInfo & SYMCRYPT_FLAG_RSAKEY_SIGN) == 0 ) + { + scError = SYMCRYPT_INVALID_ARGUMENT; + goto cleanup; + } + if (cbHashValue > cbTmp) { scError = SYMCRYPT_INVALID_ARGUMENT; @@ -1386,6 +1449,13 @@ SymCryptRsaPssVerify( PBYTE pbTmp = NULL; SIZE_T cbTmp = SymCryptRsakeySizeofModulus(pkRsakey); + // Make sure that the key may be used in Sign/Verify + if ( (pkRsakey->fAlgorithmInfo & SYMCRYPT_FLAG_RSAKEY_SIGN) == 0 ) + { + scError = SYMCRYPT_INVALID_ARGUMENT; + goto cleanup; + } + if (cbHashValue > cbTmp) { scError = SYMCRYPT_INVALID_ARGUMENT; diff --git a/lib/rsakey.c b/lib/rsakey.c index 1c3a95a..ef56208 100644 --- a/lib/rsakey.c +++ b/lib/rsakey.c @@ -209,6 +209,7 @@ SymCryptRsakeyCopy( // if( pkSrc != pkDst ) { + pkDst->fAlgorithmInfo = pkSrc->fAlgorithmInfo; pkDst->cbTotalSize = pkSrc->cbTotalSize; pkDst->hasPrivateKey = pkSrc->hasPrivateKey; pkDst->nSetBitsOfModulus = pkSrc->nSetBitsOfModulus; @@ -521,10 +522,13 @@ SymCryptRsakeyGenerate( const UINT64 defaultExponent = RSA_DEFAULT_PUBLIC_EXPONENT; + // Ensure caller has specified what algorithm(s) the key will be used with + UINT32 algorithmFlags = SYMCRYPT_FLAG_RSAKEY_SIGN | SYMCRYPT_FLAG_RSAKEY_ENCRYPT; // Ensure only allowed flags are specified - UINT32 allowedFlags = SYMCRYPT_FLAG_RSAKEY_SELFTEST; + UINT32 allowedFlags = SYMCRYPT_FLAG_KEY_NO_FIPS | algorithmFlags; - if ( ( flags & ~allowedFlags ) != 0 ) + if ( ( ( flags & ~allowedFlags ) != 0 ) || + ( ( flags & algorithmFlags ) == 0) ) { scError = SYMCRYPT_INVALID_ARGUMENT; goto cleanup; @@ -702,16 +706,30 @@ SymCryptRsakeyGenerate( // Calculate the rest of the fields scError = SymCryptRsakeyCalculatePrivateFields( pkRsakey, pdTmp, piPhi, piAcc, pbFnScratch, cbFnScratch ); - if (scError != SYMCRYPT_NO_ERROR ) + if ( scError != SYMCRYPT_NO_ERROR ) { goto cleanup; } pkRsakey->hasPrivateKey = TRUE; - if ( ( flags & SYMCRYPT_FLAG_RSAKEY_SELFTEST ) != 0 ) + pkRsakey->fAlgorithmInfo = flags; // We want to track all of the flags in the Rsakey + + if ( ( flags & SYMCRYPT_FLAG_KEY_NO_FIPS ) == 0 ) { - SYMCRYPT_RUN_KEYGEN_PCT( SymCryptRsaSignVerifyTest, pkRsakey, SYMCRYPT_SELFTEST_RSA ); + // Ensure RSA algorithm selftest is run before first use of RSA algorithm + // Per FIPS 140-3 IG, this selftest cannot be a PCT + SYMCRYPT_RUN_SELFTEST_ONCE( + SymCryptRsaSelftest, + SYMCRYPT_SELFTEST_ALGORITHM_RSA); + + // Run SignVerify PCT on generated keypair + // Our current understanding is that this PCT is sufficient for both RSA_SIGN and RSA_ENCRYPT + SYMCRYPT_RUN_KEYGEN_PCT( + SymCryptRsaSignVerifyTest, + pkRsakey, + 0, /* Do not set any algorithm selftest as run with this PCT */ + SYMCRYPT_SELFTEST_KEY_RSA_SIGN ); } cleanup: @@ -760,15 +778,25 @@ SymCryptRsakeySetValue( PBYTE pbFnScratch = NULL; UINT32 cbFnScratch = 0; + // Ensure caller has specified what algorithm(s) the key will be used with + UINT32 algorithmFlags = SYMCRYPT_FLAG_RSAKEY_SIGN | SYMCRYPT_FLAG_RSAKEY_ENCRYPT; // Ensure only allowed flags are specified - UINT32 allowedFlags = SYMCRYPT_FLAG_RSAKEY_SELFTEST; + UINT32 allowedFlags = SYMCRYPT_FLAG_KEY_NO_FIPS | SYMCRYPT_FLAG_KEY_MINIMAL_VALIDATION | algorithmFlags; - if ( ( flags & ~allowedFlags ) != 0 ) + if ( ( ( flags & ~allowedFlags ) != 0 ) || + ( ( flags & algorithmFlags ) == 0) ) { scError = SYMCRYPT_INVALID_ARGUMENT; goto cleanup; } + // Check that minimal validation flag only specified with no fips + if ( ( ( flags & SYMCRYPT_FLAG_KEY_NO_FIPS ) == 0 ) && + ( ( flags & SYMCRYPT_FLAG_KEY_MINIMAL_VALIDATION ) != 0 ) ) + { + scError = SYMCRYPT_INVALID_ARGUMENT; + goto cleanup; + } // Check if the arguments are correct if ( (pbModulus==NULL) || (cbModulus==0) || // Modulus is needed @@ -928,9 +956,20 @@ SymCryptRsakeySetValue( pkRsakey->hasPrivateKey = TRUE; } - if ( ( flags & SYMCRYPT_FLAG_RSAKEY_SELFTEST ) != 0 ) + pkRsakey->fAlgorithmInfo = flags; // We want to track all of the flags in the Rsakey + + if ( ( flags & SYMCRYPT_FLAG_KEY_NO_FIPS ) == 0 ) { - SYMCRYPT_RUN_SELFTEST_ONCE( SymCryptRsaSelftest, SYMCRYPT_SELFTEST_RSA ); + // Ensure RSA algorithm selftest is run before first use of RSA algorithm + SYMCRYPT_RUN_SELFTEST_ONCE( + SymCryptRsaSelftest, + SYMCRYPT_SELFTEST_ALGORITHM_RSA); + + if( pkRsakey->hasPrivateKey ) + { + // We do not need to run an RSA PCT on import, indicate that the test has been run + pkRsakey->fAlgorithmInfo |= SYMCRYPT_SELFTEST_KEY_RSA_SIGN; + } } cleanup: @@ -1108,3 +1147,27 @@ cleanup: return scError; } + +SYMCRYPT_ERROR +SYMCRYPT_CALL +SymCryptRsakeyExtendKeyUsage( + _Inout_ PSYMCRYPT_RSAKEY pkRsakey, + UINT32 flags ) +{ + SYMCRYPT_ERROR scError = SYMCRYPT_NO_ERROR; + + // Ensure caller has specified what algorithm(s) the key will be used with + UINT32 algorithmFlags = SYMCRYPT_FLAG_RSAKEY_SIGN | SYMCRYPT_FLAG_RSAKEY_ENCRYPT; + + if ( ( ( flags & ~algorithmFlags ) != 0 ) || + ( ( flags & algorithmFlags ) == 0) ) + { + scError = SYMCRYPT_INVALID_ARGUMENT; + goto cleanup; + } + + pkRsakey->fAlgorithmInfo |= flags; + +cleanup: + return scError; +} diff --git a/lib/sc_lib.h b/lib/sc_lib.h index 8c0c305..86d8b45 100644 --- a/lib/sc_lib.h +++ b/lib/sc_lib.h @@ -3003,34 +3003,251 @@ SYMCRYPT_CALL SymCryptFdefMontgomeryReduceMulx1024( _In_ PCSYMCRYPT_MODULUS pmMod, _Inout_ PUINT32 pSrc, - _Out_ PUINT32 pDst ); + _Out_ PUINT32 pDst); -// Helper macro for checking for specific key validation flag using bits 4 and 5 in a flags variable -// Must be updated if SYMCRYPT_FLAG_KEY_MINIMAL_VALIDATION, SYMCRYPT_FLAG_KEY_RANGE_VALIDATION, or -// SYMCRYPT_FLAG_KEY_RANGE_AND_PUBLIC_KEY_ORDER_VALIDATION are updated. -#define SYMCRYPT_FLAG_KEY_VALIDATION_MASK SYMCRYPT_FLAG_KEY_RANGE_AND_PUBLIC_KEY_ORDER_VALIDATION -// Macro for executing a module selftest and setting the corresponding flag -#define SYMCRYPT_RUN_SELFTEST_ONCE(SelftestFunction, SelftestFlag) \ -if( ( g_SymCryptFipsSelftestsPerformed & SelftestFlag ) == 0 ) \ +//===================================================== +// Current state of FIPS tests for asymmetric keys +//===================================================== + +// -------------------------------------------------------------------- +// Key type | | +// & | Alg | Description +// Operation| | +// -------------------------------------------------------------------- +// Dlkey | DH | Requires use of named safe-prime group (otherwise we cannot perform private +// Generate | | key range check, or public key order validation). +// | | +// | | From SP800-56Ar3: +// | | Check private key is in the range [1, min(2^nBitsPriv, q)-1] +// | | nBitsPriv is specified either using a default value or using +// | | SymCryptDlkeySetPrivateKeyLength, such that 2s <= nBitsPriv <= nBitsOfQ. +// | | (s is the maximum security strength for a named safe-prime group as +// | | specified in SP800 - 56arev3) +// | | Check public key is in the range [2, p-2] +// | | Check that (Public key)^q == 1 mod p +// | | +// | | FIPS 140-3 does not require a further PCT before first use of the key. +// |----------------------------------------------------------- +// | DSA | Requires use of a Dlgroup which has q, but is not a named safe-prime group. +// | | +// | | FIPS 186-4 and SP800-89 do not require DSA keypair owners to perform +// | | validation of keypairs they generate. +// | | +// | | FIPS 140-3 requires that a module generating a Dlkey keypair for use in DSA +// | | must perform a PCT on the keypair before first operational use in DSA. +// | | As the Dlgroups supported by FIPS are distinct for DH and DSA, we can perform +// | | this PCT on key generation without fear of adverse performance. +// -------------------------------------------------------------------- +// Dlkey | DH | Requires use of named safe-prime group (otherwise we cannot perform private +// SetValue | | key range check, or public key order validation). +// | | +// | | From SP800-56Ar3: +// | | If importing a private key: +// | | Check private key is in the range [1, min(2^nBitsPriv, q)-1] +// | | nBitsPriv is specified either using a default value or using +// | | SymCryptDlkeySetPrivateKeyLength, such that 2s <= nBitsPriv <= nBitsOfQ. +// | | (s is the maximum security strength for a named safe-prime group as +// | | specified in SP800-56Arev3) +// | | +// | | If importing a public key: +// | | Check public key is in the range [2, p-2] +// | | Check that (Public key)^q == 1 mod p +// | | +// | | If importing both a private and public key, as above and also: +// | | Use the imported Private key to generate a Public key, and check the +// | | generated Public key is equal to the imported Public key. +// |----------------------------------------------------------- +// | DSA | Requires use of a Dlgroup which is not a named safe-prime group. +// | | +// | | FIPS 184-4 refers to SP800-89: +// | | If importing a public key: +// | | Check public key is in the range [2, p-2] +// | | Check that (Public key)^q == 1 mod p +// | | If importing a private and public key: +// | | Use the imported Private key to generate a Public key, and check the +// | | generated Public key is equal to the imported Public key. +// -------------------------------------------------------------------- +// Eckey | ECDH | Requires use of a NIST prime Elliptic Curve (P224, P256, P384, or P521) +// SetRandom| | +// | | From SP800-56Ar3: +// | | Check private key is in range [1, GOrd-1] +// | | Check public key is nonzero, has coordinates in the underlying field, and is a +// | | point on the curve +// | | Check that GOrd*(Public key) == O +// | | +// | | FIPS 140-3 does not require a further PCT before first use of the key +// |---------------------------------------------------------- +// | ECDSA | Requires use of a NIST prime Elliptic Curve (P224, P256, P384, or P521) +// | | +// | | FIPS 186-4 and SP800-89 do not require ECDSA keypair owners to perform +// | | validation of keypairs they generate. +// | | +// | | FIPS 140-3 requires that a module generating an Eckey keypair for use in ECDSA +// | | must perform a PCT on the keypair before first operational use in ECDSA. +// | | As the Elliptic curves used in ECDH and ECDSA are the same, an Eckey may be +// | | used for both ECDH and ECDSA. We defer the ECDSA PCT from the EckeySetRandom +// | | call to the first use of EcDsaSign, or the first export of the keypair. +// -------------------------------------------------------------------- +// Eckey | ECDH | Requires use of a NIST prime Elliptic Curve (P224, P256, P384, or P521) +// SetValue | | +// | | From SP800-56Ar3: +// | | If importing a private key: +// | | Check private key is in range [1, GOrd-1] +// | | +// | | If importing a public key: +// | | Check public key is nonzero, has coordinates in the underlying field, and is +// | | a point on the curve +// | | Check that GOrd*(Public key) == O +// | | +// | | If importing a private and public key: +// | | Use the imported Private key to generate a Public key, and check the +// | | generated Public key is equal to the imported Public key. +// |---------------------------------------------------------- +// | ECDSA | Requires use of a NIST prime Elliptic Curve (P224, P256, P384, or P521) +// | | +// | | FIPS 184-4 refers to SP800-89: +// | | If importing a public key: +// | | SP800-89 refers to ANS X9.62. Assume same tests required as SP800-56Ar3: +// | | Check public key is nonzero, has coordinates in the underlying field, and is +// | | a point on the curve +// | | Check that GOrd*(Public key) == O +// | | +// | | If importing a private and public key: +// | | Use the imported Private key to generate a Public key, and check the +// | | generated Public key is equal to the imported Public key. +// -------------------------------------------------------------------- +// Rsakey | RSA | From FIPS 186-4 (SIGN) and SP800-56Br2 (ENCRYPT for key transport): +// Generate |ENCRYPT| Ensure p and q are in open range (2 ^ ((nBits - 1) / 2), 2 ^ (nBits / 2)) +// | and | Ensure |p-q| > 2^((nBits/2)-100) +// | RSA | Ensure e is coprime with (p-1) and (q-1) +// | SIGN | Ensure d is in range [2 ^ (nBits/2) + 1, LCM(p-1,q-1) - 1] +// | | Ensure that d*e == 1 mod LCM(p-1,q-1) +// | | +// | | FIPS 140-3 requires that a module generating an Rsakey keypair for use in an +// | | RSA algorithm must perform a PCT on the keypair before first operational use. +// | | +// | | For ENCRYPT, SP800-56Br2 specifies the PCT to perform as part of key +// | | generation is: +// | | Check (m^e)^d == m mod n for some m in range [2, n-2] +// | | +// | | For SIGN, FIPS 186-4 refers to SP800-89, which does not clearly specify a +// | | PCT, but does specify that for an owner to have assurance of Private Key +// | | Possession they can sign a message with the private key and validate it with +// | | the public key to check they correspond to each other. Notably, this +// | | internally will verify (m^d)^e == m mod n for some m (along with testing +// | | additional padding logic) +// | | +// | | FIPS 140-2 explicitly says that only one PCT is required if a keypair may be +// | | used in either algorithm, with the module able to choose the PCT. +// | | FIPS 140-3 does not say anything specific about only requiring one PCT, but +// | | given that mathematically (m^e)^d == (m^ed) == (m^d)^e mod n, our +// | | current understanding is that the SIGN PCT works in lieu of the ENCRYPT PCT +// | | +// | | NOTE: FIPS 140-3 explicitly says that an RSA PCT cannot be used in lieu of an +// | | RSA algorithm selftest (CAST) +// -------------------------------------------------------------------- +// Rsakey | RSA | If importing a keypair (primes and modulus): +// SetValue |ENCRYPT| SP800-56Br2 specifies: +// | | Check (m^e)^d mod n == m for some m in range [2, n-2] +// | | Check n == p*q +// | | Check p and q are in open range (2 ^ ((nBits - 1) / 2), 2 ^ (nBits / 2)) +// | | Check |p-q| > 2^((nBits/2)-100) +// | | Check e is coprime with (p-1) and (q-1) +// | | Check p and q are probably prime +// | | Check d is in range [2 ^ (nBits/2) + 1, LCM(p-1,q-1) - 1] +// | | Check that d*e == 1 mod LCM(p-1,q-1) +// | | +// | | If importing a public key (only modulus): +// | | SP800-56Br2, refers to SP800-89 which details the following Partial Public Key +// | | Validation: +// | | Check n is odd +// | | Check n is not a prime or a power of a prime +// | | Check n has no factors smaller than 752 +// |---------------------------------------------------------- +// | RSA | FIPS 186-4 refers only to SP800-89 which has weaker tests for a keypair than +// | SIGN | SP800-56Br2 (i.e. success at SP800-56Br2 tests implies success in SP800-89) +// | | The current strategy will be to always perform the stronger tests. +// -------------------------------------------------------------------- + +// Macro for executing a module selftest and setting the corresponding algorithm selftest flag +#define SYMCRYPT_RUN_SELFTEST_ONCE(AlgorithmSelftestFunction, AlgorithmSelftestFlag) \ +if( ( g_SymCryptFipsSelftestsPerformed & AlgorithmSelftestFlag ) == 0 ) \ { \ - SelftestFunction( ); \ + AlgorithmSelftestFunction( ); \ \ - SYMCRYPT_ATOMIC_OR32_PRE_RELAXED( &g_SymCryptFipsSelftestsPerformed, SelftestFlag );\ + SYMCRYPT_ATOMIC_OR32_PRE_RELAXED( &g_SymCryptFipsSelftestsPerformed, AlgorithmSelftestFlag ); \ } -// Macro for executing a key-generation PCT and setting the corresponding flag -// Note that key generation PCTs must be run on every key generated, so the selftest function -// is run regardless of whether the flag is already set. However, the key generation PCT satisfies -// the module test requirement, so setting the flag here prevents subsequent tests from being run -// on key import. -#define SYMCRYPT_RUN_KEYGEN_PCT(SelftestFunction, Key, SelftestFlag) \ +// Macro for executing a key-generation PCT, setting the corresponding algorithm selftest flag, and +// setting the per-key selftest flag. +// Note that key generation PCTs must be run on every key generated, so the KeySelftestFunction +// function is run regardless of whether the algorithm selftest flag is already set. Normally the +// per-key PCT satisfies the algorithm test requirement, so setting the AlgorithmSelftestFlag here +// prevents subsequent algorithm selftests from being run on key import. If the PCT does not satisfy +// an algorithm test requirment, the caller can specify 0, and no flag will be set. +#define SYMCRYPT_RUN_KEYGEN_PCT(KeySelftestFunction, Key, AlgorithmSelftestFlag, KeySelftestFlag) \ +if( ( Key->fAlgorithmInfo & (KeySelftestFlag | SYMCRYPT_FLAG_KEY_NO_FIPS) ) == 0 ) \ { \ - SelftestFunction( Key ); \ + KeySelftestFunction( Key ); \ \ - SYMCRYPT_ATOMIC_OR32_PRE_RELAXED( &g_SymCryptFipsSelftestsPerformed, SelftestFlag );\ + if( ( g_SymCryptFipsSelftestsPerformed & AlgorithmSelftestFlag ) != AlgorithmSelftestFlag ) \ + { \ + SYMCRYPT_ATOMIC_OR32_PRE_RELAXED(&g_SymCryptFipsSelftestsPerformed, AlgorithmSelftestFlag); \ + } \ +\ + SYMCRYPT_ATOMIC_OR32_PRE_RELAXED(&Key->fAlgorithmInfo, KeySelftestFlag); \ } +// Macro to check flag used in fAlgorithmInfo is non-zero and a power of 2 +#define CHECK_ALGORITHM_INFO_FLAG_POW2( flag ) \ + C_ASSERT( (flag != 0) && ((flag & (flag-1)) == 0) ); + +// Macro to check flags used together in fAlgorithmInfo are distinct +#define CHECK_ALGORITHM_INFO_FLAGS_DISTINCT( flag0, flag1, flag2, flag3, flag4 ) \ + C_ASSERT( (flag0 < flag1) && (flag1 < flag2) && (flag2 < flag3) && (flag3 < flag4) ); + +CHECK_ALGORITHM_INFO_FLAG_POW2(SYMCRYPT_SELFTEST_KEY_DSA); +CHECK_ALGORITHM_INFO_FLAG_POW2(SYMCRYPT_SELFTEST_KEY_ECDSA); +CHECK_ALGORITHM_INFO_FLAG_POW2(SYMCRYPT_SELFTEST_KEY_RSA_SIGN); + +CHECK_ALGORITHM_INFO_FLAG_POW2(SYMCRYPT_FLAG_KEY_NO_FIPS); +CHECK_ALGORITHM_INFO_FLAG_POW2(SYMCRYPT_FLAG_KEY_MINIMAL_VALIDATION); + +CHECK_ALGORITHM_INFO_FLAG_POW2(SYMCRYPT_FLAG_DLKEY_DSA); +CHECK_ALGORITHM_INFO_FLAG_POW2(SYMCRYPT_FLAG_DLKEY_DH); + +CHECK_ALGORITHM_INFO_FLAG_POW2(SYMCRYPT_FLAG_ECKEY_ECDSA); +CHECK_ALGORITHM_INFO_FLAG_POW2(SYMCRYPT_FLAG_ECKEY_ECDH); + +CHECK_ALGORITHM_INFO_FLAG_POW2(SYMCRYPT_FLAG_RSAKEY_SIGN); +CHECK_ALGORITHM_INFO_FLAG_POW2(SYMCRYPT_FLAG_RSAKEY_ENCRYPT); + +CHECK_ALGORITHM_INFO_FLAGS_DISTINCT(SYMCRYPT_SELFTEST_KEY_DSA, SYMCRYPT_FLAG_KEY_NO_FIPS, SYMCRYPT_FLAG_KEY_MINIMAL_VALIDATION, SYMCRYPT_FLAG_DLKEY_DSA, SYMCRYPT_FLAG_DLKEY_DH); +CHECK_ALGORITHM_INFO_FLAGS_DISTINCT(SYMCRYPT_SELFTEST_KEY_ECDSA, SYMCRYPT_FLAG_KEY_NO_FIPS, SYMCRYPT_FLAG_KEY_MINIMAL_VALIDATION, SYMCRYPT_FLAG_ECKEY_ECDSA, SYMCRYPT_FLAG_ECKEY_ECDH); +CHECK_ALGORITHM_INFO_FLAGS_DISTINCT(SYMCRYPT_SELFTEST_KEY_RSA_SIGN, SYMCRYPT_FLAG_KEY_NO_FIPS, SYMCRYPT_FLAG_KEY_MINIMAL_VALIDATION, SYMCRYPT_FLAG_RSAKEY_SIGN, SYMCRYPT_FLAG_RSAKEY_ENCRYPT); + +VOID +SYMCRYPT_CALL +SymCryptRsaSignVerifyTest( PCSYMCRYPT_RSAKEY pkRsakey ); +// +// FIPS PCT for RSA sign/verify. If the self-test fails, SymCryptFatal will be called to fastfail. +// + +VOID +SYMCRYPT_CALL +SymCryptDsaSignVerifyTest( PCSYMCRYPT_DLKEY pkDlkey ); +// +// FIPS PCT for DSA sign/verify. If the self-test fails, SymCryptFatal will be called to fastfail. +// + +VOID +SYMCRYPT_CALL +SymCryptEcDsaSignVerifyTest( PCSYMCRYPT_ECKEY pkEckey ); +// +// FIPS PCT for ECDSA sign/verify. If the self-test fails, SymCryptFatal will be called to fastfail. +// + typedef struct _SYMCRYPT_DLGROUP_DH_SAFEPRIME_PARAMS { SYMCRYPT_DLGROUP_DH_SAFEPRIMETYPE eDhSafePrimeType; diff --git a/modules_linux/common/exports.ver b/modules_linux/common/exports.ver index 594e34f..d7fefb9 100644 --- a/modules_linux/common/exports.ver +++ b/modules_linux/common/exports.ver @@ -30,7 +30,6 @@ VERSION_101.0 { SymCryptAesExpandKeyEncryptOnly; SymCryptAesKeyCopy; SymCryptAesSelftest; - SymCryptBuildString; SymCryptCbcDecrypt; SymCryptCbcEncrypt; SymCryptCbcMac; @@ -52,10 +51,6 @@ VERSION_101.0 { SymCryptChaCha20Poly1305Selftest; SymCryptChaCha20Selftest; SymCryptChaCha20SetOffset; - SymCryptCpuFeaturesNeverPresent; - SymCryptCreateTrialDivisionContext; - SymCryptCrtGenerateInverses; - SymCryptCrtSolve; SymCryptCtrMsb64; SymCryptDesBlockCipher; SymCryptDesDecrypt; @@ -69,14 +64,6 @@ VERSION_101.0 { SymCryptDesxSelftest; SymCryptDhSecretAgreement; SymCryptDhSecretAgreementSelftest; - SymCryptDigitsFromBits; - SymCryptDivisorAllocate; - SymCryptDivisorCopy; - SymCryptDivisorCreate; - SymCryptDivisorDigitsizeOfObject; - SymCryptDivisorFree; - SymCryptDivisorFromModulus; - SymCryptDivisorWipe; SymCryptDlgroupAllocate; SymCryptDlgroupCopy; SymCryptDlgroupCreate; @@ -108,7 +95,6 @@ VERSION_101.0 { SymCryptEcDhSecretAgreementSelftest; SymCryptEcDsaSelftest; SymCryptEcDsaSign; - SymCryptEcDsaSignEx; SymCryptEcDsaVerify; SymCryptEcbDecrypt; SymCryptEcbEncrypt; @@ -123,34 +109,10 @@ VERSION_101.0 { SymCryptEckeySizeofPrivateKey; SymCryptEckeySizeofPublicKey; SymCryptEckeyWipe; - SymCryptEcpointAdd; - SymCryptEcpointAddDiffNonZero; - SymCryptEcpointAllocate; - SymCryptEcpointCopy; - SymCryptEcpointCreate; - SymCryptEcpointDouble; - SymCryptEcpointFree; - SymCryptEcpointGetValue; - SymCryptEcpointIsEqual; - SymCryptEcpointIsZero; - SymCryptEcpointMaskedCopy; - SymCryptEcpointMultiScalarMul; - SymCryptEcpointNegate; - SymCryptEcpointOnCurve; - SymCryptEcpointRetrieveHandle; - SymCryptEcpointScalarMul; - SymCryptEcpointSetDistinguishedPoint; - SymCryptEcpointSetRandom; - SymCryptEcpointSetValue; - SymCryptEcpointSetZero; - SymCryptEcpointWipe; SymCryptEcurveAllocate; SymCryptEcurveBitsizeofFieldModulus; SymCryptEcurveBitsizeofGroupOrder; - SymCryptEcurveDigitsofFieldElement; - SymCryptEcurveDigitsofScalarMultiplier; SymCryptEcurveFree; - SymCryptEcurveGroupOrder; SymCryptEcurveHighBitRestrictionNumOfBits; SymCryptEcurveHighBitRestrictionPosition; SymCryptEcurveHighBitRestrictionValue; @@ -167,7 +129,6 @@ VERSION_101.0 { SymCryptEcurvePrivateKeyDefaultFormat; SymCryptEcurveSizeofFieldElement; SymCryptEcurveSizeofScalarMultiplier; - SymCryptFreeTrialDivisionContext; SymCryptGcmAuthPart; SymCryptGcmDecrypt; SymCryptGcmDecryptFinal; @@ -239,55 +200,6 @@ VERSION_101.0 { SymCryptHmacSha512Result; SymCryptHmacSha512Selftest; SymCryptHmacSha512StateCopy; - SymCryptIntAddMixedSize; - SymCryptIntAddSameSize; - SymCryptIntAddUint32; - SymCryptIntAllocate; - SymCryptIntBitsizeOfObject; - SymCryptIntBitsizeOfValue; - SymCryptIntConditionalCopy; - SymCryptIntConditionalSwap; - SymCryptIntCopy; - SymCryptIntCopyMixedSize; - SymCryptIntCreate; - SymCryptIntDigitsizeOfObject; - SymCryptIntDivMod; - SymCryptIntDivPow2; - SymCryptIntExtendedGcd; - SymCryptIntFindSmallDivisor; - SymCryptIntFree; - SymCryptIntFromDivisor; - SymCryptIntFromModulus; - SymCryptIntGenerateRandomPrime; - SymCryptIntGetBit; - SymCryptIntGetBits; - SymCryptIntGetValue; - SymCryptIntGetValueLsbits32; - SymCryptIntGetValueLsbits64; - SymCryptIntIsEqual; - SymCryptIntIsEqualUint32; - SymCryptIntIsLessThan; - SymCryptIntMaskedCopy; - SymCryptIntMillerRabinPrimalityTest; - SymCryptIntModPow2; - SymCryptIntMulMixedSize; - SymCryptIntMulPow2; - SymCryptIntMulSameSize; - SymCryptIntMulUint32; - SymCryptIntNeg; - SymCryptIntSetBits; - SymCryptIntSetValue; - SymCryptIntSetValueUint32; - SymCryptIntSetValueUint64; - SymCryptIntShr1; - SymCryptIntSquare; - SymCryptIntSubMixedSize; - SymCryptIntSubSameSize; - SymCryptIntSubUint32; - SymCryptIntToDivisor; - SymCryptIntToModElement; - SymCryptIntToModulus; - SymCryptIntWipe; SymCryptLoadLsbFirstUint32; SymCryptLoadLsbFirstUint64; SymCryptLoadMsbFirstUint32; @@ -301,11 +213,6 @@ VERSION_101.0 { SymCryptMarvin32SeedCopy; SymCryptMarvin32Selftest; SymCryptMarvin32StateCopy; - SymCryptMask32EqU32; - SymCryptMask32IsNonzeroU31; - SymCryptMask32IsZeroU31; - SymCryptMask32LtU31; - SymCryptMask32NeqU31; SymCryptMd2; SymCryptMd2Algorithm; SymCryptMd2Append; @@ -334,38 +241,7 @@ VERSION_101.0 { SymCryptMd5StateCopy; SymCryptMd5StateExport; SymCryptMd5StateImport; - SymCryptModAdd; - SymCryptModDivPow2; - SymCryptModElementAllocate; - SymCryptModElementConditionalSwap; - SymCryptModElementCopy; - SymCryptModElementCreate; - SymCryptModElementFree; - SymCryptModElementGetValue; - SymCryptModElementIsEqual; - SymCryptModElementIsZero; - SymCryptModElementMaskedCopy; - SymCryptModElementSetValue; - SymCryptModElementSetValueNegUint32; - SymCryptModElementSetValueUint32; - SymCryptModElementToInt; - SymCryptModElementWipe; - SymCryptModExp; - SymCryptModInv; - SymCryptModMul; - SymCryptModMultiExp; - SymCryptModNeg; - SymCryptModSetRandom; - SymCryptModSquare; - SymCryptModSub; SymCryptModuleInit; - SymCryptModulusAllocate; - SymCryptModulusBitsizeOfObject; - SymCryptModulusCopy; - SymCryptModulusCreate; - SymCryptModulusDigitsizeOfObject; - SymCryptModulusFree; - SymCryptModulusWipe; SymCryptParallelSha256Init; SymCryptParallelSha256Process; SymCryptParallelSha256Selftest; @@ -413,7 +289,6 @@ VERSION_101.0 { SymCryptRngAesReseed; SymCryptRngAesReseedSelftest; SymCryptRngAesUninstantiate; - SymCryptRoundUpPow2Sizet; SymCryptRsaOaepDecrypt; SymCryptRsaOaepEncrypt; SymCryptRsaSelftest; @@ -439,13 +314,6 @@ VERSION_101.0 { SymCryptRsakeySizeofPrime; SymCryptRsakeySizeofPublicExponent; SymCryptRsakeyWipe; - SymCryptScsCopy; - SymCryptScsRotateBuffer; - SymCryptScsTableInit; - SymCryptScsTableLoad; - SymCryptScsTableSetBuffer; - SymCryptScsTableStore; - SymCryptScsTableWipe; SymCryptSha1; SymCryptSha1Algorithm; SymCryptSha1Append; @@ -486,14 +354,9 @@ VERSION_101.0 { SymCryptSha512StateCopy; SymCryptSha512StateExport; SymCryptSha512StateImport; - SymCryptSizeofDivisorFromDigits; SymCryptSizeofDlgroupFromBitsizes; SymCryptSizeofDlkeyFromDlgroup; SymCryptSizeofEckeyFromCurve; - SymCryptSizeofEcpointFromCurve; - SymCryptSizeofIntFromDigits; - SymCryptSizeofModElementFromModulus; - SymCryptSizeofModulusFromDigits; SymCryptSizeofRsakeyFromParams; SymCryptSp800_108; SymCryptSp800_108Derive; @@ -519,7 +382,6 @@ VERSION_101.0 { SymCryptUint32Bytesize; SymCryptUint64Bitsize; SymCryptUint64Bytesize; - SymCryptUint64Gcd; SymCryptWipe; SymCryptWipeKnownSize; SymCryptXtsAesDecrypt; @@ -532,14 +394,17 @@ VERSION_101.0 { VERSION_101.2 { global: - SymCryptDhSecretAgreementPairwiseConsistencyTest; - SymCryptDsaSignVerifyTest; - SymCryptEcDhSecretAgreementPairwiseConsistencyTest; - SymCryptEcDsaSignVerifyTest; - SymCryptRsaSignVerifyTest; SymCryptSessionDestroy; SymCryptSessionGcmDecrypt; SymCryptSessionGcmEncrypt; SymCryptSessionReceiverInit; SymCryptSessionSenderInit; -} VERSION_101.0; \ No newline at end of file +} VERSION_101.0; +VERSION_102.0 +{ + global: + SymCryptDlkeyExtendKeyUsage; + SymCryptEckeyExtendKeyUsage; + SymCryptRsakeyExtendKeyUsage; + SymCryptRsakeyCreate; +} VERSION_101.2; \ No newline at end of file diff --git a/modules_linux/common/module.c b/modules_linux/common/module.c index 59fbe1d..ebf85f4 100644 --- a/modules_linux/common/module.c +++ b/modules_linux/common/module.c @@ -59,7 +59,7 @@ VOID __attribute__((constructor)) SymCryptModuleMain() SymCryptPbkdf2_HmacSha1SelfTest(); - g_SymCryptFipsSelftestsPerformed |= SYMCRYPT_SELFTEST_STARTUP; + g_SymCryptFipsSelftestsPerformed |= SYMCRYPT_SELFTEST_ALGORITHM_STARTUP; } } diff --git a/unittest/exe_moduletest/moduletest.cpp b/unittest/exe_moduletest/moduletest.cpp index ea03fb5..4642644 100644 --- a/unittest/exe_moduletest/moduletest.cpp +++ b/unittest/exe_moduletest/moduletest.cpp @@ -42,7 +42,7 @@ main( int argc, _In_reads_( argc ) char * argv[] ) } else { - SYMCRYPT_FIPS_ASSERT( (g_SymCryptFipsSelftestsPerformed & SYMCRYPT_SELFTEST_STARTUP) != 0 ); + SYMCRYPT_FIPS_ASSERT( (g_SymCryptFipsSelftestsPerformed & SYMCRYPT_SELFTEST_ALGORITHM_STARTUP) != 0 ); SymCryptDhSecretAgreementSelftest(); SymCryptEcDhSecretAgreementSelftest(); diff --git a/unittest/lib/old-testRsa.cpp b/unittest/lib/old-testRsa.cpp index f47346d..9746b0e 100644 --- a/unittest/lib/old-testRsa.cpp +++ b/unittest/lib/old-testRsa.cpp @@ -191,7 +191,7 @@ testRsaGenerateOneKey( UINT32 iSize, UINT32 iImpl ) pubExp |= (UINT64)1 << (nPubBits - 1); pubExp |= 1; - scError = SymCryptRsakeyGenerate( pkSymCryptKey, &pubExp, 1, 0 ); + scError = SymCryptRsakeyGenerate( pkSymCryptKey, &pubExp, 1, SYMCRYPT_FLAG_RSAKEY_SIGN | SYMCRYPT_FLAG_RSAKEY_ENCRYPT ); CHECK( scError == SYMCRYPT_NO_ERROR, "?" ); pRes = (PBYTE) pkSymCryptKey; @@ -630,7 +630,7 @@ testRsaImportOneKey( pcbPrimes, 2, SYMCRYPT_NUMBER_FORMAT_MSB_FIRST, - 0, + SYMCRYPT_FLAG_RSAKEY_SIGN | SYMCRYPT_FLAG_RSAKEY_ENCRYPT, pkSymCryptKey ); CHECK( scError == SYMCRYPT_NO_ERROR, "?" ); @@ -1013,7 +1013,7 @@ testRsaPkcs1Errors() pKey = SymCryptRsakeyAllocate( ¶ms, 0 ); CHECK( pKey != 0, "?" ); - scError = SymCryptRsakeyGenerate( pKey, 0, 0, 0 ); + scError = SymCryptRsakeyGenerate( pKey, 0, 0, SYMCRYPT_FLAG_RSAKEY_SIGN | SYMCRYPT_FLAG_RSAKEY_ENCRYPT ); CHECK( scError == SYMCRYPT_NO_ERROR, "Error generating pkcs1 key" ); for( i=0; i::setKey( PCRSAKEY_TESTBLOB pcKeyBlob ) &pcKeyBlob->u64PubExp, 1, ppPrime, cbPrime, 2, SYMCRYPT_NUMBER_FORMAT_MSB_FIRST, - 0, + SYMCRYPT_FLAG_RSAKEY_SIGN, state.pKey ); CHECK( scError == SYMCRYPT_NO_ERROR, "?" ); @@ -4371,7 +4372,7 @@ RsaSignImp::setKey( PCRSAKEY_TESTBLOB pcKeyBlob ) &pcKeyBlob->u64PubExp, 1, ppPrime, cbPrime, 2, SYMCRYPT_NUMBER_FORMAT_MSB_FIRST, - 0, + SYMCRYPT_FLAG_RSAKEY_SIGN, state.pKey ); CHECK( scError == SYMCRYPT_NO_ERROR, "?" ); @@ -4590,7 +4591,7 @@ RsaEncImp::setKey( PCRSAKEY_TESTBLOB pcKeyBlob ) &pcKeyBlob->u64PubExp, 1, ppPrime, cbPrime, 2, SYMCRYPT_NUMBER_FORMAT_MSB_FIRST, - 0, + SYMCRYPT_FLAG_RSAKEY_ENCRYPT, state.pKey ); CHECK( scError == SYMCRYPT_NO_ERROR, "?" ); @@ -4801,7 +4802,7 @@ RsaEncImp::setKey( PCRSAKEY_TESTBLOB pcKeyBlob ) &pcKeyBlob->u64PubExp, 1, ppPrime, cbPrime, 2, SYMCRYPT_NUMBER_FORMAT_MSB_FIRST, - 0, + SYMCRYPT_FLAG_RSAKEY_ENCRYPT, state.pKey ); CHECK( scError == SYMCRYPT_NO_ERROR, "?" ); @@ -5030,7 +5031,7 @@ RsaEncImp::setKey( PCRSAKEY_TESTBLOB pcKeyBlob ) &pcKeyBlob->u64PubExp, 1, ppPrime, cbPrime, 2, SYMCRYPT_NUMBER_FORMAT_MSB_FIRST, - 0, + SYMCRYPT_FLAG_RSAKEY_ENCRYPT, state.pKey ); CHECK( scError == SYMCRYPT_NO_ERROR, "?" ); @@ -5477,12 +5478,14 @@ SetupSymCryptDsaAndDh( PBYTE buf1, PBYTE buf2, PBYTE buf3 ) UINT32 signatureSize = 0; PUINT32 puiSignatureSize = NULL; + UINT32 generateFlags = SYMCRYPT_FLAG_DLKEY_DH | SYMCRYPT_FLAG_DLKEY_DSA | SYMCRYPT_FLAG_KEY_NO_FIPS; + pPtrs[0] = SymCryptDlkeyCreate( buf2 + buff2Offset, dlkeysize, pDlgroup ); - scError = SymCryptDlkeyGenerate( 0, pPtrs[0] ); + scError = SymCryptDlkeyGenerate( generateFlags, pPtrs[0] ); CHECK( scError == SYMCRYPT_NO_ERROR, "?" ); pPtrs[1] = SymCryptDlkeyCreate( buf2 + buff2Offset + dlkeysize, dlkeysize, pDlgroup ); - scError = SymCryptDlkeyGenerate( 0, pPtrs[1] ); + scError = SymCryptDlkeyGenerate( generateFlags, pPtrs[1] ); CHECK( scError == SYMCRYPT_NO_ERROR, "?" ); signatureSize = 2*SymCryptDlkeySizeofPrivateKey( pPtrs[0] ); @@ -5517,7 +5520,7 @@ SetupSymCryptDsaAndDh( PBYTE buf1, PBYTE buf2, PBYTE buf3 ) // Verify the signature to make sure everything is ok scError = SymCryptDsaVerify( ((PSYMCRYPT_DLKEY *) buf2)[0], - buf2, // Sign the keys' buffer + buf2, // Verify the keys' buffer SymCryptDlkeySizeofPrivateKey( ((PSYMCRYPT_DLKEY *)buf2)[0] ), buf3 + sizeof(UINT32), *((PUINT32) buf3), @@ -5636,11 +5639,11 @@ DlImp::~DlImp() //============================ PSYMCRYPT_DLKEY -dlkeyObjectFromTestBlob( PCSYMCRYPT_DLGROUP pGroup, PCDLKEY_TESTBLOB pBlob, BOOL setPrivate = TRUE ) +dlkeyObjectFromTestBlob( PCSYMCRYPT_DLGROUP pGroup, PCDLKEY_TESTBLOB pBlob, UINT32 algFlags, BOOL setPrivate = TRUE ) { PSYMCRYPT_DLKEY pRes; SYMCRYPT_ERROR scError; - UINT32 flags = 0; + UINT32 flags = algFlags; PCBYTE pbPrivKey = NULL; SIZE_T cbPrivKey = 0; PCBYTE pbPubKey = NULL; @@ -5654,32 +5657,21 @@ dlkeyObjectFromTestBlob( PCSYMCRYPT_DLGROUP pGroup, PCDLKEY_TESTBLOB pBlob, BOOL BYTE randByte = g_rng.byte(); - if(randByte & 1) + if (!pGroup->fHasPrimeQ || + pBlob->fPrivateModP || + ((algFlags == SYMCRYPT_FLAG_DLKEY_DH) && (!pGroup->isSafePrimeGroup)) || + ((algFlags == SYMCRYPT_FLAG_DLKEY_DSA) && (pGroup->isSafePrimeGroup)) || + (randByte & 0x1)) { - flags |= SYMCRYPT_FLAG_KEY_KEYPAIR_REGENERATION_VALIDATION; - } - - // If Dlgroup has a set Q and Dlkey wasn't explicitly generated with private key mod P - if ( pGroup->fHasPrimeQ && !pBlob->fPrivateModP ) - { - switch((randByte >> 1) & 3) + flags |= SYMCRYPT_FLAG_KEY_NO_FIPS; + if (randByte & 0x2) { - case 0: - break; - case 1: - flags |= SYMCRYPT_FLAG_KEY_MINIMAL_VALIDATION; - break; - case 2: - flags |= SYMCRYPT_FLAG_KEY_RANGE_VALIDATION; - break; - case 3: - default: - flags |= SYMCRYPT_FLAG_KEY_RANGE_AND_PUBLIC_KEY_ORDER_VALIDATION; - break; + flags |= SYMCRYPT_FLAG_DLKEY_DSA; + flags |= SYMCRYPT_FLAG_DLKEY_DH; } } - if (setPrivate || (randByte & 0x8)) + if (setPrivate || (randByte & 0x4)) { pbPrivKey = &pBlob->abPrivKey[0]; cbPrivKey = pBlob->cbPrivKey; @@ -5692,6 +5684,11 @@ dlkeyObjectFromTestBlob( PCSYMCRYPT_DLGROUP pGroup, PCDLKEY_TESTBLOB pBlob, BOOL } } + if (((flags & SYMCRYPT_FLAG_KEY_NO_FIPS) != 0) && (randByte & 0x8)) + { + flags |= SYMCRYPT_FLAG_KEY_MINIMAL_VALIDATION; + } + if (!setPrivate) { pbPubKey = &pBlob->abPubKey[0]; @@ -5725,12 +5722,14 @@ algImpKeyPerfFunction( PBYTE buf1, PBYTE buf2, PBYTE buf3, SIZE_T PSYMCRYPT_DLKEY pKey1 = SymCryptDlkeyCreate( buf2 + 64, PERF_BUFFER_SIZE/4, pGroup ); PSYMCRYPT_DLKEY pKey2 = SymCryptDlkeyCreate( buf2 + 64 + PERF_BUFFER_SIZE/4, PERF_BUFFER_SIZE/4, pGroup ); + UINT32 generateFlags = SYMCRYPT_FLAG_DLKEY_DH | (pGroup->isSafePrimeGroup ? 0 : SYMCRYPT_FLAG_KEY_NO_FIPS); + CHECK( pKey1 != NULL && pKey2 != NULL, "Failed to create keys" ); - scError = SymCryptDlkeyGenerate( 0, pKey1 ); + scError = SymCryptDlkeyGenerate( generateFlags, pKey1 ); CHECK( scError == SYMCRYPT_NO_ERROR, "?" ); - scError = SymCryptDlkeyGenerate( 0, pKey2 ); + scError = SymCryptDlkeyGenerate( generateFlags, pKey2 ); CHECK( scError == SYMCRYPT_NO_ERROR, "?" ); ((PSYMCRYPT_DLKEY *) buf2)[0] = pKey1; @@ -5758,10 +5757,12 @@ algImpDataPerfFunction< ImpSc, AlgDh>( PBYTE buf1, PBYTE buf2, PBYTE buf3, SIZE_ PSYMCRYPT_DLGROUP pGroup = *(PSYMCRYPT_DLGROUP *) buf1; + UINT32 generateFlags = SYMCRYPT_FLAG_DLKEY_DH | (pGroup->isSafePrimeGroup ? 0 : SYMCRYPT_FLAG_KEY_NO_FIPS); + PSYMCRYPT_DLKEY pKey = SymCryptDlkeyCreate( buf3, (1 << 16), pGroup ); CHECK( pKey != NULL, "?" ); - scError = SymCryptDlkeyGenerate( 0, pKey ); + scError = SymCryptDlkeyGenerate( generateFlags, pKey ); CHECK( scError == SYMCRYPT_NO_ERROR, "?" ); scError = SymCryptDlkeyGetValue( pKey, NULL, 0, buf3 + (1 << 16), pGroup->cbPrimeP, SYMCRYPT_NUMBER_FORMAT_MSB_FIRST, 0 ); @@ -5828,7 +5829,7 @@ DhImp::setKey( _In_ PCDLKEY_TESTBLOB pcKeyBlob ) if( pcKeyBlob != NULL ) { state.pGroup = dlgroupObjectFromTestBlob( pcKeyBlob->pGroup ); - state.pKey = dlkeyObjectFromTestBlob( state.pGroup, pcKeyBlob ); + state.pKey = dlkeyObjectFromTestBlob( state.pGroup, pcKeyBlob, SYMCRYPT_FLAG_DLKEY_DH ); CHECK( state.pGroup != NULL && state.pKey != NULL, "?" ); } @@ -5846,7 +5847,7 @@ DhImp::sharedSecret( PSYMCRYPT_DLKEY pKey2; SYMCRYPT_ERROR scError; - pKey2 = dlkeyObjectFromTestBlob( state.pGroup, pcPubkey, /*setPrivate=*/ FALSE ); + pKey2 = dlkeyObjectFromTestBlob( state.pGroup, pcPubkey, SYMCRYPT_FLAG_DLKEY_DH, /*setPrivate=*/ FALSE ); CHECK( pKey2 != NULL, "?") scError = SymCryptDhSecretAgreement( state.pKey, @@ -5878,7 +5879,7 @@ algImpKeyPerfFunction( PBYTE buf1, PBYTE buf2, PBYTE buf3, SIZE_T CHECK( pKey != NULL, "Failed to create key" ); - scError = SymCryptDlkeyGenerate( 0, pKey ); + scError = SymCryptDlkeyGenerate( SYMCRYPT_FLAG_DLKEY_DSA, pKey ); CHECK( scError == SYMCRYPT_NO_ERROR, "?" ); ((PSYMCRYPT_DLKEY *) buf2)[0] = pKey; @@ -5977,7 +5978,7 @@ DsaImp::setKey( _In_ PCDLKEY_TESTBLOB pcKeyBlob ) if( pcKeyBlob != NULL ) { state.pGroup = dlgroupObjectFromTestBlob( pcKeyBlob->pGroup ); - state.pKey = dlkeyObjectFromTestBlob( state.pGroup, pcKeyBlob ); + state.pKey = dlkeyObjectFromTestBlob( state.pGroup, pcKeyBlob, SYMCRYPT_FLAG_DLKEY_DSA ); CHECK( state.pGroup != NULL && state.pKey != NULL, "?" ); } @@ -6143,7 +6144,7 @@ SetupSymCryptEcdsaAndEcdh( PBYTE buf1, PBYTE buf2, PBYTE buf3 ) PSYMCRYPT_ECKEY * pPtrs = ((PSYMCRYPT_ECKEY *) buf2); pPtrs[0] = SymCryptEckeyCreate( buf2 + 32, eckeySize, pCurve ); - scError = SymCryptEckeySetRandom( 0, pPtrs[0] ); + scError = SymCryptEckeySetRandom( SYMCRYPT_FLAG_ECKEY_ECDSA | SYMCRYPT_FLAG_ECKEY_ECDH, pPtrs[0] ); CHECK( scError == SYMCRYPT_NO_ERROR, "?" ); pPtrs[1] = (PSYMCRYPT_ECKEY) ((PBYTE)buf2 + 32 + eckeySize); // This will hold the hash of the message @@ -6168,19 +6169,19 @@ SetupSymCryptEcdsaAndEcdh( PBYTE buf1, PBYTE buf2, PBYTE buf3 ) SymCryptEcurveSizeofFieldElement( *(PSYMCRYPT_ECURVE *) buf1 )); CHECK( scError == SYMCRYPT_NO_ERROR, "SymCryptEcDhSecretAgreement failed" ); - // Same for ECDSA - scError = SymCryptEcDsaSign( - pPtrs[0], - (PBYTE) pPtrs[1], - SYMCRYPT_SHA512_RESULT_SIZE, - SYMCRYPT_NUMBER_FORMAT_MSB_FIRST, - 0, - buf3 + sizeof(UINT32), - signatureSize ); - CHECK( scError == SYMCRYPT_NO_ERROR, "SymCryptEcDsaSign failed" ); - if (pCurve->type != SYMCRYPT_ECURVE_TYPE_MONTGOMERY) { + // Same for ECDSA + scError = SymCryptEcDsaSign( + pPtrs[0], + (PBYTE) pPtrs[1], + SYMCRYPT_SHA512_RESULT_SIZE, + SYMCRYPT_NUMBER_FORMAT_MSB_FIRST, + 0, + buf3 + sizeof(UINT32), + signatureSize ); + CHECK( scError == SYMCRYPT_NO_ERROR, "SymCryptEcDsaSign failed" ); + // Verify the signature to make sure everything is ok scError = SymCryptEcDsaVerify( ((PSYMCRYPT_ECKEY *) buf2)[0], diff --git a/unittest/lib/testDh.cpp b/unittest/lib/testDh.cpp index 4625ace..3beb471 100644 --- a/unittest/lib/testDh.cpp +++ b/unittest/lib/testDh.cpp @@ -490,7 +490,7 @@ VOID testDlSimple() pkDlkey = SymCryptDlkeyAllocate( pDlgroup ); CHECK( pkDlkey!=NULL, "?"); - scError = SymCryptDlkeyGenerate( SYMCRYPT_FLAG_DLKEY_SELFTEST_DH, pkDlkey ); + scError = SymCryptDlkeyGenerate( SYMCRYPT_FLAG_DLKEY_DSA, pkDlkey ); CHECK( scError == SYMCRYPT_NO_ERROR, "?" ); //printDlKey( pkDlkey ); @@ -598,7 +598,7 @@ VOID testDlSimple() //printDlGroup( pDlgroup ); // Create a new key and make sure it is mod P - scError = SymCryptDlkeyGenerate( SYMCRYPT_FLAG_DLKEY_SELFTEST_DH, pkDlkey ); + scError = SymCryptDlkeyGenerate( SYMCRYPT_FLAG_DLKEY_DSA | SYMCRYPT_FLAG_KEY_NO_FIPS, pkDlkey ); CHECK( scError == SYMCRYPT_NO_ERROR, "?" ); CHECK(SymCryptDlkeySizeofPrivateKey(pkDlkey) == cbExpP, "?") @@ -696,8 +696,10 @@ VOID testDlSimple() //printDlGroup( pDlgroup ); // Create a new key and use the mod P flag - scError = SymCryptDlkeyGenerate( SYMCRYPT_FLAG_DLKEY_GEN_MODP | SYMCRYPT_FLAG_DLKEY_SELFTEST_DH, pkDlkey ); - CHECK( scError == SYMCRYPT_NO_ERROR, "?" ); + scError = SymCryptDlkeyGenerate( + SYMCRYPT_FLAG_DLKEY_DSA | SYMCRYPT_FLAG_DLKEY_GEN_MODP | SYMCRYPT_FLAG_KEY_NO_FIPS, + pkDlkey); + CHECK(scError == SYMCRYPT_NO_ERROR, "?"); CHECK(SymCryptDlkeySizeofPrivateKey(pkDlkey) == cbExpP, "?") @@ -811,10 +813,10 @@ createKatFileSingleDh( FILE * f, PCDLGROUP_TESTBLOB pBlob ) PSYMCRYPT_DLKEY pKey1 = SymCryptDlkeyAllocate( pGroup ); PSYMCRYPT_DLKEY pKey2 = SymCryptDlkeyAllocate( pGroup ); - scError = SymCryptDlkeyGenerate( SYMCRYPT_FLAG_DLKEY_SELFTEST_DH, pKey1 ); + scError = SymCryptDlkeyGenerate( SYMCRYPT_FLAG_DLKEY_DH, pKey1 ); CHECK( scError == SYMCRYPT_NO_ERROR, "Error generating DH key" ); - scError = SymCryptDlkeyGenerate( SYMCRYPT_FLAG_DLKEY_SELFTEST_DH, pKey2 ); + scError = SymCryptDlkeyGenerate( SYMCRYPT_FLAG_DLKEY_DH, pKey2 ); CHECK( scError == SYMCRYPT_NO_ERROR, "Error generating DH key" ); UINT32 cbPrivKey1 = SymCryptDlkeySizeofPrivateKey( pKey1 ); @@ -1009,15 +1011,11 @@ testDhtestGroups( DhImplementation * pDh, INT64 line ) } } - scError = SymCryptDlkeyGenerate( SYMCRYPT_FLAG_DLKEY_SELFTEST_DH, pKey1 ); + scError = SymCryptDlkeyGenerate( SYMCRYPT_FLAG_DLKEY_DH | SYMCRYPT_FLAG_KEY_NO_FIPS, pKey1 ); CHECK( scError == SYMCRYPT_NO_ERROR, "Error generating key" ); - scError = SymCryptDlkeyGenerate( - SYMCRYPT_FLAG_KEY_RANGE_AND_PUBLIC_KEY_ORDER_VALIDATION | SYMCRYPT_FLAG_DLKEY_SELFTEST_DH, - pKey1 ); + scError = SymCryptDlkeyGenerate( SYMCRYPT_FLAG_DLKEY_DH | (pGroup->isSafePrimeGroup ? 0 : SYMCRYPT_FLAG_KEY_NO_FIPS), pKey1 ); CHECK( scError == SYMCRYPT_NO_ERROR, "Error generating key" ); - scError = SymCryptDlkeyGenerate( - SYMCRYPT_FLAG_DLKEY_GEN_MODP | SYMCRYPT_FLAG_DLKEY_SELFTEST_DH, - pKey2 ); + scError = SymCryptDlkeyGenerate( SYMCRYPT_FLAG_DLKEY_DH | SYMCRYPT_FLAG_KEY_NO_FIPS | SYMCRYPT_FLAG_DLKEY_GEN_MODP, pKey2 ); CHECK( scError == SYMCRYPT_NO_ERROR, "Error generating key" ); DLKEY_TESTBLOB blob1; @@ -1060,7 +1058,7 @@ testDhtestGroups( DhImplementation * pDh, INT64 line ) &blob1.abPrivKey[0], blob1.cbPrivKey, &blob1.abPubKey[0], cbP, SYMCRYPT_NUMBER_FORMAT_MSB_FIRST, - SYMCRYPT_FLAG_KEY_RANGE_AND_PUBLIC_KEY_ORDER_VALIDATION | SYMCRYPT_FLAG_KEY_KEYPAIR_REGENERATION_VALIDATION | SYMCRYPT_FLAG_DLKEY_SELFTEST_DH, + SYMCRYPT_FLAG_DLKEY_DH, pKey1 ); CHECK4( scError == SYMCRYPT_NO_ERROR, "Error (%d) importing key - nBitsPriv %d", scError, nBitsPriv ); @@ -1074,7 +1072,7 @@ testDhtestGroups( DhImplementation * pDh, INT64 line ) &blob1.abPrivKey[0], blob1.cbPrivKey, &blob1.abPubKey[0], cbP, SYMCRYPT_NUMBER_FORMAT_MSB_FIRST, - SYMCRYPT_FLAG_KEY_RANGE_AND_PUBLIC_KEY_ORDER_VALIDATION | SYMCRYPT_FLAG_KEY_KEYPAIR_REGENERATION_VALIDATION | SYMCRYPT_FLAG_DLKEY_SELFTEST_DH, + SYMCRYPT_FLAG_DLKEY_DH, pKey1 ); CHECK5( scError == SYMCRYPT_INVALID_ARGUMENT, "Unexpected return (%d) importing key - nBitsPrivGenerated %d nBitsPriv %d", scError, nBitsPrivGenerated, nBitsPriv ); } @@ -1089,7 +1087,7 @@ testDhtestGroups( DhImplementation * pDh, INT64 line ) &blob1.abPrivKey[0], blob1.cbPrivKey, &blob1.abPubKey[0], cbP, SYMCRYPT_NUMBER_FORMAT_MSB_FIRST, - SYMCRYPT_FLAG_KEY_RANGE_AND_PUBLIC_KEY_ORDER_VALIDATION | SYMCRYPT_FLAG_KEY_KEYPAIR_REGENERATION_VALIDATION | SYMCRYPT_FLAG_DLKEY_SELFTEST_DH, + SYMCRYPT_FLAG_DLKEY_DH, pKey1 ); CHECK5( scError == SYMCRYPT_NO_ERROR, "Error (%d) importing key - nBitsPrivGenerated %d nBitsPriv %d", scError, nBitsPrivGenerated, nBitsPriv ); } diff --git a/unittest/lib/testDl.cpp b/unittest/lib/testDl.cpp index b24a0d7..6a7d9c9 100644 --- a/unittest/lib/testDl.cpp +++ b/unittest/lib/testDl.cpp @@ -288,9 +288,7 @@ VOID testDlSimple() pkDlkey = SymCryptDlkeyAllocate( pDlgroup ); CHECK( pkDlkey!=NULL, "?"); - scError = SymCryptDlkeyGenerate( - SYMCRYPT_FLAG_DLKEY_SELFTEST_DSA | SYMCRYPT_FLAG_DLKEY_SELFTEST_DH, - pkDlkey ); + scError = SymCryptDlkeyGenerate( SYMCRYPT_FLAG_DLKEY_DSA, pkDlkey ); CHECK( scError == SYMCRYPT_NO_ERROR, "?" ); printDlKey( pkDlkey ); @@ -398,9 +396,7 @@ VOID testDlSimple() printDlGroup( pDlgroup ); // Create a new key and make sure it is mod P - scError = SymCryptDlkeyGenerate( - SYMCRYPT_FLAG_DLKEY_SELFTEST_DSA | SYMCRYPT_FLAG_DLKEY_SELFTEST_DH, - pkDlkey ); + scError = SymCryptDlkeyGenerate( SYMCRYPT_FLAG_DLKEY_DSA, pkDlkey ); CHECK( scError == SYMCRYPT_NO_ERROR, "?" ); CHECK(SymCryptDlkeySizeofPrivateKey(pkDlkey) == cbExpP, "?") @@ -498,9 +494,7 @@ VOID testDlSimple() printDlGroup( pDlgroup ); // Create a new key and use the mod P flag - scError = SymCryptDlkeyGenerate( - SYMCRYPT_FLAG_DLKEY_GEN_MODP | SYMCRYPT_FLAG_DLKEY_SELFTEST_DSA | SYMCRYPT_FLAG_DLKEY_SELFTEST_DH, - pkDlkey ); + scError = SymCryptDlkeyGenerate( SYMCRYPT_FLAG_DLKEY_GEN_MODP | SYMCRYPT_FLAG_DLKEY_DSA, pkDlkey ); CHECK( scError == SYMCRYPT_NO_ERROR, "?" ); CHECK(SymCryptDlkeySizeofPrivateKey(pkDlkey) == cbExpP, "?") diff --git a/unittest/lib/testDl_sc.cpp b/unittest/lib/testDl_sc.cpp index 9517251..a9f66d0 100644 --- a/unittest/lib/testDl_sc.cpp +++ b/unittest/lib/testDl_sc.cpp @@ -25,21 +25,29 @@ template<> VOID algImpTestInteropGenerateKeyEntry< ImpSc >(PBYTE pKeyEntry) pKE->pGroups[IMPSC_INDEX] = (PBYTE) pDlgroup; - // Dsa and first Dh keys + // Dsa keys pkSymCryptKey = SymCryptDlkeyAllocate( pDlgroup ); CHECK( pkSymCryptKey != NULL, "?" ); - scError = SymCryptDlkeyGenerate( 0, pkSymCryptKey ); + scError = SymCryptDlkeyGenerate( SYMCRYPT_FLAG_DLKEY_DSA, pkSymCryptKey ); CHECK( scError == SYMCRYPT_NO_ERROR, "?" ); pKE->pKeysDsa[IMPSC_INDEX] = (PBYTE) pkSymCryptKey; + + // First Dh key + pkSymCryptKey = SymCryptDlkeyAllocate( pDlgroup ); + CHECK( pkSymCryptKey != NULL, "?" ); + + scError = SymCryptDlkeyGenerate( SYMCRYPT_FLAG_DLKEY_DH | SYMCRYPT_FLAG_KEY_NO_FIPS, pkSymCryptKey ); + CHECK( scError == SYMCRYPT_NO_ERROR, "?" ); + pKE->pKeysDhA[IMPSC_INDEX] = (PBYTE) pkSymCryptKey; // Second Dh key pkSymCryptKey = SymCryptDlkeyAllocate( pDlgroup ); CHECK( pkSymCryptKey != NULL, "?" ); - scError = SymCryptDlkeyGenerate( 0, pkSymCryptKey ); + scError = SymCryptDlkeyGenerate( SYMCRYPT_FLAG_DLKEY_DH | SYMCRYPT_FLAG_KEY_NO_FIPS, pkSymCryptKey ); CHECK( scError == SYMCRYPT_NO_ERROR, "?" ); pKE->pKeysDhB[IMPSC_INDEX] = (PBYTE) pkSymCryptKey; diff --git a/unittest/lib/testDsa.cpp b/unittest/lib/testDsa.cpp index a17c8db..a3830e2 100644 --- a/unittest/lib/testDsa.cpp +++ b/unittest/lib/testDsa.cpp @@ -169,7 +169,7 @@ createKatFileSingleDsa( FILE * f, PCDLGROUP_TESTBLOB pBlob ) PSYMCRYPT_DLKEY pKey = SymCryptDlkeyAllocate( pGroup ); - scError = SymCryptDlkeyGenerate( SYMCRYPT_FLAG_DLKEY_SELFTEST_DSA, pKey ); + scError = SymCryptDlkeyGenerate( SYMCRYPT_FLAG_DLKEY_DSA, pKey ); CHECK( scError == SYMCRYPT_NO_ERROR, "Error generating DL key" ); UINT32 cbPrivKey = SymCryptDlkeySizeofPrivateKey( pKey ); @@ -354,7 +354,7 @@ testDsatestGroups( DsaImplementation * pDsa, INT64 line ) PSYMCRYPT_DLKEY pKey = SymCryptDlkeyAllocate( pGroup ); CHECK( pKey != NULL, "Could not create keys" ); - scError = SymCryptDlkeyGenerate( SYMCRYPT_FLAG_DLKEY_SELFTEST_DSA, pKey ); + scError = SymCryptDlkeyGenerate( SYMCRYPT_FLAG_DLKEY_DSA, pKey ); CHECK( scError == SYMCRYPT_NO_ERROR, "Error generating key" ); DLKEY_TESTBLOB blob; diff --git a/unittest/lib/testEcc.cpp b/unittest/lib/testEcc.cpp index 1249524..78e4c56 100644 --- a/unittest/lib/testEcc.cpp +++ b/unittest/lib/testEcc.cpp @@ -479,9 +479,7 @@ testEccArithmetic( _In_ PCSYMCRYPT_ECURVE pCurve ) do { - scError = SymCryptEckeySetRandom( - SYMCRYPT_FLAG_KEY_RANGE_AND_PUBLIC_KEY_ORDER_VALIDATION | SYMCRYPT_FLAG_ECKEY_SELFTEST_ECDSA | SYMCRYPT_FLAG_ECKEY_SELFTEST_ECDH, - pkKey1 ); + scError = SymCryptEckeySetRandom( SYMCRYPT_FLAG_ECKEY_ECDSA | SYMCRYPT_FLAG_ECKEY_ECDH, pkKey1 ); CHECK( scError == SYMCRYPT_NO_ERROR, "Set random key failed" ); CHECK( SymCryptEcpointOnCurve( pCurve, pkKey1->poPublicKey, pbScratch, cbScratch), "Public key not on curve"); @@ -900,7 +898,7 @@ testEcdsaVerify( cbQx + cbQy, SYMCRYPT_NUMBER_FORMAT_MSB_FIRST, SYMCRYPT_ECPOINT_FORMAT_XY, - SYMCRYPT_FLAG_KEY_RANGE_AND_PUBLIC_KEY_ORDER_VALIDATION | SYMCRYPT_FLAG_ECKEY_SELFTEST_ECDSA, + SYMCRYPT_FLAG_ECKEY_ECDSA, pkPublic ); CHECK3( scError == SYMCRYPT_NO_ERROR, "Public key set value failed for ECDSA record at line %lld", line ); @@ -1003,7 +1001,7 @@ testEcdsaSign( 0, SYMCRYPT_NUMBER_FORMAT_MSB_FIRST, SYMCRYPT_ECPOINT_FORMAT_XY, - SYMCRYPT_FLAG_KEY_RANGE_VALIDATION | SYMCRYPT_FLAG_ECKEY_SELFTEST_ECDSA, + SYMCRYPT_FLAG_ECKEY_ECDSA, pkPrivate ); CHECK3( scError == SYMCRYPT_NO_ERROR, "Private key set value failed for ECDSA record at line %lld", line ); @@ -1080,7 +1078,7 @@ testEcdh( PCBYTE pbOptPublicKey = NULL; SIZE_T cbOptPublicKey = 0; BYTE randByte = g_rng.byte(); - UINT32 flags = SYMCRYPT_FLAG_ECKEY_SELFTEST_ECDH; + UINT32 flags = SYMCRYPT_FLAG_ECKEY_ECDH; // Allocate the keys pkPrivate = SymCryptEckeyAllocate( pCurve ); @@ -1090,26 +1088,15 @@ testEcdh( // Set the private and public key for party A // Randomize flags and whether we provide the public key to exercise more codepaths - if (randByte & 1) + if (randByte & 0x1) { - flags |= SYMCRYPT_FLAG_KEY_KEYPAIR_REGENERATION_VALIDATION; + flags |= SYMCRYPT_FLAG_KEY_NO_FIPS; } - switch((randByte >> 1) & 0x3) + if (randByte & 0x2) { - case 0: - break; - case 1: - flags |= SYMCRYPT_FLAG_KEY_MINIMAL_VALIDATION; - break; - case 2: - flags |= SYMCRYPT_FLAG_KEY_RANGE_VALIDATION; - break; - case 3: - default: - flags |= SYMCRYPT_FLAG_KEY_RANGE_AND_PUBLIC_KEY_ORDER_VALIDATION; - break; + flags |= SYMCRYPT_FLAG_ECKEY_ECDSA; } - if (randByte & 0x8) + if (randByte & 0x4) { memcpy(pbPublicKey, pbQxa, cbQxa); memcpy(pbPublicKey+cbQxa, pbQya, cbQya); @@ -1145,26 +1132,18 @@ testEcdh( // Set the public key for party B // Randomize flags to exercise more codepaths - flags = 0; + flags = SYMCRYPT_FLAG_ECKEY_ECDH; if (randByte & 0x10) { - // Should do nothing as we won't provide private key, but doesn't hurt to check! - flags |= SYMCRYPT_FLAG_KEY_KEYPAIR_REGENERATION_VALIDATION; + flags |= SYMCRYPT_FLAG_KEY_NO_FIPS; } - switch((randByte >> 5) & 0x3) + if ((randByte & 0x20) && (flags & SYMCRYPT_FLAG_KEY_NO_FIPS)) { - case 0: - break; - case 1: - flags |= SYMCRYPT_FLAG_KEY_MINIMAL_VALIDATION; - break; - case 2: - flags |= SYMCRYPT_FLAG_KEY_RANGE_VALIDATION; - break; - case 3: - default: - flags |= SYMCRYPT_FLAG_KEY_RANGE_AND_PUBLIC_KEY_ORDER_VALIDATION; - break; + flags |= SYMCRYPT_FLAG_KEY_MINIMAL_VALIDATION; + } + if (randByte & 0x40) + { + flags |= SYMCRYPT_FLAG_ECKEY_ECDSA; } memcpy(pbPublicKey, pbQxb, cbQxb); memcpy(pbPublicKey+cbQxb, pbQyb, cbQyb); diff --git a/unittest/lib/testMontgomery.cpp b/unittest/lib/testMontgomery.cpp index ba620f8..665ae98 100644 --- a/unittest/lib/testMontgomery.cpp +++ b/unittest/lib/testMontgomery.cpp @@ -226,7 +226,7 @@ testMontgomery(PSYMCRYPT_ECURVE pCurve) do { - scError = SymCryptEckeySetRandom( 0, pkKey1 ); + scError = SymCryptEckeySetRandom( SYMCRYPT_FLAG_ECKEY_ECDH, pkKey1 ); CHECK( scError == SYMCRYPT_NO_ERROR, "Set random key failed" ); scError = SymCryptEcpointScalarMul( pCurve, pkKey1->piPrivateKey, NULL, 0, poSrc, pbScratch, cbScratch ); diff --git a/unittest/lib/testRsaSign.cpp b/unittest/lib/testRsaSign.cpp index 1ea2aa3..8dcb7e5 100644 --- a/unittest/lib/testRsaSign.cpp +++ b/unittest/lib/testRsaSign.cpp @@ -197,7 +197,7 @@ rsaTestKeysAddOne( UINT32 bitSize ) u64PubExp = 65537; } - scError = SymCryptRsakeyGenerate( pKey, &u64PubExp, 1, SYMCRYPT_FLAG_RSAKEY_SELFTEST ); + scError = SymCryptRsakeyGenerate( pKey, &u64PubExp, 1, SYMCRYPT_FLAG_RSAKEY_SIGN | SYMCRYPT_FLAG_RSAKEY_ENCRYPT ); CHECK( scError == SYMCRYPT_NO_ERROR, "?" ); PRSAKEY_TESTBLOB pBlob = &g_RsaTestKeyBlobs[ g_nRsaTestKeyBlobs++ ]; @@ -324,7 +324,7 @@ rsaKeyFromTestBlob( PCRSAKEY_TESTBLOB pBlob ) &pBlob->u64PubExp, 1, ppPrime, cbPrime, 2, SYMCRYPT_NUMBER_FORMAT_MSB_FIRST, - SYMCRYPT_FLAG_RSAKEY_SELFTEST, + SYMCRYPT_FLAG_RSAKEY_SIGN | SYMCRYPT_FLAG_RSAKEY_ENCRYPT, pKey ); CHECK( scError == SYMCRYPT_NO_ERROR, "?" );