/** * @file configCmdSet.c * @author NXP Semiconductors * @version 1.0 * @par License * * Copyright 2017 NXP * SPDX-License-Identifier: Apache-2.0 * * @par Description * Command handling for 'set'. Includes optional console handling */ #include #include #include #include // project specific include files #include "sm_types.h" #include "sm_apdu.h" #include "tst_sm_util.h" #include "tst_a71ch_util.h" #include "probeAxUtil.h" #include "configCmd.h" #include "configCli.h" #include "a71_debug.h" #include "axHostCrypto.h" #include "tstHostCrypto.h" #ifdef OPENSSL #include #endif #define FLOW_VERBOSE_PROBE_A70 #ifdef FLOW_VERBOSE_PROBE_A70 #define FPRINTF(...) printf (__VA_ARGS__) #else #define FPRINTF(...) #endif // Warning: defining DBG_PROBE_A70 also exposes Private Key being set in log // #define DBG_PROBE_A70 #ifdef DBG_PROBE_A70 #define DBGPRINTF(...) printf (__VA_ARGS__) #else #define DBGPRINTF(...) #endif #ifdef OPENSSL /* The following macro defines a function body with the following function signature: EC_KEY *PEM_read_eckey(FILE *fp, EC_KEY **x, pem_password_cb *cb, void *u) */ IMPLEMENT_PEM_read_fp(eckey, EC_KEY, "EC PRIVATE KEY", ECPrivateKey) #endif /** * Wrap key */ int a7xConfigCmdkWrapping(U8 * key, U16 * keyLen, U8 * wrapKey, U16 wrapKeyLen) { U8 wrappedKey[72]; U16 wrappedKeyLen = sizeof(wrappedKey); U16 ret = 0; if (*keyLen == 65) { // public key ret = HOSTCRYPTO_AesWrapKeyRFC3394(wrapKey, wrapKeyLen, wrappedKey, &wrappedKeyLen, key + 1, (*keyLen) - 1); } else { ret = HOSTCRYPTO_AesWrapKeyRFC3394(wrapKey, wrapKeyLen, wrappedKey, &wrappedKeyLen, key, *keyLen); } if (ret == SW_OK) { *keyLen = wrappedKeyLen; memcpy(key, wrappedKey, wrappedKeyLen); } else { return AX_CLI_WRAP_ERROR; } return AX_CLI_EXEC_OK; } /** * A hook for the command line handler to invoke A71 commands */ int a7xConfigCmdSetGp(U16 offset, U8 *gpData, U16 gpDataLen, U16 *sw) { int error = AX_CLI_EXEC_FAILED; *sw = a7xCmdSetGp(offset, gpData, gpDataLen); if (*sw == SW_OK) { error = AX_CLI_EXEC_OK; } return error; } /** * API wrapper for set gp command. Can be called from GUI. */ U16 a7xCmdSetGp(U16 offset, U8 *gpData, U16 gpDataLen) { U16 sw; sw = A71_SetGpData(offset, gpData, gpDataLen); return sw; } /** * A hook for the command line handler to invoke A71 commands */ // #define DUMP_DER_IN_FILE int a7xConfigCmdSetGpFromPemfile(U16 offset, char *szFilename, U16 *sw) { int error = AX_CLI_EXEC_FAILED; X509 *x; FILE *fp; #ifdef DUMP_DER_IN_FILE FILE *fpOut; #endif int len; unsigned char *buf; printf("Filename: %s\n", szFilename); fp = fopen(szFilename, "r"); if (!fp) { printf("Unable to open the file: %s\n", szFilename); return AX_CLI_FILE_OPEN_FAILED; } x = PEM_read_X509(fp, NULL, NULL, NULL); if (x == NULL) { printf("%s is not a valid pem file / certificate\n", szFilename); fclose(fp); return AX_CLI_FILE_PEM_READ_FAILED; } #ifdef DUMP_DER_IN_FILE fpOut = fopen("cert.der", "wb"); if (!fpOut) { printf("Unable to open the file: cert.der\n"); return AX_CLI_FILE_OPEN_FAILED; } i2d_X509_fp(fpOut, x); fclose(fpOut); #endif buf = NULL; len = i2d_X509(x, &buf); if (len < 0) { fclose(fp); return AX_CLI_PEM_CONVERT_FAILED; } else { int nStorageSize = A7X_CONFIG_GP_STORAGE_MAX; // No check is done on the actual GP storage size of the device attached int nMaxPos = offset + len; printf("Certificate Size (DER format) = %d byte\n", len); // Write to GP storage // (1) Is there enough storage? if (nMaxPos > nStorageSize) { printf("nMaxPos=%d; nStorageSize=%d\n", nMaxPos, nStorageSize); // No point in writing certificate as it will not fit free(buf); fclose(fp); return AX_CLI_BUFFER_SIZE_ERROR; } // (2) Write (and hope no segment is locked along the way) *sw = A71_SetGpData(offset, buf, (U16)len); free(buf); fclose(fp); } if (*sw == SW_OK) { error = AX_CLI_EXEC_OK; } else { error = AX_CLI_EXEC_FAILED; } return error; } /** * A hook for the command line handler to invoke A71 commands */ int a7xConfigCmdSetEccWrap(a71_SecureStorageClass_t ssc, U8 index, eccKeyComponents_t *eccKc, U8 * wrapKey, U16 wrapKeyLen, U16 *sw) { int error = AX_CLI_EXEC_FAILED; switch (ssc) { case A71_SSC_KEY_PAIR: error = a7xConfigCmdkWrapping(eccKc->priv, &eccKc->privLen, wrapKey, wrapKeyLen); break; case A71_SSC_PUBLIC_KEY: error = a7xConfigCmdkWrapping(eccKc->pub, &eccKc->pubLen, wrapKey, wrapKeyLen); if (error != AX_CLI_EXEC_OK) { return error; } break; default: break; } *sw = a7xCmdSetEcc(ssc, index, eccKc); if (*sw == SW_OK) { error = AX_CLI_EXEC_OK; } return error; } /** * A hook for the command line handler to invoke A71 commands */ int a7xConfigCmdSetEcc(a71_SecureStorageClass_t ssc, U8 index, eccKeyComponents_t *eccKc, U16 *sw) { int error = AX_CLI_EXEC_FAILED; *sw = a7xCmdSetEcc(ssc, index, eccKc); if (*sw == SW_OK) { error = AX_CLI_EXEC_OK; } return error; } /** * API wrapper for set ecc (keypair/pub) command. Can be called from GUI. */ U16 a7xCmdSetEcc(a71_SecureStorageClass_t ssc, U8 index, eccKeyComponents_t *eccKc) { U16 sw; switch (ssc) { case A71_SSC_KEY_PAIR: sw = A71_SetEccKeyPair(index, eccKc->pub, eccKc->pubLen, eccKc->priv, eccKc->privLen); break; case A71_SSC_PUBLIC_KEY: sw = A71_SetEccPublicKey(index, eccKc->pub, eccKc->pubLen); break; default: sw = A7X_CONFIG_STATUS_API_ERROR; break; } return sw; } /** * A hook for the command line handler to invoke A71 commands */ int a7xConfigCmdSetEccFromPemfile(a71_SecureStorageClass_t ssc, U8 index, char *szFilename, int argc, char ** argv, int *argCurrent, U16 *sw) { int error = AX_CLI_EXEC_FAILED; eccKeyComponents_t eccKc; eccKc.bits = 256; eccKc.curve = ECCCurve_NIST_P256; eccKc.privLen = 0; eccKc.pubLen = 0; error = a7xConfigGetEccKcFromPemfile(&eccKc, ssc, szFilename); if (error == AX_CLI_EXEC_OK) { if (ssc == A71_SSC_KEY_PAIR) { error = a7xConfigCmdCheckWrapping(eccKc.priv, &eccKc.privLen, argc, argv, argCurrent); } else if (ssc == A71_SSC_PUBLIC_KEY) { error = a7xConfigCmdCheckWrapping(eccKc.pub, &eccKc.pubLen, argc, argv, argCurrent); } if (error != AX_CLI_EXEC_OK) { return AX_CLI_EXEC_OK; } error = AX_CLI_EXEC_FAILED; *sw = a7xCmdSetEcc(ssc, index, &eccKc); if (*sw == SW_OK) { error = AX_CLI_EXEC_OK; } } return error; } /** * Get ecc (keypair/pub) as key pair components (key value contained in PEM key). Can be called from GUI. */ int a7xConfigGetEccKcFromPemfile(eccKeyComponents_t *eccKc, a71_SecureStorageClass_t ssc, const char *szKeyFile) { #ifdef OPENSSL // eccKeyComponents_t eccKcTls; FILE *fp; EC_KEY *ec_key = NULL; EVP_PKEY * pkey = NULL; const EC_POINT *pub_key = NULL; const BIGNUM *key_bn = BN_new(); U16 bufLen = 0; /* Read external key file and set public and (optional) private key values */ fp = fopen(szKeyFile, "r"); if (!fp) { printf("Unable to open the file: %s\n", szKeyFile); return AX_CLI_FILE_OPEN_FAILED; } ec_key = PEM_read_eckey(fp, NULL, NULL, NULL); // TODO: Evaluate/Investigate whether comparing to NULL captures all error conditions if (ec_key == NULL) { // Need to set the file to start and try to read t for public key fseek(fp, 0, SEEK_SET); // If pem file contains only public key read it pkey = PEM_read_PUBKEY(fp, NULL, NULL, NULL); if (pkey != NULL) { ec_key = EVP_PKEY_get1_EC_KEY(pkey); } if (ec_key == NULL) { printf("Failed to extract ECC key from %s.\n", szKeyFile); fclose(fp); return AX_CLI_FILE_PEM_READ_FAILED; } } fclose(fp); // TODO: Compare the ECC keypair's curve - as stored in the PEM file - with the one claimed in cryptoType/bits if (ssc == A71_SSC_KEY_PAIR) { U16 sw; sw = HOSTCRYPTO_GetPrivateKey(ec_key, eccKc->priv, &(eccKc->privLen), (U16)sizeof(eccKc->priv)); if (sw != SW_OK) { printf("HOSTCRYPTO_GetPrivateKey failed with 0x%04X.\n", sw); return AX_CLI_PEM_CONVERT_FAILED; } if ( ((eccKc->privLen)*8) != eccKc->bits ) { printf("KeyLen in pemfile (%d) does not match bits (%d) in function invocation.\n", bufLen*8, eccKc->bits); return AX_CLI_BIT_CURVE_ERROR; } #ifdef DBG_PROBE_A70 axPrintByteArray("ECCPrivateKey", eccKc->priv, eccKc->privLen, AX_COLON_32); #else printf("ECCPrivateKey: hidden\n"); #endif } // How do we know the key length? // Set Public Key pub_key = EC_KEY_get0_public_key(ec_key); key_bn = EC_POINT_point2bn(EC_KEY_get0_group(ec_key), pub_key, POINT_CONVERSION_UNCOMPRESSED, NULL, NULL); eccKc->pubLen = (U16)BN_bn2bin(key_bn, eccKc->pub); bufLen = (U16)(EC_GROUP_get_degree(EC_KEY_get0_group(ec_key))+7)/8; if ( (bufLen*8) != eccKc->bits ) { printf("KeyLen in pemfile (%d) does not match bits (%d) in function invocation.\n", bufLen*8, eccKc->bits); return AX_CLI_BIT_CURVE_ERROR; } // bufLen = 2*bufLen + 1; //Public key length axPrintByteArray("ECCPublicKey", eccKc->pub, eccKc->pubLen, AX_COLON_32); return AX_CLI_EXEC_OK; #else return AX_CLI_NOT_IMPLEMENTED; #endif } /** * A hook for the command line handler to invoke A71 commands * Applied Keywrapping is implicit in the length of the secret * 16 byte: no key wrapping * 24 byte: wrapped with rfc3394 */ int a7xConfigCmdSetSymWrap(U8 index, U8 *symSecret, U16 symSecretLen, U8 * wrapKey, U16 wrapKeyLen, U16 *sw) { int error = AX_CLI_EXEC_FAILED; if (wrapKeyLen>0) { U16 keyLen = symSecretLen; error = a7xConfigCmdkWrapping(symSecret, &keyLen, wrapKey, wrapKeyLen); if (error != AX_CLI_EXEC_OK) { return error; } *sw = a7xCmdSetSym(index, symSecret, keyLen); if (*sw == SW_OK) { error = AX_CLI_EXEC_OK; } } else { *sw = a7xCmdSetSym(index, symSecret, symSecretLen); if (*sw == SW_OK) { error = AX_CLI_EXEC_OK; } } return error; } /** * A hook for the command line handler to invoke A71 commands * Applied Keywrapping is implicit in the length of the secret * 16 byte: no key wrapping * 24 byte: wrapped with rfc3394 */ int a7xConfigCmdSetSym(U8 index, U8 *symSecret, U16 symSecretLen, U16 *sw) { int error = AX_CLI_EXEC_FAILED; *sw = a7xCmdSetSym(index, symSecret, symSecretLen); if (*sw == SW_OK) { error = AX_CLI_EXEC_OK; } return error; } /** * API wrapper for set sym command. Can be called from GUI. * Applied Keywrapping is implicit in the length of the secret * */ U16 a7xCmdSetSymWrap(U8 index, U8 *symSecret, U16 symSecretLen, U8 * wrapKey, U16 wrapKeyLen) { U16 error = AX_CLI_EXEC_FAILED; if (wrapKeyLen>0) { U16 keyLen = symSecretLen; error = (U16)a7xConfigCmdkWrapping(symSecret, &keyLen, wrapKey, wrapKeyLen); if (error != AX_CLI_EXEC_OK) { return error; } return a7xCmdSetSym(index, symSecret, keyLen); } else { return a7xCmdSetSym(index, symSecret, symSecretLen); } } /** * API wrapper for set sym command. Can be called from GUI. * Applied Keywrapping is implicit in the length of the secret * 16 byte: no key wrapping * 24 byte: wrapped with rfc3394 */ U16 a7xCmdSetSym(U8 index, U8 *symSecret, U16 symSecretLen) { U16 sw; switch (symSecretLen) { case 16: sw = A71_SetSymKey(index, symSecret, symSecretLen); break; case 24: sw = A71_SetRfc3394WrappedAesKey(index, symSecret, symSecretLen); break; default: sw = A7X_CONFIG_STATUS_API_ERROR; break; } return sw; } /** * A hook for the command line handler to invoke A71 commands */ int a7xConfigCmdSetCnt(U8 index, U8 *cnt, U16 cntLen, U16 *sw) { int error = AX_CLI_EXEC_FAILED; *sw = a7xCmdSetCnt(index, cnt, cntLen); if (*sw == SW_OK) { error = AX_CLI_EXEC_OK; } return error; } /** * API wrapper for set monotonic counter command. Can be called from GUI. */ U16 a7xCmdSetCnt(U8 index, U8 *cnt, U16 cntLen) { U16 sw; if (cntLen != 4) { DBGPRINTF("axCmdSetCnt(..., cntLen=%d)\n", cntLen); sw = A7X_CONFIG_STATUS_API_ERROR; } else { U32 counter; counter = (cnt[0] << 24) + (cnt[1] << 16) + (cnt[2] << 8) + cnt[3]; sw = A71_SetCounter(index, counter); } return sw; } /** * A hook for the command line handler to invoke A71 commands * Applied Keywrapping is implicit in the length of the config key * 16 byte: no key wrapping * 24 byte: wrapped with rfc3394 */ int a7xConfigCmdSetConfigKey(U8 index, U8 *configKey, U16 configKeyLen, U16 *sw) { int error = AX_CLI_EXEC_FAILED; *sw = a7xCmdSetConfigKey(index, configKey, configKeyLen); if (*sw == SW_OK) { error = AX_CLI_EXEC_OK; } return error; } /** * API wrapper for SetConfigKey command. Can be called from GUI. * Applied Keywrapping is implicit in the length of the secret * 16 byte: no key wrapping * 24 byte: wrapped with rfc3394 */ U16 a7xCmdSetConfigKey(U8 index, U8 *configKey, U16 configKeyLen) { U16 sw; switch (configKeyLen) { case 16: sw = A71_SetConfigKey(index, configKey, configKeyLen); break; case 24: sw = A71_SetRfc3394WrappedConfigKey(index, configKey, configKeyLen); break; default: sw = A7X_CONFIG_STATUS_API_ERROR; break; } return sw; }