459 lines
17 KiB
C
459 lines
17 KiB
C
/**
|
|
* MIT License
|
|
*
|
|
* Copyright (c) 2018 Infineon Technologies AG
|
|
*
|
|
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
* of this software and associated documentation files (the "Software"), to deal
|
|
* in the Software without restriction, including without limitation the rights
|
|
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
* copies of the Software, and to permit persons to whom the Software is
|
|
* furnished to do so, subject to the following conditions:
|
|
*
|
|
* The above copyright notice and this permission notice shall be included in all
|
|
* copies or substantial portions of the Software.
|
|
*
|
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
* SOFTWARE
|
|
*
|
|
* \file
|
|
*
|
|
* \brief This file implements the OPTIGA Crypto toolbox APIs.
|
|
*
|
|
* \addtogroup grOptigaCrypt
|
|
* @{
|
|
*/
|
|
|
|
#include "optiga/optiga_crypt.h"
|
|
#include "optiga/pal/pal_os_lock.h"
|
|
|
|
optiga_lib_status_t optiga_crypt_random(optiga_rng_types_t rng_type,
|
|
uint8_t * random_data,
|
|
uint16_t random_data_length)
|
|
{
|
|
optiga_lib_status_t return_value = OPTIGA_LIB_ERROR;
|
|
|
|
sRngOptions_d rand_options;
|
|
sCmdResponse_d rand_response;
|
|
|
|
rand_options.eRngType = (eRngType_d)rng_type;
|
|
rand_options.wRandomDataLen = random_data_length;
|
|
|
|
rand_response.prgbBuffer = random_data;
|
|
rand_response.wBufferLength = random_data_length;
|
|
rand_response.wRespLength = 0;
|
|
|
|
while (pal_os_lock_acquire() != OPTIGA_LIB_SUCCESS);
|
|
return_value = CmdLib_GetRandom(&rand_options,&rand_response);
|
|
pal_os_lock_release();
|
|
|
|
if (CMD_LIB_OK != return_value)
|
|
{
|
|
return OPTIGA_LIB_ERROR;
|
|
}
|
|
return OPTIGA_LIB_SUCCESS;
|
|
}
|
|
|
|
optiga_lib_status_t optiga_crypt_hash_start(optiga_hash_context_t * hash_ctx)
|
|
{
|
|
optiga_lib_status_t return_value;
|
|
uint8_t rgbDataStream[1];
|
|
sCalcHash_d hash_options;
|
|
|
|
hash_options.eHashAlg = (eHashAlg_d)(hash_ctx->hash_algo);
|
|
hash_options.eHashDataType = eDataStream;
|
|
hash_options.eHashSequence = eStartHash;
|
|
|
|
hash_options.sDataStream.prgbStream = rgbDataStream;
|
|
hash_options.sDataStream.wLen =0x00; //No data
|
|
|
|
hash_options.sContextInfo.pbContextData = hash_ctx->context_buffer;
|
|
hash_options.sContextInfo.dwContextLen = hash_ctx->context_buffer_length;
|
|
hash_options.sContextInfo.eContextAction = eExport;
|
|
|
|
while (pal_os_lock_acquire() != OPTIGA_LIB_SUCCESS);
|
|
return_value = CmdLib_CalcHash(&hash_options);
|
|
pal_os_lock_release();
|
|
|
|
if (CMD_LIB_OK != return_value)
|
|
{
|
|
return OPTIGA_LIB_ERROR;
|
|
}
|
|
return OPTIGA_LIB_SUCCESS;
|
|
}
|
|
|
|
optiga_lib_status_t optiga_crypt_hash_update(optiga_hash_context_t * hash_ctx,
|
|
uint8_t source_of_data_to_hash,
|
|
void * data_to_hash)
|
|
{
|
|
optiga_lib_status_t return_value;
|
|
sCalcHash_d hash_options;
|
|
//To read the maximum communication buffer size.
|
|
uint16_t max_comms_buffer;
|
|
//To hold the remaining communication buffer size to hold the data
|
|
uint16_t remaining_comm_buffer_size = 0;
|
|
|
|
//Hash the data
|
|
//Available_Size = (wMaxCommsBuffer - #CALC_HASH_FIXED_OVERHEAD_SIZE)
|
|
uint16_t remaining_comm_bfr_sz_basic;
|
|
|
|
//Import context to security chip, calculate hash and export hash
|
|
//Available_Size = (wMaxCommsBuffer - #CALC_HASH_FIXED_OVERHEAD_SIZE - #CALC_HASH_IMPORT_AND_EXPORT_OVERHEAD_SIZE - #CALC_HASH_SHA256_CONTEXT_SIZE)
|
|
uint16_t remaining_comm_bfr_sz_with_import_export;
|
|
|
|
//Import context to security chip and calculate hash
|
|
//Available_Size = (wMaxCommsBuffer - #CALC_HASH_FIXED_OVERHEAD_SIZE - #CALC_HASH_IMPORT_OR_EXPORT_OVERHEAD_SIZE - #CALC_HASH_SHA256_CONTEXT_SIZE)
|
|
uint16_t remaining_comm_bfr_sz_with_import;
|
|
|
|
//Calulate hash and export context out of security chip
|
|
//Available_Size = (wMaxCommsBuffer - CALC_HASH_FIXED_OVERHEAD_SIZE - CALC_HASH_IMPORT_OR_EXPORT_OVERHEAD_SIZE)
|
|
uint16_t remaining_comm_bfr_sz_with_export;
|
|
|
|
uint32_t size_of_data_to_hash = 0;
|
|
uint8_t chaining = 0;
|
|
|
|
hash_options.eHashAlg = (eHashAlg_d)(hash_ctx->hash_algo);
|
|
hash_options.eHashDataType = source_of_data_to_hash == OPTIGA_CRYPT_HOST_DATA?eDataStream:eOIDData;
|
|
hash_options.eHashSequence = eContinueHash;
|
|
|
|
//Hash context
|
|
hash_options.sContextInfo.pbContextData = hash_ctx->context_buffer;
|
|
hash_options.sContextInfo.dwContextLen = hash_ctx->context_buffer_length;
|
|
hash_options.sContextInfo.eContextAction = eImportExport;
|
|
|
|
max_comms_buffer = CmdLib_GetMaxCommsBufferSize();
|
|
|
|
remaining_comm_bfr_sz_basic = max_comms_buffer - CALC_HASH_FIXED_OVERHEAD_SIZE;
|
|
remaining_comm_bfr_sz_with_import_export = max_comms_buffer -(CALC_HASH_FIXED_OVERHEAD_SIZE + \
|
|
CALC_HASH_IMPORT_AND_EXPORT_OVERHEAD_SIZE + \
|
|
CALC_HASH_SHA256_CONTEXT_SIZE);
|
|
|
|
remaining_comm_bfr_sz_with_import = max_comms_buffer -(CALC_HASH_FIXED_OVERHEAD_SIZE+ \
|
|
CALC_HASH_IMPORT_OR_EXPORT_OVERHEAD_SIZE+ \
|
|
CALC_HASH_SHA256_CONTEXT_SIZE);
|
|
|
|
remaining_comm_bfr_sz_with_export = max_comms_buffer -(CALC_HASH_FIXED_OVERHEAD_SIZE + \
|
|
CALC_HASH_IMPORT_OR_EXPORT_OVERHEAD_SIZE);
|
|
|
|
if ((eDataType_d)source_of_data_to_hash == OPTIGA_CRYPT_HOST_DATA)
|
|
{
|
|
hash_options.sDataStream.prgbStream = (uint8_t *)(((hash_data_from_host_t *)data_to_hash)->buffer);
|
|
size_of_data_to_hash = ((hash_data_from_host_t *)data_to_hash)->length;
|
|
remaining_comm_buffer_size = size_of_data_to_hash;
|
|
|
|
//Verify whether (Import & export) + data options can be set in one command or not
|
|
if (remaining_comm_bfr_sz_with_import_export<size_of_data_to_hash)
|
|
{
|
|
chaining = 1;
|
|
remaining_comm_buffer_size = remaining_comm_bfr_sz_with_import;
|
|
if (remaining_comm_bfr_sz_with_import>size_of_data_to_hash)
|
|
{
|
|
remaining_comm_buffer_size = size_of_data_to_hash;
|
|
}
|
|
hash_options.sContextInfo.eContextAction = eImport;
|
|
}
|
|
hash_options.sDataStream.wLen = remaining_comm_buffer_size;
|
|
}
|
|
else
|
|
{
|
|
hash_options.sOIDData.wOID = ((hash_data_in_optiga_t *)data_to_hash)->oid;
|
|
hash_options.sOIDData.wOffset = ((hash_data_in_optiga_t *)data_to_hash)->offset;
|
|
hash_options.sOIDData.wLength = ((hash_data_in_optiga_t *)data_to_hash)->length;
|
|
}
|
|
|
|
while (1)
|
|
{
|
|
while (pal_os_lock_acquire() != OPTIGA_LIB_SUCCESS);
|
|
return_value = CmdLib_CalcHash(&hash_options);
|
|
pal_os_lock_release();
|
|
|
|
if (CMD_LIB_OK != return_value)
|
|
{
|
|
break;
|
|
}
|
|
|
|
if (!chaining)
|
|
{
|
|
return_value = OPTIGA_LIB_SUCCESS;
|
|
break;
|
|
}
|
|
else
|
|
{
|
|
hash_options.sDataStream.prgbStream += remaining_comm_buffer_size;
|
|
size_of_data_to_hash -= remaining_comm_buffer_size;
|
|
|
|
remaining_comm_buffer_size = size_of_data_to_hash;
|
|
hash_options.sContextInfo.eContextAction = eUnused;
|
|
//Verify whether export + data options can be set in one command or not
|
|
if (remaining_comm_bfr_sz_with_export < size_of_data_to_hash)
|
|
{
|
|
remaining_comm_buffer_size = remaining_comm_bfr_sz_basic;
|
|
if (remaining_comm_bfr_sz_basic > size_of_data_to_hash)
|
|
{
|
|
remaining_comm_buffer_size = size_of_data_to_hash;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
hash_options.sContextInfo.eContextAction = eExport;
|
|
chaining = 0;
|
|
}
|
|
hash_options.sDataStream.wLen = remaining_comm_buffer_size;
|
|
}
|
|
}
|
|
|
|
return return_value;
|
|
}
|
|
|
|
optiga_lib_status_t optiga_crypt_hash_finalize(optiga_hash_context_t * hash_ctx,
|
|
uint8_t * hash_output)
|
|
{
|
|
optiga_lib_status_t return_value;
|
|
uint8_t datastream[1];
|
|
sCalcHash_d hash_options;
|
|
|
|
hash_options.eHashAlg = (eHashAlg_d)hash_ctx->hash_algo;
|
|
hash_options.eHashDataType = eDataStream;
|
|
hash_options.eHashSequence = eFinalizeHash;
|
|
hash_options.sDataStream.prgbStream = datastream;
|
|
hash_options.sDataStream.wLen = 0x00; //No data
|
|
|
|
hash_options.sContextInfo.pbContextData = hash_ctx->context_buffer;
|
|
hash_options.sContextInfo.dwContextLen = hash_ctx->context_buffer_length;
|
|
hash_options.sContextInfo.eContextAction = eImport;
|
|
|
|
hash_options.sOutHash.prgbBuffer = hash_output;
|
|
if(hash_options.eHashAlg == eSHA256)
|
|
{
|
|
hash_options.sOutHash.wBufferLength = 32;
|
|
}
|
|
|
|
while (pal_os_lock_acquire() != OPTIGA_LIB_SUCCESS);
|
|
return_value = CmdLib_CalcHash(&hash_options);
|
|
pal_os_lock_release();
|
|
|
|
if (CMD_LIB_OK != return_value)
|
|
{
|
|
return OPTIGA_LIB_ERROR;
|
|
}
|
|
return OPTIGA_LIB_SUCCESS;
|
|
}
|
|
|
|
optiga_lib_status_t optiga_crypt_ecc_generate_keypair(optiga_ecc_curve_t curve_id,
|
|
uint8_t key_usage,
|
|
bool_t export_private_key,
|
|
void * private_key,
|
|
uint8_t * public_key,
|
|
uint16_t * public_key_length)
|
|
{
|
|
optiga_lib_status_t return_value;
|
|
sKeyPairOption_d keypair_options;
|
|
sOutKeyPair_d public_key_out;
|
|
|
|
keypair_options.eAlgId = (eAlgId_d)curve_id;
|
|
keypair_options.eKeyUsage = (eKeyUsage_d)key_usage;
|
|
|
|
|
|
if (export_private_key)
|
|
{
|
|
keypair_options.eKeyExport = eExportKeyPair;
|
|
|
|
public_key_out.sPublicKey.prgbStream = public_key;
|
|
public_key_out.sPublicKey.wLen = *public_key_length;
|
|
public_key_out.sPrivateKey.prgbStream = private_key;
|
|
public_key_out.sPrivateKey.wLen = 0xffff;
|
|
}
|
|
else
|
|
{
|
|
keypair_options.eKeyExport = eStorePrivKeyOnly;
|
|
keypair_options.wOIDPrivKey = *(uint16_t *)private_key;
|
|
|
|
public_key_out.sPublicKey.prgbStream = public_key;
|
|
public_key_out.sPublicKey.wLen = *public_key_length;
|
|
}
|
|
|
|
|
|
|
|
while (pal_os_lock_acquire() != OPTIGA_LIB_SUCCESS);
|
|
return_value = CmdLib_GenerateKeyPair(&keypair_options,&public_key_out);
|
|
pal_os_lock_release();
|
|
|
|
if (CMD_LIB_OK != return_value)
|
|
{
|
|
return OPTIGA_LIB_ERROR;
|
|
}
|
|
//store updated public key length .
|
|
*( public_key_length) = public_key_out.sPublicKey.wLen;
|
|
return OPTIGA_LIB_SUCCESS;
|
|
}
|
|
|
|
optiga_lib_status_t optiga_crypt_ecdsa_sign (uint8_t * digest,
|
|
uint8_t digest_length,
|
|
optiga_key_id_t private_key,
|
|
uint8_t * signature,
|
|
uint16_t * signature_length)
|
|
{
|
|
optiga_lib_status_t return_value;
|
|
sbBlob_d sign;
|
|
sCalcSignOptions_d sign_options;
|
|
|
|
sign_options.eSignScheme = eECDSA_FIPS_186_3_WITHOUT_HASH;
|
|
sign_options.wOIDSignKey = private_key;
|
|
|
|
sign_options.sDigestToSign.prgbStream = digest;
|
|
sign_options.sDigestToSign.wLen = digest_length;
|
|
|
|
sign.prgbStream = signature;
|
|
sign.wLen = *signature_length;
|
|
|
|
while (pal_os_lock_acquire() != OPTIGA_LIB_SUCCESS);
|
|
return_value = CmdLib_CalculateSign(&sign_options,&sign);
|
|
pal_os_lock_release();
|
|
|
|
if (CMD_LIB_OK != return_value)
|
|
{
|
|
return OPTIGA_LIB_ERROR;
|
|
}
|
|
*signature_length = sign.wLen;
|
|
return OPTIGA_LIB_SUCCESS;
|
|
}
|
|
|
|
optiga_lib_status_t optiga_crypt_ecdsa_verify (uint8_t * digest,
|
|
uint8_t digest_length,
|
|
uint8_t * signature,
|
|
uint16_t signature_length,
|
|
uint8_t public_key_source_type,
|
|
void * public_key)
|
|
{
|
|
optiga_lib_status_t return_value;
|
|
sVerifyOption_d verifysign_options;
|
|
sbBlob_d sign, dgst;
|
|
|
|
verifysign_options.eSignScheme = eECDSA_FIPS_186_3_WITHOUT_HASH;
|
|
verifysign_options.sPubKeyInput.eAlgId = (eAlgId_d )(((public_key_from_host_t *)public_key)->curve);
|
|
|
|
if (public_key_source_type == OPTIGA_CRYPT_HOST_DATA)
|
|
{
|
|
verifysign_options.eVerifyDataType = eDataStream;
|
|
verifysign_options.sPubKeyInput.sDataStream.prgbStream = (uint8_t *)((( public_key_from_host_t *)public_key)->public_key);
|
|
verifysign_options.sPubKeyInput.sDataStream.wLen = (((public_key_from_host_t *)public_key)->length);
|
|
}
|
|
else if (public_key_source_type == OPTIGA_CRYPT_OID_DATA)
|
|
{
|
|
verifysign_options.eVerifyDataType = eOIDData;
|
|
verifysign_options.wOIDPubKey = *((uint16_t *)public_key);
|
|
}
|
|
|
|
dgst.prgbStream = digest;
|
|
dgst.wLen = digest_length;
|
|
|
|
sign.prgbStream = signature;
|
|
sign.wLen = signature_length;
|
|
|
|
while (pal_os_lock_acquire() != OPTIGA_LIB_SUCCESS);
|
|
return_value = CmdLib_VerifySign(&verifysign_options, &dgst, &sign);
|
|
pal_os_lock_release();
|
|
|
|
if(CMD_LIB_OK == return_value)
|
|
{
|
|
return_value = OPTIGA_LIB_SUCCESS;
|
|
}
|
|
|
|
return return_value;
|
|
}
|
|
|
|
optiga_lib_status_t optiga_crypt_ecdh(optiga_key_id_t private_key,
|
|
public_key_from_host_t * public_key,
|
|
bool_t export_to_host,
|
|
uint8_t * shared_secret)
|
|
{
|
|
optiga_lib_status_t return_value = OPTIGA_LIB_ERROR;
|
|
sCalcSSecOptions_d shared_secret_options;
|
|
sbBlob_d sharedsecret;
|
|
|
|
shared_secret_options.eKeyAgreementType = eECDH_NISTSP80056A;
|
|
shared_secret_options.wOIDPrivKey = private_key;
|
|
|
|
public_key->curve == OPTIGA_ECC_NIST_P_256 ? (sharedsecret.wLen = 32) : (sharedsecret.wLen = 64);
|
|
|
|
shared_secret_options.ePubKeyAlgId = (eAlgId_d)public_key->curve;
|
|
shared_secret_options.sPubKey.prgbStream = public_key->public_key;
|
|
shared_secret_options.sPubKey.wLen = public_key->length;
|
|
|
|
if (export_to_host == 1)
|
|
{
|
|
shared_secret_options.wOIDSharedSecret = 0x0000;
|
|
sharedsecret.prgbStream = (uint8_t *)shared_secret;
|
|
}
|
|
else
|
|
{
|
|
//shared secret is stored in OID of OPTIGA
|
|
shared_secret_options.wOIDSharedSecret = *((uint16_t *)shared_secret);
|
|
}
|
|
|
|
while (pal_os_lock_acquire() != OPTIGA_LIB_SUCCESS);
|
|
return_value = CmdLib_CalculateSharedSecret(&shared_secret_options, &sharedsecret);
|
|
pal_os_lock_release();
|
|
|
|
if(CMD_LIB_OK == return_value)
|
|
{
|
|
return_value = OPTIGA_LIB_SUCCESS;
|
|
}
|
|
|
|
return return_value;
|
|
}
|
|
|
|
|
|
optiga_lib_status_t optiga_crypt_tls_prf_sha256(uint16_t secret,
|
|
uint8_t * label,
|
|
uint16_t label_length,
|
|
uint8_t * seed,
|
|
uint16_t seed_length,
|
|
uint16_t derived_key_length,
|
|
bool_t export_to_host,
|
|
uint8_t * derived_key)
|
|
{
|
|
optiga_lib_status_t return_value = OPTIGA_LIB_ERROR;
|
|
sDeriveKeyOptions_d derivekey_options;
|
|
sbBlob_d derivekey_output_buffer;
|
|
|
|
derivekey_options.eKDM = eTLS_PRF_SHA256;
|
|
derivekey_options.sSeed.prgbStream = seed;
|
|
derivekey_options.sSeed.wLen = seed_length;
|
|
derivekey_options.wOIDSharedSecret = secret;
|
|
|
|
if (derived_key_length < 16)
|
|
{
|
|
derived_key_length += (16 - derived_key_length);
|
|
}
|
|
|
|
derivekey_options.wDerivedKeyLen = derived_key_length;
|
|
|
|
if (export_to_host == 1)
|
|
{
|
|
derivekey_options.wOIDDerivedKey = 0x0000;
|
|
derivekey_output_buffer.prgbStream = (uint8_t *)derived_key;
|
|
derivekey_output_buffer.wLen = derived_key_length;
|
|
}
|
|
else
|
|
{
|
|
derivekey_options.wOIDDerivedKey = *((uint16_t *)derived_key);
|
|
}
|
|
|
|
while (pal_os_lock_acquire() != OPTIGA_LIB_SUCCESS);
|
|
return_value = CmdLib_DeriveKey(&derivekey_options, &derivekey_output_buffer);
|
|
pal_os_lock_release();
|
|
|
|
if(CMD_LIB_OK == return_value)
|
|
{
|
|
return_value = OPTIGA_LIB_SUCCESS;
|
|
}
|
|
|
|
return return_value;
|
|
}
|