blob: cffe55cd642a4aa3a2af4a4e05a8770be2337d23 [file] [log] [blame]
/**
* @file ex_sst_kp.c
* @author NXP Semiconductors
* @version 1.0
* @par License
*
* Copyright 2016 NXP
* SPDX-License-Identifier: Apache-2.0
*
* @par Description
* Example invocation of ECC key pair secure storage specific functionality of the A71CH
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <assert.h>
#include "a71ch_ex.h"
#include "a71_debug.h"
#include "sm_types.h"
#include "sm_apdu.h"
#include "ax_util.h"
#include "tst_sm_util.h"
#include "tst_a71ch_util.h"
#include "tstHostCrypto.h"
#include "HostCryptoAPI.h"
/**
* Demonstrate storage of key pairs:
* - ::exSstKeyPair
*
*/
U8 exSstKp()
{
U8 result = 1;
PRINTF( "\r\n-----------\r\nStart exSstKp()\r\n------------\r\n");
DEV_ClearChannelState();
// No channel encryption
result &= exSstKeyPair(INIT_MODE_RESET);
// With channel encryption
result &= exSstKeyPair(INIT_MODE_RESET_DO_SCP03);
// overall result
PRINTF( "\r\n-----------\r\nEnd exSstKp(), result = %s\r\n------------\r\n", ((result == 1)? "OK": "FAILED"));
return result;
}
/**
* Demonstrate
* - setting/getting/erasing/freezing of key pairs
* - demonstrate key can be used through sign operations
*
* @param[in] initMode Visit the documentation of ::a71chInitModule for
* more information on this parameter
* @param[in] appletVersion The applet version
*
* @return 1 if passed.
*/
U8 exSstKeyPair(U8 initMode)
{
U8 result = 1;
U16 err;
int i;
HLSE_RET_CODE retcode;
ECCCurve_t eccCurve = ECCCurve_NIST_P256;
EC_KEY *eccKeyTls[A71CH_KEY_PAIR_MAX] = {0};
eccKeyComponents_t eccKcTls[A71CH_KEY_PAIR_MAX] = {0};
EC_KEY *eccKeyAlt = NULL;
eccKeyComponents_t eccKcAlt;
U8 fetchedPubKey[65];
U16 fetchedPubKeyLen = sizeof(fetchedPubKey);
U8 hashSha256[32];
U16 hashSha256Len = sizeof(hashSha256);
U8 signature[128];
U16 signatureLen = sizeof(signature);
HLSE_MECHANISM_INFO mechInfo;
// const U16 expectedPubKeyLen = 65;
const U16 expectedPrivKeyLen = 32;
SST_Index_t kpIndex;
PRINTF("\r\n-----------\r\nStart exSstKeyPair(%s)\r\n------------\r\n", getInitModeAsString(initMode));
// Initialize the A71CH (Debug mode restrictions may apply)
result &= a71chInitModule(initMode);
// Start by creating, inserting and checking keys
for (i=0; i<A71CH_KEY_PAIR_MAX; i++)
{
eccKeyTls[i] = NULL;
err = HOSTCRYPTO_GenerateEccKey(eccCurve, &eccKeyTls[i]);
result &= AX_CHECK_SW(err, SW_OK, "err");
err = HOSTCRYPTO_GetPublicKey(eccKeyTls[i], eccKcTls[i].pub, &(eccKcTls[i].pubLen), (64 << 1)+1);
result &= AX_CHECK_SW(err, SW_OK, "err");
err = HOSTCRYPTO_GetPrivateKey(eccKeyTls[i], eccKcTls[i].priv, &(eccKcTls[i].privLen), 64);
result &= AX_CHECK_SW(err, SW_OK, "err");
eccKcTls[i].bits = expectedPrivKeyLen << 3;
eccKcTls[i].curve = eccCurve;
PRINTF( "\r\nA71_SetEccKeyPair(0x%02X)\r\n", (SST_Index_t)i);
err = A71_SetEccKeyPair((SST_Index_t) i, eccKcTls[i].pub, eccKcTls[i].pubLen,
eccKcTls[i].priv, eccKcTls[i].privLen);
result &= AX_CHECK_SW(err, SW_OK, "err");
}
// Read out and verify public key
for (i=0; i<A71CH_KEY_PAIR_MAX; i++)
{
PRINTF( "\r\nA71_GetPublicKeyEccKeyPair (0x%02X)\r\n", (SST_Index_t)i);
fetchedPubKeyLen = sizeof(fetchedPubKey);
err = A71_GetPublicKeyEccKeyPair ((SST_Index_t) i, fetchedPubKey, &fetchedPubKeyLen);
result &= AX_CHECK_SW(err, SW_OK, "err");
// Compare with reference value
result &= AX_COMPARE_BYTE_ARRAY("eccKcTls[i].pub", eccKcTls[i].pub, eccKcTls[i].pubLen,
"fetchedPubKey", fetchedPubKey, fetchedPubKeyLen, AX_COLON_32);
}
// Create alternative key
err = HOSTCRYPTO_GenerateEccKey(eccCurve, &eccKeyAlt);
result &= AX_CHECK_SW(err, SW_OK, "err");
err = HOSTCRYPTO_GetPublicKey(eccKeyAlt, eccKcAlt.pub, &(eccKcAlt.pubLen), (64 << 1)+1);
result &= AX_CHECK_SW(err, SW_OK, "err");
err = HOSTCRYPTO_GetPrivateKey(eccKeyAlt, eccKcAlt.priv, &(eccKcAlt.privLen), 64);
result &= AX_CHECK_SW(err, SW_OK, "err");
eccKcAlt.bits = expectedPrivKeyLen << 3;
eccKcAlt.curve = eccCurve;
// Fill up the hash with some reference data
hashSha256Len = sizeof(hashSha256);
for (i=0; i<hashSha256Len; i++) { hashSha256[i] = (U8)i; }
// Sign a hash of correct length on the host and do the verification on the A71CH
for (i=0; i<A71CH_KEY_PAIR_MAX; i++)
{
signatureLen = sizeof(signature);
PRINTF("\r\nA71_EccSign(0x%02X)\r\n", (SST_Index_t)i);
err = A71_EccSign((SST_Index_t)i, hashSha256, hashSha256Len, signature, &signatureLen);
result &= AX_CHECK_SW(err, SW_OK, "err");
// Verify ... on opposite platform
PRINTF("\r\n(Host)ECDSA_verify API with eccKeyTls[i] (verify signature created on A71CH).\r\n");
memset(&mechInfo, 0, sizeof(mechInfo));
mechInfo.mechanism = HLSE_ECDSA_VERIFY;
retcode = HLCRYPT_Verify(&mechInfo,(U8 *)eccKeyTls[i],0,hashSha256,hashSha256Len,signature,signatureLen);
if (retcode == HLSE_SW_OK)
{
PRINTF("Verification OK for eccKeyTls[i].\r\n");
}
else
{
PRINTF("Return value: %d, Verification Not OK for eccKeyTls[i]. Test Failed!\r\n", retcode);
result &= 0;
break;
}
}
// Erase the keypair at index 0 & verify the value is no longer readable
// ** Erase **
kpIndex = A71CH_KEY_PAIR_0;
PRINTF("\r\nA71_EraseEccKeyPair(index=0x%02X)\r\n", kpIndex);
err = A71_EraseEccKeyPair(kpIndex);
result &= AX_CHECK_SW(err, SW_OK, "err");
// ** Check whether erase was effective **
PRINTF("\r\nA71_GetPublicKeyEccKeyPair (index=0x%02X)\r\n", kpIndex);
fetchedPubKeyLen = sizeof(fetchedPubKey);
err = A71_GetPublicKeyEccKeyPair ((SST_Index_t)kpIndex, fetchedPubKey, &fetchedPubKeyLen);
result &= AX_CHECK_SW(err, SW_CONDITIONS_NOT_SATISFIED, "Get Public Ecc Key was supposed to fail");
// Fill in the original keypair again
kpIndex = A71CH_KEY_PAIR_0;
PRINTF( "\r\nA71_SetEccKeyPair(0x%02X)\r\n", kpIndex);
err = A71_SetEccKeyPair((SST_Index_t)kpIndex, eccKcTls[kpIndex].pub, eccKcTls[kpIndex].pubLen,
eccKcTls[kpIndex].priv, eccKcTls[kpIndex].privLen);
result &= AX_CHECK_SW(err, SW_OK, "err");
// Now Lock the first half of the slots for update
for (kpIndex=0; kpIndex<A71CH_KEY_PAIR_MAX>>1; kpIndex++)
{
PRINTF( "\r\nA71_FreezeEccKeyPair(0x%02x)\r\n", kpIndex);
err = A71_FreezeEccKeyPair((SST_Index_t)kpIndex);
result &= AX_CHECK_SW(err, SW_OK, "err");
}
// Now fetch and compare the values with the reference values
for (kpIndex=0; kpIndex<A71CH_KEY_PAIR_MAX; kpIndex++)
{
PRINTF( "\r\nA71_GetPublicKeyEccKeyPair (0x%02x)\r\n", kpIndex);
fetchedPubKeyLen = sizeof(fetchedPubKey);
err = A71_GetPublicKeyEccKeyPair ((SST_Index_t)kpIndex, fetchedPubKey, &fetchedPubKeyLen);
result &= AX_CHECK_SW(err, SW_OK, "err");
result &= AX_COMPARE_BYTE_ARRAY("eccKcTls[kpIndex]", eccKcTls[kpIndex].pub, eccKcTls[kpIndex].pubLen,
"fetchedKey", fetchedPubKey, fetchedPubKeyLen, AX_COLON_32);
}
// Check whether the locked half (i.e. first half) is truly 'frozen' ....
for (kpIndex=0; kpIndex<A71CH_KEY_PAIR_MAX>>1; kpIndex++)
{
PRINTF( "\r\nA71_SetEccKeyPair(0x%02x)\r\n", kpIndex);
err = A71_SetEccKeyPair((SST_Index_t)kpIndex, eccKcAlt.pub, eccKcAlt.pubLen, eccKcAlt.priv, eccKcAlt.privLen);
result &= AX_CHECK_SW(err, SW_COMMAND_NOT_ALLOWED, "Expected to fail, frozen credential cannot be overwritten");
}
// Overwrite the second half
for (kpIndex=A71CH_KEY_PAIR_MAX>>1; kpIndex<A71CH_KEY_PAIR_MAX; kpIndex++)
{
PRINTF( "\r\nA71_SetEccKeyPair(0x%02x)\r\n", kpIndex);
err = A71_SetEccKeyPair((SST_Index_t)kpIndex, eccKcAlt.pub, eccKcAlt.pubLen, eccKcAlt.priv, eccKcAlt.privLen);
result &= AX_CHECK_SW(err, SW_OK, "err");
}
// Check that the second half was overwritten, by signing a hash of correct length on the A71CH and do the verification on the Host
for (kpIndex=A71CH_KEY_PAIR_MAX>>1; kpIndex<A71CH_KEY_PAIR_MAX; kpIndex++)
{
signatureLen = sizeof(signature);
PRINTF("\r\nA71_EccSign(0x%02X)\r\n", (SST_Index_t)kpIndex);
err = A71_EccSign((SST_Index_t)kpIndex, hashSha256, hashSha256Len, signature, &signatureLen);
result &= AX_CHECK_SW(err, SW_OK, "err");
// Verify ... on opposite platform
PRINTF("\r\n(Host)ECDSA_verify API with eccKeyAlt (verify signature created on A71CH).\r\n");
memset(&mechInfo, 0, sizeof(mechInfo));
mechInfo.mechanism = HLSE_ECDSA_VERIFY;
retcode = HLCRYPT_Verify(&mechInfo,(U8 *)eccKeyAlt,0,hashSha256,hashSha256Len,signature,signatureLen);
if (retcode == HLSE_SW_OK)
{
PRINTF("Verification OK for eccKeyAlt.\r\n");
}
else
{
PRINTF("Return value: %d, Verification Not OK for eccKeyAlt. Test Failed!\r\n", retcode);
result &= 0;
break;
}
}
// Put back the original (reference) values in the second half
for (kpIndex=A71CH_KEY_PAIR_MAX>>1; kpIndex<A71CH_KEY_PAIR_MAX; kpIndex++)
{
PRINTF( "\r\nA71_SetEccKeyPair(0x%02X)\r\n", (SST_Index_t)kpIndex);
err = A71_SetEccKeyPair((SST_Index_t) kpIndex, eccKcTls[kpIndex].pub, eccKcTls[kpIndex].pubLen,
eccKcTls[kpIndex].priv, eccKcTls[kpIndex].privLen);
result &= AX_CHECK_SW(err, SW_OK, "err");
}
// Check all keys are still fine by doing a sign/verify operation
for (i=0; i<A71CH_KEY_PAIR_MAX; i++)
{
signatureLen = sizeof(signature);
PRINTF("\r\nA71_EccSign(0x%02X)\r\n", (SST_Index_t)i);
err = A71_EccSign((SST_Index_t)i, hashSha256, hashSha256Len, signature, &signatureLen);
result &= AX_CHECK_SW(err, SW_OK, "err");
// Verify ... on opposite platform
PRINTF("\r\n(Host)ECDSA_verify API with eccKeyTls[i] (verify signature created on A71CH).\r\n");
memset(&mechInfo, 0, sizeof(mechInfo));
mechInfo.mechanism = HLSE_ECDSA_VERIFY;
retcode = HLCRYPT_Verify(&mechInfo,(U8 *)eccKeyTls[i],0,hashSha256,hashSha256Len,signature,signatureLen);
if (retcode == HLSE_SW_OK)
{
PRINTF("Verification OK for eccKeyTls[i].\r\n");
}
else
{
PRINTF("Return value: %d, Verification Not OK for eccKeyTls[i]. Test Failed!\r\n", retcode);
result &= 0;
break;
}
}
// Now disable the plain insertion/reading out of Symmetric keys & Keypairs
PRINTF("\r\nA71_InjectLock()\r\n");
err = A71_InjectLock();
result &= AX_CHECK_SW(err, SW_OK, "err");
assert(result);
for (kpIndex=A71CH_KEY_PAIR_MAX>>1; kpIndex<A71CH_KEY_PAIR_MAX; kpIndex++)
{
PRINTF( "\r\nA71_SetEccKeyPair(0x%02X)\r\n", (SST_Index_t)kpIndex);
err = A71_SetEccKeyPair((SST_Index_t) kpIndex, eccKcTls[kpIndex].pub, eccKcTls[kpIndex].pubLen,
eccKcTls[kpIndex].priv, eccKcTls[kpIndex].privLen);
result &= AX_CHECK_SW(err, SW_COMMAND_NOT_ALLOWED, "err");
}
HOSTCRYPTO_FreeEccKey(&eccKeyAlt);
for (i=0; i<A71CH_KEY_PAIR_MAX; i++)
{
HOSTCRYPTO_FreeEccKey(&eccKeyTls[i]);
}
PRINTF( "\r\n-----------\r\nEnd exSstKeyPair(%s), result = %s\r\n------------\r\n", getInitModeAsString(initMode),
((result == 1)? "OK": "FAILED"));
return result;
}