/** * @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; }