SECStatus ectest_validate_point(ECDH_BAD *bad) { ECParams ecParams = { 0 }; SECItem point = { siBuffer, NULL, 0 }; SECStatus rv = SECFailure; PLArenaPool *arena = NULL; rv = init_params(&ecParams, bad->curve, &arena, bad->fieldType); if (rv != SECSuccess) { return rv; } SECU_HexString2SECItem(arena, &point, bad->point); rv = EC_ValidatePublicKey(&ecParams, &point); PORT_FreeArena(arena, PR_FALSE); return rv; }
/* ** Performs an ECDH key derivation by computing the scalar point ** multiplication of privateValue and publicValue (with or without the ** cofactor) and returns the x-coordinate of the resulting elliptic ** curve point in derived secret. If successful, derivedSecret->data ** is set to the address of the newly allocated buffer containing the ** derived secret, and derivedSecret->len is the size of the secret ** produced. It is the caller's responsibility to free the allocated ** buffer containing the derived secret. */ SECStatus ECDH_Derive(SECItem *publicValue, ECParams *ecParams, SECItem *privateValue, PRBool withCofactor, SECItem *derivedSecret, int kmflag) { SECStatus rv = SECFailure; unsigned int len = 0; SECItem pointQ = {siBuffer, NULL, 0}; mp_int k; /* to hold the private value */ mp_int cofactor; mp_err err = MP_OKAY; #if EC_DEBUG int i; #endif if (!publicValue || !ecParams || !privateValue || !derivedSecret) { PORT_SetError(SEC_ERROR_INVALID_ARGS); return SECFailure; } if (EC_ValidatePublicKey(ecParams, publicValue, kmflag) != SECSuccess) { return SECFailure; } memset(derivedSecret, 0, sizeof *derivedSecret); len = (ecParams->fieldID.size + 7) >> 3; pointQ.len = 2*len + 1; if ((pointQ.data = PORT_Alloc(2*len + 1, kmflag)) == NULL) goto cleanup; MP_DIGITS(&k) = 0; CHECK_MPI_OK( mp_init(&k, kmflag) ); CHECK_MPI_OK( mp_read_unsigned_octets(&k, privateValue->data, (mp_size) privateValue->len) ); if (withCofactor && (ecParams->cofactor != 1)) { /* multiply k with the cofactor */ MP_DIGITS(&cofactor) = 0; CHECK_MPI_OK( mp_init(&cofactor, kmflag) ); mp_set(&cofactor, ecParams->cofactor); CHECK_MPI_OK( mp_mul(&k, &cofactor, &k) ); } /* Multiply our private key and peer's public point */ if ((ec_points_mul(ecParams, NULL, &k, publicValue, &pointQ, kmflag) != SECSuccess) || ec_point_at_infinity(&pointQ)) goto cleanup; /* Allocate memory for the derived secret and copy * the x co-ordinate of pointQ into it. */ SECITEM_AllocItem(NULL, derivedSecret, len, kmflag); memcpy(derivedSecret->data, pointQ.data + 1, len); rv = SECSuccess; #if EC_DEBUG printf("derived_secret:\n"); for (i = 0; i < derivedSecret->len; i++) printf("%02x:", derivedSecret->data[i]); printf("\n"); #endif cleanup: mp_clear(&k); if (pointQ.data) { PORT_ZFree(pointQ.data, 2*len + 1); } return rv; }
SECStatus ectest_ecdh_kat(ECDH_KAT *kat) { ECCurveName curve = kat->curve; ECParams ecParams = { 0 }; ECPrivateKey *ecPriv = NULL; SECItem theirKey = { siBuffer, NULL, 0 }; SECStatus rv = SECFailure; PLArenaPool *arena = NULL; SECItem seed = { siBuffer, NULL, 0 }; SECItem answer = { siBuffer, NULL, 0 }; SECItem answer2 = { siBuffer, NULL, 0 }; SECItem derived = { siBuffer, NULL, 0 }; SECItem ecEncodedParams = { siBuffer, NULL, 0 }; int i; arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE); if (!arena) { return SECFailure; } rv = SECU_ecName2params(curve, &ecEncodedParams); if (rv != SECSuccess) { goto cleanup; } EC_FillParams(arena, &ecEncodedParams, &ecParams); if (kat->our_pubhex) { SECU_HexString2SECItem(arena, &answer, kat->our_pubhex); } SECU_HexString2SECItem(arena, &seed, kat->privhex); rv = EC_NewKeyFromSeed(&ecParams, &ecPriv, seed.data, seed.len); if (rv != SECSuccess) { rv = SECFailure; goto cleanup; } if (kat->our_pubhex) { if (SECITEM_CompareItem(&answer, &ecPriv->publicValue) != SECEqual) { rv = SECFailure; goto cleanup; } } SECU_HexString2SECItem(arena, &theirKey, kat->their_pubhex); SECU_HexString2SECItem(arena, &answer2, kat->common_key); rv = EC_ValidatePublicKey(&ecParams, &theirKey); if (rv != SECSuccess) { printf("EC_ValidatePublicKey failed\n"); goto cleanup; } for (i = 0; i < kat->iterations; ++i) { rv = ECDH_Derive(&theirKey, &ecParams, &ecPriv->privateValue, PR_TRUE, &derived); if (rv != SECSuccess) { rv = SECFailure; goto cleanup; } rv = SECITEM_CopyItem(ecParams.arena, &theirKey, &ecPriv->privateValue); if (rv != SECSuccess) { goto cleanup; } rv = SECITEM_CopyItem(ecParams.arena, &ecPriv->privateValue, &derived); if (rv != SECSuccess) { goto cleanup; } SECITEM_FreeItem(&derived, PR_FALSE); } if (SECITEM_CompareItem(&answer2, &ecPriv->privateValue) != SECEqual) { printf("expected: "); printBuf(&answer2); printf("derived: "); printBuf(&ecPriv->privateValue); rv = SECFailure; goto cleanup; } cleanup: SECITEM_FreeItem(&ecEncodedParams, PR_FALSE); PORT_FreeArena(arena, PR_FALSE); if (ecPriv) { PORT_FreeArena(ecPriv->ecParams.arena, PR_FALSE); } if (derived.data) { SECITEM_FreeItem(&derived, PR_FALSE); } return rv; }
static int fips_ecdsa_sign_verify(uint8_t *encodedParams, unsigned int encodedParamsLen, uint8_t *knownSignature, unsigned int knownSignatureLen) { /* ECDSA Known Seed info for curves nistp256 */ static uint8_t ecdsa_Known_Seed[] = { 0x6a, 0x9b, 0xf6, 0xf7, 0xce, 0xed, 0x79, 0x11, 0xf0, 0xc7, 0xc8, 0x9a, 0xa5, 0xd1, 0x57, 0xb1, 0x7b, 0x5a, 0x3b, 0x76, 0x4e, 0x7b, 0x7c, 0xbc, 0xf2, 0x76, 0x1c, 0x1c, 0x7f, 0xc5, 0x53, 0x2f }; static uint8_t msg[] = { "Sun Microsystems Solaris is awesome!" }; unsigned char sha1[SHA1_DIGEST_SIZE]; /* SHA-1 hash (160 bits) */ unsigned char sig[2*MAX_ECKEY_LEN]; SECItem signature, digest; SECItem encodedparams; ECParams *ecparams = NULL; ECPrivateKey *ecdsa_private_key = NULL; ECPublicKey ecdsa_public_key; SECStatus ecdsaStatus = SECSuccess; SHA1_CTX *sha1_context = NULL; int rv = CKR_DEVICE_ERROR; (void) memset(&ecdsa_public_key, 0, sizeof (ECPublicKey)); /* construct the ECDSA private/public key pair */ encodedparams.type = siBuffer; encodedparams.data = (unsigned char *) encodedParams; encodedparams.len = encodedParamsLen; if (EC_DecodeParams(&encodedparams, &ecparams, 0) != SECSuccess) { return (CKR_ARGUMENTS_BAD); } /* * Generates a new EC key pair. The private key is a supplied * random value (in seed) and the public key is the result of * performing a scalar point multiplication of that value with * the curve's base point. */ ecdsaStatus = ec_NewKey(ecparams, &ecdsa_private_key, ecdsa_Known_Seed, sizeof (ecdsa_Known_Seed), 0); if (ecdsaStatus != SECSuccess) { goto loser; } /* construct public key from private key. */ ecdsaStatus = EC_CopyParams(ecdsa_private_key->ecParams.arena, &ecdsa_public_key.ecParams, &ecdsa_private_key->ecParams); if (ecdsaStatus != SECSuccess) { goto loser; } ecdsa_public_key.publicValue = ecdsa_private_key->publicValue; /* validate public key value */ ecdsaStatus = EC_ValidatePublicKey(&ecdsa_public_key.ecParams, &ecdsa_public_key.publicValue, 0); if (ecdsaStatus != SECSuccess) { goto loser; } /* validate public key value */ ecdsaStatus = EC_ValidatePublicKey(&ecdsa_private_key->ecParams, &ecdsa_private_key->publicValue, 0); if (ecdsaStatus != SECSuccess) { goto loser; } /* * ECDSA Known Answer Signature Test. */ #ifdef _KERNEL if ((sha1_context = kmem_zalloc(sizeof (SHA1_CTX), KM_SLEEP)) == NULL) { #else if ((sha1_context = malloc(sizeof (SHA1_CTX))) == NULL) { #endif ecdsaStatus = SECFailure; rv = CKR_HOST_MEMORY; goto loser; } SHA1Init(sha1_context); #ifdef __sparcv9 SHA1Update(sha1_context, msg, (uint_t)sizeof (msg)); #else /* !__sparcv9 */ SHA1Update(sha1_context, msg, sizeof (msg)); #endif /* __sparcv9 */ SHA1Final(sha1, sha1_context); digest.type = siBuffer; digest.data = sha1; digest.len = SHA1_DIGEST_SIZE; (void) memset(sig, 0, sizeof (sig)); signature.type = siBuffer; signature.data = sig; signature.len = sizeof (sig); ecdsaStatus = ECDSA_SignDigestWithSeed(ecdsa_private_key, &signature, &digest, ecdsa_Known_Seed, sizeof (ecdsa_Known_Seed), 0); if (ecdsaStatus != SECSuccess) { goto loser; } if ((signature.len != knownSignatureLen) || (memcmp(signature.data, knownSignature, knownSignatureLen) != 0)) { ecdsaStatus = SECFailure; goto loser; } /* * ECDSA Known Answer Verification Test. */ ecdsaStatus = ECDSA_VerifyDigest(&ecdsa_public_key, &signature, &digest, 0); loser: if (ecdsa_public_key.publicValue.data != NULL) free_ecpubkey(&ecdsa_public_key); if (ecdsa_private_key != NULL) free_ecprivkey(ecdsa_private_key); free_ecparams(ecparams, B_TRUE); if (sha1_context != NULL) #ifdef _KERNEL kmem_free(sha1_context, sizeof (SHA1_CTX)); #else free(sha1_context); #endif if (ecdsaStatus != SECSuccess) { return (rv); } return (CKR_OK); } int fips_ecdsa_post() { /* ECDSA Known curve nistp256 == SEC_OID_SECG_EC_SECP256R1 params */ static uint8_t ecdsa_known_P256_EncodedParams[] = { 0x06, 0x08, 0x2a, 0x86, 0x48, 0xce, 0x3d, 0x03, 0x01, 0x07 }; static uint8_t ecdsa_known_P256_signature[] = { 0x07, 0xb1, 0xcb, 0x57, 0x20, 0xa7, 0x10, 0xd6, 0x9d, 0x37, 0x4b, 0x1c, 0xdc, 0x35, 0x90, 0xff, 0x1a, 0x2d, 0x98, 0x95, 0x1b, 0x2f, 0xeb, 0x7f, 0xbb, 0x81, 0xca, 0xc0, 0x69, 0x75, 0xea, 0xc5, 0x2b, 0xdb, 0x86, 0x76, 0xe7, 0x32, 0xba, 0x13, 0x03, 0x7f, 0x7f, 0x92, 0x77, 0xd8, 0x35, 0xfe, 0x99, 0xb4, 0xb7, 0x85, 0x5a, 0xfb, 0xfb, 0xce, 0x5d, 0x0e, 0xbc, 0x01, 0xfa, 0x44, 0x97, 0x7e }; int rv; /* ECDSA GF(p) prime field curve test */ rv = fips_ecdsa_sign_verify(ecdsa_known_P256_EncodedParams, sizeof (ecdsa_known_P256_EncodedParams), ecdsa_known_P256_signature, sizeof (ecdsa_known_P256_signature)); if (rv != CKR_OK) { return (CKR_DEVICE_ERROR); } return (CKR_OK); } static void free_ecparams(ECParams *params, boolean_t freeit) { SECITEM_FreeItem(¶ms->fieldID.u.prime, B_FALSE); SECITEM_FreeItem(¶ms->curve.a, B_FALSE); SECITEM_FreeItem(¶ms->curve.b, B_FALSE); SECITEM_FreeItem(¶ms->curve.seed, B_FALSE); SECITEM_FreeItem(¶ms->base, B_FALSE); SECITEM_FreeItem(¶ms->order, B_FALSE); SECITEM_FreeItem(¶ms->DEREncoding, B_FALSE); SECITEM_FreeItem(¶ms->curveOID, B_FALSE); if (freeit) #ifdef _KERNEL kmem_free(params, sizeof (ECParams)); #else free(params); #endif }