blob: 551d8b158f88e3e4595704ebfc7de74f85a30601 [file] [log] [blame]
/*
*
* Copyright 2018-2020 NXP
* SPDX-License-Identifier: Apache-2.0
*/
#include <fsl_sss_mbedtls_apis.h>
#define MBEDTLS_DO_LITTLE_ENDIAN
#if SSS_HAVE_MBEDTLS
#include <mbedtls/version.h>
#include <stdlib.h>
#ifdef MBEDTLS_FS_IO
#include <memory.h>
#endif
#include <inttypes.h>
#include <mbedtls/aes.h>
#include <mbedtls/base64.h>
#include <mbedtls/cmac.h>
#include <mbedtls/des.h>
#include <mbedtls/ecdh.h>
#include <mbedtls/md.h>
#include <nxEnsure.h>
#include <nxLog_sss.h>
#include <sm_types.h>
#include <stdio.h>
#include <string.h>
#include <fsl_sss_util_asn1_der.h>
// #include "../../ex/inc/ex_sss_objid.h" // Enable to test SIMW-656
#define MAX_KEY_OBJ_COUNT KS_N_ENTIRES
#define MAX_FILE_NAME_SIZE 255
#define MAX_SHARED_SECRET_DERIVED_DATA 255
#define BEGIN_PRIVATE "-----BEGIN PRIVATE KEY-----\n"
#define END_PRIVATE "\n-----END PRIVATE KEY-----"
#define BEGIN_PUBLIC "-----BEGIN PUBLIC KEY-----\n"
#define END_PUBLIC "\n-----END PUBLIC KEY-----"
#define CIPHER_BLOCK_SIZE 16
/* ************************************************************************** */
/* Functions : Private sss mbedtls delceration */
/* ************************************************************************** */
static sss_status_t sss_mbedtls_drbg_seed(sss_mbedtls_session_t *pSession, const char *pers, size_t persLen);
#if SSSFTR_SW_ECC && SSS_HAVE_TESTCOUNTERPART
static sss_status_t sss_mbedtls_generate_ecp_key(
mbedtls_pk_context *pkey, sss_mbedtls_session_t *pSession, size_t keyBitLen, sss_cipher_type_t key_typ);
#endif
#if SSSFTR_SW_RSA && SSS_HAVE_TESTCOUNTERPART
static sss_status_t sss_mbedtls_generate_rsa_key(
mbedtls_pk_context *pkey, sss_mbedtls_session_t *pSession, size_t keyBitLen);
#endif
#if SSSFTR_SW_TESTCOUNTERPART
static sss_status_t sss_mbedtls_hkdf_extract(const mbedtls_md_info_t *md,
const uint8_t *salt,
size_t salt_len,
const uint8_t *ikm,
size_t ikm_len,
uint8_t *prk);
static sss_status_t sss_mbedtls_hkdf_expand(const mbedtls_md_info_t *md,
const uint8_t *prk,
size_t prk_len,
const uint8_t *info,
size_t info_len,
uint8_t *okm,
size_t okm_len);
#endif
static sss_status_t sss_mbedtls_set_key(
sss_mbedtls_object_t *keyObject, const uint8_t *data, size_t dataLen, size_t keyBitLen);
#if SSS_HAVE_TESTCOUNTERPART
static sss_status_t sss_mbedtls_aead_ccm_finish(
sss_mbedtls_aead_t *context, uint8_t *destData, size_t *destLen, uint8_t *tag, size_t *tagLen);
static sss_status_t sss_mbedtls_aead_ccm_update(sss_mbedtls_aead_t *context, const uint8_t *srcData, size_t srcLen);
#endif
/* ************************************************************************** */
/* Functions : sss_mbedtls_session */
/* ************************************************************************** */
#ifndef MBEDTLS_CTR_DRBG_C
#error Need MBEDTLS_CTR_DRBG_C defined
#endif
sss_status_t sss_mbedtls_session_create(sss_mbedtls_session_t *session,
sss_type_t subsystem,
uint32_t application_id,
sss_connection_type_t connection_type,
void *connectionData)
{
sss_status_t retval = kStatus_SSS_Success;
/* Nothing special to be handled */
return retval;
}
sss_status_t sss_mbedtls_session_open(sss_mbedtls_session_t *session,
sss_type_t subsystem,
uint32_t application_id,
sss_connection_type_t connection_type,
void *connectionData)
{
sss_status_t retval = kStatus_SSS_InvalidArgument;
memset(session, 0, sizeof(*session));
static const char pers[] = "mbedtls_session";
ENSURE_OR_GO_EXIT(connection_type == kSSS_ConnectionType_Plain);
#ifdef MBEDTLS_FS_IO
if (connectionData == NULL) {
/* Nothing */
}
else {
const char *szRootPath = (const char *)connectionData;
session->szRootPath = szRootPath;
}
#else
if (connectionData != NULL) {
/* Can't support connectionData != NULL for mbedTLS without
* MBEDTLS_FS_IO */
retval = kStatus_SSS_InvalidArgument;
goto exit;
}
#endif
retval = kStatus_SSS_Fail;
session->ctr_drbg = SSS_MALLOC(sizeof(*session->ctr_drbg));
ENSURE_OR_GO_EXIT(session->ctr_drbg != NULL);
session->entropy = SSS_MALLOC(sizeof(*session->entropy));
ENSURE_OR_GO_EXIT(session->entropy != NULL);
retval = kStatus_SSS_InvalidArgument;
mbedtls_ctr_drbg_init((session->ctr_drbg));
mbedtls_entropy_init((session->entropy));
retval = sss_mbedtls_drbg_seed(session, pers, sizeof(pers) - 1);
if (retval != kStatus_SSS_Success) {
LOG_E("MbedTLS:DRBG Failed");
goto exit;
}
/* Success */
session->subsystem = subsystem;
exit:
return retval;
}
sss_status_t sss_mbedtls_session_prop_get_u32(sss_mbedtls_session_t *session, uint32_t property, uint32_t *pValue)
{
sss_status_t retval = kStatus_SSS_Fail;
/* TBU */
return retval;
}
sss_status_t sss_mbedtls_session_prop_get_au8(
sss_mbedtls_session_t *session, uint32_t property, uint8_t *pValue, size_t *pValueLen)
{
sss_status_t retval = kStatus_SSS_Fail;
/* TBU */
return retval;
}
void sss_mbedtls_session_close(sss_mbedtls_session_t *session)
{
if (session->ctr_drbg != NULL)
SSS_FREE(session->ctr_drbg);
if (session->entropy != NULL)
SSS_FREE(session->entropy);
memset(session, 0, sizeof(*session));
}
void sss_mbedtls_session_delete(sss_mbedtls_session_t *session)
{
;
}
/* End: mbedtls_session */
/* ************************************************************************** */
/* Functions : sss_mbedtls_keyobj */
/* ************************************************************************** */
sss_status_t sss_mbedtls_key_object_init(sss_mbedtls_object_t *keyObject, sss_mbedtls_key_store_t *keyStore)
{
sss_status_t retval = kStatus_SSS_Fail;
ENSURE_OR_GO_CLEANUP(keyObject);
ENSURE_OR_GO_CLEANUP(keyStore);
memset(keyObject, 0, sizeof(*keyObject));
keyObject->keyStore = keyStore;
retval = kStatus_SSS_Success;
cleanup:
return retval;
}
sss_status_t sss_mbedtls_key_object_allocate_handle(sss_mbedtls_object_t *keyObject,
uint32_t keyId,
sss_key_part_t key_part,
sss_cipher_type_t cipherType,
size_t keyByteLenMax,
uint32_t options)
{
sss_status_t retval = kStatus_SSS_Fail;
ENSURE_OR_GO_CLEANUP(keyObject);
ENSURE_OR_GO_CLEANUP(keyId != 0);
ENSURE_OR_GO_CLEANUP(keyId != 0xFFFFFFFFu);
#ifdef EX_SSS_OBJID_TEST_START
if (keyId < EX_SSS_OBJID_TEST_START)
return kStatus_SSS_Fail;
if (keyId > EX_SSS_OBJID_TEST_END)
return kStatus_SSS_Fail;
#endif
if (options != kKeyObject_Mode_Persistent && options != kKeyObject_Mode_Transient) {
LOG_E("sss_mbedtls_key_object_allocate_handle option invalid 0x%X", options);
retval = kStatus_SSS_Fail;
goto cleanup;
}
if ((unsigned int)key_part > UINT8_MAX) {
LOG_E(" Only objectType 8 bits wide supported");
retval = kStatus_SSS_Fail;
goto cleanup;
}
#if defined(MBEDTLS_FS_IO) && !AX_EMBEDDED
if (options == kKeyObject_Mode_Persistent) {
uint32_t i;
sss_mbedtls_object_t **ks;
ENSURE_OR_GO_CLEANUP(keyObject->keyStore);
ENSURE_OR_GO_CLEANUP(keyObject->keyStore->max_object_count != 0);
retval = ks_common_update_fat(
keyObject->keyStore->keystore_shadow, keyId, key_part, cipherType, 0, 0, (uint16_t)keyByteLenMax);
ENSURE_OR_GO_CLEANUP(retval == kStatus_SSS_Success);
ks = keyObject->keyStore->objects;
retval = kStatus_SSS_Fail;
for (i = 0; i < keyObject->keyStore->max_object_count; i++) {
if (ks[i] == NULL) {
ks[i] = keyObject;
retval = ks_mbedtls_key_object_create(keyObject, keyId, key_part, cipherType, keyByteLenMax, options);
break;
}
}
}
else
#endif
{
retval = ks_mbedtls_key_object_create(keyObject, keyId, key_part, cipherType, keyByteLenMax, options);
}
cleanup:
return retval;
}
sss_status_t sss_mbedtls_key_object_get_handle(sss_mbedtls_object_t *keyObject, uint32_t keyId)
{
sss_status_t retval = kStatus_SSS_Fail;
#if defined(MBEDTLS_FS_IO) && !AX_EMBEDDED
uint32_t i;
ENSURE_OR_GO_CLEANUP(keyObject);
ENSURE_OR_GO_CLEANUP(keyObject->keyStore);
retval = kStatus_SSS_Success;
/* If key store already has loaded this and shared this - fail */
for (i = 0; i < keyObject->keyStore->max_object_count; i++) {
if (keyObject->keyStore->objects[i] != NULL && keyObject->keyStore->objects[i]->keyId == keyId) {
/* Key Object already loaded and shared in another instance */
LOG_E("KeyID 0x%X already loaded / shared", keyId);
retval = kStatus_SSS_Fail;
break;
}
}
if (retval == kStatus_SSS_Success) {
for (i = 0; i < keyObject->keyStore->max_object_count; i++) {
if (keyObject->keyStore->objects[i] == NULL) {
retval = ks_mbedtls_load_key(keyObject, keyObject->keyStore->keystore_shadow, keyId);
if (retval == kStatus_SSS_Success) {
keyObject->keyStore->objects[i] = keyObject;
}
break;
}
}
}
cleanup:
#endif
return retval;
}
sss_status_t sss_mbedtls_key_object_set_user(sss_mbedtls_object_t *keyObject, uint32_t user, uint32_t options)
{
sss_status_t retval = kStatus_SSS_Fail;
ENSURE_OR_GO_EXIT((keyObject->accessRights & kAccessPermission_SSS_ChangeAttributes));
retval = kStatus_SSS_Success;
keyObject->user_id = user;
exit:
return retval;
}
sss_status_t sss_mbedtls_key_object_set_purpose(sss_mbedtls_object_t *keyObject, sss_mode_t purpose, uint32_t options)
{
sss_status_t retval = kStatus_SSS_Fail;
ENSURE_OR_GO_EXIT((keyObject->accessRights & kAccessPermission_SSS_ChangeAttributes));
retval = kStatus_SSS_Success;
keyObject->purpose = purpose;
exit:
return retval;
}
sss_status_t sss_mbedtls_key_object_set_access(sss_mbedtls_object_t *keyObject, uint32_t access, uint32_t options)
{
sss_status_t retval = kStatus_SSS_Fail;
ENSURE_OR_GO_EXIT((keyObject->accessRights & kAccessPermission_SSS_ChangeAttributes));
retval = kStatus_SSS_Success;
keyObject->accessRights = access;
exit:
return retval;
}
sss_status_t sss_mbedtls_key_object_set_eccgfp_group(sss_mbedtls_object_t *keyObject, sss_eccgfp_group_t *group)
{
sss_status_t retval = kStatus_SSS_Success;
/* TBU */
return retval;
}
sss_status_t sss_mbedtls_key_object_get_user(sss_mbedtls_object_t *keyObject, uint32_t *user)
{
sss_status_t retval = kStatus_SSS_Success;
*user = keyObject->user_id;
return retval;
}
sss_status_t sss_mbedtls_key_object_get_purpose(sss_mbedtls_object_t *keyObject, sss_mode_t *purpose)
{
sss_status_t retval = kStatus_SSS_Success;
*purpose = keyObject->purpose;
return retval;
}
sss_status_t sss_mbedtls_key_object_get_access(sss_mbedtls_object_t *keyObject, uint32_t *access)
{
sss_status_t retval = kStatus_SSS_Success;
*access = keyObject->accessRights;
return retval;
}
void sss_mbedtls_key_object_free(sss_mbedtls_object_t *keyObject)
{
if (keyObject != NULL) {
#ifdef MBEDTLS_FS_IO
if (keyObject->keyStore != NULL && keyObject->objectType != 0) {
unsigned int i = 0;
for (i = 0; i < keyObject->keyStore->max_object_count; i++) {
if (keyObject->keyStore->objects[i] == keyObject) {
keyObject->keyStore->objects[i] = NULL;
break;
}
}
}
#endif
if (keyObject->contents != NULL && keyObject->contents_must_free) {
switch (keyObject->objectType) {
case kSSS_KeyPart_Public:
case kSSS_KeyPart_Pair:
case kSSS_KeyPart_Private: {
mbedtls_pk_context *pk;
pk = (mbedtls_pk_context *)keyObject->contents;
mbedtls_pk_free(pk);
SSS_FREE(pk);
break;
}
default:
SSS_FREE(keyObject->contents);
}
}
memset(keyObject, 0, sizeof(*keyObject));
} /* if (keyObject != NULL) */
}
/* End: mbedtls_keyobj */
/* ************************************************************************** */
/* Functions : sss_mbedtls_keyderive */
/* ************************************************************************** */
sss_status_t sss_mbedtls_derive_key_context_init(sss_mbedtls_derive_key_t *context,
sss_mbedtls_session_t *session,
sss_mbedtls_object_t *keyObject,
sss_algorithm_t algorithm,
sss_mode_t mode)
{
sss_status_t retval = kStatus_SSS_Fail;
#if SSSFTR_SW_ECC
ENSURE_OR_GO_CLEANUP(context);
ENSURE_OR_GO_CLEANUP(session);
ENSURE_OR_GO_CLEANUP(keyObject);
ENSURE_OR_GO_CLEANUP(keyObject->contents);
context->session = session;
context->keyObject = keyObject;
context->algorithm = algorithm;
context->mode = mode;
retval = kStatus_SSS_Success;
cleanup:
#endif
return retval;
}
sss_status_t sss_mbedtls_derive_key_one_go(sss_mbedtls_derive_key_t *context,
const uint8_t *saltData,
size_t saltLen,
const uint8_t *info,
size_t infoLen,
sss_mbedtls_object_t *derivedKeyObject,
uint16_t deriveDataLen)
{
size_t adjustedSaltLen = saltLen;
if (context->mode == kMode_SSS_HKDF_ExpandOnly) {
adjustedSaltLen = 0;
}
// The actual implementation (also used by legacy SSS API) decides
// on the saltLen parameter to apply either HKDF_EE or HKDK_ExpandOnly (saltLen == 0)
return sss_mbedtls_derive_key_go(
context, saltData, adjustedSaltLen, info, infoLen, derivedKeyObject, deriveDataLen, NULL, NULL);
}
sss_status_t sss_mbedtls_derive_key_sobj_one_go(sss_mbedtls_derive_key_t *context,
sss_mbedtls_object_t *saltKeyObject,
const uint8_t *info,
size_t infoLen,
sss_mbedtls_object_t *derivedKeyObject,
uint16_t deriveDataLen)
{
uint8_t saltData[1024] = {0};
size_t saltLen = sizeof(saltData);
size_t dummySize;
sss_status_t status;
// The actual implementation (also used by legacy SSS API) decides
// on the saltLen parameter to apply either HKDF_EE or HKDK_ExpandOnly (saltLen == 0)
if (context->mode != kMode_SSS_HKDF_ExpandOnly) {
status = sss_mbedtls_key_store_get_key(saltKeyObject->keyStore, saltKeyObject, saltData, &saltLen, &dummySize);
if (status != kStatus_SSS_Success) {
return kStatus_SSS_Fail;
}
}
else {
saltLen = 0;
}
return sss_mbedtls_derive_key_go(
context, saltData, saltLen, info, infoLen, derivedKeyObject, deriveDataLen, NULL, NULL);
}
// In HKDF Expand only mode PRK is unbounded, we set a maximum of 256 byte
// RFC5869 Section 2.3
#define HKDF_PRK_MAX 256
sss_status_t sss_mbedtls_derive_key_go(sss_mbedtls_derive_key_t *context,
const uint8_t *saltData,
size_t saltLen,
const uint8_t *info,
size_t infoLen,
sss_mbedtls_object_t *derivedKeyObject,
uint16_t deriveDataLen,
uint8_t *hkdfOutput,
size_t *hkdfOutputLen)
{
sss_status_t retval = kStatus_SSS_Fail;
#if SSSFTR_SW_TESTCOUNTERPART
const mbedtls_md_info_t *md = NULL;
uint8_t *secret;
size_t secretLen;
secret = context->keyObject->contents;
secretLen = context->keyObject->contents_size;
uint8_t prk[HKDF_PRK_MAX] = {
0,
};
size_t prk_len = 0;
mbedtls_md_type_t md_alg = MBEDTLS_MD_NONE;
switch (context->algorithm) {
case kAlgorithm_SSS_SHA1:
case kAlgorithm_SSS_HMAC_SHA1:
md_alg = MBEDTLS_MD_SHA1;
break;
case kAlgorithm_SSS_SHA256:
case kAlgorithm_SSS_HMAC_SHA256:
md_alg = MBEDTLS_MD_SHA256;
break;
case kAlgorithm_SSS_SHA384:
case kAlgorithm_SSS_HMAC_SHA384:
md_alg = MBEDTLS_MD_SHA384;
break;
case kAlgorithm_SSS_SHA512:
case kAlgorithm_SSS_HMAC_SHA512:
md_alg = MBEDTLS_MD_SHA512;
break;
default:
return kStatus_SSS_Fail;
}
md = mbedtls_md_info_from_type(md_alg);
if (saltLen == 0) {
/* Copy key as is */
if (HKDF_PRK_MAX >= secretLen) {
memcpy(prk, secret, secretLen);
prk_len = secretLen;
}
else {
LOG_E("HKDF Expand only (mbedTLS implementation): buffer too small");
return kStatus_SSS_Fail;
}
}
else {
retval = sss_mbedtls_hkdf_extract(md, saltData, saltLen, secret, secretLen, prk);
prk_len = mbedtls_md_get_size(md);
if (retval != kStatus_SSS_Success) {
return kStatus_SSS_Fail;
}
}
retval = sss_mbedtls_hkdf_expand(md, prk, prk_len, info, infoLen, derivedKeyObject->contents, deriveDataLen);
if (retval == kStatus_SSS_Success) {
derivedKeyObject->contents_size = deriveDataLen;
}
#endif
return retval;
}
sss_status_t sss_mbedtls_derive_key_dh(sss_mbedtls_derive_key_t *context,
sss_mbedtls_object_t *otherPartyKeyObject,
sss_mbedtls_object_t *derivedKeyObject)
{
#if SSSFTR_SW_ECC
sss_status_t retval = kStatus_SSS_Success;
int ret = -1;
mbedtls_pk_context *pKeyPrv;
mbedtls_ecp_keypair *pEcpPrv;
#if defined(MBEDTLS_ECDH_C)
mbedtls_pk_context *pKeyExt;
mbedtls_ecp_keypair *pEcpExt;
#endif
size_t keyLen = 0;
size_t sharedSecretLen;
size_t sharedSecretLen_Derived;
const mbedtls_ecp_curve_info *p_curve_info = NULL;
mbedtls_mpi rawSharedData;
pKeyPrv = (mbedtls_pk_context *)context->keyObject->contents;
pEcpPrv = mbedtls_pk_ec(*pKeyPrv);
#if defined(MBEDTLS_ECDH_C)
pKeyExt = (mbedtls_pk_context *)otherPartyKeyObject->contents;
pEcpExt = mbedtls_pk_ec(*pKeyExt);
#endif
mbedtls_mpi_init(&rawSharedData);
/* Compute the size of the shared secret */
if (otherPartyKeyObject->cipherType == kSSS_CipherType_EC_MONTGOMERY) {
if (pEcpPrv->grp.id == MBEDTLS_ECP_DP_CURVE448) {
keyLen = 56;
}
else {
keyLen = 32;
}
}
else {
p_curve_info = mbedtls_ecp_curve_info_from_grp_id(pEcpPrv->grp.id);
keyLen = (size_t)(((p_curve_info->bit_size + 7)) / 8);
}
sharedSecretLen = (size_t)(keyLen);
#if defined(MBEDTLS_ECDH_C)
ret = mbedtls_ecdh_compute_shared(&pEcpPrv->grp,
&rawSharedData,
&(pEcpExt->Q),
&(pEcpPrv->d),
mbedtls_ctr_drbg_random,
context->session->ctr_drbg);
#endif
if (ret != 0) {
LOG_E("mbedtls_ecdh_compute_shared returned -0x%04x", -ret);
retval = kStatus_SSS_Fail;
goto exit;
}
sharedSecretLen_Derived = mbedtls_mpi_size(&rawSharedData);
if (sharedSecretLen_Derived > sharedSecretLen) {
LOG_E("Failed: Incorrect shared key length");
mbedtls_mpi_free(&rawSharedData);
retval = kStatus_SSS_Fail;
goto exit;
}
derivedKeyObject->contents_size = keyLen;
ret = mbedtls_mpi_write_binary(&rawSharedData, derivedKeyObject->contents, derivedKeyObject->contents_size);
if (ret != 0) {
LOG_E("Failed: unable to write shared key");
retval = kStatus_SSS_Fail;
goto exit;
}
mbedtls_mpi_free(&rawSharedData);
#ifdef MBEDTLS_DO_LITTLE_ENDIAN
if (otherPartyKeyObject->cipherType == kSSS_CipherType_EC_MONTGOMERY) {
// Change Endianness Shared Secret in case of Montgomery Curve
uint8_t *pVal = (uint8_t *)derivedKeyObject->contents;
for (size_t keyValueIdx = 0; keyValueIdx < (derivedKeyObject->contents_size >> 1); keyValueIdx++) {
uint8_t swapByte = pVal[keyValueIdx];
pVal[keyValueIdx] = pVal[derivedKeyObject->contents_size - 1 - keyValueIdx];
pVal[derivedKeyObject->contents_size - 1 - keyValueIdx] = swapByte;
}
}
#endif
exit:
return retval;
#else
return kStatus_SSS_Fail;
#endif
}
void sss_mbedtls_derive_key_context_free(sss_mbedtls_derive_key_t *context)
{
memset(context, 0, sizeof(*context));
}
/* End: mbedtls_keyderive */
/* ************************************************************************** */
/* Functions : sss_mbedtls_keystore */
/* ************************************************************************** */
sss_status_t sss_mbedtls_key_store_context_init(sss_mbedtls_key_store_t *keyStore, sss_mbedtls_session_t *session)
{
sss_status_t retval = kStatus_SSS_Fail;
ENSURE_OR_GO_CLEANUP(keyStore);
ENSURE_OR_GO_CLEANUP(session);
memset(keyStore, 0, sizeof(*keyStore));
keyStore->session = session;
retval = kStatus_SSS_Success;
cleanup:
return retval;
}
sss_status_t sss_mbedtls_key_store_allocate(sss_mbedtls_key_store_t *keyStore, uint32_t keyStoreId)
{
sss_status_t retval = kStatus_SSS_Fail;
ENSURE_OR_GO_CLEANUP(keyStore);
ENSURE_OR_GO_CLEANUP(keyStore->session);
#if defined(MBEDTLS_FS_IO) && !AX_EMBEDDED
/* This function is called once per session so keystore
object and shadow objects Should be equal to Null */
ENSURE_OR_GO_CLEANUP(keyStore->objects == NULL);
ENSURE_OR_GO_CLEANUP(keyStore->keystore_shadow == NULL);
keyStore->max_object_count = MAX_KEY_OBJ_COUNT;
keyStore->objects = (sss_mbedtls_object_t **)SSS_MALLOC(MAX_KEY_OBJ_COUNT * sizeof(sss_mbedtls_object_t *));
ENSURE_OR_GO_CLEANUP(keyStore->objects != NULL);
memset(keyStore->objects, 0, (MAX_KEY_OBJ_COUNT * sizeof(sss_mbedtls_object_t *)));
ks_sw_fat_allocate(&keyStore->keystore_shadow);
if (keyStore->session->szRootPath != NULL) {
ks_sw_fat_load(keyStore->session->szRootPath, keyStore->keystore_shadow);
}
retval = kStatus_SSS_Success;
#else
retval = kStatus_SSS_Success;
#endif
cleanup:
return retval;
}
sss_status_t sss_mbedtls_key_store_save(sss_mbedtls_key_store_t *keyStore)
{
sss_status_t retval = kStatus_SSS_Fail;
ENSURE_OR_GO_CLEANUP(keyStore);
ENSURE_OR_GO_CLEANUP(keyStore->session);
#if defined(MBEDTLS_FS_IO) && !AX_EMBEDDED
ENSURE_OR_GO_CLEANUP(keyStore->session->szRootPath)
ENSURE_OR_GO_CLEANUP(keyStore->objects)
uint32_t i;
for (i = 0; i < keyStore->max_object_count; i++) {
if (NULL != keyStore->objects[i]) {
ks_mbedtls_store_key(keyStore->objects[i]);
}
}
retval = ks_mbedtls_fat_update(keyStore);
#endif
cleanup:
return retval;
}
sss_status_t sss_mbedtls_key_store_load(sss_mbedtls_key_store_t *keyStore)
{
sss_status_t retval = kStatus_SSS_Fail;
ENSURE_OR_GO_CLEANUP(keyStore);
ENSURE_OR_GO_CLEANUP(keyStore->session);
#if defined(MBEDTLS_FS_IO) && !AX_EMBEDDED
if (keyStore->objects == NULL) {
sss_mbedtls_key_store_allocate(keyStore, 0);
}
if (keyStore->session->szRootPath) {
if (NULL == keyStore->keystore_shadow) {
ks_sw_fat_allocate(&keyStore->keystore_shadow);
}
retval = ks_sw_fat_load(keyStore->session->szRootPath, keyStore->keystore_shadow);
keyStore->max_object_count = keyStore->keystore_shadow->maxEntries;
}
#endif
cleanup:
return retval;
}
sss_status_t sss_mbedtls_key_store_set_key(sss_mbedtls_key_store_t *keyStore,
sss_mbedtls_object_t *keyObject,
const uint8_t *data,
size_t dataLen,
size_t keyBitLen,
void *options,
size_t optionsLen)
{
sss_status_t retval = kStatus_SSS_Fail;
//mbedtls_pk_context *pk = NULL;
//size_t keyByteLen = keyBitLen / 8;
ENSURE_OR_GO_CLEANUP(keyObject);
ENSURE_OR_GO_CLEANUP(keyObject->contents);
ENSURE_OR_GO_CLEANUP((keyObject->accessRights & kAccessPermission_SSS_Write));
//pk = (mbedtls_pk_context *)keyObject->contents;
retval = sss_mbedtls_set_key(keyObject, data, dataLen, keyBitLen);
cleanup:
return retval;
}
sss_status_t sss_mbedtls_key_store_generate_key(
sss_mbedtls_key_store_t *keyStore, sss_mbedtls_object_t *keyObject, size_t keyBitLen, void *options)
{
sss_status_t retval = kStatus_SSS_Fail;
#if SSS_HAVE_TESTCOUNTERPART && (SSSFTR_SW_ECC || SSSFTR_SW_RSA)
sss_mbedtls_session_t *pS = keyStore->session;
mbedtls_pk_context *pkey;
sss_key_part_t key_part = keyObject->objectType;
sss_cipher_type_t cipher_type = keyObject->cipherType;
ENSURE_OR_GO_CLEANUP(keyObject->contents); /* Must be allocated in allocate handle */
ENSURE_OR_GO_CLEANUP(keyStore);
ENSURE_OR_GO_CLEANUP(keyObject);
ENSURE_OR_GO_CLEANUP(keyObject->contents);
pkey = (mbedtls_pk_context *)keyObject->contents;
if (key_part != kSSS_KeyPart_Pair) {
retval = kStatus_SSS_Success;
goto cleanup;
}
mbedtls_pk_init(pkey);
switch (cipher_type) {
#if SSSFTR_SW_ECC
case kSSS_CipherType_EC_NIST_P:
case kSSS_CipherType_EC_NIST_K:
case kSSS_CipherType_EC_BRAINPOOL:
case kSSS_CipherType_EC_MONTGOMERY:
retval = sss_mbedtls_generate_ecp_key(pkey, pS, keyBitLen, cipher_type);
break;
#endif
#if SSSFTR_SW_RSA
case kSSS_CipherType_RSA:
retval = sss_mbedtls_generate_rsa_key(pkey, pS, keyBitLen);
break;
#endif
default:
break;
}
cleanup:
#endif
return retval;
}
sss_status_t sss_mbedtls_key_store_get_key(sss_mbedtls_key_store_t *keyStore,
sss_mbedtls_object_t *keyObject,
uint8_t *data,
size_t *dataLen,
size_t *pKeyBitLen)
{
sss_status_t retval = kStatus_SSS_Fail;
#if SSSFTR_SW_RSA || SSSFTR_SW_ECC
mbedtls_pk_context *pk = NULL;
int ret = -1;
uint8_t output[1600] = {0};
unsigned char *c = output;
#endif
ENSURE_OR_GO_CLEANUP(keyObject);
ENSURE_OR_GO_CLEANUP((keyObject->accessRights & kAccessPermission_SSS_Read));
switch (keyObject->objectType) {
case kSSS_KeyPart_Default:
memcpy(data, keyObject->contents, keyObject->contents_size);
*dataLen = keyObject->contents_size;
*pKeyBitLen = keyObject->contents_size * 8;
retval = kStatus_SSS_Success;
break;
#if SSSFTR_SW_RSA || SSSFTR_SW_ECC
case kSSS_KeyPart_Public:
case kSSS_KeyPart_Pair:
pk = (mbedtls_pk_context *)keyObject->contents;
if (keyObject->cipherType == kSSS_CipherType_EC_MONTGOMERY) {
mbedtls_ecp_keypair *pEcpPub = mbedtls_pk_ec(*pk);
size_t pubKey_size = 0;
size_t header_size = 0;
if (pEcpPub->grp.id == MBEDTLS_ECP_DP_CURVE25519) {
pubKey_size = 32;
*pKeyBitLen = 256;
header_size = der_ecc_mont_dh_25519_header_len;
memcpy(data, gecc_der_header_mont_dh_25519, header_size);
}
else if (pEcpPub->grp.id == MBEDTLS_ECP_DP_CURVE448) {
pubKey_size = 56;
*pKeyBitLen = 448;
header_size = der_ecc_mont_dh_448_header_len;
memcpy(data, gecc_der_header_mont_dh_448, header_size);
}
else {
LOG_E(
"Only mont_dh_25519 (bit length 256) and mont_dh_448 (bit "
"length 448)");
goto cleanup;
}
ret = mbedtls_mpi_write_binary(&pEcpPub->Q.X, output, pubKey_size);
ENSURE_OR_GO_CLEANUP(0 == ret);
*dataLen = pubKey_size + header_size;
#ifdef MBEDTLS_DO_LITTLE_ENDIAN
/* Reverse the public key */
{
size_t i = 0;
while (i < pubKey_size) {
data[i + header_size] = output[pubKey_size - i - 1];
i++;
}
}
#else
memcpy(data, output, pubKey_size);
#endif
retval = kStatus_SSS_Success;
}
else {
ret = mbedtls_pk_write_pubkey_der(pk, output, sizeof(output));
if (ret > 0) {
if ((*dataLen) >= (size_t)ret) {
*pKeyBitLen = mbedtls_pk_get_bitlen(pk);
//*pKeyBitLen = ret * 8;
*dataLen = ret;
/* Data is put at end, so copy it to front of output buffer */
c = output + sizeof(output) - ret;
memcpy(data, c, ret);
retval = kStatus_SSS_Success;
}
}
}
break;
#endif // SSSFTR_SW_RSA || SSSFTR_SW_ECC
default:
break;
}
cleanup:
return retval;
}
sss_status_t sss_mbedtls_key_store_open_key(sss_mbedtls_key_store_t *keyStore, sss_mbedtls_object_t *keyObject)
{
sss_status_t retval = kStatus_SSS_Success;
return retval;
}
sss_status_t sss_mbedtls_key_store_freeze_key(sss_mbedtls_key_store_t *keyStore, sss_mbedtls_object_t *keyObject)
{
sss_status_t retval = kStatus_SSS_Success;
return retval;
}
sss_status_t sss_mbedtls_key_store_erase_key(sss_mbedtls_key_store_t *keyStore, sss_mbedtls_object_t *keyObject)
{
sss_status_t retval = kStatus_SSS_Fail;
#if SSS_HAVE_TESTCOUNTERPART
ENSURE_OR_GO_EXIT(keyStore);
ENSURE_OR_GO_EXIT(keyObject);
ENSURE_OR_GO_EXIT(keyObject->keyStore);
ENSURE_OR_GO_EXIT((keyObject->accessRights & kAccessPermission_SSS_Delete));
if (keyObject->keyMode == kKeyObject_Mode_Persistent) {
#if defined(MBEDTLS_FS_IO) && !AX_EMBEDDED
unsigned int i = 0;
/* first check if key exists delete key from shadow KS*/
retval = ks_common_remove_fat(keyObject->keyStore->keystore_shadow, keyObject->keyId);
ENSURE_OR_GO_CLEANUP(retval == kStatus_SSS_Success);
/* Update shadow keystore in file system*/
retval = ks_mbedtls_fat_update(keyObject->keyStore);
ENSURE_OR_GO_CLEANUP(retval == kStatus_SSS_Success);
/*Clear key object from file*/
retval = ks_mbedtls_remove_key(keyObject);
for (i = 0; i < keyObject->keyStore->max_object_count; i++) {
if (keyObject->keyStore->objects[i] == keyObject) {
keyObject->keyStore->objects[i] = NULL;
break;
}
}
#endif
}
else {
retval = kStatus_SSS_Success;
}
#if defined(MBEDTLS_FS_IO) && !AX_EMBEDDED
cleanup:
#endif
exit:
#endif
return retval;
}
void sss_mbedtls_key_store_context_free(sss_mbedtls_key_store_t *keyStore)
{
#if defined(MBEDTLS_FS_IO) && !AX_EMBEDDED
if (NULL != keyStore->objects) {
uint32_t i;
for (i = 0; i < keyStore->max_object_count; i++) {
if (keyStore->objects[i] != NULL) {
//sss_mbedtls_key_object_free(keyStore->objects[i]);
keyStore->objects[i] = NULL;
}
}
SSS_FREE(keyStore->objects);
keyStore->objects = NULL;
}
if (NULL != keyStore->keystore_shadow) {
ks_sw_fat_free(keyStore->keystore_shadow);
}
#endif
memset(keyStore, 0, sizeof(*keyStore));
}
/* End: mbedtls_keystore */
/* ************************************************************************** */
/* Functions : sss_mbedtls_asym */
/* ************************************************************************** */
sss_status_t sss_mbedtls_asymmetric_context_init(sss_mbedtls_asymmetric_t *context,
sss_mbedtls_session_t *session,
sss_mbedtls_object_t *keyObject,
sss_algorithm_t algorithm,
sss_mode_t mode)
{
sss_status_t retval = kStatus_SSS_Fail;
#if SSSFTR_SW_ECC || SSSFTR_SW_RSA
ENSURE_OR_GO_CLEANUP(context);
ENSURE_OR_GO_CLEANUP(keyObject);
ENSURE_OR_GO_CLEANUP(keyObject->keyStore->session->subsystem == kType_SSS_mbedTLS);
context->session = session;
context->keyObject = keyObject;
context->algorithm = algorithm;
context->mode = mode;
retval = kStatus_SSS_Success;
cleanup:
#endif
return retval;
}
sss_status_t sss_mbedtls_asymmetric_encrypt(
sss_mbedtls_asymmetric_t *context, const uint8_t *srcData, size_t srcLen, uint8_t *destData, size_t *destLen)
{
sss_status_t retval = kStatus_SSS_Fail;
#if SSSFTR_SW_ECC || SSSFTR_SW_RSA
int ret;
sss_mbedtls_object_t *keyObj = context->keyObject;
sss_mbedtls_session_t *pS = context->session;
mbedtls_pk_context *pKey;
pKey = (mbedtls_pk_context *)keyObj->contents;
sss_algorithm_t algo = context->algorithm;
ENSURE_OR_GO_EXIT((context->keyObject->accessRights & kAccessPermission_SSS_Use));
retval = kStatus_SSS_Success;
switch (algo) {
case kAlgorithm_SSS_RSAES_PKCS1_V1_5:
mbedtls_rsa_set_padding(mbedtls_pk_rsa(*pKey), MBEDTLS_RSA_PKCS_V15, 0);
break;
case kAlgorithm_SSS_RSAES_PKCS1_OAEP_SHA1:
mbedtls_rsa_set_padding(mbedtls_pk_rsa(*pKey), MBEDTLS_RSA_PKCS_V21, MBEDTLS_MD_SHA1);
break;
case kAlgorithm_SSS_RSAES_PKCS1_OAEP_SHA224:
mbedtls_rsa_set_padding(mbedtls_pk_rsa(*pKey), MBEDTLS_RSA_PKCS_V21, MBEDTLS_MD_SHA224);
break;
case kAlgorithm_SSS_RSAES_PKCS1_OAEP_SHA256:
mbedtls_rsa_set_padding(mbedtls_pk_rsa(*pKey), MBEDTLS_RSA_PKCS_V21, MBEDTLS_MD_SHA256);
break;
case kAlgorithm_SSS_RSAES_PKCS1_OAEP_SHA384:
mbedtls_rsa_set_padding(mbedtls_pk_rsa(*pKey), MBEDTLS_RSA_PKCS_V21, MBEDTLS_MD_SHA384);
break;
case kAlgorithm_SSS_RSAES_PKCS1_OAEP_SHA512:
mbedtls_rsa_set_padding(mbedtls_pk_rsa(*pKey), MBEDTLS_RSA_PKCS_V21, MBEDTLS_MD_SHA512);
break;
default:
retval = kStatus_SSS_Fail;
goto exit;
}
ret = mbedtls_pk_encrypt(pKey, srcData, srcLen, destData, destLen, *destLen, mbedtls_ctr_drbg_random, pS->ctr_drbg);
retval = kStatus_SSS_Fail;
ENSURE_OR_GO_EXIT(ret == 0);
retval = kStatus_SSS_Success;
*destLen = (mbedtls_pk_rsa(*pKey))->len;
exit:
#endif
return retval;
}
sss_status_t sss_mbedtls_asymmetric_decrypt(
sss_mbedtls_asymmetric_t *context, const uint8_t *srcData, size_t srcLen, uint8_t *destData, size_t *destLen)
{
sss_status_t retval = kStatus_SSS_Fail;
#if SSSFTR_SW_ECC || SSSFTR_SW_RSA
int ret;
sss_mbedtls_object_t *keyObj = context->keyObject;
sss_mbedtls_session_t *pS = context->session;
mbedtls_pk_context *pKey;
sss_algorithm_t algo = context->algorithm;
retval = kStatus_SSS_Success;
ENSURE_OR_GO_EXIT((context->keyObject->accessRights & kAccessPermission_SSS_Use));
pKey = (mbedtls_pk_context *)keyObj->contents;
switch (algo) {
case kAlgorithm_SSS_RSAES_PKCS1_V1_5:
mbedtls_rsa_set_padding(mbedtls_pk_rsa(*pKey), MBEDTLS_RSA_PKCS_V15, 0);
break;
case kAlgorithm_SSS_RSAES_PKCS1_OAEP_SHA1:
mbedtls_rsa_set_padding(mbedtls_pk_rsa(*pKey), MBEDTLS_RSA_PKCS_V21, MBEDTLS_MD_SHA1);
break;
case kAlgorithm_SSS_RSAES_PKCS1_OAEP_SHA224:
mbedtls_rsa_set_padding(mbedtls_pk_rsa(*pKey), MBEDTLS_RSA_PKCS_V21, MBEDTLS_MD_SHA224);
break;
case kAlgorithm_SSS_RSAES_PKCS1_OAEP_SHA256:
mbedtls_rsa_set_padding(mbedtls_pk_rsa(*pKey), MBEDTLS_RSA_PKCS_V21, MBEDTLS_MD_SHA256);
break;
case kAlgorithm_SSS_RSAES_PKCS1_OAEP_SHA384:
mbedtls_rsa_set_padding(mbedtls_pk_rsa(*pKey), MBEDTLS_RSA_PKCS_V21, MBEDTLS_MD_SHA384);
break;
case kAlgorithm_SSS_RSAES_PKCS1_OAEP_SHA512:
mbedtls_rsa_set_padding(mbedtls_pk_rsa(*pKey), MBEDTLS_RSA_PKCS_V21, MBEDTLS_MD_SHA512);
break;
default:
retval = kStatus_SSS_Fail;
goto exit;
}
ret = mbedtls_pk_decrypt(pKey, srcData, srcLen, destData, destLen, *destLen, mbedtls_ctr_drbg_random, pS->ctr_drbg);
retval = kStatus_SSS_Fail;
ENSURE_OR_GO_EXIT(ret == 0);
retval = kStatus_SSS_Success;
exit:
#endif
return retval;
}
#if SSSFTR_SW_ECC || SSSFTR_SW_RSA
static mbedtls_md_type_t sss_mbedtls_set_padding_get_hash(sss_algorithm_t algorithm, mbedtls_pk_context *pKey)
{
mbedtls_md_type_t md_alg = MBEDTLS_MD_NONE;
switch (algorithm) {
case kAlgorithm_SSS_RSASSA_PKCS1_V1_5_SHA1:
case kAlgorithm_SSS_RSASSA_PKCS1_PSS_MGF1_SHA1:
case kAlgorithm_SSS_SHA1: {
md_alg = MBEDTLS_MD_SHA1;
} break;
case kAlgorithm_SSS_RSASSA_PKCS1_V1_5_SHA224:
case kAlgorithm_SSS_RSASSA_PKCS1_PSS_MGF1_SHA224:
case kAlgorithm_SSS_SHA224: {
md_alg = MBEDTLS_MD_SHA224;
} break;
case kAlgorithm_SSS_RSASSA_PKCS1_V1_5_SHA256:
case kAlgorithm_SSS_RSASSA_PKCS1_PSS_MGF1_SHA256:
case kAlgorithm_SSS_SHA256: {
md_alg = MBEDTLS_MD_SHA256;
} break;
case kAlgorithm_SSS_RSASSA_PKCS1_V1_5_SHA384:
case kAlgorithm_SSS_RSASSA_PKCS1_PSS_MGF1_SHA384:
case kAlgorithm_SSS_SHA384: {
md_alg = MBEDTLS_MD_SHA384;
} break;
case kAlgorithm_SSS_RSASSA_PKCS1_V1_5_SHA512:
case kAlgorithm_SSS_RSASSA_PKCS1_PSS_MGF1_SHA512:
case kAlgorithm_SSS_SHA512: {
md_alg = MBEDTLS_MD_SHA512;
} break;
default:
md_alg = MBEDTLS_MD_NONE;
break;
}
if (algorithm >= kAlgorithm_SSS_RSASSA_PKCS1_PSS_MGF1_SHA1 &&
algorithm <= kAlgorithm_SSS_RSASSA_PKCS1_PSS_MGF1_SHA512) {
mbedtls_rsa_set_padding(mbedtls_pk_rsa(*pKey), MBEDTLS_RSA_PKCS_V21, md_alg);
}
else if ((algorithm >= kAlgorithm_SSS_RSASSA_PKCS1_V1_5_SHA1 &&
algorithm <= kAlgorithm_SSS_RSASSA_PKCS1_V1_5_SHA512) ||
algorithm == kAlgorithm_SSS_RSASSA_PKCS1_V1_5_NO_HASH) {
mbedtls_rsa_set_padding(mbedtls_pk_rsa(*pKey), MBEDTLS_RSA_PKCS_V15, md_alg);
}
return md_alg;
}
#endif
sss_status_t sss_mbedtls_asymmetric_sign_digest(
sss_mbedtls_asymmetric_t *context, uint8_t *digest, size_t digestLen, uint8_t *signature, size_t *signatureLen)
{
sss_status_t retval = kStatus_SSS_Fail;
#if SSSFTR_SW_ECC || SSSFTR_SW_RSA
int ret = 1;
mbedtls_md_type_t md_alg = MBEDTLS_MD_NONE;
sss_mbedtls_session_t *pS;
mbedtls_pk_context *pKey;
ENSURE_OR_GO_EXIT((context->keyObject->accessRights & kAccessPermission_SSS_Use));
pS = context->session;
pKey = (mbedtls_pk_context *)context->keyObject->contents;
md_alg = sss_mbedtls_set_padding_get_hash(context->algorithm, pKey);
ret = mbedtls_pk_sign(
pKey, md_alg, digest, digestLen, signature, signatureLen, mbedtls_ctr_drbg_random, pS->ctr_drbg);
ENSURE_OR_GO_EXIT(ret == 0);
retval = kStatus_SSS_Success;
exit:
#endif
return retval;
}
sss_status_t sss_mbedtls_asymmetric_verify_digest(
sss_mbedtls_asymmetric_t *context, uint8_t *digest, size_t digestLen, uint8_t *signature, size_t signatureLen)
{
sss_status_t retval = kStatus_SSS_Fail;
#if SSSFTR_SW_ECC || SSSFTR_SW_RSA
int ret = 1;
mbedtls_md_type_t md_alg = MBEDTLS_MD_NONE;
mbedtls_pk_context *pKey;
ENSURE_OR_GO_EXIT((context->keyObject->accessRights & kAccessPermission_SSS_Use));
pKey = (mbedtls_pk_context *)context->keyObject->contents;
md_alg = sss_mbedtls_set_padding_get_hash(context->algorithm, pKey);
ret = mbedtls_pk_verify(pKey, md_alg, digest, digestLen, signature, signatureLen);
ENSURE_OR_GO_EXIT(ret == 0);
retval = kStatus_SSS_Success;
exit:
#endif
return retval;
}
void sss_mbedtls_asymmetric_context_free(sss_mbedtls_asymmetric_t *context)
{
memset(context, 0, sizeof(*context));
}
/* End: mbedtls_asym */
/* ************************************************************************** */
/* Functions : sss_mbedtls_symm */
/* ************************************************************************** */
sss_status_t sss_mbedtls_symmetric_context_init(sss_mbedtls_symmetric_t *context,
sss_mbedtls_session_t *session,
sss_mbedtls_object_t *keyObject,
sss_algorithm_t algorithm,
sss_mode_t mode)
{
sss_status_t retval = kStatus_SSS_Success;
context->session = session;
context->keyObject = keyObject;
context->algorithm = algorithm;
context->mode = mode;
return retval;
}
sss_status_t sss_mbedtls_cipher_one_go(sss_mbedtls_symmetric_t *context,
uint8_t *iv,
size_t ivLen,
const uint8_t *srcData,
uint8_t *destData,
size_t dataLen)
{
sss_status_t retval = kStatus_SSS_Fail;
mbedtls_aes_context aes_ctx;
#if defined(MBEDTLS_DES_C)
mbedtls_des_context des_ctx;
#endif
int mbedtls_ret = 1; /* Fail by default */
switch (context->algorithm) {
#if SSS_HAVE_TESTCOUNTERPART
case kAlgorithm_SSS_AES_ECB:
#endif //SSS_HAVE_TESTCOUNTERPART
case kAlgorithm_SSS_AES_CBC:
mbedtls_aes_init(&aes_ctx);
if (context->mode == kMode_SSS_Encrypt) {
mbedtls_ret = mbedtls_aes_setkey_enc(
&aes_ctx, context->keyObject->contents, (unsigned int)(context->keyObject->contents_size * 8));
}
else if (context->mode == kMode_SSS_Decrypt) {
mbedtls_ret = mbedtls_aes_setkey_dec(
&aes_ctx, context->keyObject->contents, (unsigned int)(context->keyObject->contents_size * 8));
}
break;
#if SSS_HAVE_TESTCOUNTERPART
case kAlgorithm_SSS_AES_CTR: {
mbedtls_aes_init(&aes_ctx);
mbedtls_ret = mbedtls_aes_setkey_enc(
&aes_ctx, context->keyObject->contents, (unsigned int)(context->keyObject->contents_size * 8));
} break;
case kAlgorithm_SSS_DES_CBC:
case kAlgorithm_SSS_DES_ECB:
case kAlgorithm_SSS_DES3_CBC:
case kAlgorithm_SSS_DES3_ECB:
mbedtls_des_init(&des_ctx);
if (context->mode == kMode_SSS_Encrypt) {
mbedtls_ret = mbedtls_des_setkey_enc(&des_ctx, context->keyObject->contents);
}
else if (context->mode == kMode_SSS_Decrypt) {
mbedtls_ret = mbedtls_des_setkey_dec(&des_ctx, context->keyObject->contents);
}
break;
#endif //SSS_HAVE_TESTCOUNTERPART
default:
goto exit;
}
ENSURE_OR_GO_EXIT(mbedtls_ret == 0);
if (context->mode == kMode_SSS_Encrypt) {
switch (context->algorithm) {
#if SSS_HAVE_TESTCOUNTERPART
case kAlgorithm_SSS_AES_ECB:
mbedtls_ret = mbedtls_aes_crypt_ecb(&aes_ctx, MBEDTLS_AES_ENCRYPT, srcData, destData);
break;
#endif //SSS_HAVE_TESTCOUNTERPART
case kAlgorithm_SSS_AES_CBC:
mbedtls_ret = mbedtls_aes_crypt_cbc(&aes_ctx, MBEDTLS_AES_ENCRYPT, dataLen, iv, srcData, destData);
break;
case kAlgorithm_SSS_AES_CTR: {
uint8_t stream_block[16] = {
0,
};
size_t size_left = 0;
mbedtls_ret = mbedtls_aes_crypt_ctr(&aes_ctx, dataLen, &size_left, iv, stream_block, srcData, destData);
} break;
#if defined(MBEDTLS_DES_C)
case kAlgorithm_SSS_DES_ECB:
mbedtls_ret = mbedtls_des_crypt_ecb(&des_ctx, srcData, destData);
break;
case kAlgorithm_SSS_DES_CBC:
mbedtls_ret = mbedtls_des_crypt_cbc(&des_ctx, MBEDTLS_DES_ENCRYPT, dataLen, iv, srcData, destData);
break;
#endif
default:
break;
}
}
else if (context->mode == kMode_SSS_Decrypt) {
switch (context->algorithm) {
case kAlgorithm_SSS_AES_CBC:
mbedtls_ret = mbedtls_aes_crypt_cbc(&aes_ctx, MBEDTLS_AES_DECRYPT, dataLen, iv, srcData, destData);
break;
#if SSS_HAVE_TESTCOUNTERPART
case kAlgorithm_SSS_AES_ECB:
mbedtls_ret = mbedtls_aes_crypt_ecb(&aes_ctx, MBEDTLS_AES_DECRYPT, srcData, destData);
break;
case kAlgorithm_SSS_AES_CTR: {
uint8_t stream_block[16] = {
0,
};
size_t size_left = 0;
mbedtls_ret = mbedtls_aes_crypt_ctr(&aes_ctx, dataLen, &size_left, iv, stream_block, srcData, destData);
} break;
#endif //SSS_HAVE_TESTCOUNTERPART
#if defined(MBEDTLS_DES_C)
case kAlgorithm_SSS_DES_ECB:
mbedtls_ret = mbedtls_des_crypt_ecb(&des_ctx, srcData, destData);
break;
case kAlgorithm_SSS_DES_CBC:
mbedtls_ret = mbedtls_des_crypt_cbc(&des_ctx, MBEDTLS_DES_DECRYPT, dataLen, iv, srcData, destData);
break;
#endif
default:
break;
}
}
else {
goto exit;
}
ENSURE_OR_GO_EXIT(mbedtls_ret == 0);
switch (context->algorithm) {
#if SSS_HAVE_TESTCOUNTERPART
case kAlgorithm_SSS_AES_ECB:
case kAlgorithm_SSS_AES_CTR:
#endif //SSS_HAVE_TESTCOUNTERPART
case kAlgorithm_SSS_AES_CBC:
mbedtls_aes_free(&aes_ctx);
break;
#if SSS_HAVE_TESTCOUNTERPART
case kAlgorithm_SSS_DES_CBC:
case kAlgorithm_SSS_DES_ECB:
case kAlgorithm_SSS_DES3_CBC:
case kAlgorithm_SSS_DES3_ECB:
mbedtls_des_free(&des_ctx);
break;
#endif //SSS_HAVE_TESTCOUNTERPART
default:
goto exit;
}
retval = kStatus_SSS_Success;
exit:
return retval;
}
sss_status_t sss_mbedtls_cipher_init(sss_mbedtls_symmetric_t *context, uint8_t *iv, size_t ivLen)
{
sss_status_t retval = kStatus_SSS_Fail;
#if SSS_HAVE_TESTCOUNTERPART
const mbedtls_cipher_info_t *cipher_info = NULL;
context->cipher_ctx = (mbedtls_cipher_context_t *)SSS_MALLOC(sizeof(mbedtls_cipher_context_t));
ENSURE_OR_GO_EXIT(context->cipher_ctx != NULL);
retval = kStatus_SSS_Success;
if (context->algorithm == kAlgorithm_SSS_AES_ECB) {
mbedtls_cipher_type_t cipher_type = MBEDTLS_CIPHER_NONE;
switch (context->keyObject->keyBitLen) {
case 128:
cipher_type = MBEDTLS_CIPHER_AES_128_ECB;
break;
case 192:
cipher_type = MBEDTLS_CIPHER_AES_192_ECB;
break;
case 256:
cipher_type = MBEDTLS_CIPHER_AES_256_ECB;
break;
}
if (cipher_type != MBEDTLS_CIPHER_NONE) {
cipher_info = mbedtls_cipher_info_from_type(cipher_type);
}
}
else if (context->algorithm == kAlgorithm_SSS_AES_CBC) {
mbedtls_cipher_type_t cipher_type = MBEDTLS_CIPHER_NONE;
switch (context->keyObject->keyBitLen) {
case 128:
cipher_type = MBEDTLS_CIPHER_AES_128_CBC;
break;
case 192:
cipher_type = MBEDTLS_CIPHER_AES_192_CBC;
break;
case 256:
cipher_type = MBEDTLS_CIPHER_AES_256_CBC;
break;
}
if (cipher_type != MBEDTLS_CIPHER_NONE) {
cipher_info = mbedtls_cipher_info_from_type(cipher_type);
}
}
else if (context->algorithm == kAlgorithm_SSS_AES_CTR) {
mbedtls_cipher_type_t cipher_type = MBEDTLS_CIPHER_NONE;
switch (context->keyObject->keyBitLen) {
case 128:
cipher_type = MBEDTLS_CIPHER_AES_128_CTR;
break;
case 192:
cipher_type = MBEDTLS_CIPHER_AES_192_CTR;
break;
case 256:
cipher_type = MBEDTLS_CIPHER_AES_256_CTR;
break;
}
if (cipher_type != MBEDTLS_CIPHER_NONE) {
cipher_info = mbedtls_cipher_info_from_type(cipher_type);
}
}
else {
retval = kStatus_SSS_InvalidArgument;
goto exit;
}
mbedtls_cipher_init(context->cipher_ctx);
if (0 == mbedtls_cipher_setup(context->cipher_ctx, cipher_info)) {
if (context->mode == kMode_SSS_Encrypt) {
if (mbedtls_cipher_setkey(context->cipher_ctx,
context->keyObject->contents,
(unsigned int)(context->keyObject->contents_size * 8),
MBEDTLS_ENCRYPT) != 0) {
retval = kStatus_SSS_InvalidArgument;
}
}
else if (context->mode == kMode_SSS_Decrypt) {
if (mbedtls_cipher_setkey(context->cipher_ctx,
context->keyObject->contents,
(unsigned int)(context->keyObject->contents_size * 8),
MBEDTLS_DECRYPT) != 0) {
retval = kStatus_SSS_InvalidArgument;
}
}
else {
retval = kStatus_SSS_InvalidArgument;
}
if (retval == kStatus_SSS_Success) {
mbedtls_cipher_set_iv(context->cipher_ctx, iv, ivLen);
mbedtls_cipher_reset(context->cipher_ctx);
}
}
exit:
#endif
return retval;
}
sss_status_t sss_mbedtls_cipher_update(
sss_mbedtls_symmetric_t *context, const uint8_t *srcData, size_t srcLen, uint8_t *destData, size_t *destLen)
{
sss_status_t retval = kStatus_SSS_Fail;
#if SSS_HAVE_TESTCOUNTERPART
uint8_t inputData[CIPHER_BLOCK_SIZE] = {
0,
};
size_t inputData_len = 0;
size_t src_offset = 0;
size_t output_offset = 0;
size_t outBuffSize = *destLen;
size_t blockoutLen = 0;
int retMbedtlsVal;
if ((context->cache_data_len + srcLen) < CIPHER_BLOCK_SIZE) {
/* Insufficinet data to process . Cache the data */
memcpy((context->cache_data + context->cache_data_len), srcData, srcLen);
context->cache_data_len = context->cache_data_len + srcLen;
*destLen = 0;
return kStatus_SSS_Success;
}
else {
/* Concatenate the unprocessed and current input data*/
memcpy(inputData, context->cache_data, context->cache_data_len);
inputData_len = context->cache_data_len;
memcpy((inputData + inputData_len), srcData, (CIPHER_BLOCK_SIZE - context->cache_data_len));
inputData_len += (CIPHER_BLOCK_SIZE - context->cache_data_len);
src_offset += (CIPHER_BLOCK_SIZE - context->cache_data_len);
context->cache_data_len = 0;
blockoutLen = outBuffSize;
ENSURE_OR_GO_EXIT(blockoutLen >= inputData_len);
retMbedtlsVal = mbedtls_cipher_update(
context->cipher_ctx, inputData, inputData_len, (destData + output_offset), &blockoutLen);
ENSURE_OR_GO_EXIT(retMbedtlsVal == 0);
outBuffSize -= blockoutLen;
output_offset += blockoutLen;
while (srcLen - src_offset >= CIPHER_BLOCK_SIZE) {
memcpy(inputData, (srcData + src_offset), CIPHER_BLOCK_SIZE);
src_offset += CIPHER_BLOCK_SIZE;
blockoutLen = outBuffSize;
inputData_len = CIPHER_BLOCK_SIZE;
ENSURE_OR_GO_EXIT(blockoutLen >= inputData_len);
retMbedtlsVal = mbedtls_cipher_update(
context->cipher_ctx, inputData, inputData_len, (destData + output_offset), &blockoutLen);
ENSURE_OR_GO_EXIT(retMbedtlsVal == 0);
outBuffSize -= blockoutLen;
output_offset += blockoutLen;
}
*destLen = output_offset;
/* Copy unprocessed data to cache */
if ((srcLen - src_offset) > 0) {
memcpy(context->cache_data, (srcData + src_offset), (srcLen - src_offset));
context->cache_data_len = (srcLen - src_offset);
}
}
retval = kStatus_SSS_Success;
exit:
if (retval == kStatus_SSS_Fail) {
*destLen = 0;
}
#endif
return retval;
}
sss_status_t sss_mbedtls_cipher_finish(
sss_mbedtls_symmetric_t *context, const uint8_t *srcData, size_t srcLen, uint8_t *destData, size_t *destLen)
{
sss_status_t retval = kStatus_SSS_Fail;
#if SSS_HAVE_TESTCOUNTERPART
uint8_t srcdata_updated[2 * CIPHER_BLOCK_SIZE] = {
0,
};
size_t srcdata_updated_len = 0;
size_t outBuffSize = *destLen;
size_t blockoutLen = 0;
int retMbedtlsVal;
uint8_t temp[16] = {
0,
};
size_t temp_len = sizeof(temp);
if (srcLen > CIPHER_BLOCK_SIZE) {
LOG_E("srcLen cannot be grater than 16 bytes. Call update function ");
*destLen = 0;
goto exit;
}
if (context->cache_data_len != 0) {
memcpy(srcdata_updated, context->cache_data, context->cache_data_len);
srcdata_updated_len = context->cache_data_len;
context->cache_data_len = 0;
}
if (srcLen != 0) {
memcpy((srcdata_updated + srcdata_updated_len), srcData, srcLen);
srcdata_updated_len += srcLen;
}
srcdata_updated_len = srcdata_updated_len + (CIPHER_BLOCK_SIZE - (srcdata_updated_len % 16));
if (*destLen < srcdata_updated_len) {
LOG_E("Output buffer not sufficient");
goto exit;
}
if (srcdata_updated_len > 0) {
blockoutLen = outBuffSize;
ENSURE_OR_GO_EXIT(blockoutLen >= CIPHER_BLOCK_SIZE);
retMbedtlsVal =
mbedtls_cipher_update(context->cipher_ctx, srcdata_updated, CIPHER_BLOCK_SIZE, destData, &blockoutLen);
ENSURE_OR_GO_EXIT(retMbedtlsVal == 0);
*destLen = blockoutLen;
outBuffSize -= blockoutLen;
}
if (srcdata_updated_len > CIPHER_BLOCK_SIZE) {
blockoutLen = outBuffSize;
ENSURE_OR_GO_EXIT(blockoutLen >= CIPHER_BLOCK_SIZE);
retMbedtlsVal = mbedtls_cipher_update(context->cipher_ctx,
srcdata_updated + CIPHER_BLOCK_SIZE,
CIPHER_BLOCK_SIZE,
destData + CIPHER_BLOCK_SIZE,
&blockoutLen);
ENSURE_OR_GO_EXIT(retMbedtlsVal == 0);
*destLen += blockoutLen;
}
mbedtls_cipher_finish(context->cipher_ctx, temp, &temp_len);
mbedtls_cipher_free(context->cipher_ctx);
memset(context->cipher_ctx, 0, sizeof(*(context->cipher_ctx)));
SSS_FREE(context->cipher_ctx);
retval = kStatus_SSS_Success;
exit:
#endif
return retval;
}
sss_status_t sss_mbedtls_cipher_crypt_ctr(sss_mbedtls_symmetric_t *context,
const uint8_t *srcData,
uint8_t *destData,
size_t size,
uint8_t *initialCounter,
uint8_t *lastEncryptedCounter,
size_t *szLeft)
{
sss_status_t retval = kStatus_SSS_Fail;
mbedtls_aes_context ctx;
int mbedtls_ret;
mbedtls_aes_init(&ctx);
switch (context->mode) {
case kMode_SSS_Encrypt:
case kMode_SSS_Decrypt:
ENSURE_OR_GO_EXIT(context->algorithm == kAlgorithm_SSS_AES_CTR);
mbedtls_ret = mbedtls_aes_setkey_enc(
&ctx, context->keyObject->contents, (unsigned int)(context->keyObject->contents_size * 8));
ENSURE_OR_GO_EXIT(mbedtls_ret == 0);
mbedtls_ret =
mbedtls_aes_crypt_ctr(&ctx, size, szLeft, initialCounter, lastEncryptedCounter, srcData, destData);
ENSURE_OR_GO_EXIT(mbedtls_ret == 0);
break;
default:
retval = MBEDTLS_ERR_AES_INVALID_KEY_LENGTH;
goto exit;
}
mbedtls_aes_free(&ctx);
retval = kStatus_SSS_Success;
exit:
return retval;
}
void sss_mbedtls_symmetric_context_free(sss_mbedtls_symmetric_t *context)
{
memset(context, 0, sizeof(*context));
}
/* End: mbedtls_symm */
/* ************************************************************************** */
/* Functions : sss_mbedtls_aead */
/* ************************************************************************** */
sss_status_t sss_mbedtls_aead_context_init(sss_mbedtls_aead_t *context,
sss_mbedtls_session_t *session,
sss_mbedtls_object_t *keyObject,
sss_algorithm_t algorithm,
sss_mode_t mode)
{
sss_status_t retval = kStatus_SSS_Fail;
ENSURE_OR_GO_CLEANUP(context);
ENSURE_OR_GO_CLEANUP(session);
ENSURE_OR_GO_CLEANUP(keyObject);
context->session = session;
context->keyObject = keyObject;
context->algorithm = algorithm;
context->mode = mode;
if (algorithm == kAlgorithm_SSS_AES_GCM) {
context->gcm_ctx = (mbedtls_gcm_context *)SSS_MALLOC(sizeof(mbedtls_gcm_context));
ENSURE_OR_GO_CLEANUP(context->gcm_ctx);
}
else if (algorithm == kAlgorithm_SSS_AES_CCM) {
context->ccm_ctx = (mbedtls_ccm_context *)SSS_MALLOC(sizeof(mbedtls_ccm_context));
ENSURE_OR_GO_CLEANUP(context->ccm_ctx);
}
else {
LOG_E("Improper Algorithm passed!");
goto cleanup;
}
context->pCcm_aad = NULL;
context->pCcm_data = NULL;
context->pNonce = NULL;
retval = kStatus_SSS_Success;
cleanup:
return retval;
}
sss_status_t sss_mbedtls_aead_one_go(sss_mbedtls_aead_t *context,
const uint8_t *srcData,
uint8_t *destData,
size_t size,
uint8_t *nonce,
size_t nonceLen,
const uint8_t *aad,
size_t aadLen,
uint8_t *tag,
size_t *tagLen)
{
sss_status_t retval = kStatus_SSS_Fail;
int ret = 1;
size_t stagLength = *tagLen;
if (context->algorithm == kAlgorithm_SSS_AES_GCM) {
/* Initialize gcm context */
mbedtls_gcm_init(context->gcm_ctx);
/* Set key to the context */
ret = mbedtls_gcm_setkey(context->gcm_ctx,
MBEDTLS_CIPHER_ID_AES,
context->keyObject->contents,
(unsigned int)(context->keyObject->contents_size * 8));
ENSURE_OR_GO_CLEANUP(ret == 0);
/* Check the mode and perform requested operation */
if (context->mode == kMode_SSS_Encrypt) {
ret = mbedtls_gcm_crypt_and_tag(context->gcm_ctx,
MBEDTLS_GCM_ENCRYPT,
size,
nonce,
nonceLen,
aad,
aadLen,
srcData,
destData,
stagLength,
tag);
}
else {
ret = mbedtls_gcm_auth_decrypt(
context->gcm_ctx, size, nonce, nonceLen, aad, aadLen, tag, stagLength, srcData, destData);
}
}
ENSURE_OR_GO_CLEANUP(ret == 0);
*tagLen = stagLength;
retval = kStatus_SSS_Success;
cleanup:
return retval;
}
sss_status_t sss_mbedtls_aead_init(
sss_mbedtls_aead_t *context, uint8_t *nonce, size_t nonceLen, size_t tagLen, size_t aadLen, size_t payloadLen)
{
sss_status_t retval = kStatus_SSS_Fail;
ENSURE_OR_GO_CLEANUP(context);
ENSURE_OR_GO_CLEANUP(nonce);
/* Save the nonce and its length in context */
context->pNonce = nonce;
context->nonceLen = nonceLen;
context->ccm_aadLen = aadLen;
context->ccm_dataTotalLen = payloadLen;
if (context->algorithm == kAlgorithm_SSS_AES_CCM) {
if (context->ccm_dataTotalLen) {
context->pCcm_data = SSS_MALLOC(payloadLen);
if (context->pCcm_data) {
memset(context->pCcm_data, 0, payloadLen);
context->ccm_dataoffset = 0;
}
else {
LOG_E("malloc failed");
goto cleanup;
}
}
}
context->cache_data_len = 0;
memset(context->cache_data, 0x00, sizeof(context->cache_data));
retval = kStatus_SSS_Success;
cleanup:
return retval;
}
sss_status_t sss_mbedtls_aead_update_aad(sss_mbedtls_aead_t *context, const uint8_t *aadData, size_t aadDataLen)
{
sss_status_t retval = kStatus_SSS_Fail;
int ret = 1;
int mode = (context->mode == kMode_SSS_Encrypt) ? MBEDTLS_GCM_ENCRYPT : MBEDTLS_GCM_DECRYPT;
if (context->algorithm == kAlgorithm_SSS_AES_GCM) {
/* Initialize gcm context */
mbedtls_gcm_init(context->gcm_ctx);
/* Set key to the context */
ret = mbedtls_gcm_setkey(context->gcm_ctx,
MBEDTLS_CIPHER_ID_AES,
context->keyObject->contents,
(unsigned int)(context->keyObject->contents_size * 8));
ENSURE_OR_GO_CLEANUP(ret == 0);
/* Add aad Data */
ret = mbedtls_gcm_starts(context->gcm_ctx, mode, context->pNonce, context->nonceLen, aadData, aadDataLen);
ENSURE_OR_GO_CLEANUP(ret == 0);
}
else if (context->algorithm == kAlgorithm_SSS_AES_CCM) {
/* Initialize ccm context */
mbedtls_ccm_init(context->ccm_ctx);
/* Set key to the context */
ret = mbedtls_ccm_setkey(context->ccm_ctx,
MBEDTLS_CIPHER_ID_AES,
context->keyObject->contents,
(unsigned int)(context->keyObject->contents_size * 8));
ENSURE_OR_GO_CLEANUP(ret == 0);
context->pCcm_aad = aadData;
context->ccm_aadLen = aadDataLen;
}
retval = kStatus_SSS_Success;
cleanup:
return retval;
}
sss_status_t sss_mbedtls_aead_update(
sss_mbedtls_aead_t *context, const uint8_t *srcData, size_t srcLen, uint8_t *destData, size_t *destLen)
{
sss_status_t retval = kStatus_SSS_Fail;
#if SSS_HAVE_TESTCOUNTERPART
uint8_t inputData[CIPHER_BLOCK_SIZE] = {
0,
};
size_t inputData_len = 0;
size_t src_offset = 0;
size_t output_offset = 0;
size_t outBuffSize = *destLen;
size_t blockoutLen = 0;
int ret = 1;
if (context->algorithm == kAlgorithm_SSS_AES_CCM) {
if ((srcData != NULL) && (srcLen > 0)) {
retval = sss_mbedtls_aead_ccm_update(context, srcData, srcLen);
}
ENSURE_OR_GO_CLEANUP(retval == kStatus_SSS_Success);
*destLen = 0;
}
else {
if ((context->cache_data_len + srcLen) < CIPHER_BLOCK_SIZE) {
/* Insufficinet data to process . Cache the data */
memcpy((context->cache_data + context->cache_data_len), srcData, srcLen);
context->cache_data_len = context->cache_data_len + srcLen;
*destLen = 0;
return kStatus_SSS_Success;
}
else {
/* Concatenate the unprocessed and current input data*/
memcpy(inputData, context->cache_data, context->cache_data_len);
inputData_len = context->cache_data_len;
memcpy((inputData + inputData_len), srcData, (CIPHER_BLOCK_SIZE - context->cache_data_len));
inputData_len += (CIPHER_BLOCK_SIZE - context->cache_data_len);
src_offset += (CIPHER_BLOCK_SIZE - context->cache_data_len);
blockoutLen = outBuffSize;
/* Add Source Data */
ret = mbedtls_gcm_update(context->gcm_ctx, inputData_len, inputData, (destData + output_offset));
ENSURE_OR_GO_CLEANUP(ret == 0);
blockoutLen = inputData_len;
outBuffSize -= blockoutLen;
output_offset += blockoutLen;
while (srcLen - src_offset >= CIPHER_BLOCK_SIZE) {
memcpy(inputData, (srcData + src_offset), 16);
src_offset += CIPHER_BLOCK_SIZE;
blockoutLen = outBuffSize;
/* Add Source Data */
ret = mbedtls_gcm_update(context->gcm_ctx, inputData_len, inputData, (destData + output_offset));
ENSURE_OR_GO_CLEANUP(ret == 0);
blockoutLen = inputData_len;
outBuffSize -= blockoutLen;
output_offset += blockoutLen;
}
*destLen = output_offset;
/* Copy unprocessed data to cache */
memcpy(context->cache_data, (srcData + src_offset), (srcLen - src_offset));
context->cache_data_len = (srcLen - src_offset);
}
}
retval = kStatus_SSS_Success;
cleanup:
if (retval == kStatus_SSS_Fail) {
*destLen = 0;
}
#endif /*End of SSS_HAVE_TESTCOUNTERPART*/
return retval;
}
#if SSS_HAVE_TESTCOUNTERPART
static sss_status_t sss_mbedtls_aead_ccm_update(sss_mbedtls_aead_t *context, const uint8_t *srcData, size_t srcLen)
{
sss_status_t retval = kStatus_SSS_Fail;
if ((context->ccm_dataoffset + srcLen) <= (context->ccm_dataTotalLen)) {
memcpy(context->pCcm_data + context->ccm_dataoffset, srcData, srcLen);
context->ccm_dataoffset = context->ccm_dataoffset + srcLen;
retval = kStatus_SSS_Success;
}
else {
/*Free the allocated memory in init*/
if (context->pCcm_data != NULL) {
SSS_FREE(context->pCcm_data);
context->pCcm_data = NULL;
}
}
return retval;
}
#endif //#if SSS_HAVE_TESTCOUNTERPART
sss_status_t sss_mbedtls_aead_finish(sss_mbedtls_aead_t *context,
const uint8_t *srcData,
size_t srcLen,
uint8_t *destData,
size_t *destLen,
uint8_t *tag,
size_t *tagLen)
{
sss_status_t retval = kStatus_SSS_Fail;
#if SSS_HAVE_TESTCOUNTERPART
size_t stagLen = *tagLen;
int ret = 1;
uint8_t srcdata_updated[2 * CIPHER_BLOCK_SIZE] = {
0,
};
size_t srcdata_updated_len = 0;
if (context->algorithm == kAlgorithm_SSS_AES_CCM) { /* Check if finish has got source data */
if ((srcData != NULL) && (srcLen > 0)) {
retval = sss_mbedtls_aead_ccm_update(context, srcData, srcLen);
ENSURE_OR_GO_EXIT(retval == kStatus_SSS_Success);
}
retval = sss_mbedtls_aead_ccm_finish(context, destData, destLen, tag, tagLen);
ENSURE_OR_GO_EXIT(retval == kStatus_SSS_Success);
}
else {
if (srcLen > CIPHER_BLOCK_SIZE) {
LOG_E("srcLen cannot be grater than 16 bytes. Call update function ");
*destLen = 0;
goto exit;
}
if (context->cache_data_len != 0) {
memcpy(srcdata_updated, context->cache_data, context->cache_data_len);
srcdata_updated_len = context->cache_data_len;
}
if (srcLen != 0) {
memcpy((srcdata_updated + srcdata_updated_len), srcData, srcLen);
srcdata_updated_len += srcLen;
}
if (srcdata_updated_len % CIPHER_BLOCK_SIZE != 0) {
srcdata_updated_len = srcdata_updated_len + (CIPHER_BLOCK_SIZE - (srcdata_updated_len % 16));
}
/* Add Source Data */
ret = mbedtls_gcm_update(context->gcm_ctx, srcdata_updated_len, srcdata_updated, destData);
*destLen = srcdata_updated_len;
ENSURE_OR_GO_EXIT(ret == 0);
/* Get Tag for Enc*/
ret = mbedtls_gcm_finish(context->gcm_ctx, tag, stagLen);
ENSURE_OR_GO_EXIT(ret == 0);
*tagLen = stagLen;
}
retval = kStatus_SSS_Success;
exit:
#endif
return retval;
}
#if SSS_HAVE_TESTCOUNTERPART
static sss_status_t sss_mbedtls_aead_ccm_finish(
sss_mbedtls_aead_t *context, uint8_t *destData, size_t *destLen, uint8_t *tag, size_t *tagLen)
{
sss_status_t retval = kStatus_SSS_Fail;
size_t stagLen = *tagLen;
int ret = 1;
/* Check the mode and perform requested operation */
if (context->mode == kMode_SSS_Encrypt) {
ret = mbedtls_ccm_encrypt_and_tag(context->ccm_ctx,
context->ccm_dataTotalLen,
context->pNonce,
context->nonceLen,
context->pCcm_aad,
context->ccm_aadLen,
context->pCcm_data,
destData,
tag,
stagLen);
}
else {
ret = mbedtls_ccm_auth_decrypt(context->ccm_ctx,
context->ccm_dataTotalLen,
context->pNonce,
context->nonceLen,
context->pCcm_aad,
context->ccm_aadLen,
context->pCcm_data,
destData,
tag,
stagLen);
}
ENSURE_OR_GO_EXIT(ret == 0);
*destLen = context->ccm_dataTotalLen;
retval = kStatus_SSS_Success;
exit:
return retval;
}
#endif //if SSS_HAVE_TESTCOUNTERPART
void sss_mbedtls_aead_context_free(sss_mbedtls_aead_t *context)
{
if (context != NULL) {
if (context->algorithm == kAlgorithm_SSS_AES_GCM) {
if (context->gcm_ctx != NULL) {
mbedtls_gcm_free(context->gcm_ctx);
SSS_FREE(context->gcm_ctx);
}
}
else if (context->algorithm == kAlgorithm_SSS_AES_CCM) {
if (context->ccm_ctx != NULL) {
mbedtls_ccm_free(context->ccm_ctx);
SSS_FREE(context->ccm_ctx);
if (context->pCcm_data != NULL) {
SSS_FREE(context->pCcm_data);
context->pCcm_data = NULL;
}
}
}
if (context->pCcm_aad != NULL)
context->pCcm_aad = NULL;
if (context->pNonce != NULL)
context->pNonce = NULL;
memset(context, 0, sizeof(*context));
}
}
/* End: mbedtls_aead */
/* ************************************************************************** */
/* Functions : sss_mbedtls_mac */
/* ************************************************************************** */
sss_status_t sss_mbedtls_mac_context_init(sss_mbedtls_mac_t *context,
sss_mbedtls_session_t *session,
sss_mbedtls_object_t *keyObject,
sss_algorithm_t algorithm,
sss_mode_t mode)
{
sss_status_t status = kStatus_SSS_Fail;
ENSURE_OR_GO_CLEANUP(context);
ENSURE_OR_GO_CLEANUP(session);
ENSURE_OR_GO_CLEANUP(keyObject);
context->session = session;
context->keyObject = keyObject;
context->algorithm = algorithm;
context->mode = mode;
context->cipher_ctx = NULL;
if (context->algorithm == kAlgorithm_SSS_CMAC_AES) {
context->cipher_ctx = (mbedtls_cipher_context_t *)SSS_MALLOC(sizeof(mbedtls_cipher_context_t));
ENSURE_OR_GO_CLEANUP(context->cipher_ctx);
}
#if SSSFTR_SW_TESTCOUNTERPART
if (algorithm == kAlgorithm_SSS_HMAC_SHA1 || algorithm == kAlgorithm_SSS_HMAC_SHA224 ||
algorithm == kAlgorithm_SSS_HMAC_SHA256 || algorithm == kAlgorithm_SSS_HMAC_SHA384 ||
algorithm == kAlgorithm_SSS_HMAC_SHA512) {
context->HmacCtx = (mbedtls_md_context_t *)SSS_MALLOC(sizeof(mbedtls_md_context_t));
ENSURE_OR_GO_CLEANUP(context->HmacCtx);
}
#endif
status = kStatus_SSS_Success;
cleanup:
return status;
}
sss_status_t sss_mbedtls_mac_one_go(
sss_mbedtls_mac_t *context, const uint8_t *message, size_t messageLen, uint8_t *mac, size_t *macLen)
{
sss_status_t status = kStatus_SSS_Fail;
int ret;
const mbedtls_cipher_info_t *cipher_info;
#if SSS_HAVE_TESTCOUNTERPART
const mbedtls_md_info_t *md_info = NULL;
#endif
uint8_t *key;
size_t keylen;
ENSURE_OR_GO_CLEANUP(context);
ENSURE_OR_GO_CLEANUP(context->keyObject->contents);
key = context->keyObject->contents;
keylen = context->keyObject->contents_size;
if (context->algorithm == kAlgorithm_SSS_CMAC_AES) {
mbedtls_cipher_type_t cipher_type = MBEDTLS_CIPHER_NONE;
switch (keylen * 8) {
case 128:
cipher_type = MBEDTLS_CIPHER_AES_128_ECB;
break;
#if SSS_HAVE_TESTCOUNTERPART
case 192:
cipher_type = MBEDTLS_CIPHER_AES_192_ECB;
break;
case 256:
cipher_type = MBEDTLS_CIPHER_AES_256_ECB;
break;
#endif
default:
LOG_E("key bit not supported");
goto cleanup;
}
cipher_info = mbedtls_cipher_info_from_type(cipher_type);
if (cipher_info != NULL) {
mbedtls_cipher_init(context->cipher_ctx);
ret = mbedtls_cipher_setup(context->cipher_ctx, cipher_info);
if (ret == 0) {
if (ret == 0) {
#ifdef MBEDTLS_CMAC_C
ret = mbedtls_cipher_cmac_starts(context->cipher_ctx, key, (keylen * 8));
if (ret == 0) {
ret = mbedtls_cipher_cmac_update(context->cipher_ctx, message, messageLen);
if (ret == 0) {
ret = mbedtls_cipher_cmac_finish(context->cipher_ctx, mac);
if (ret == 0) {
*macLen = context->cipher_ctx->cipher_info->block_size;
status = kStatus_SSS_Success;
}
}
}
#endif
}
}
}
}
#if SSS_HAVE_TESTCOUNTERPART
else if (context->algorithm == kAlgorithm_SSS_HMAC_SHA1 || context->algorithm == kAlgorithm_SSS_HMAC_SHA224 ||
context->algorithm == kAlgorithm_SSS_HMAC_SHA256 || context->algorithm == kAlgorithm_SSS_HMAC_SHA384 ||
context->algorithm == kAlgorithm_SSS_HMAC_SHA512) {
/*For HMAC any Key length is supported*/
switch (context->algorithm) {
case kAlgorithm_SSS_HMAC_SHA1:
md_info = mbedtls_md_info_from_type(MBEDTLS_MD_SHA1);
break;
case kAlgorithm_SSS_HMAC_SHA224:
md_info = mbedtls_md_info_from_type(MBEDTLS_MD_SHA224);
break;
case kAlgorithm_SSS_HMAC_SHA256:
md_info = mbedtls_md_info_from_type(MBEDTLS_MD_SHA256);
break;
case kAlgorithm_SSS_HMAC_SHA384:
md_info = mbedtls_md_info_from_type(MBEDTLS_MD_SHA384);
break;
case kAlgorithm_SSS_HMAC_SHA512:
md_info = mbedtls_md_info_from_type(MBEDTLS_MD_SHA512);
break;
default:
LOG_E("Invalid HMAC algorithm");
status = kStatus_SSS_Fail;
goto cleanup;
}
if (md_info != NULL) {
ret = mbedtls_md_hmac(md_info, key, keylen, message, messageLen, mac);
if (ret == 0) {
*macLen = mbedtls_md_get_size(md_info);
status = kStatus_SSS_Success;
}
}
}
#endif //SSS_HAVE_TESTCOUNTERPART
else {
LOG_E("Invalid algorithm type");
}
cleanup:
return status;
}
sss_status_t sss_mbedtls_mac_init(sss_mbedtls_mac_t *context)
{
sss_status_t status = kStatus_SSS_Fail;
int ret;
uint8_t *key;
size_t keylen;
mbedtls_cipher_type_t cipher_type = MBEDTLS_CIPHER_NONE;
ENSURE_OR_GO_CLEANUP(context->keyObject->contents);
key = context->keyObject->contents;
keylen = context->keyObject->contents_size;
if (context->algorithm == kAlgorithm_SSS_CMAC_AES) {
const mbedtls_cipher_info_t *cipher_info = NULL;
switch (context->keyObject->keyBitLen) {
case 128:
cipher_type = MBEDTLS_CIPHER_AES_128_ECB;
break;
#if SSS_HAVE_TESTCOUNTERPART
case 192:
cipher_type = MBEDTLS_CIPHER_AES_192_ECB;
break;
case 256:
cipher_type = MBEDTLS_CIPHER_AES_256_ECB;
break;
#endif
default:
LOG_E("key bit not supported");
goto cleanup;
}
if (cipher_type != MBEDTLS_CIPHER_NONE) {
cipher_info = mbedtls_cipher_info_from_type(cipher_type);
}
if (cipher_info != NULL) {
mbedtls_cipher_init(context->cipher_ctx);
ret = mbedtls_cipher_setup(context->cipher_ctx, cipher_info);
if (ret == 0) {
#ifdef MBEDTLS_CMAC_C
ret = mbedtls_cipher_cmac_starts(context->cipher_ctx, key, (keylen * 8));
#endif
if (ret == 0)
status = kStatus_SSS_Success;
}
}
}
#if SSS_HAVE_TESTCOUNTERPART
else if (context->algorithm == kAlgorithm_SSS_HMAC_SHA1 || context->algorithm == kAlgorithm_SSS_HMAC_SHA224 ||
context->algorithm == kAlgorithm_SSS_HMAC_SHA256 || context->algorithm == kAlgorithm_SSS_HMAC_SHA384 ||
context->algorithm == kAlgorithm_SSS_HMAC_SHA512) {
/* for HMAC any key length is supported */
const mbedtls_md_info_t *md_info = NULL;
mbedtls_md_context_t *hmac_ctx;
hmac_ctx = context->HmacCtx;
mbedtls_md_init(hmac_ctx);
switch (context->algorithm) {
case kAlgorithm_SSS_HMAC_SHA1:
md_info = mbedtls_md_info_from_type(MBEDTLS_MD_SHA1);
break;
case kAlgorithm_SSS_HMAC_SHA224:
md_info = mbedtls_md_info_from_type(MBEDTLS_MD_SHA224);
break;
case kAlgorithm_SSS_HMAC_SHA256:
md_info = mbedtls_md_info_from_type(MBEDTLS_MD_SHA256);
break;
case kAlgorithm_SSS_HMAC_SHA384:
md_info = mbedtls_md_info_from_type(MBEDTLS_MD_SHA384);
break;
case kAlgorithm_SSS_HMAC_SHA512:
md_info = mbedtls_md_info_from_type(MBEDTLS_MD_SHA512);
break;
default:
status = kStatus_SSS_Fail;
goto cleanup;
}
if (md_info != NULL) {
/* Below, third parameter '1' indicates that HMAC is to be setup*/
ret = mbedtls_md_setup(hmac_ctx, md_info, 1);
if (ret == 0) {
ret = mbedtls_md_hmac_starts(hmac_ctx, key, (keylen));
if (ret == 0) {
status = kStatus_SSS_Success;
}
}
}
}
#endif //SSS_HAVE_TESTCOUNTERPART
else {
LOG_E("invalid algorithm mode for sss_mbedtls_mac_context_init ");
}
cleanup:
return status;
}
sss_status_t sss_mbedtls_mac_update(sss_mbedtls_mac_t *context, const uint8_t *message, size_t messageLen)
{
int ret = 1;
sss_status_t status = kStatus_SSS_InvalidArgument;
ENSURE_OR_GO_EXIT(message != NULL);
status = kStatus_SSS_Fail;
LOG_AU8_D(message, messageLen);
if (context->algorithm == kAlgorithm_SSS_CMAC_AES) {
#ifdef MBEDTLS_CMAC_C
mbedtls_cipher_context_t *ctx;
ctx = context->cipher_ctx;
ret = mbedtls_cipher_cmac_update(ctx, message, messageLen);
#endif
if (ret == 0) {
status = kStatus_SSS_Success;
}
}
#if SSSFTR_SW_TESTCOUNTERPART
else if (context->algorithm == kAlgorithm_SSS_HMAC_SHA1 || context->algorithm == kAlgorithm_SSS_HMAC_SHA224 ||
context->algorithm == kAlgorithm_SSS_HMAC_SHA256 || context->algorithm == kAlgorithm_SSS_HMAC_SHA384 ||
context->algorithm == kAlgorithm_SSS_HMAC_SHA512) {
mbedtls_md_context_t *hmac_ctx;
hmac_ctx = context->HmacCtx;
ret = mbedtls_md_hmac_update(hmac_ctx, message, messageLen);
if (ret == 0) {
status = kStatus_SSS_Success;
}
}
#endif
else {
LOG_E("invalid algorithm mode for sss_mbedtls_mac_update");
}
exit:
return status;
}
sss_status_t sss_mbedtls_mac_finish(sss_mbedtls_mac_t *context, uint8_t *mac, size_t *macLen)
{
int ret = 1;
sss_status_t status = kStatus_SSS_InvalidArgument;
ENSURE_OR_GO_EXIT((mac != NULL) && (macLen != NULL));
status = kStatus_SSS_Fail;
if (context->algorithm == kAlgorithm_SSS_CMAC_AES) {
mbedtls_cipher_context_t *ctx;
ctx = context->cipher_ctx;
#ifdef MBEDTLS_CMAC_C
ret = mbedtls_cipher_cmac_finish(ctx, mac);
#endif
if (ret == 0) {
*macLen = ctx->cipher_info->block_size;
status = kStatus_SSS_Success;
}
}
#if SSS_HAVE_TESTCOUNTERPART
else if (context->algorithm == kAlgorithm_SSS_HMAC_SHA1 || context->algorithm == kAlgorithm_SSS_HMAC_SHA224 ||
context->algorithm == kAlgorithm_SSS_HMAC_SHA256 || context->algorithm == kAlgorithm_SSS_HMAC_SHA384 ||
context->algorithm == kAlgorithm_SSS_HMAC_SHA512) {
mbedtls_md_context_t *hmacctx;
hmacctx = context->HmacCtx;
ret = mbedtls_md_hmac_finish(hmacctx, mac);
if (ret == 0) {
*macLen = mbedtls_md_get_size(hmacctx->md_info);
status = kStatus_SSS_Success;
}
}
#endif //SSS_HAVE_TESTCOUNTERPART
else {
LOG_E("Invalid algorithm type for sss_mbedtls_mac_finish");
}
exit:
return status;
}
void sss_mbedtls_mac_context_free(sss_mbedtls_mac_t *context)
{
if (context != NULL) {
if (context->cipher_ctx != NULL) {
mbedtls_cipher_free(context->cipher_ctx);
SSS_FREE(context->cipher_ctx);
}
memset(context, 0, sizeof(*context));
}
}
/* ************************************************************************** */
/* Functions : sss_mbedtls_md */
/* ************************************************************************** */
sss_status_t sss_mbedtls_digest_context_init(
sss_mbedtls_digest_t *context, sss_mbedtls_session_t *session, sss_algorithm_t algorithm, sss_mode_t mode)
{
sss_status_t retval = kStatus_SSS_Fail;
#if SSS_HAVE_TESTCOUNTERPART
ENSURE_OR_GO_CLEANUP(context);
memset(context, 0, sizeof(*context));
context->session = session;
context->algorithm = algorithm;
context->mode = mode;
retval = kStatus_SSS_Success;
cleanup:
#endif //SSS_HAVE_TESTCOUNTERPART
return retval;
}
sss_status_t sss_mbedtls_digest_one_go(
sss_mbedtls_digest_t *context, const uint8_t *message, size_t messageLen, uint8_t *digest, size_t *digestLen)
{
sss_status_t retval = kStatus_SSS_Fail;
#if SSS_HAVE_TESTCOUNTERPART
int ret;
const mbedtls_md_info_t *mdinfo = NULL;
mbedtls_md_type_t md_type = MBEDTLS_MD_NONE;
switch (context->algorithm) {
case kAlgorithm_SSS_SHA1:
md_type = MBEDTLS_MD_SHA1;
*digestLen = 20;
break;
case kAlgorithm_SSS_SHA224:
md_type = MBEDTLS_MD_SHA224;
*digestLen = 28;
break;
case kAlgorithm_SSS_SHA256:
md_type = MBEDTLS_MD_SHA256;
*digestLen = 32;
break;
case kAlgorithm_SSS_SHA384:
md_type = MBEDTLS_MD_SHA384;
*digestLen = 48;
break;
case kAlgorithm_SSS_SHA512:
md_type = MBEDTLS_MD_SHA512;
*digestLen = 64;
break;
default: {
LOG_E("Algorithm mode not suported");
goto exit;
}
}
mdinfo = mbedtls_md_info_from_type(md_type);
ret = mbedtls_md(mdinfo, message, messageLen, digest);
if (ret != 0) {
LOG_E("mbedtls_md failed");
*digestLen = 0;
goto exit;
}
retval = kStatus_SSS_Success;
exit:
#endif //SSS_HAVE_TESTCOUNTERPART
return retval;
}
sss_status_t sss_mbedtls_digest_init(sss_mbedtls_digest_t *context)
{
sss_status_t retval = kStatus_SSS_Fail;
#if SSS_HAVE_TESTCOUNTERPART
const mbedtls_md_info_t *mdinfo = NULL;
mbedtls_md_type_t md_type = MBEDTLS_MD_NONE;
int ret;
mbedtls_md_init(&context->md_ctx);
switch (context->algorithm) {
case kAlgorithm_SSS_SHA1:
md_type = MBEDTLS_MD_SHA1;
break;
case kAlgorithm_SSS_SHA224:
md_type = MBEDTLS_MD_SHA224;
break;
case kAlgorithm_SSS_SHA256:
md_type = MBEDTLS_MD_SHA256;
break;
case kAlgorithm_SSS_SHA384:
md_type = MBEDTLS_MD_SHA384;
break;
case kAlgorithm_SSS_SHA512:
md_type = MBEDTLS_MD_SHA512;
break;
default:
LOG_E("Algorithm mode not suported");
goto exit;
}
mdinfo = mbedtls_md_info_from_type(md_type);
ret = mbedtls_md_init_ctx(&context->md_ctx, mdinfo);
ENSURE_OR_GO_EXIT(ret == 0);
mbedtls_md_starts(&context->md_ctx);
retval = kStatus_SSS_Success;
exit:
#endif //SSS_HAVE_TESTCOUNTERPART
return retval;
}
sss_status_t sss_mbedtls_digest_update(sss_mbedtls_digest_t *context, const uint8_t *message, size_t messageLen)
{
sss_status_t retval = kStatus_SSS_Fail;
#if SSS_HAVE_TESTCOUNTERPART
int ret = mbedtls_md_update(&context->md_ctx, message, messageLen);
ENSURE_OR_GO_EXIT(ret == 0);
retval = kStatus_SSS_Success;
exit:
#endif //SSS_HAVE_TESTCOUNTERPART
return retval;
}
sss_status_t sss_mbedtls_digest_finish(sss_mbedtls_digest_t *context, uint8_t *digest, size_t *digestLen)
{
sss_status_t retval = kStatus_SSS_Fail;
#if SSS_HAVE_TESTCOUNTERPART
int ret;
switch (context->algorithm) {
case kAlgorithm_SSS_SHA1:
*digestLen = 20;
break;
case kAlgorithm_SSS_SHA224:
*digestLen = 28;
break;
case kAlgorithm_SSS_SHA256:
*digestLen = 32;
break;
case kAlgorithm_SSS_SHA384:
*digestLen = 48;
break;
case kAlgorithm_SSS_SHA512:
*digestLen = 64;
break;
default: {
LOG_E("Algorithm mode not suported");
goto exit;
}
}
ret = mbedtls_md_finish(&context->md_ctx, digest);
if (ret != 0) {
LOG_E("mbedtls_md_update failed");
*digestLen = 0;
goto exit;
}
retval = kStatus_SSS_Success;
exit:
#endif //SSS_HAVE_TESTCOUNTERPART
return retval;
}
void sss_mbedtls_digest_context_free(sss_mbedtls_digest_t *context)
{
// if (context->md_ctx)
// mbedtls_md_free(&context->md_ctx);
memset(context, 0, sizeof(*context));
}
/* End: mbedtls_md */
/* ************************************************************************** */
/* Functions : sss_mbedtls_rng */
/* ************************************************************************** */
sss_status_t sss_mbedtls_rng_context_init(sss_mbedtls_rng_context_t *context, sss_mbedtls_session_t *session)
{
sss_status_t retval = kStatus_SSS_Fail;
ENSURE_OR_GO_EXIT(context);
context->session = session;
if (session->ctr_drbg == NULL) {
session->ctr_drbg = SSS_MALLOC(sizeof(*session->ctr_drbg));
ENSURE_OR_GO_EXIT(session->ctr_drbg != NULL);
mbedtls_ctr_drbg_init((session->ctr_drbg));
}
if (session->entropy == NULL) {
session->entropy = SSS_MALLOC(sizeof(*session->entropy));
ENSURE_OR_GO_EXIT(session->entropy != NULL);
mbedtls_entropy_init((session->entropy));
}
retval = kStatus_SSS_Success;
exit:
return retval;
}
sss_status_t sss_mbedtls_rng_get_random(sss_mbedtls_rng_context_t *context, uint8_t *random_data, size_t dataLen)
{
sss_status_t retval = kStatus_SSS_Fail;
size_t chunk = 0;
size_t offset = 0;
int ret = -1;
while (dataLen > 0) {
if (dataLen > MBEDTLS_CTR_DRBG_MAX_REQUEST) {
chunk = MBEDTLS_CTR_DRBG_MAX_REQUEST;
}
else {
chunk = dataLen;
}
ret = mbedtls_ctr_drbg_random(context->session->ctr_drbg, (random_data + offset), chunk);
ENSURE_OR_GO_EXIT(ret == 0);
offset += chunk;
dataLen -= chunk;
}
retval = kStatus_SSS_Success;
exit:
return retval;
}
sss_status_t sss_mbedtls_rng_context_free(sss_mbedtls_rng_context_t *context)
{
sss_status_t retval = kStatus_SSS_Success;
memset(context, 0, sizeof(*context));
return retval;
}
/* End: mbedtls_rng */
/* ************************************************************************** */
/* Functions : Private sss mbedtls functions */
/* ************************************************************************** */
// FIXME: Handle data/dataLen
static sss_status_t sss_mbedtls_set_key(
sss_mbedtls_object_t *keyObject, const uint8_t *data, size_t dataLen, size_t keyBitLen)
{
sss_status_t retval = kStatus_SSS_Fail;
#if SSSFTR_SW_ECC || SSSFTR_SW_RSA
size_t base64_olen;
int ret;
char pem_format[2048];
#endif
switch (keyObject->objectType) {
case kSSS_KeyPart_Default:
ENSURE_OR_GO_EXIT(dataLen <= keyObject->contents_max_size);
if (data != NULL) /* For empty certificate */
memcpy(keyObject->contents, data, dataLen);
keyObject->contents_size = dataLen;
keyObject->keyBitLen = keyBitLen;
retval = kStatus_SSS_Success;
break;
#if SSSFTR_SW_ECC || SSSFTR_SW_RSA
case kSSS_KeyPart_Private:
case kSSS_KeyPart_Pair: {
mbedtls_pk_context *pk = (mbedtls_pk_context *)keyObject->contents;
if (keyObject->cipherType == kSSS_CipherType_EC_MONTGOMERY) {
mbedtls_ecp_keypair *pEcpPrv = NULL;
sss_status_t asn_retval = kStatus_SSS_Fail;
ret = mbedtls_pk_setup(pk, mbedtls_pk_info_from_type(MBEDTLS_PK_ECKEY));
ENSURE_OR_GO_EXIT(ret == 0);
pEcpPrv = mbedtls_pk_ec(*pk);
if (keyBitLen == 256) {
ret = mbedtls_ecp_group_load(&pEcpPrv->grp, MBEDTLS_ECP_DP_CURVE25519);
}
else if (keyBitLen == 448) {
ret = mbedtls_ecp_group_load(&pEcpPrv->grp, MBEDTLS_ECP_DP_CURVE448);
}
else {
ret = 1;
}
ENSURE_OR_GO_EXIT(ret == 0);
#ifdef MBEDTLS_DO_LITTLE_ENDIAN // Reverse Endianness
{
size_t i = 0;
uint16_t publicKeyIndex = 0;
size_t publicKeyLen = 0;
uint16_t privateKeyIndex = 0;
size_t privateKeyLen = 0;
uint8_t pubKeyReversed[64] = {
0,
};
const uint8_t *pPublicKey = NULL;
uint8_t prvKeyReversed[64] = {
0,
};
const uint8_t *pPrivateKey = NULL;
asn_retval = sss_util_rfc8410_asn1_get_ec_pair_key_index(
data, dataLen, &publicKeyIndex, &publicKeyLen, &privateKeyIndex, &privateKeyLen);
if (asn_retval != kStatus_SSS_Success) {
LOG_W("error in sss_util_rfc8410_asn1_get_ec_pair_key_index");
goto exit;
}
while (i < publicKeyLen) {
pubKeyReversed[i] = data[publicKeyIndex + publicKeyLen - i - 1];
i++;
}
pPublicKey = &pubKeyReversed[0];
i = 0;
while (i < privateKeyLen) {
prvKeyReversed[i] = data[privateKeyIndex + privateKeyLen - i - 1];
i++;
}
/* RFC 7748, Sec 5 Par 5*/
if (keyBitLen == 256) {
prvKeyReversed[privateKeyLen - 1] = prvKeyReversed[privateKeyLen - 1] & 0xF8;
prvKeyReversed[0] = prvKeyReversed[0] & 0x7F;
prvKeyReversed[0] = prvKeyReversed[0] | 0x40;
}
else {
prvKeyReversed[privateKeyLen - 1] = prvKeyReversed[privateKeyLen - 1] & 0xFC;
prvKeyReversed[0] = prvKeyReversed[0] | 0x80;
}
pPrivateKey = &prvKeyReversed[0];
ret = mbedtls_mpi_read_binary(&pEcpPrv->d, pPrivateKey, privateKeyLen);
ENSURE_OR_GO_EXIT(ret == 0);
ret = mbedtls_mpi_read_binary(&pEcpPrv->Q.X, pPublicKey, publicKeyLen);
ENSURE_OR_GO_EXIT(ret == 0);
ret = mbedtls_mpi_lset(&pEcpPrv->Q.Z, 1);
ENSURE_OR_GO_EXIT(ret == 0);
retval = kStatus_SSS_Success;
}
#else
ret = mbedtls_mpi_read_binary(&pEcpPrv->d, data, dataLen);
ENSURE_OR_GO_EXIT(ret == 0);
retval = kStatus_SSS_Success;
#endif
}
else {
ret = mbedtls_pk_parse_key(pk, data, dataLen, NULL, 0);
(ret == 0) ? (retval = kStatus_SSS_Success) : (retval = kStatus_SSS_Fail);
}
} break;
case kSSS_KeyPart_Public: {
uint8_t base64_format[2048];
mbedtls_pk_context *pk = (mbedtls_pk_context *)keyObject->contents;
if (keyObject->cipherType == kSSS_CipherType_EC_MONTGOMERY) {
mbedtls_ecp_keypair *pEcpPub = NULL;
ret = mbedtls_pk_setup(pk, mbedtls_pk_info_from_type(MBEDTLS_PK_ECKEY));
ENSURE_OR_GO_EXIT(ret == 0);
pEcpPub = mbedtls_pk_ec(*pk);
if (keyBitLen == 256) {
ret = mbedtls_ecp_group_load(&pEcpPub->grp, MBEDTLS_ECP_DP_CURVE25519);
}
else if (keyBitLen == 448) {
ret = mbedtls_ecp_group_load(&pEcpPub->grp, MBEDTLS_ECP_DP_CURVE448);
}
else {
ret = 1;
}
ENSURE_OR_GO_EXIT(ret == 0);
#ifdef MBEDTLS_DO_LITTLE_ENDIAN // Reverse Endianness
{
size_t i = 0;
size_t publicKeyIndex = 0;
size_t publicKeyLen = dataLen;
size_t nByteKey = 32; // Corresponds to kSE05x_ECCurve_ECC_MONT_DH_25519
uint8_t pubKeyReversed[64] = {
0,
};
const uint8_t *pPublicKey = NULL;
// #define TMP_ENDIAN_VERBOSE
#ifdef TMP_ENDIAN_VERBOSE
printf("Pub Key Before Reverse & header strip:\n");
for (size_t z = 0; z < publicKeyLen; z++) {
printf("%02X.", data[publicKeyIndex + z]);
}
printf("\n");
printf("keyBitLen = %d\n", (int)keyBitLen);
#endif
if (keyBitLen == 256) {
publicKeyIndex = der_ecc_mont_dh_25519_header_len;
publicKeyLen -= der_ecc_mont_dh_25519_header_len;
}
else {
nByteKey = 56;
publicKeyIndex = der_ecc_mont_dh_448_header_len;
publicKeyLen -= der_ecc_mont_dh_448_header_len;
}
while (i < nByteKey) {
pubKeyReversed[i] = data[publicKeyIndex + publicKeyLen - i - 1];
i++;
}
pPublicKey = &pubKeyReversed[0];
#ifdef TMP_ENDIAN_VERBOSE
printf("Pub Key After Reverse:\n");
for (size_t z = 0; z < publicKeyLen; z++) {
printf("%02X.", pPublicKey[z]);
}
printf("\n");
#endif
ret = mbedtls_mpi_read_binary(&pEcpPub->Q.X, pPublicKey, publicKeyLen);
}
#else
ret = mbedtls_mpi_read_binary(&pEcpPub->Q.X, data, dataLen);
#endif // Reverse Endianess
(ret == 0) ? (retval = kStatus_SSS_Success) : (retval = kStatus_SSS_Fail);
if (retval == kStatus_SSS_Success) {
mbedtls_mpi_lset(&pEcpPub->Q.Z, 1);
}
}
else {
ret = mbedtls_base64_encode(base64_format, sizeof(base64_format), &base64_olen, data, dataLen);
SNPRINTF(pem_format, sizeof(pem_format), BEGIN_PUBLIC "%s" END_PUBLIC, base64_format);
ret = mbedtls_pk_parse_public_key(pk, (const uint8_t *)pem_format, strlen(pem_format) + 1);
(ret == 0) ? (retval = kStatus_SSS_Success) : (retval = kStatus_SSS_Fail);
}
} break;
#endif // SSSFTR_SW_ECC || SSSFTR_SW_RSA
default:
retval = kStatus_SSS_Fail;
LOG_E("Key type not supported");
break;
}
exit:
return retval;
}
static sss_status_t sss_mbedtls_drbg_seed(sss_mbedtls_session_t *pSession, const char *pers, size_t persLen)
{
int ret;
sss_status_t retval = kStatus_SSS_Fail;
ret = mbedtls_ctr_drbg_seed(
pSession->ctr_drbg, &mbedtls_entropy_func, pSession->entropy, (const unsigned char *)pers, persLen);
ENSURE_OR_GO_EXIT(ret == 0);
retval = kStatus_SSS_Success;
exit:
return (retval);
}
#if SSSFTR_SW_ECC && SSS_HAVE_TESTCOUNTERPART
static mbedtls_ecp_group_id get_nist_p_group_id(size_t keyBitLen)
{
mbedtls_ecp_group_id groupId = MBEDTLS_ECP_DP_NONE;
switch (keyBitLen) {
case 192:
groupId = MBEDTLS_ECP_DP_SECP192R1;
break;
case 224:
groupId = MBEDTLS_ECP_DP_SECP224R1;
break;
case 256:
groupId = MBEDTLS_ECP_DP_SECP256R1;
break;
case 384:
groupId = MBEDTLS_ECP_DP_SECP384R1;
break;
case 521:
groupId = MBEDTLS_ECP_DP_SECP521R1;
break;
default:
break;
}
return groupId;
}
static mbedtls_ecp_group_id get_bp_group_id(size_t keyBitLen)
{
mbedtls_ecp_group_id groupId = MBEDTLS_ECP_DP_NONE;
switch (keyBitLen) {
case 256:
groupId = MBEDTLS_ECP_DP_BP256R1;
break;
case 384:
groupId = MBEDTLS_ECP_DP_BP384R1;
break;
case 512:
groupId = MBEDTLS_ECP_DP_BP512R1;
break;
default:
break;
}
return groupId;
}
static mbedtls_ecp_group_id get_nist_k_group_id(size_t keyBitLen)
{
mbedtls_ecp_group_id groupId = MBEDTLS_ECP_DP_NONE;
switch (keyBitLen) {
case 192:
groupId = MBEDTLS_ECP_DP_SECP192K1;
break;
case 224:
groupId = MBEDTLS_ECP_DP_SECP224K1;
break;
case 256:
groupId = MBEDTLS_ECP_DP_SECP256K1;
break;
default:
break;
}
return groupId;
}
static mbedtls_ecp_group_id get_mont_group_id(size_t keyBitLen)
{
mbedtls_ecp_group_id groupId = MBEDTLS_ECP_DP_NONE;
switch (keyBitLen) {
case 256:
groupId = MBEDTLS_ECP_DP_CURVE25519;
break;
case 448:
groupId = MBEDTLS_ECP_DP_CURVE448;
break;
default:
break;
}
return groupId;
}
static sss_status_t sss_mbedtls_generate_ecp_key(
mbedtls_pk_context *pkey, sss_mbedtls_session_t *pSession, size_t keyBitLen, sss_cipher_type_t cipher_typ)
{
int ret;
sss_status_t retval = kStatus_SSS_Fail;
mbedtls_ecp_group_id groupId = MBEDTLS_ECP_DP_NONE;
ret = mbedtls_pk_setup(pkey, mbedtls_pk_info_from_type(MBEDTLS_PK_ECKEY));
ENSURE_OR_GO_EXIT(ret == 0);
retval = kStatus_SSS_Success;
if (cipher_typ == kSSS_CipherType_EC_NIST_P) {
groupId = get_nist_p_group_id(keyBitLen);
}
else if (cipher_typ == kSSS_CipherType_EC_BRAINPOOL) {
groupId = get_bp_group_id(keyBitLen);
}
else if (cipher_typ == kSSS_CipherType_EC_NIST_K) {
groupId = get_nist_k_group_id(keyBitLen);
}
else if (cipher_typ == kSSS_CipherType_EC_MONTGOMERY) {
groupId = get_mont_group_id(keyBitLen);
}
else {
LOG_E(" sss_openssl_generate_ecp_key: Invalid key type ");
}
if (groupId != MBEDTLS_ECP_DP_NONE) {
ret = mbedtls_ecp_gen_key(groupId, mbedtls_pk_ec(*pkey), mbedtls_ctr_drbg_random, pSession->ctr_drbg);
}
else {
LOG_E(" Don't have support keyBitLen", keyBitLen);
ret = 1;
}
if (ret != 0) {
LOG_E(" mbedtls_ecp_gen_key returned -0x%04x", -ret);
retval = kStatus_SSS_Fail;
goto exit;
}
exit:
return retval;
}
#endif // SSSFTR_SW_ECC
#if SSSFTR_SW_RSA && SSS_HAVE_TESTCOUNTERPART
static sss_status_t sss_mbedtls_generate_rsa_key(
mbedtls_pk_context *pkey, sss_mbedtls_session_t *pSession, size_t keyBitLen)
{
int ret;
sss_status_t retval = kStatus_SSS_Fail;
ret = mbedtls_pk_setup(pkey, mbedtls_pk_info_from_type(MBEDTLS_PK_RSA));
ENSURE_OR_GO_EXIT(ret == 0);
ENSURE_OR_GO_EXIT(keyBitLen == 512 || keyBitLen == 1024 || keyBitLen == 1152 || keyBitLen == 2048 ||
keyBitLen == 3072 || keyBitLen == 4096);
ret = mbedtls_rsa_gen_key(
mbedtls_pk_rsa(*pkey), mbedtls_ctr_drbg_random, (pSession->ctr_drbg), (unsigned int)keyBitLen, 65537);
ENSURE_OR_GO_EXIT(ret == 0);
retval = kStatus_SSS_Success;
exit:
return retval;
}
#endif
#if SSSFTR_SW_TESTCOUNTERPART
static sss_status_t sss_mbedtls_hkdf_expand(const mbedtls_md_info_t *md,
const uint8_t *prk,
size_t prk_len,
const uint8_t *info,
size_t info_len,
uint8_t *okm,
size_t okm_len)
{
size_t hash_len;
size_t N;
size_t T_len = 0, where = 0, i, ret;
mbedtls_md_context_t ctx;
unsigned char T[MBEDTLS_MD_MAX_SIZE];
sss_status_t retval = kStatus_SSS_Success;
if (okm == NULL) {
retval = kStatus_SSS_InvalidArgument;
goto exit;
}
hash_len = mbedtls_md_get_size(md);
if (info == NULL) {
info = (const unsigned char *)"";
}
N = okm_len / hash_len;
if ((okm_len % hash_len) != 0) {
N++;
}
if (N > 255) {
retval = kStatus_SSS_InvalidArgument;
goto exit;
}
mbedtls_md_init(&ctx);
if ((ret = mbedtls_md_setup(&ctx, md, 1)) != 0) {
mbedtls_md_free(&ctx);
retval = kStatus_SSS_Fail;
goto exit;
}
/* Section 2.3. */
for (i = 1; i <= N; i++) {
unsigned char c = (unsigned char)i;
ret = mbedtls_md_hmac_starts(&ctx, prk, prk_len) || mbedtls_md_hmac_update(&ctx, T, T_len) ||
mbedtls_md_hmac_update(&ctx, info, info_len) ||
/* The constant concatenated to the end of each T(n) is a single
octet. */
mbedtls_md_hmac_update(&ctx, &c, 1) || mbedtls_md_hmac_finish(&ctx, T);
if (ret != 0) {
mbedtls_md_free(&ctx);
retval = kStatus_SSS_Fail;
goto exit;
}
memcpy(okm + where, T, (i != N) ? hash_len : (okm_len - where));
where += hash_len;
T_len = hash_len;
}
mbedtls_md_free(&ctx);
exit:
return retval;
}
static sss_status_t sss_mbedtls_hkdf_extract(
const mbedtls_md_info_t *md, const uint8_t *salt, size_t salt_len, const uint8_t *ikm, size_t ikm_len, uint8_t *prk)
{
int hash_len;
int ret;
unsigned char null_salt[MBEDTLS_MD_MAX_SIZE] = {'\0'};
sss_status_t retval = kStatus_SSS_Success;
hash_len = mbedtls_md_get_size(md);
if (salt == NULL) {
salt = null_salt;
salt_len = hash_len;
}
ret = mbedtls_md_hmac(md, salt, salt_len, ikm, ikm_len, prk);
if (ret != 0) {
retval = kStatus_SSS_Fail;
}
return retval;
}
#endif // SSSFTR_SW_TESTCOUNTERPART
/* Low level implementation for sss_mbedtls_key_object_allocate_handle */
sss_status_t ks_mbedtls_key_object_create(sss_mbedtls_object_t *keyObject,
uint32_t keyId,
sss_key_part_t keyPart,
sss_cipher_type_t cipherType,
size_t keyByteLenMax,
uint32_t keyMode)
{
size_t size = 0;
sss_status_t retval = kStatus_SSS_Fail;
ENSURE_OR_GO_CLEANUP(keyObject);
keyObject->keyId = keyId;
keyObject->objectType = keyPart;
keyObject->cipherType = cipherType;
keyObject->contents_max_size = keyByteLenMax;
keyObject->contents_must_free = 1;
keyObject->keyMode = keyMode;
keyObject->accessRights = 0x1F; /* Bitwise OR of all sss_access_permission. */
switch (keyPart) {
case kSSS_KeyPart_Default:
size = keyByteLenMax;
break;
#if SSSFTR_SW_ECC || SSSFTR_SW_RSA
case kSSS_KeyPart_Pair:
case kSSS_KeyPart_Private:
case kSSS_KeyPart_Public:
size = sizeof(mbedtls_pk_context);
break;
#endif // SSSFTR_SW_ECC || SSSFTR_SW_RSA
default:
break;
}
if (size != 0) {
keyObject->contents = SSS_MALLOC(size);
keyObject->contents_must_free = 1;
ENSURE_OR_GO_CLEANUP(keyObject->contents);
memset(keyObject->contents, 0, size);
retval = kStatus_SSS_Success;
}
cleanup:
return retval;
}
#endif /* SSS_HAVE_MBEDTLS */