blob: fff3b19cf074c982a6f6994a89df885cdce5dddd [file] [log] [blame]
/**
* @file axEccRefPem.c
* @author NXP Semiconductors
* @version 1.0
* @par License
*
* Copyright 2017 NXP
* SPDX-License-Identifier: Apache-2.0
*
* @par Description
* Creating a reference ECC pem file
*/
#include "axEccRefPem.h"
/**
* Create a PEM file containing a key reference.
*
* \note In case pubKeyLen is 0 , the value of the public key will be retrieved
from the attached secure element (based on \p storageClass and \p keyIndex parameters)
*
* @param[in] storageClass Interpretation depends on attached Secure Element. In case of A71CH, either ::A71CH_SSI_KEY_PAIR (key pair)
or ::A71CH_SSI_PUBLIC_KEY (public key)
* @param[in] keyIndex Interpretation depends on attached Secure Element. In case of A71CH index of Secure Storage Class item
* @param[in] filepath Filename/path of pem key file to be created.
* @param[in] pubKey Value of public key to be used in pem key file.
* @param[in] pubKeyLen Length of \p pubKey. In case a value of 0 is passed, the value of the public key will be retrieved
from the attached secure element.
*
* @retval ::SW_OK Upon successful execution
*/
U16 axEccWritePemRefKey(U8 storageClass, U8 keyIndex, const char* filepath, const U8 *pubKey, U16 pubKeyLen)
{
U16 sw;
EC_KEY *eckey;
BIO* out = NULL;
if ((eckey = EC_KEY_new()) == NULL)
{
printf("axEccWritePemRefKey: Unable to allocate memory for EC_KEY.\n");
return ERR_MEMORY;
}
sw = axEccGenRefKey(eckey, NID_X9_62_prime256v1, storageClass, keyIndex, pubKey, pubKeyLen);
if (sw != SW_OK)
{
printf("axEccWritePemRefKey: axEccGenRefKey() failed with status code 0x%04X.\n", sw);
EC_KEY_free(eckey);
return sw;
}
// ***** Write Key to file ******
out = BIO_new(BIO_s_file());
if (out == NULL)
{
printf("axEccWritePemRefKey: BIO error\n");
EC_KEY_free(eckey);
return ERR_FILE_SYSTEM;
}
if (BIO_write_filename(out, (void *)filepath) <= 0)
{
printf("axEccWritePemRefKey: out File error\n");
BIO_vfree(out);
EC_KEY_free(eckey);
return ERR_FILE_SYSTEM;
}
if (!PEM_write_bio_ECPrivateKey(out, eckey, NULL, NULL, 0, NULL, NULL))
{
printf("axEccWritePemRefKey: Unable to write Key\n");
BIO_vfree(out);
EC_KEY_free(eckey);
return ERR_FILE_SYSTEM;
}
BIO_vfree(out);
EC_KEY_free(eckey);
return SW_OK;
}
/**
* Create an EC_KEY structure containing a key reference.
*
* \note In case pubKeyLen is 0 , the value of the public key will be retrieved
from the attached secure element (based on \p storageClass and \p keyIndex parameters)
*
* @param[in,out] ecKey IN: Structure allocated by caller; OUT: Key structure containing a key reference (referring to a key stored
in a Secure Element).
* @param[in] nid OpenSSL specific number indicating an ECC curve
* @param[in] storageClass Interpretation depends on attached Secure Element. In case of A71CH, either ::A71CH_SSI_KEY_PAIR (key pair)
or ::A71CH_SSI_PUBLIC_KEY (public key)
* @param[in] keyIndex Interpretation depends on attached Secure Element. In case of A71CH index of Secure Storage Class item
* @param[in] pubKey Value of public key to be used in pem key file.
* @param[in] pubKeyLen Length of \p pubKey. In case a value of 0 is passed, the value of the public key will be retrieved
from the attached secure element.
*
* @retval ::SW_OK Upon successful execution
*/
U16 axEccGenRefKey(EC_KEY *eckey, int nid, U8 storageClass, U8 keyIndex, const U8 *pubKey, U16 pubKeyLen)
{
U16 sw;
U8 pubKeyBuf[1+2*96];
U16 pubKeyBufLen = sizeof(pubKeyBuf);
U8 privKey[96];
U16 privKeyLen;
EC_GROUP *group = NULL;
EC_POINT *pub_key = NULL;
int i;
int j = 0;
int key_field_len;
BIGNUM *X = NULL;
BIGNUM *Y = NULL;
BIGNUM *bn_priv = NULL;
if (pubKeyLen != 0)
{
memcpy(pubKeyBuf, pubKey, pubKeyLen);
pubKeyBufLen = pubKeyLen;
}
else
{
// printf("Fetch public key from Secure Module.\n");
pubKeyBufLen = sizeof(pubKeyBuf);
#ifdef TGT_A70CI
sw = SST_GetPublicKey(storageClass, pubKeyBuf, &pubKeyBufLen);
#elif defined(TGT_A70CM)
sw = SST_Get_ECCPublicKey(storageClass, keyIndex, pubKeyBuf, &pubKeyBufLen);
#else
if (storageClass == A71CH_SSI_PUBLIC_KEY)
{
sw = A71_GetEccPublicKey(keyIndex, pubKeyBuf, &pubKeyBufLen);
}
else if (storageClass == A71CH_SSI_KEY_PAIR)
{
sw = A71_GetPublicKeyEccKeyPair(keyIndex, pubKeyBuf, &pubKeyBufLen);
}
else
{
sw = ERR_API_ERROR;
}
#endif
if (sw != SW_OK)
{
printf("Fetching public key from Secure Element fails with status code: 0x%04X.\n", sw);
return sw;
}
}
/* create new ecdsa key (== EC_KEY) */
group = EC_GROUP_new_by_curve_name(nid);
if (group == NULL)
{
printf("Unable to allocate memory for EC_GROUP\n");
return ERR_MEMORY;
}
if (EC_KEY_set_group(eckey, group) == 0)
{
printf("Unable to set group for new key\n");
EC_GROUP_free(group);
return ERR_CRYPTO_ENGINE_FAILED;
}
key_field_len = (EC_GROUP_get_degree(group)+7)/8;
if (key_field_len < 160/8)
/* drop the curve */
{
printf("group degree > 160\n");
return ERR_GENERAL_ERROR;
}
/* create key */
if (!EC_KEY_generate_key(eckey))
{
printf("Unable to create ECC key\n");
return ERR_CRYPTO_ENGINE_FAILED;
}
// Set the ID on private key and insert public key
// BN_set_word(eckey->priv_key, keyIndex);
privKeyLen = (U16)BN_bn2bin( EC_KEY_get0_private_key(eckey), privKey);
privKey[privKeyLen-1] = keyIndex;
privKey[privKeyLen-2] = storageClass;
/* Insert Key ID in EC key (twice) */
for (j=0; j<2; j++)
{
for (i=3; i<7; i++)
{
privKey[privKeyLen-i-(j*4)] = (U8)(EMBSE_REFKEY_ID >> 8*(i-3));
// printf("%d.", privKeyLen-i-(j*4));
}
}
/* Replace the more significant byte of the private key with:
MSB : 0x10
Subsequent bytes : 0x00 */
privKey[0] = 0x10;
for (i=11; i<(privKeyLen); i++) { privKey[privKeyLen-i] = 0x00; }
// Insert reference key into private key space
bn_priv = BN_bin2bn(privKey, privKeyLen, NULL);
if (bn_priv == NULL)
{
printf("axEccGenRefKey: Failed to covert private key into BN.\n");
return ERR_CRYPTO_ENGINE_FAILED;
}
if (!EC_KEY_set_private_key(eckey, bn_priv))
{
printf("axEccGenRefKey: Failed to set private key.\n");
return ERR_CRYPTO_ENGINE_FAILED;
}
// Insert public key
if (pubKeyBufLen != (2*key_field_len+1))
{
printf("axEccGenRefKey: Error in public key length..\n");
return ERR_GENERAL_ERROR;
}
// Convert coord-X to BN
X = BN_bin2bn(&pubKeyBuf[1], key_field_len, NULL);
if (X == NULL)
{
printf("axEccGenRefKey: Bignum error X-coord SE public key.\n");
return ERR_CRYPTO_ENGINE_FAILED;
}
// Convert coord-Y to BN
Y = BN_bin2bn(&pubKeyBuf[1+key_field_len], key_field_len, NULL);
if (Y == NULL)
{
printf("axEccGenRefKey: Bignum error Y-coord SE public key.\n");
return ERR_CRYPTO_ENGINE_FAILED;
}
// Create a new point object
pub_key = EC_POINT_new(group);
if (!EC_POINT_set_affine_coordinates_GFp(group, pub_key, X, Y, NULL))
{
printf("axEccGenRefKey: Error setting EC_POINT.\n");
return ERR_CRYPTO_ENGINE_FAILED;
}
if (1 != EC_KEY_set_public_key(eckey, pub_key))
{
printf("axEccGenRefKey: Error inserting SE public Key.\n");
return ERR_CRYPTO_ENGINE_FAILED;
}
EC_KEY_set_asn1_flag(eckey, nid);
// Clean up memory
BN_free(X);
BN_free(Y);
BN_free(bn_priv);
EC_POINT_free(pub_key);
EC_GROUP_free(group);
return SW_OK;
}