/** | |
* @file ex_sst.c | |
* @author NXP Semiconductors | |
* @version 1.0 | |
* @par License | |
* | |
* Copyright 2016 NXP | |
* SPDX-License-Identifier: Apache-2.0 | |
* | |
* @par Description | |
* Example invocation of 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" | |
static U8 exSstSym(U8 initMode); | |
static U8 exSstPub(U8 initMode); | |
/** | |
* Demonstrate storage of symmetric keys: | |
* - ::exSstSym | |
* | |
* Demonstrate storage of public keys: | |
* - ::exSstPub | |
* | |
*/ | |
U8 exSst() | |
{ | |
U8 result = 1; | |
PRINTF( "\r\n-----------\r\nStart exSst()\r\n------------\r\n"); | |
DEV_ClearChannelState(); | |
// No channel encryption | |
// --------------------- | |
// - Sym keys | |
result &= exSstSym(INIT_MODE_RESET); | |
// - Public keys | |
result &= exSstPub(INIT_MODE_RESET); | |
// Using channel encryption | |
// ------------------------ | |
// - Sym keys | |
result &= exSstSym(INIT_MODE_RESET_DO_SCP03); | |
// - Public keys | |
result &= exSstPub(INIT_MODE_RESET_DO_SCP03); | |
// overall result | |
PRINTF( "\r\n-----------\r\nEnd exSst(), result = %s\r\n------------\r\n", ((result == 1)? "OK": "FAILED")); | |
return result; | |
} | |
/** | |
* Demonstrate | |
* - setting/erasing/freezing of symmetric keys | |
* - blocking injection of unwrapped symmetric keys | |
* | |
* @param[in] initMode Visit the documentation of ::a71chInitModule for | |
* more information on this parameter | |
* @param[in] appletVersion The applet version | |
* | |
* @return 1 if successful. | |
*/ | |
static U8 exSstSym(U8 initMode) | |
{ | |
U8 result = 1; | |
U16 err; | |
U8 info[] = {0x01, 0x02, 0x03, 0x04}; | |
U16 infoLen = sizeof(info); | |
U8 derivedData[32]; | |
U16 derivedDataLen = sizeof(derivedData); | |
const U8 aesRef[A71CH_SYM_KEY_MAX_B][16] = { | |
{0xDB, 0xFE, 0xE9, 0xE3, 0xB2, 0x76, 0x15, 0x4D, 0x67, 0xF9, 0xD8, 0x4C, 0xB9, 0x35, 0x54, 0x56}, | |
{0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f}, | |
{0xC0, 0x79, 0xEF, 0x82, 0xCD, 0xF7, 0x12, 0xF2, 0x87, 0x28, 0xFD, 0x18, 0xED, 0xD7, 0xF2, 0xE4}, | |
{0xAA, 0xBB, 0xCC, 0xDD, 0xEE, 0xFF, 0x06, 0x07, 0x08, 0x09, 0xA0, 0xB0, 0xB1, 0xB2, 0xB3, 0xB4}, | |
{0xDB, 0xFE, 0xE9, 0xE3, 0xB2, 0x76, 0x15, 0x4D, 0x67, 0xF9, 0xD8, 0x4C, 0xB9, 0x35, 0x54, 0x56}, // First 4 repeated | |
{0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f}, | |
{0xC0, 0x79, 0xEF, 0x82, 0xCD, 0xF7, 0x12, 0xF2, 0x87, 0x28, 0xFD, 0x18, 0xED, 0xD7, 0xF2, 0xE4}, | |
{0xAA, 0xBB, 0xCC, 0xDD, 0xEE, 0xFF, 0x06, 0x07, 0x08, 0x09, 0xA0, 0xB0, 0xB1, 0xB2, 0xB3, 0xB4} | |
}; | |
// aesRef keys wrapped with themselves | |
const U8 aesRefWrapped[A71CH_SYM_KEY_MAX_B][24] = { | |
{0x83, 0x49, 0x96, 0xFE, 0x38, 0xD4, 0xBC, 0x97, 0x85, 0xA2, 0xC5, 0x1F, 0x9F, 0xD6, 0x4E, 0xF3, | |
0x9C, 0x2C, 0x5A, 0xE0, 0xF2, 0x82, 0x02, 0x3F}, | |
{0x93, 0x5A, 0x3E, 0xB1, 0x01, 0xC3, 0x4A, 0xDD, 0x02, 0x5E, 0x17, 0x0B, 0x46, 0xFF, 0x0D, 0xB2, | |
0x3E, 0x5C, 0x2F, 0xAE, 0x8C, 0x8F, 0x83, 0x70}, | |
{0xD0, 0x7B, 0xEB, 0x03, 0xE3, 0xB0, 0x01, 0x4F, 0xD9, 0x7D, 0x42, 0x3B, 0x9E, 0x51, 0x23, 0xEE, | |
0x9A, 0x4B, 0x49, 0xAB, 0x9F, 0x10, 0xBE, 0x18}, | |
{0x2D, 0x36, 0x31, 0xEA, 0xF4, 0x69, 0xAD, 0xAF, 0x08, 0xE5, 0xB5, 0xEE, 0x97, 0xF5, 0x0A, 0x14, | |
0xC2, 0x6A, 0x6F, 0xE8, 0xDC, 0xBB, 0x39, 0xF3}, | |
{0x83, 0x49, 0x96, 0xFE, 0x38, 0xD4, 0xBC, 0x97, 0x85, 0xA2, 0xC5, 0x1F, 0x9F, 0xD6, 0x4E, 0xF3, // First 4 repeated | |
0x9C, 0x2C, 0x5A, 0xE0, 0xF2, 0x82, 0x02, 0x3F}, | |
{0x93, 0x5A, 0x3E, 0xB1, 0x01, 0xC3, 0x4A, 0xDD, 0x02, 0x5E, 0x17, 0x0B, 0x46, 0xFF, 0x0D, 0xB2, | |
0x3E, 0x5C, 0x2F, 0xAE, 0x8C, 0x8F, 0x83, 0x70}, | |
{0xD0, 0x7B, 0xEB, 0x03, 0xE3, 0xB0, 0x01, 0x4F, 0xD9, 0x7D, 0x42, 0x3B, 0x9E, 0x51, 0x23, 0xEE, | |
0x9A, 0x4B, 0x49, 0xAB, 0x9F, 0x10, 0xBE, 0x18}, | |
{0x2D, 0x36, 0x31, 0xEA, 0xF4, 0x69, 0xAD, 0xAF, 0x08, 0xE5, 0xB5, 0xEE, 0x97, 0xF5, 0x0A, 0x14, | |
0xC2, 0x6A, 0x6F, 0xE8, 0xDC, 0xBB, 0x39, 0xF3} | |
}; | |
// derivedDataRef used as reference | |
const U8 derivedDataRef[A71CH_SYM_KEY_MAX_B][32] = { | |
{0x36, 0x54, 0xBE, 0x49, 0x32, 0xB6, 0xE3, 0x84, 0xB8, 0x0C, 0xF5, 0xFC, 0xF7, 0x7B, 0x93, 0x93, | |
0x82, 0x59, 0xD0, 0x45, 0x7E, 0xED, 0xE3, 0xB8, 0x6F, 0xC0, 0x91, 0x99, 0x67, 0x10, 0xA4, 0xF3}, | |
{0x9E, 0xA8, 0xD4, 0x14, 0xE2, 0x9A, 0x9A, 0x42, 0x2B, 0x45, 0x65, 0x21, 0xA1, 0x08, 0xA9, 0x85, | |
0x97, 0x52, 0x03, 0xC3, 0x15, 0x23, 0xC0, 0xE2, 0x05, 0x86, 0x40, 0x8C, 0xE3, 0xAF, 0x39, 0x7F}, | |
{0xE8, 0x50, 0xE2, 0x1A, 0xB3, 0xBB, 0x41, 0xC0, 0x79, 0x39, 0x80, 0x1D, 0xA5, 0x87, 0x2F, 0x4C, | |
0x4D, 0xE8, 0xB4, 0x6C, 0x2D, 0x56, 0x88, 0xA4, 0x44, 0x21, 0x65, 0xD6, 0xEB, 0xD8, 0x83, 0x3E}, | |
{0x2D, 0xCA, 0xE0, 0x37, 0x32, 0x7D, 0xA9, 0x97, 0xC6, 0x50, 0xAC, 0x9B, 0x93, 0x1E, 0x6F, 0x46, | |
0xB6, 0xB5, 0x2B, 0xF6, 0x36, 0x57, 0xB2, 0x65, 0x70, 0x04, 0x5A, 0x06, 0x26, 0x37, 0x77, 0x2E}, | |
{0x36, 0x54, 0xBE, 0x49, 0x32, 0xB6, 0xE3, 0x84, 0xB8, 0x0C, 0xF5, 0xFC, 0xF7, 0x7B, 0x93, 0x93, // First 4 repeated | |
0x82, 0x59, 0xD0, 0x45, 0x7E, 0xED, 0xE3, 0xB8, 0x6F, 0xC0, 0x91, 0x99, 0x67, 0x10, 0xA4, 0xF3}, | |
{0x9E, 0xA8, 0xD4, 0x14, 0xE2, 0x9A, 0x9A, 0x42, 0x2B, 0x45, 0x65, 0x21, 0xA1, 0x08, 0xA9, 0x85, | |
0x97, 0x52, 0x03, 0xC3, 0x15, 0x23, 0xC0, 0xE2, 0x05, 0x86, 0x40, 0x8C, 0xE3, 0xAF, 0x39, 0x7F}, | |
{0xE8, 0x50, 0xE2, 0x1A, 0xB3, 0xBB, 0x41, 0xC0, 0x79, 0x39, 0x80, 0x1D, 0xA5, 0x87, 0x2F, 0x4C, | |
0x4D, 0xE8, 0xB4, 0x6C, 0x2D, 0x56, 0x88, 0xA4, 0x44, 0x21, 0x65, 0xD6, 0xEB, 0xD8, 0x83, 0x3E}, | |
{0x2D, 0xCA, 0xE0, 0x37, 0x32, 0x7D, 0xA9, 0x97, 0xC6, 0x50, 0xAC, 0x9B, 0x93, 0x1E, 0x6F, 0x46, | |
0xB6, 0xB5, 0x2B, 0xF6, 0x36, 0x57, 0xB2, 0x65, 0x70, 0x04, 0x5A, 0x06, 0x26, 0x37, 0x77, 0x2E} | |
}; | |
#if 0 | |
// ddDataAfterUpdate used as reference | |
static U8 ddDataAfterUpdate[A71CH_SYM_KEY_MAX_B][32] = { | |
{0x36, 0x54, 0xBE, 0x49, 0x32, 0xB6, 0xE3, 0x84, 0xB8, 0x0C, 0xF5, 0xFC, 0xF7, 0x7B, 0x93, 0x93, | |
0x82, 0x59, 0xD0, 0x45, 0x7E, 0xED, 0xE3, 0xB8, 0x6F, 0xC0, 0x91, 0x99, 0x67, 0x10, 0xA4, 0xF3}, | |
{0x9E, 0xA8, 0xD4, 0x14, 0xE2, 0x9A, 0x9A, 0x42, 0x2B, 0x45, 0x65, 0x21, 0xA1, 0x08, 0xA9, 0x85, | |
0x97, 0x52, 0x03, 0xC3, 0x15, 0x23, 0xC0, 0xE2, 0x05, 0x86, 0x40, 0x8C, 0xE3, 0xAF, 0x39, 0x7F}, | |
{0x48, 0x37, 0x34, 0x13, 0x78, 0x8C, 0x4E, 0xFB, 0x10, 0xD6, 0xC7, 0xE1, 0xD8, 0xB7, 0x70, 0xE4, // Updated | |
0xA0, 0xF8, 0x57, 0x0D, 0xA6, 0xFF, 0x79, 0xA3, 0xE7, 0xBD, 0xB6, 0xF6, 0x5A, 0xB5, 0x2B, 0xD0}, | |
{0xDE, 0x12, 0xE2, 0x55, 0xB8, 0x3E, 0x37, 0xC1, 0xAB, 0xBF, 0x3D, 0xD8, 0x58, 0xFE, 0x6C, 0x2E, // Updated | |
0xAB, 0xE2, 0x71, 0xA1, 0xEC, 0x12, 0xC4, 0xDE, 0x05, 0x95, 0xD7, 0x84, 0x22, 0xA5, 0xFB, 0x76}, | |
{0x36, 0x54, 0xBE, 0x49, 0x32, 0xB6, 0xE3, 0x84, 0xB8, 0x0C, 0xF5, 0xFC, 0xF7, 0x7B, 0x93, 0x93, // First 4 repeated | |
0x82, 0x59, 0xD0, 0x45, 0x7E, 0xED, 0xE3, 0xB8, 0x6F, 0xC0, 0x91, 0x99, 0x67, 0x10, 0xA4, 0xF3}, | |
{0x9E, 0xA8, 0xD4, 0x14, 0xE2, 0x9A, 0x9A, 0x42, 0x2B, 0x45, 0x65, 0x21, 0xA1, 0x08, 0xA9, 0x85, | |
0x97, 0x52, 0x03, 0xC3, 0x15, 0x23, 0xC0, 0xE2, 0x05, 0x86, 0x40, 0x8C, 0xE3, 0xAF, 0x39, 0x7F}, | |
{0x48, 0x37, 0x34, 0x13, 0x78, 0x8C, 0x4E, 0xFB, 0x10, 0xD6, 0xC7, 0xE1, 0xD8, 0xB7, 0x70, 0xE4, // Updated | |
0xA0, 0xF8, 0x57, 0x0D, 0xA6, 0xFF, 0x79, 0xA3, 0xE7, 0xBD, 0xB6, 0xF6, 0x5A, 0xB5, 0x2B, 0xD0}, | |
{0xDE, 0x12, 0xE2, 0x55, 0xB8, 0x3E, 0x37, 0xC1, 0xAB, 0xBF, 0x3D, 0xD8, 0x58, 0xFE, 0x6C, 0x2E, // Updated | |
0xAB, 0xE2, 0x71, 0xA1, 0xEC, 0x12, 0xC4, 0xDE, 0x05, 0x95, 0xD7, 0x84, 0x22, 0xA5, 0xFB, 0x76} | |
}; | |
#endif | |
static U8 ddDataAfterUpdate[A71CH_SYM_KEY_MAX_B][32] = { | |
{0x36, 0x54, 0xBE, 0x49, 0x32, 0xB6, 0xE3, 0x84, 0xB8, 0x0C, 0xF5, 0xFC, 0xF7, 0x7B, 0x93, 0x93, | |
0x82, 0x59, 0xD0, 0x45, 0x7E, 0xED, 0xE3, 0xB8, 0x6F, 0xC0, 0x91, 0x99, 0x67, 0x10, 0xA4, 0xF3}, | |
{0x9E, 0xA8, 0xD4, 0x14, 0xE2, 0x9A, 0x9A, 0x42, 0x2B, 0x45, 0x65, 0x21, 0xA1, 0x08, 0xA9, 0x85, | |
0x97, 0x52, 0x03, 0xC3, 0x15, 0x23, 0xC0, 0xE2, 0x05, 0x86, 0x40, 0x8C, 0xE3, 0xAF, 0x39, 0x7F}, | |
{0xE8, 0x50, 0xE2, 0x1A, 0xB3, 0xBB, 0x41, 0xC0, 0x79, 0x39, 0x80, 0x1D, 0xA5, 0x87, 0x2F, 0x4C, | |
0x4D, 0xE8, 0xB4, 0x6C, 0x2D, 0x56, 0x88, 0xA4, 0x44, 0x21, 0x65, 0xD6, 0xEB, 0xD8, 0x83, 0x3E}, | |
{0x2D, 0xCA, 0xE0, 0x37, 0x32, 0x7D, 0xA9, 0x97, 0xC6, 0x50, 0xAC, 0x9B, 0x93, 0x1E, 0x6F, 0x46, | |
0xB6, 0xB5, 0x2B, 0xF6, 0x36, 0x57, 0xB2, 0x65, 0x70, 0x04, 0x5A, 0x06, 0x26, 0x37, 0x77, 0x2E}, | |
{0x36, 0x54, 0xBE, 0x49, 0x32, 0xB6, 0xE3, 0x84, 0xB8, 0x0C, 0xF5, 0xFC, 0xF7, 0x7B, 0x93, 0x93, // First 4 repeated | |
0x82, 0x59, 0xD0, 0x45, 0x7E, 0xED, 0xE3, 0xB8, 0x6F, 0xC0, 0x91, 0x99, 0x67, 0x10, 0xA4, 0xF3}, | |
{0x9E, 0xA8, 0xD4, 0x14, 0xE2, 0x9A, 0x9A, 0x42, 0x2B, 0x45, 0x65, 0x21, 0xA1, 0x08, 0xA9, 0x85, | |
0x97, 0x52, 0x03, 0xC3, 0x15, 0x23, 0xC0, 0xE2, 0x05, 0x86, 0x40, 0x8C, 0xE3, 0xAF, 0x39, 0x7F}, | |
{0xE8, 0x50, 0xE2, 0x1A, 0xB3, 0xBB, 0x41, 0xC0, 0x79, 0x39, 0x80, 0x1D, 0xA5, 0x87, 0x2F, 0x4C, | |
0x4D, 0xE8, 0xB4, 0x6C, 0x2D, 0x56, 0x88, 0xA4, 0x44, 0x21, 0x65, 0xD6, 0xEB, 0xD8, 0x83, 0x3E}, | |
{0x2D, 0xCA, 0xE0, 0x37, 0x32, 0x7D, 0xA9, 0x97, 0xC6, 0x50, 0xAC, 0x9B, 0x93, 0x1E, 0x6F, 0x46, | |
0xB6, 0xB5, 0x2B, 0xF6, 0x36, 0x57, 0xB2, 0x65, 0x70, 0x04, 0x5A, 0x06, 0x26, 0x37, 0x77, 0x2E} | |
}; | |
U8 indexAesKey = 0; | |
U8 nBlock = 0x01; | |
PRINTF("\r\n-----------\r\nStart exSstSym(%s)\r\n------------\r\n", getInitModeAsString(initMode)); | |
// Initialize the A71CH (Debug mode restrictions may apply) | |
result &= a71chInitModule(initMode); | |
// Fill up the symmetric key store with reference values (straight, no wrapping) | |
for (indexAesKey=0; indexAesKey<A71CH_SYM_KEY_MAX; indexAesKey++) | |
{ | |
PRINTF( "\r\nA71_SetSymKey(0x%02x)\r\n", indexAesKey); | |
err = A71_SetSymKey((SST_Index_t)indexAesKey, aesRef[indexAesKey], sizeof(aesRef[indexAesKey])); | |
result &= AX_CHECK_SW(err, SW_OK, "err"); | |
axPrintByteArray("aesRef[indexAesKey]", aesRef[indexAesKey], sizeof(aesRef[indexAesKey]), AX_COLON_32); | |
} | |
// To demonstrate the slots are filled up with keys, do a KDF | |
for (indexAesKey=0; indexAesKey<A71CH_SYM_KEY_MAX; indexAesKey++) | |
{ | |
PRINTF( "\r\nA71_HkdfExpandSymKey(0x%02x)\r\n", indexAesKey); | |
derivedDataLen = sizeof(derivedData); | |
err = A71_HkdfExpandSymKey((SST_Index_t)indexAesKey, nBlock, info, infoLen, derivedData, derivedDataLen); | |
result &= AX_CHECK_SW(err, SW_OK, "err"); | |
axPrintByteArray("derivedData", derivedData, derivedDataLen, AX_COLON_32); | |
result &= AX_COMPARE_BYTE_ARRAY("derivedDataRef[indexAesKey]", derivedDataRef[indexAesKey], sizeof(derivedDataRef[indexAesKey]), | |
"derivedData", derivedData, derivedDataLen, AX_COLON_32); | |
} | |
// Erase the symmetric key at index 1 & verify the value is no longer useable | |
// ** Erase ** | |
indexAesKey = A71CH_SYM_KEY_1; | |
PRINTF("\r\nA71_EraseSymKey(index=0x%02X)\r\n", indexAesKey); | |
err = A71_EraseSymKey(indexAesKey); | |
result &= AX_CHECK_SW(err, SW_OK, "err"); | |
// ** Verify value is no longer useable ** | |
PRINTF( "\r\nA71_HkdfExpandSymKey(0x%02x)\r\n", indexAesKey); | |
derivedDataLen = sizeof(derivedData); | |
err = A71_HkdfExpandSymKey((SST_Index_t)indexAesKey, nBlock, info, infoLen, derivedData, derivedDataLen); | |
result &= AX_CHECK_SW(err, SW_CONDITIONS_NOT_SATISFIED, "Expected to fail as the key was erased"); | |
// Fill in the original value again | |
indexAesKey = A71CH_SYM_KEY_1; | |
PRINTF( "\r\nA71_SetSymKey(0x%02x)\r\n", indexAesKey); | |
err = A71_SetSymKey((SST_Index_t)indexAesKey, aesRef[indexAesKey], sizeof(aesRef[indexAesKey])); | |
result &= AX_CHECK_SW(err, SW_OK, "err"); | |
// Slots are filled up with known keys, do a KDF as proof | |
for (indexAesKey=0; indexAesKey<A71CH_SYM_KEY_MAX; indexAesKey++) | |
{ | |
PRINTF( "\r\nA71_HkdfExpandSymKey(0x%02x)\r\n", indexAesKey); | |
derivedDataLen = sizeof(derivedData); | |
err = A71_HkdfExpandSymKey((SST_Index_t)indexAesKey, nBlock, info, infoLen, derivedData, derivedDataLen); | |
result &= AX_CHECK_SW(err, SW_OK, "err"); | |
// axPrintByteArray("derivedData", derivedData, derivedDataLen, AX_COLON_32); | |
result &= AX_COMPARE_BYTE_ARRAY("derivedDataRef[indexAesKey]", derivedDataRef[indexAesKey], sizeof(derivedDataRef[indexAesKey]), | |
"derivedData", derivedData, derivedDataLen, AX_COLON_32); | |
} | |
// Overwrite the second half | |
for (indexAesKey=A71CH_SYM_KEY_MAX>>1; indexAesKey<A71CH_SYM_KEY_MAX; indexAesKey++) | |
{ | |
U8 tmpKey[16]; | |
int j; | |
for (j=0; j<16; j++) {tmpKey[j] = (U8)indexAesKey;} | |
PRINTF( "\r\nA71_SetSymKey(0x%02x)\r\n", indexAesKey); | |
err = A71_SetSymKey((SST_Index_t)indexAesKey, tmpKey, sizeof(tmpKey)); | |
result &= AX_CHECK_SW(err, SW_OK, "err"); | |
// Calculate and store the expected derivedData based on the new sym keys written. | |
err = HOSTCRYPTO_HkdfExpandSha256(tmpKey, sizeof(tmpKey), info, infoLen, ddDataAfterUpdate[indexAesKey], sizeof(ddDataAfterUpdate[indexAesKey])); | |
result &= AX_CHECK_SW(err, SW_OK, "err"); | |
} | |
// Check that the second half was overwritten (compare with another set of reference data) | |
for (indexAesKey=A71CH_SYM_KEY_MAX>>1; indexAesKey<A71CH_SYM_KEY_MAX; indexAesKey++) | |
{ | |
PRINTF( "\r\nA71_HkdfExpandSymKey(0x%02x)\r\n", indexAesKey); | |
derivedDataLen = sizeof(derivedData); | |
err = A71_HkdfExpandSymKey((SST_Index_t)indexAesKey, nBlock, info, infoLen, derivedData, derivedDataLen); | |
result &= AX_CHECK_SW(err, SW_OK, "err"); | |
// axPrintByteArray("derivedData", derivedData, derivedDataLen, AX_CARRAY_16); | |
result &= AX_COMPARE_BYTE_ARRAY("ddDataAfterUpdate[indexAesKey]", ddDataAfterUpdate[indexAesKey], sizeof(ddDataAfterUpdate[indexAesKey]), | |
"derivedData", derivedData, derivedDataLen, AX_COLON_32); | |
} | |
// Put back the original (reference) values in the second half | |
// Fill up the symmetric key store with reference values (straight, no wrapping) | |
for (indexAesKey=A71CH_SYM_KEY_MAX>>1; indexAesKey<A71CH_SYM_KEY_MAX; indexAesKey++) | |
{ | |
PRINTF( "\r\nA71_SetSymKey(0x%02x)\r\n", indexAesKey); | |
err = A71_SetSymKey((SST_Index_t)indexAesKey, aesRef[indexAesKey], sizeof(aesRef[indexAesKey])); | |
result &= AX_CHECK_SW(err, SW_OK, "err"); | |
axPrintByteArray("aesRef[indexAesKey]", aesRef[indexAesKey], sizeof(aesRef[indexAesKey]), AX_COLON_32); | |
} | |
// Slots are filled up with known keys, do a KDF as proof | |
for (indexAesKey=0; indexAesKey<A71CH_SYM_KEY_MAX; indexAesKey++) | |
{ | |
PRINTF( "\r\nA71_HkdfExpandSymKey(0x%02x)\r\n", indexAesKey); | |
derivedDataLen = sizeof(derivedData); | |
err = A71_HkdfExpandSymKey((SST_Index_t)indexAesKey, nBlock, info, infoLen, derivedData, derivedDataLen); | |
result &= AX_CHECK_SW(err, SW_OK, "err"); | |
// axPrintByteArray("derivedData", derivedData, derivedDataLen, AX_COLON_32); | |
result &= AX_COMPARE_BYTE_ARRAY("derivedDataRef[indexAesKey]", derivedDataRef[indexAesKey], sizeof(derivedDataRef[indexAesKey]), | |
"derivedData", derivedData, derivedDataLen, AX_COLON_32); | |
} | |
// Now disable the plain insertion of Symmetric keys | |
PRINTF("\r\nA71_InjectLock()\r\n"); | |
err = A71_InjectLock(); | |
result &= AX_CHECK_SW(err, SW_OK, "err"); | |
assert(result); | |
// Inserting a key in second half - plain mode - must fail. | |
for (indexAesKey=A71CH_SYM_KEY_MAX>>1; indexAesKey<A71CH_SYM_KEY_MAX; indexAesKey++) | |
{ | |
U8 tmpKey[16]; | |
int j; | |
for (j=0; j<16; j++) {tmpKey[j] = (U8)indexAesKey;} | |
PRINTF( "\r\nA71_SetSymKey(0x%02x)\r\n", indexAesKey); | |
err = A71_SetSymKey((SST_Index_t)indexAesKey, tmpKey, sizeof(tmpKey)); | |
result &= AX_CHECK_SW(err, SW_COMMAND_NOT_ALLOWED, "Expected to fail. Inject lock state does not allow insertion plain symmetric keys"); | |
} | |
// Inserting a wrapped key must succeed (just inserting the same key) | |
for (indexAesKey=A71CH_SYM_KEY_MAX>>1; indexAesKey<A71CH_SYM_KEY_MAX; indexAesKey++) | |
{ | |
PRINTF("\r\nA71_SetRfc3394WrappedAesKey(0x%02X)\r\n", indexAesKey); | |
err = A71_SetRfc3394WrappedAesKey(indexAesKey, aesRefWrapped[indexAesKey], 24); | |
result &= AX_CHECK_SW(err, SW_OK, "err"); | |
assert(result); | |
} | |
// Slots are filled up with known keys, do a KDF as proof | |
for (indexAesKey=0; indexAesKey<A71CH_SYM_KEY_MAX; indexAesKey++) | |
{ | |
PRINTF( "\r\nA71_HkdfExpandSymKey(0x%02x)\r\n", indexAesKey); | |
derivedDataLen = sizeof(derivedData); | |
err = A71_HkdfExpandSymKey((SST_Index_t)indexAesKey, nBlock, info, infoLen, derivedData, derivedDataLen); | |
result &= AX_CHECK_SW(err, SW_OK, "err"); | |
// axPrintByteArray("derivedData", derivedData, derivedDataLen, AX_COLON_32); | |
result &= AX_COMPARE_BYTE_ARRAY("derivedDataRef[indexAesKey]", derivedDataRef[indexAesKey], sizeof(derivedDataRef[indexAesKey]), | |
"derivedData", derivedData, derivedDataLen, AX_COLON_32); | |
} | |
PRINTF( "\r\n-----------\r\nEnd exSstSym(%s), result = %s\r\n------------\r\n", getInitModeAsString(initMode), ((result == 1)? "OK": "FAILED")); | |
return result; | |
} | |
/** | |
* Demonstrate | |
* - setting/getting/erasing/freezing of public keys | |
* - demonstrate key can be used through verify operation | |
* - illustrate setting a public key after INJECT_PLAIN lock has been set | |
* | |
* @param[in] initMode Visit the documentation of ::a71chInitModule for more information on this parameter. A debug reset must be issued for the test | |
* to be successfull. | |
* @param[in] appletVersion In case an applet older than Revision 1.2 (0x012x) is attached, a negative test is skipped. | |
*/ | |
static U8 exSstPub(U8 initMode) | |
{ | |
U8 result = 1; | |
U16 err; | |
int i; | |
HLSE_RET_CODE retcode; | |
U8 isOk = 0x00; | |
HLSE_MECHANISM_INFO mechInfo; | |
ECCCurve_t eccCurve = ECCCurve_NIST_P256; | |
EC_KEY *eccKeyCA[A71CH_PUBLIC_KEY_MAX] = {0}; | |
eccKeyComponents_t eccKcCA[A71CH_PUBLIC_KEY_MAX] = {0}; | |
EC_KEY *eccKeyAlternative = NULL; | |
eccKeyComponents_t eccKcAlternative = {0}; | |
U8 fetchedPubKey[65]; | |
U16 fetchedPubKeyLen = sizeof(fetchedPubKey); | |
U8 hashSha256[32]; | |
U16 hashSha256Len = sizeof(hashSha256); | |
U8 signatureOnHost[128]; | |
U32 signatureOnHostLen = sizeof(signatureOnHost); | |
// const U16 expectedPubKeyLen = 65; | |
const U16 expectedPrivKeyLen = 32; | |
SST_Index_t pubKeyIndex; | |
// When inject lock is set, public keys must be wrapped before being written. | |
SST_Index_t indexCfgKey; | |
U8 configKeyPublicKey[16] = { | |
0xAA, 0xBB, 0xCC, 0xDD, 0xEE, 0xFF, 0x00, 0x11, | |
0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88, 0x99 }; | |
U8 wrappedKey[64+8]; | |
U16 wrappedKeyLen = sizeof(wrappedKey); | |
PRINTF("\r\n-----------\r\nStart exSstPub(%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_PUBLIC_KEY_MAX; i++) | |
{ | |
eccKeyCA[i] = NULL; | |
err = HOSTCRYPTO_GenerateEccKey(eccCurve, &eccKeyCA[i]); | |
result &= AX_CHECK_SW(err, SW_OK, "err"); | |
err = HOSTCRYPTO_GetPublicKey(eccKeyCA[i], eccKcCA[i].pub, &(eccKcCA[i].pubLen), (64 << 1)+1); | |
result &= AX_CHECK_SW(err, SW_OK, "err"); | |
err = HOSTCRYPTO_GetPrivateKey(eccKeyCA[i], eccKcCA[i].priv, &(eccKcCA[i].privLen), 64); | |
result &= AX_CHECK_SW(err, SW_OK, "err"); | |
eccKcCA[i].bits = expectedPrivKeyLen << 3; | |
eccKcCA[i].curve = eccCurve; | |
PRINTF( "\r\nA71_SetEccPublicKey(0x%02X)\r\n", (SST_Index_t)i); | |
err = A71_SetEccPublicKey ((SST_Index_t) i, eccKcCA[i].pub, eccKcCA[i].pubLen); | |
result &= AX_CHECK_SW(err, SW_OK, "err"); | |
} | |
// Read out and verify public key | |
for (i=0; i<A71CH_PUBLIC_KEY_MAX; i++) | |
{ | |
PRINTF( "\r\nA71_GetEccPublicKey(0x%02X)\r\n", (SST_Index_t)i); | |
fetchedPubKeyLen = sizeof(fetchedPubKey); | |
err = A71_GetEccPublicKey ((SST_Index_t) i, fetchedPubKey, &fetchedPubKeyLen); | |
result &= AX_CHECK_SW(err, SW_OK, "err"); | |
// Compare with reference value | |
result &= AX_COMPARE_BYTE_ARRAY("eccKcCA[i].pub", eccKcCA[i].pub, eccKcCA[i].pubLen, | |
"fetchedPubKey", fetchedPubKey, fetchedPubKeyLen, AX_COLON_32); | |
} | |
// Create alternative key | |
err = HOSTCRYPTO_GenerateEccKey(eccCurve, &eccKeyAlternative); | |
result &= AX_CHECK_SW(err, SW_OK, "err"); | |
err = HOSTCRYPTO_GetPublicKey(eccKeyAlternative, eccKcAlternative.pub, &(eccKcAlternative.pubLen), (64 << 1)+1); | |
result &= AX_CHECK_SW(err, SW_OK, "err"); | |
err = HOSTCRYPTO_GetPrivateKey(eccKeyAlternative, eccKcAlternative.priv, &(eccKcAlternative.privLen), 64); | |
result &= AX_CHECK_SW(err, SW_OK, "err"); | |
eccKcAlternative.bits = expectedPrivKeyLen << 3; | |
eccKcAlternative.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_PUBLIC_KEY_MAX; i++) | |
{ | |
PRINTF("\r\n(Host)ECDSA_sign API with eccKeyCA[i].\r\n"); | |
signatureOnHostLen = sizeof(signatureOnHost); | |
memset(&mechInfo, 0, sizeof(mechInfo)); | |
mechInfo.mechanism = HLSE_ECDSA_SIGN; | |
retcode = HLCRYPT_Sign(&mechInfo, (U8 *)eccKeyCA[i], 0,hashSha256, hashSha256Len, signatureOnHost, &signatureOnHostLen); | |
if (retcode != HLSE_SW_OK) | |
{ | |
PRINTF("(Host)ECDSA_sign operation failed.\r\n"); | |
result &= 0; | |
} | |
else | |
{ | |
axPrintByteArray("signatureOnHost", signatureOnHost, (U16)signatureOnHostLen, AX_COLON_32); | |
} | |
// Verify on A71CH | |
isOk = 0x00; | |
PRINTF("\r\nA71_EccVerify(0x%02X)\r\n", (SST_Index_t)i); | |
err = A71_EccVerify((SST_Index_t) i, hashSha256, hashSha256Len, signatureOnHost, (U16)signatureOnHostLen, &isOk); | |
result &= AX_CHECK_SW(err, SW_OK, "err"); | |
result &= AX_CHECK_U8(isOk, 1, "Signature verification failed"); | |
// It's also possible to do a verification on the A71CH by passing the public key by value | |
// In case the key has been provisioned inside the A71CH, referring to the key by index is preferred | |
// as it does not imply an EEPROM write operation | |
isOk = 0x00; | |
PRINTF("\r\nA71_EccVerifyWithKey(PubkeyByValue)\r\n"); | |
err = A71_EccVerifyWithKey(eccKcCA[i].pub, eccKcCA[i].pubLen, hashSha256, hashSha256Len, | |
signatureOnHost, (U16)signatureOnHostLen, &isOk); | |
result &= AX_CHECK_SW(err, SW_OK, "err"); | |
result &= AX_CHECK_U8(isOk, 1, "Signature verification failed"); | |
} | |
// Erase the public key at index 0 & verify the value is no longer readable | |
// ** Erase ** | |
pubKeyIndex = A71CH_PUBLIC_KEY_0; | |
PRINTF("\r\nA71_EraseEccPublicKey(index=0x%02X)\r\n", pubKeyIndex); | |
err = A71_EraseEccPublicKey(pubKeyIndex); | |
result &= AX_CHECK_SW(err, SW_OK, "err"); | |
// ** Check whether erase was effective ** | |
PRINTF("\r\nA71_GetEccPublicKey(index=0x%02X)\r\n", pubKeyIndex); | |
fetchedPubKeyLen = sizeof(fetchedPubKey); | |
err = A71_GetEccPublicKey((SST_Index_t)pubKeyIndex, fetchedPubKey, &fetchedPubKeyLen); | |
result &= AX_CHECK_SW(err, SW_CONDITIONS_NOT_SATISFIED, "Get Public Ecc Key was supposed to fail"); | |
// Fill in the original value again | |
pubKeyIndex = A71CH_PUBLIC_KEY_0; | |
PRINTF( "\r\nA71_SetEccPublicKey(0x%02x)\r\n", pubKeyIndex); | |
err = A71_SetEccPublicKey((SST_Index_t)pubKeyIndex, eccKcCA[pubKeyIndex].pub, eccKcCA[pubKeyIndex].pubLen); | |
result &= AX_CHECK_SW(err, SW_OK, "err"); | |
// Now Lock the first half of the slots for update | |
for (pubKeyIndex=0; pubKeyIndex<A71CH_PUBLIC_KEY_MAX>>1; pubKeyIndex++) | |
{ | |
PRINTF( "\r\nA71_FreezeEccPublicKey(0x%02x)\r\n", pubKeyIndex); | |
err = A71_FreezeEccPublicKey((SST_Index_t)pubKeyIndex); | |
result &= AX_CHECK_SW(err, SW_OK, "err"); | |
} | |
// Now fetch and compare the values with the reference values | |
for (pubKeyIndex=0; pubKeyIndex<A71CH_PUBLIC_KEY_MAX; pubKeyIndex++) | |
{ | |
PRINTF( "\r\nA71_GetEccPublicKey(0x%02x)\r\n", pubKeyIndex); | |
fetchedPubKeyLen = sizeof(fetchedPubKey); | |
err = A71_GetEccPublicKey((SST_Index_t)pubKeyIndex, fetchedPubKey, &fetchedPubKeyLen); | |
result &= AX_CHECK_SW(err, SW_OK, "err"); | |
result &= AX_COMPARE_BYTE_ARRAY("eccKcCA[pubKeyIndex]", eccKcCA[pubKeyIndex].pub, eccKcCA[pubKeyIndex].pubLen, | |
"fetchedKey", fetchedPubKey, fetchedPubKeyLen, AX_COLON_32); | |
} | |
// Check whether the locked half (i.e. first half) is truly 'frozen' .... | |
for (pubKeyIndex=0; pubKeyIndex<A71CH_PUBLIC_KEY_MAX>>1; pubKeyIndex++) | |
{ | |
PRINTF( "\r\nA71_SetEccPublicKey(0x%02x)\r\n", pubKeyIndex); | |
err = A71_SetEccPublicKey((SST_Index_t)pubKeyIndex, eccKcAlternative.pub, eccKcAlternative.pubLen); | |
result &= AX_CHECK_SW(err, SW_COMMAND_NOT_ALLOWED, "Expected to fail, frozen credential cannot be overwritten"); | |
} | |
// Overwrite the second half | |
for (pubKeyIndex=A71CH_PUBLIC_KEY_MAX>>1; pubKeyIndex<A71CH_PUBLIC_KEY_MAX; pubKeyIndex++) | |
{ | |
PRINTF( "\r\nA71_SetEccPublicKey(0x%02x)\r\n", pubKeyIndex); | |
err = A71_SetEccPublicKey((SST_Index_t)pubKeyIndex, eccKcAlternative.pub, eccKcAlternative.pubLen); | |
result &= AX_CHECK_SW(err, SW_OK, "err"); | |
} | |
// Check that the second half was overwritten, by signing a hash of correct length on the host and do the verification on the A71CH | |
for (pubKeyIndex=A71CH_PUBLIC_KEY_MAX>>1; pubKeyIndex<A71CH_PUBLIC_KEY_MAX; pubKeyIndex++) | |
{ | |
PRINTF("\r\n(Host)ECDSA_sign API with eccKeyCA[i].\r\n"); | |
signatureOnHostLen = sizeof(signatureOnHost); | |
memset(&mechInfo, 0, sizeof(mechInfo)); | |
mechInfo.mechanism = HLSE_ECDSA_SIGN; | |
retcode = HLCRYPT_Sign(&mechInfo, (U8 *)eccKeyAlternative, 0,hashSha256, hashSha256Len, signatureOnHost, &signatureOnHostLen); | |
if (retcode != HLSE_SW_OK) | |
{ | |
PRINTF("(Host)ECDSA_sign operation failed.\r\n"); | |
result &= 0; | |
} | |
else | |
{ | |
axPrintByteArray("signatureOnHost", signatureOnHost, (U16)signatureOnHostLen, AX_COLON_32); | |
} | |
// Verify on A71CH | |
isOk = 0x00; | |
PRINTF( "\r\nA71_EccVerify(0x%02X)\r\n", (SST_Index_t)pubKeyIndex); | |
err = A71_EccVerify((SST_Index_t) pubKeyIndex, hashSha256, hashSha256Len, signatureOnHost, (U16)signatureOnHostLen, &isOk); | |
result &= AX_CHECK_SW(err, SW_OK, "err"); | |
result &= AX_CHECK_U8(isOk, 1, "Signature verification failed"); | |
} | |
// Put back the original (reference) values in the second half | |
for (pubKeyIndex=A71CH_PUBLIC_KEY_MAX>>1; pubKeyIndex<A71CH_PUBLIC_KEY_MAX; pubKeyIndex++) | |
{ | |
PRINTF( "\r\nA71_SetEccPublicKey(0x%02x)\r\n", pubKeyIndex); | |
err = A71_SetEccPublicKey ((SST_Index_t) pubKeyIndex, eccKcCA[pubKeyIndex].pub, eccKcCA[pubKeyIndex].pubLen); | |
result &= AX_CHECK_SW(err, SW_OK, "err"); | |
} | |
// Check all keys are still fine by doing a verify operation | |
for (i=0; i<A71CH_PUBLIC_KEY_MAX; i++) | |
{ | |
PRINTF("\r\n(Host)ECDSA_sign API with eccKeyCA[i].\r\n"); | |
signatureOnHostLen = sizeof(signatureOnHost); | |
memset(&mechInfo, 0, sizeof(mechInfo)); | |
mechInfo.mechanism = HLSE_ECDSA_SIGN; | |
retcode = HLCRYPT_Sign(&mechInfo, (U8 *)eccKeyCA[i], 0,hashSha256, hashSha256Len, signatureOnHost, &signatureOnHostLen); | |
if (retcode != HLSE_SW_OK) | |
{ | |
PRINTF("(Host)ECDSA_sign operation failed.\r\n"); | |
result &= 0; | |
} | |
else | |
{ | |
axPrintByteArray("signatureOnHost", signatureOnHost, (U16)signatureOnHostLen, AX_COLON_32); | |
} | |
// Verify on A71CH | |
isOk = 0x00; | |
PRINTF( "\r\nA71_EccVerify(0x%02X)\r\n", (SST_Index_t)i); | |
err = A71_EccVerify((SST_Index_t) i, hashSha256, hashSha256Len, signatureOnHost, (U16)signatureOnHostLen, &isOk); | |
result &= AX_CHECK_SW(err, SW_OK, "err"); | |
result &= AX_CHECK_U8(isOk, 1, "Signature verification failed"); | |
} | |
// Now disable the plain insertion/reading out of Symmetric keys & Keypairs | |
// THIS ALSO IMPACTS functionality of Public Key Storage, second half of storage is only writeable when public key | |
// has been wrapped. | |
// ** First set wrapping key (in secure element) | |
indexCfgKey = A71CH_CFG_KEY_IDX_PUBLIC_KEYS; | |
PRINTF("\r\nA71_SetConfigKey(0x%02x)\r\n", indexCfgKey); | |
err = A71_SetConfigKey((SST_Index_t)indexCfgKey, configKeyPublicKey, sizeof(configKeyPublicKey)); | |
result &= AX_CHECK_SW(err, SW_OK, "err"); | |
PRINTF("\r\nA71_InjectLock()\r\n"); | |
err = A71_InjectLock(); | |
result &= AX_CHECK_SW(err, SW_OK, "err"); | |
assert(result); | |
{ | |
// Setting unwrapped public keys (in second half) MUST fail | |
for (pubKeyIndex = A71CH_PUBLIC_KEY_MAX >> 1; pubKeyIndex < A71CH_PUBLIC_KEY_MAX; pubKeyIndex++) | |
{ | |
PRINTF("\r\nA71_SetEccPublicKey(0x%02X) - unwrapped (negative test)\r\n", (SST_Index_t)pubKeyIndex); | |
err = A71_SetEccPublicKey((SST_Index_t)pubKeyIndex, eccKcAlternative.pub, eccKcAlternative.pubLen); | |
result &= AX_CHECK_SW(err, SW_COMMAND_NOT_ALLOWED, "err"); | |
} | |
} | |
// Setting wrapped public keys (in second half) MUST succeed | |
// ** Wrapping key must have been set before Inject Lock was requested | |
// ** Wrap the public key (strip first character before wrapping) on host | |
PRINTF("\r\nHOSTCRYPTO_AesWrapKeyRFC3394(eccKcAlternative)\r\n"); | |
err = HOSTCRYPTO_AesWrapKeyRFC3394(configKeyPublicKey, sizeof(configKeyPublicKey), | |
wrappedKey, &wrappedKeyLen, &(eccKcAlternative.pub[1]), eccKcAlternative.pubLen - 1); | |
result &= AX_CHECK_SW(err, SW_OK, "err"); | |
axPrintByteArray("wrappedKey", wrappedKey, wrappedKeyLen, AX_COLON_32); | |
// ** Setting the wrapped public key (in second half) | |
for (pubKeyIndex=A71CH_PUBLIC_KEY_MAX>>1; pubKeyIndex<A71CH_PUBLIC_KEY_MAX; pubKeyIndex++) | |
{ | |
PRINTF( "\r\nA71_SetEccPublicKey(0x%02X) - wrapped\r\n", (SST_Index_t)pubKeyIndex); | |
err = A71_SetEccPublicKey ((SST_Index_t)pubKeyIndex, wrappedKey, wrappedKeyLen); | |
result &= AX_CHECK_SW(err, SW_OK, "err"); | |
} | |
// Retrieving and comparing second half public keys | |
for (pubKeyIndex=A71CH_PUBLIC_KEY_MAX>>1; pubKeyIndex<A71CH_PUBLIC_KEY_MAX; pubKeyIndex++) | |
{ | |
PRINTF( "\r\nA71_GetEccPublicKey(0x%02x)\r\n", pubKeyIndex); | |
fetchedPubKeyLen = sizeof(fetchedPubKey); | |
err = A71_GetEccPublicKey((SST_Index_t)pubKeyIndex, fetchedPubKey, &fetchedPubKeyLen); | |
result &= AX_CHECK_SW(err, SW_OK, "err"); | |
result &= AX_COMPARE_BYTE_ARRAY("eccKcAlternative.pub", eccKcAlternative.pub, eccKcAlternative.pubLen, | |
"fetchedKey", fetchedPubKey, fetchedPubKeyLen, AX_COLON_32); | |
} | |
HOSTCRYPTO_FreeEccKey(&eccKeyAlternative); | |
for (i=0; i<A71CH_PUBLIC_KEY_MAX; i++) | |
{ | |
HOSTCRYPTO_FreeEccKey(&eccKeyCA[i]); | |
} | |
PRINTF( "\r\n-----------\r\nEnd exSstPub(%s), result = %s\r\n------------\r\n", getInitModeAsString(initMode), | |
((result == 1)? "OK": "FAILED")); | |
return result; | |
} |