blob: 1f553cfb78291ff697a190fd70e0d43a6ff76079 [file] [log] [blame]
/*
*
* Copyright 2018-2020 NXP
* SPDX-License-Identifier: Apache-2.0
*/
#include <fsl_sss_openssl_apis.h>
#if SSS_HAVE_OPENSSL
#include <inttypes.h>
#include <memory.h>
#include <nxEnsure.h>
#include <openssl/aes.h>
#include <openssl/bio.h>
#include <openssl/bn.h>
#include <openssl/buffer.h>
#include <openssl/cmac.h>
#include <openssl/crypto.h>
#include <openssl/des.h>
#include <openssl/ec.h>
#include <openssl/ecdh.h>
#include <openssl/err.h>
#include <openssl/evp.h>
#include <openssl/hmac.h>
#include <openssl/opensslv.h>
#include <openssl/pem.h>
#include <openssl/rand.h>
#include <openssl/rsa.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#if (OPENSSL_VERSION_NUMBER < 0x10100000L)
#else
#include <openssl/modes.h>
#endif
#include "nxLog_sss.h"
#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_EC_PRIVATE "-----BEGIN EC PRIVATE KEY-----\n"
#define END_EC_PRIVATE "\n-----END EC PRIVATE KEY-----"
#define BEGIN_PUBLIC "-----BEGIN PUBLIC KEY-----\n"
#define END_PUBLIC "\n-----END PUBLIC KEY-----"
#define BEGIN_RSA_PRIVATE "-----BEGIN RSA PRIVATE KEY-----\n"
#define END_RSA_PRIVATE "\n-----END RSA PRIVATE KEY-----"
#define CIPHER_BLOCK_SIZE 16
#ifndef RSA_PSS_SALTLEN_DIGEST
#define RSA_PSS_SALTLEN_DIGEST -1
#endif
/* ************************************************************************** */
/* Functions : Private sss openssl delceration */
/* ************************************************************************** */
static sss_status_t sss_openssl_generate_ecp_key(sss_openssl_object_t *keyObject, size_t keyBitLen);
static sss_status_t sss_openssl_generate_rsa_key(sss_openssl_object_t *keyObject, size_t keyBitLen);
static sss_status_t sss_openssl_set_key(
sss_openssl_object_t *keyObject, const uint8_t *keyBuf, size_t keyBufLen, size_t keyBitLen);
static sss_status_t sss_openssl_hkdf_extract(const EVP_MD *md,
const uint8_t *salt,
size_t salt_len,
const uint8_t *ikm,
size_t ikm_len,
uint8_t *prk,
unsigned int *prk_len);
static sss_status_t sss_openssl_hkdf_expand(const EVP_MD *md,
const uint8_t *prk,
size_t prk_len,
const uint8_t *info,
size_t info_len,
uint8_t *okm,
size_t okm_len);
static sss_status_t sss_openssl_aead_init_ctx(sss_openssl_aead_t *context);
static sss_status_t sss_openssl_aead_one_go_encrypt(sss_openssl_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);
static sss_status_t sss_openssl_aead_one_go_decrypt(sss_openssl_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);
static int aead_update(sss_openssl_aead_t *context,
sss_mode_t mode,
const uint8_t *srcData,
size_t srcLen,
uint8_t *destData,
size_t *destLen);
static sss_status_t sss_openssl_aead_ccm_init(
sss_openssl_aead_t *context, size_t nonceLen, size_t tagLen, size_t aadLen, size_t payloadLen);
static sss_status_t sss_openssl_aead_ccm_final(
sss_openssl_aead_t *context, uint8_t *destData, size_t *destLen, uint8_t *tag, size_t *tagLen);
static sss_status_t sss_openssl_aead_ccm_Decryptfinal(sss_openssl_aead_t *context, uint8_t *destData, size_t *destLen);
static sss_status_t sss_openssl_aead_ccm_Encryptfinal(sss_openssl_aead_t *context, uint8_t *destData, size_t *destLen);
static sss_status_t sss_openssl_aead_ccm_update(sss_openssl_aead_t *context, const uint8_t *srcData, size_t srcLen);
/* ************************************************************************** */
/* Functions : sss_openssl_session */
/* ************************************************************************** */
sss_status_t sss_openssl_session_create(sss_openssl_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_openssl_session_open(sss_openssl_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));
#if SSS_HAVE_OPENSSL
memset(session, 0, sizeof(*session));
OpenSSL_add_all_algorithms();
if (connectionData == NULL) {
retval = kStatus_SSS_Success;
session->subsystem = subsystem;
}
else {
const char *szRootPath = (const char *)connectionData;
session->szRootPath = szRootPath;
retval = kStatus_SSS_Success;
session->subsystem = subsystem;
}
#else
if (connectionData == NULL) {
retval = kStatus_SSS_Success;
session->subsystem = subsystem;
}
else {
/* Can't support connectionData != NULL for openssl without
* openssl_FS_IO */
retval = kStatus_SSS_InvalidArgument;
}
#endif
return retval;
}
sss_status_t sss_openssl_session_prop_get_u32(sss_openssl_session_t *session, uint32_t property, uint32_t *pValue)
{
sss_status_t retval = kStatus_SSS_Fail;
/* TBU */
return retval;
}
sss_status_t sss_openssl_session_prop_get_au8(
sss_openssl_session_t *session, uint32_t property, uint8_t *pValue, size_t *pValueLen)
{
sss_status_t retval = kStatus_SSS_Fail;
/* TBU */
return retval;
}
void sss_openssl_session_close(sss_openssl_session_t *session)
{
#if (OPENSSL_VERSION_NUMBER < 0x10100000L)
ERR_remove_thread_state(NULL);
#endif
#ifdef __linux__
EVP_cleanup();
#endif
memset(session, 0, sizeof(*session));
}
void sss_openssl_session_delete(sss_openssl_session_t *session)
{
;
}
/* End: openssl_session */
/* ************************************************************************** */
/* Functions : sss_openssl_keyobj */
/* ************************************************************************** */
sss_status_t sss_openssl_key_object_init(sss_openssl_object_t *keyObject, sss_openssl_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_openssl_key_object_allocate(sss_openssl_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;
if (size != 0) {
keyObject->contents = SSS_MALLOC(size);
ENSURE_OR_GO_CLEANUP(keyObject->contents);
memset(keyObject->contents, 0, size);
retval = kStatus_SSS_Success;
}
break;
case kSSS_KeyPart_Public:
case kSSS_KeyPart_Pair:
case kSSS_KeyPart_Private:
/* Initialize the Generic key strucute if not done. */
keyObject->contents = EVP_PKEY_new();
retval = kStatus_SSS_Success;
break;
default:
break;
}
cleanup:
return retval;
}
sss_status_t sss_openssl_key_object_allocate_handle(sss_openssl_object_t *keyObject,
uint32_t keyId,
sss_key_part_t keyPart,
sss_cipher_type_t cipherType,
size_t keyByteLenMax,
uint32_t options)
{
sss_status_t retval = kStatus_SSS_Fail;
ENSURE_OR_GO_CLEANUP(keyObject);
if (options != kKeyObject_Mode_Persistent && options != kKeyObject_Mode_Transient) {
LOG_E("sss_openssl_key_object_allocate_handle option invalid 0x%X", options);
goto cleanup;
}
ENSURE_OR_GO_CLEANUP((size_t)keyPart < UINT8_MAX);
if (options == kKeyObject_Mode_Persistent) {
#ifdef SSS_HAVE_OPENSSL
uint32_t i;
sss_openssl_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, keyPart, cipherType, 0, 0, (uint16_t)keyByteLenMax);
ENSURE_OR_GO_CLEANUP(retval == kStatus_SSS_Success);
ks = keyObject->keyStore->objects;
for (i = 0; i < keyObject->keyStore->max_object_count; i++) {
if (ks[i] == NULL) {
ks[i] = keyObject;
retval = sss_openssl_key_object_allocate(keyObject, keyId, keyPart, cipherType, keyByteLenMax, options);
break;
}
}
#endif
}
else {
retval = sss_openssl_key_object_allocate(keyObject, keyId, keyPart, cipherType, keyByteLenMax, options);
}
cleanup:
return retval;
}
sss_status_t sss_openssl_key_object_get_handle(sss_openssl_object_t *keyObject, uint32_t keyId)
{
sss_status_t retval = kStatus_SSS_Fail;
#ifdef SSS_HAVE_OPENSSL
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_W("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_openssl_load_key(keyObject, keyObject->keyStore->keystore_shadow, keyId);
if (retval == kStatus_SSS_Success) {
keyObject->keyStore->objects[i] = keyObject;
}
break;
}
}
}
#endif
cleanup:
return retval;
}
sss_status_t sss_openssl_key_object_set_user(sss_openssl_object_t *keyObject, uint32_t user, uint32_t options)
{
sss_status_t retval = kStatus_SSS_Success;
if (!(keyObject->accessRights & kAccessPermission_SSS_ChangeAttributes)) {
LOG_E(" Don't have access rights to change the attributes");
return kStatus_SSS_Fail;
}
keyObject->user_id = user;
return retval;
}
sss_status_t sss_openssl_key_object_set_purpose(sss_openssl_object_t *keyObject, sss_mode_t purpose, uint32_t options)
{
sss_status_t retval = kStatus_SSS_Success;
if (!(keyObject->accessRights & kAccessPermission_SSS_ChangeAttributes)) {
LOG_E(" Don't have access rights to change the attributes");
return kStatus_SSS_Fail;
}
keyObject->purpose = purpose;
return retval;
}
sss_status_t sss_openssl_key_object_set_access(sss_openssl_object_t *keyObject, uint32_t access, uint32_t options)
{
sss_status_t retval = kStatus_SSS_Success;
if (!(keyObject->accessRights & kAccessPermission_SSS_ChangeAttributes)) {
LOG_E(" Don't have access rights to use the key");
return kStatus_SSS_Fail;
}
keyObject->accessRights = access;
return retval;
}
sss_status_t sss_openssl_key_object_set_eccgfp_group(sss_openssl_object_t *keyObject, sss_eccgfp_group_t *group)
{
sss_status_t retval = kStatus_SSS_Success;
/* TBU */
return retval;
}
sss_status_t sss_openssl_key_object_get_user(sss_openssl_object_t *keyObject, uint32_t *user)
{
sss_status_t retval = kStatus_SSS_Success;
*user = keyObject->user_id;
return retval;
}
sss_status_t sss_openssl_key_object_get_purpose(sss_openssl_object_t *keyObject, sss_mode_t *purpose)
{
sss_status_t retval = kStatus_SSS_Success;
*purpose = keyObject->purpose;
return retval;
}
sss_status_t sss_openssl_key_object_get_access(sss_openssl_object_t *keyObject, uint32_t *access)
{
sss_status_t retval = kStatus_SSS_Success;
*access = keyObject->accessRights;
return retval;
}
void sss_openssl_key_object_free(sss_openssl_object_t *keyObject)
{
EVP_PKEY *pKey = NULL;
RSA *pRSA = NULL;
unsigned int i = 0;
ENSURE_OR_GO_EXIT(keyObject)
if (keyObject->keyStore != NULL && keyObject->objectType != 0) {
for (i = 0; i < keyObject->keyStore->max_object_count; i++) {
if (keyObject->keyStore->objects[i] == keyObject) {
keyObject->keyStore->objects[i] = NULL;
break;
}
}
}
if (keyObject->contents != NULL && keyObject->contents_must_free) {
switch (keyObject->cipherType) {
case kSSS_CipherType_RSA:
pKey = (EVP_PKEY *)keyObject->contents;
pRSA = (RSA *)EVP_PKEY_get0(pKey);
if (pRSA) {
#if (OPENSSL_VERSION_NUMBER < 0x10100000L)
if (pRSA->references)
pRSA->references = 0;
#else
/* not in 1.1 and above */
#endif
}
EVP_PKEY_free(pKey);
break;
case kSSS_CipherType_EC_NIST_P:
case kSSS_CipherType_EC_NIST_K:
case kSSS_CipherType_EC_BRAINPOOL:
case kSSS_CipherType_EC_MONTGOMERY:
case kSSS_CipherType_EC_TWISTED_ED:
pKey = (EVP_PKEY *)keyObject->contents;
EVP_PKEY_free(pKey);
break;
default:
SSS_FREE(keyObject->contents);
}
}
memset(keyObject, 0, sizeof(*keyObject));
exit:
return;
}
/* End: openssl_keyobj */
/* ************************************************************************** */
/* Functions : sss_openssl_keyderive */
/* ************************************************************************** */
sss_status_t sss_openssl_derive_key_context_init(sss_openssl_derive_key_t *context,
sss_openssl_session_t *session,
sss_openssl_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);
ENSURE_OR_GO_CLEANUP(keyObject->contents);
context->session = session;
context->keyObject = keyObject;
context->algorithm = algorithm;
context->mode = mode;
retval = kStatus_SSS_Success;
cleanup:
return retval;
}
sss_status_t sss_openssl_derive_key_one_go(sss_openssl_derive_key_t *context,
const uint8_t *saltData,
size_t saltLen,
const uint8_t *info,
size_t infoLen,
sss_openssl_object_t *derivedKeyObject,
uint16_t deriveDataLen)
{
size_t adjustedSaltLen = saltLen;
if (context->mode == kMode_SSS_HKDF_ExpandOnly) {
adjustedSaltLen = 0;
}
return sss_openssl_derive_key_go(
context, saltData, adjustedSaltLen, info, infoLen, derivedKeyObject, deriveDataLen, NULL, NULL);
}
sss_status_t sss_openssl_derive_key_sobj_one_go(sss_openssl_derive_key_t *context,
sss_openssl_object_t *saltKeyObject,
const uint8_t *info,
size_t infoLen,
sss_openssl_object_t *derivedKeyObject,
uint16_t deriveDataLen)
{
uint8_t saltData[1024] = {0};
size_t saltLen = sizeof(saltData);
size_t dummySize;
sss_status_t status;
if (context->mode != kMode_SSS_HKDF_ExpandOnly) {
status = sss_openssl_key_store_get_key(saltKeyObject->keyStore, saltKeyObject, saltData, &saltLen, &dummySize);
if (status != kStatus_SSS_Success) {
return kStatus_SSS_Fail;
}
}
else {
saltLen = 0;
}
// Not yet fully implemented
// TODO:
// - deal with saltKeyObject
return sss_openssl_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_openssl_derive_key_go(sss_openssl_derive_key_t *context,
const uint8_t *saltData,
size_t saltLen,
const uint8_t *info,
size_t infoLen,
sss_openssl_object_t *derivedKeyObject,
uint16_t deriveDataLen,
uint8_t *hkdfOutput,
size_t *hkdfOutputLen)
{
sss_status_t retval = kStatus_SSS_Success;
const EVP_MD *md = NULL;
uint8_t *secret = NULL;
size_t secretLen = 0;
secret = context->keyObject->contents;
secretLen = context->keyObject->contents_size;
uint8_t prk[HKDF_PRK_MAX];
unsigned int prk_len = 0;
/* Initialize the MD */
switch (context->algorithm) {
case kAlgorithm_SSS_SHA1:
case kAlgorithm_SSS_HMAC_SHA1:
md = EVP_sha1();
break;
case kAlgorithm_SSS_SHA256:
case kAlgorithm_SSS_HMAC_SHA256:
md = EVP_sha256();
break;
case kAlgorithm_SSS_SHA384:
case kAlgorithm_SSS_HMAC_SHA384:
md = EVP_sha384();
break;
case kAlgorithm_SSS_SHA512:
case kAlgorithm_SSS_HMAC_SHA512:
md = EVP_sha512();
break;
default:
return kStatus_SSS_Fail;
}
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 (OpenSSL implementation): buffer too small");
return kStatus_SSS_Fail;
}
}
else {
retval = sss_openssl_hkdf_extract(md, saltData, saltLen, secret, secretLen, prk, &prk_len);
if (retval != kStatus_SSS_Success) {
return kStatus_SSS_Fail;
}
}
retval = sss_openssl_hkdf_expand(md, prk, prk_len, info, infoLen, derivedKeyObject->contents, deriveDataLen);
derivedKeyObject->contents_size = deriveDataLen;
return retval;
}
sss_status_t sss_openssl_derive_key_dh(sss_openssl_derive_key_t *context,
sss_openssl_object_t *otherPartyKeyObject,
sss_openssl_object_t *derivedKeyObject)
{
sss_status_t retval = kStatus_SSS_Success;
EVP_PKEY *pKeyPrv = NULL;
EC_KEY *pEcpPrv = NULL;
EVP_PKEY *pKeyExt = NULL;
EC_KEY *pEcpExt = NULL;
size_t sharedSecretLen;
int sharedSecretLen_Derived;
EC_GROUP *pEC_Group = NULL;
uint8_t *secret = NULL;
pKeyPrv = (EVP_PKEY *)context->keyObject->contents;
pKeyExt = (EVP_PKEY *)otherPartyKeyObject->contents;
if (context->keyObject->cipherType == kSSS_CipherType_EC_MONTGOMERY) {
EVP_PKEY_CTX *ctx;
ctx = EVP_PKEY_CTX_new(pKeyPrv, NULL);
if (!ctx) {
return kStatus_SSS_Fail;
}
if (EVP_PKEY_derive_init(ctx) <= 0) {
return kStatus_SSS_Fail;
}
if (EVP_PKEY_derive_set_peer(ctx, pKeyExt) <= 0) {
return kStatus_SSS_Fail;
}
/* Determine buffer length */
if (EVP_PKEY_derive(ctx, NULL, &sharedSecretLen) <= 0) {
return kStatus_SSS_Fail;
}
secret = (uint8_t *)SSS_MALLOC(sharedSecretLen);
sharedSecretLen_Derived = sharedSecretLen;
if (EVP_PKEY_derive(ctx, secret, &sharedSecretLen) <= 0) {
return kStatus_SSS_Fail;
}
EVP_PKEY_CTX_free(ctx);
}
else {
pEcpPrv = EVP_PKEY_get1_EC_KEY(pKeyPrv);
pEcpExt = EVP_PKEY_get1_EC_KEY(pKeyExt);
sharedSecretLen = (EC_GROUP_get_degree(EC_KEY_get0_group(pEcpExt)) + 7) / 8;
secret = (uint8_t *)SSS_MALLOC(sharedSecretLen);
sharedSecretLen_Derived =
ECDH_compute_key(secret, sharedSecretLen, EC_KEY_get0_public_key(pEcpExt), pEcpPrv, NULL);
}
memcpy(derivedKeyObject->contents, secret, sharedSecretLen_Derived);
derivedKeyObject->contents_size = sharedSecretLen_Derived;
EC_GROUP_free(pEC_Group);
EC_KEY_free(pEcpPrv);
EC_KEY_free(pEcpExt);
SSS_FREE(secret);
return retval;
}
void sss_openssl_derive_key_context_free(sss_openssl_derive_key_t *context)
{
if (context->keyObject)
sss_openssl_key_object_free(context->keyObject);
memset(context, 0, sizeof(*context));
}
/* End: openssl_keyderive */
/* ************************************************************************** */
/* Functions : sss_openssl_keystore */
/* ************************************************************************** */
sss_status_t sss_openssl_key_store_context_init(sss_openssl_key_store_t *keyStore, sss_openssl_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_openssl_key_store_allocate(sss_openssl_key_store_t *keyStore, uint32_t keyStoreId)
{
sss_status_t retval = kStatus_SSS_Fail;
ENSURE_OR_GO_CLEANUP(keyStore);
retval = kStatus_SSS_Success;
#ifdef SSS_HAVE_OPENSSL
if (keyStore->objects == NULL) {
keyStore->max_object_count = MAX_KEY_OBJ_COUNT;
keyStore->objects = (sss_openssl_object_t **)SSS_MALLOC(MAX_KEY_OBJ_COUNT * sizeof(sss_openssl_object_t *));
memset(keyStore->objects, 0, (MAX_KEY_OBJ_COUNT * sizeof(sss_openssl_object_t *)));
if (NULL == keyStore->objects) {
LOG_E("Could not allocate key store");
retval = kStatus_SSS_Fail;
}
else {
ks_sw_fat_allocate(&keyStore->keystore_shadow);
ks_sw_fat_load(keyStore->session->szRootPath, keyStore->keystore_shadow);
retval = kStatus_SSS_Success;
}
}
else {
LOG_E("KeyStore already allocated");
retval = kStatus_SSS_Fail;
}
#endif
cleanup:
return retval;
}
sss_status_t sss_openssl_key_store_save(sss_openssl_key_store_t *keyStore)
{
sss_status_t retval = kStatus_SSS_Fail;
ENSURE_OR_GO_CLEANUP(keyStore);
ENSURE_OR_GO_CLEANUP(keyStore->session);
#ifdef SSS_HAVE_OPENSSL
ENSURE_OR_GO_CLEANUP(keyStore->session->szRootPath);
if (NULL != keyStore->objects) {
uint32_t i;
for (i = 0; i < keyStore->max_object_count; i++) {
if (NULL != keyStore->objects[i]) {
retval = ks_openssl_store_key(keyStore->objects[i]);
/*Check added as part of security boundry checks*/
ENSURE_OR_GO_CLEANUP(retval == kStatus_SSS_Success);
}
}
}
retval = ks_openssl_fat_update(keyStore);
#endif
cleanup:
return retval;
}
sss_status_t sss_openssl_key_store_load(sss_openssl_key_store_t *keyStore)
{
sss_status_t retval = kStatus_SSS_Fail;
ENSURE_OR_GO_CLEANUP(keyStore);
ENSURE_OR_GO_CLEANUP(keyStore->session);
#ifdef SSS_HAVE_OPENSSL
if (keyStore->objects == NULL) {
retval = sss_openssl_key_store_allocate(keyStore, 0);
/*Check added as part of security boundry checks*/
ENSURE_OR_GO_CLEANUP(retval == kStatus_SSS_Success);
}
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_openssl_key_store_set_key(sss_openssl_key_store_t *keyStore,
sss_openssl_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;
uint8_t opensslData[256] = {
0,
};
size_t opensslDataLen = sizeof(opensslData);
ENSURE_OR_GO_CLEANUP(keyObject);
ENSURE_OR_GO_CLEANUP(keyObject->contents);
if (!(keyObject->accessRights & kAccessPermission_SSS_Write)) {
return retval;
}
if ((keyObject->objectType == kSSS_KeyPart_Pair) && (keyObject->cipherType == kSSS_CipherType_EC_MONTGOMERY)) {
LOG_W("OpenSSL keystore cannot handle EC_MONT keypair with public key: Removing public key");
ENSURE_OR_GO_CLEANUP(dataLen <= opensslDataLen);
memcpy(opensslData, data, dataLen);
if ((data[1] == 0x51) && (data[4] == 1)) {
opensslData[1] -= 0x23;
opensslData[4] = 0;
opensslDataLen = dataLen - 0x23;
}
else if ((data[1] == 0x81) && (data[4] == 1)) {
opensslData[1] -= 0x3b;
opensslData[4] = 0;
opensslDataLen = dataLen - 0x3b;
}
else {
LOG_E("OpenSSL keystore cannot handle EC_MONT keypair with public key: Cannot remove public key");
opensslDataLen = dataLen;
}
retval = sss_openssl_set_key(keyObject, opensslData, opensslDataLen, keyBitLen);
}
else {
retval = sss_openssl_set_key(keyObject, data, dataLen, keyBitLen);
}
cleanup:
return retval;
}
sss_status_t sss_openssl_key_store_generate_key(
sss_openssl_key_store_t *keyStore, sss_openssl_object_t *keyObject, size_t keyBitLen, void *options)
{
sss_status_t retval = kStatus_SSS_Success;
sss_cipher_type_t cipher_type = keyObject->cipherType;
ENSURE_OR_GO_EXIT(keyStore);
ENSURE_OR_GO_EXIT(keyObject);
switch (cipher_type) {
case kSSS_CipherType_EC_NIST_P:
case kSSS_CipherType_EC_NIST_K:
case kSSS_CipherType_EC_BRAINPOOL:
case kSSS_CipherType_EC_MONTGOMERY:
case kSSS_CipherType_EC_TWISTED_ED:
retval = sss_openssl_generate_ecp_key(keyObject, keyBitLen);
break;
case kSSS_CipherType_RSA:
retval = sss_openssl_generate_rsa_key(keyObject, keyBitLen);
break;
default:
break;
}
exit:
return retval;
}
sss_status_t sss_openssl_key_store_get_key(sss_openssl_key_store_t *keyStore,
sss_openssl_object_t *keyObject,
uint8_t *data,
size_t *dataLen,
size_t *pKeyBitLen)
{
sss_status_t retval = kStatus_SSS_Fail;
EVP_PKEY *pk = NULL;
int len = 0;
ENSURE_OR_GO_CLEANUP(keyObject);
ENSURE_OR_GO_CLEANUP(keyObject->contents);
if (!(keyObject->accessRights & kAccessPermission_SSS_Read)) {
return kStatus_SSS_Fail;
}
switch (keyObject->objectType) {
case kSSS_KeyPart_Default:
memcpy(data, keyObject->contents, keyObject->contents_size);
*dataLen = keyObject->contents_size;
break;
case kSSS_KeyPart_Public:
case kSSS_KeyPart_Pair: {
pk = (EVP_PKEY *)keyObject->contents;
len = i2d_PUBKEY(pk, &data);
if (len < 0 || (int)(*dataLen) < len) {
goto cleanup;
}
*dataLen = len;
*pKeyBitLen = len * 8;
break;
}
default:
break;
}
retval = kStatus_SSS_Success;
cleanup:
return retval;
}
#if 0
/* To be reviewed: Purnank */
sss_status_t sss_openssl_key_store_get_key_fromoffset(sss_openssl_key_store_t *keyStore,
sss_openssl_object_t *keyObject,
uint8_t *data,
size_t *dataLen,
size_t *pKeyBitLen,
uint16_t offset)
{
sss_status_t retval = kStatus_SSS_Success;
return retval;
}
#endif
sss_status_t sss_openssl_key_store_open_key(sss_openssl_key_store_t *keyStore, sss_openssl_object_t *keyObject)
{
sss_status_t retval = kStatus_SSS_Success;
return retval;
}
sss_status_t sss_openssl_key_store_freeze_key(sss_openssl_key_store_t *keyStore, sss_openssl_object_t *keyObject)
{
sss_status_t retval = kStatus_SSS_Success;
return retval;
}
sss_status_t sss_openssl_key_store_erase_key(sss_openssl_key_store_t *keyStore, sss_openssl_object_t *keyObject)
{
sss_status_t retval = kStatus_SSS_Fail;
ENSURE_OR_GO_EXIT(keyStore);
ENSURE_OR_GO_EXIT(keyObject);
ENSURE_OR_GO_EXIT(keyObject->keyStore);
if (!(keyObject->accessRights & kAccessPermission_SSS_Delete)) {
LOG_E("Don't have access right to delete the key");
return retval;
}
if (keyObject->keyMode == kKeyObject_Mode_Persistent) {
#ifdef SSS_HAVE_OPENSSL
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_openssl_fat_update(keyObject->keyStore);
ENSURE_OR_GO_CLEANUP(retval == kStatus_SSS_Success);
/*Clear key object from file*/
retval = ks_openssl_remove_key(keyObject);
/*Check added as part of security boundary checks*/
ENSURE_OR_GO_CLEANUP(retval == kStatus_SSS_Success);
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;
}
#ifdef SSS_HAVE_OPENSSL
cleanup:
#endif
exit:
return retval;
}
void sss_openssl_key_store_context_free(sss_openssl_key_store_t *keyStore)
{
if (NULL != keyStore->objects) {
uint32_t i;
for (i = 0; i < keyStore->max_object_count; i++) {
if (keyStore->objects[i] != NULL) {
sss_openssl_key_object_free(keyStore->objects[i]);
keyStore->objects[i] = NULL;
}
}
SSS_FREE(keyStore->objects);
}
ks_sw_fat_free(keyStore->keystore_shadow);
memset(keyStore, 0, sizeof(*keyStore));
}
int openssl_get_padding(sss_algorithm_t algorithm)
{
int padding = 0;
switch (algorithm) {
case kAlgorithm_SSS_RSASSA_PKCS1_V1_5_SHA1:
case kAlgorithm_SSS_RSASSA_PKCS1_V1_5_SHA224:
case kAlgorithm_SSS_RSASSA_PKCS1_V1_5_SHA256:
case kAlgorithm_SSS_RSASSA_PKCS1_V1_5_SHA384:
case kAlgorithm_SSS_RSASSA_PKCS1_V1_5_SHA512:
case kAlgorithm_SSS_RSASSA_PKCS1_V1_5_NO_HASH:
case kAlgorithm_SSS_RSAES_PKCS1_V1_5:
padding = RSA_PKCS1_PADDING;
break;
case kAlgorithm_SSS_RSASSA_PKCS1_PSS_MGF1_SHA1:
case kAlgorithm_SSS_RSASSA_PKCS1_PSS_MGF1_SHA224:
case kAlgorithm_SSS_RSASSA_PKCS1_PSS_MGF1_SHA256:
case kAlgorithm_SSS_RSASSA_PKCS1_PSS_MGF1_SHA384:
case kAlgorithm_SSS_RSASSA_PKCS1_PSS_MGF1_SHA512:
padding = RSA_PKCS1_PSS_PADDING;
break;
case kAlgorithm_SSS_RSAES_PKCS1_OAEP_SHA1:
case kAlgorithm_SSS_RSAES_PKCS1_OAEP_SHA224:
case kAlgorithm_SSS_RSAES_PKCS1_OAEP_SHA256:
case kAlgorithm_SSS_RSAES_PKCS1_OAEP_SHA384:
case kAlgorithm_SSS_RSAES_PKCS1_OAEP_SHA512:
padding = RSA_PKCS1_OAEP_PADDING;
break;
default:
padding = RSA_PKCS1_PADDING;
}
return padding;
}
/* End: openssl_keystore */
/* ************************************************************************** */
/* Functions : sss_openssl_asym */
/* ************************************************************************** */
sss_status_t sss_openssl_asymmetric_context_init(sss_openssl_asymmetric_t *context,
sss_openssl_session_t *session,
sss_openssl_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(keyObject);
ENSURE_OR_GO_CLEANUP(keyObject->keyStore->session->subsystem == kType_SSS_OpenSSL);
context->session = session;
context->keyObject = keyObject;
context->algorithm = algorithm;
context->mode = mode;
retval = kStatus_SSS_Success;
cleanup:
return retval;
}
sss_status_t sss_openssl_asymmetric_encrypt(
sss_openssl_asymmetric_t *context, const uint8_t *srcData, size_t srcLen, uint8_t *destData, size_t *destLen)
{
sss_status_t retval = kStatus_SSS_Success;
int ret;
sss_openssl_object_t *keyObj = context->keyObject;
EVP_PKEY *pKey = NULL;
RSA *pRSA = NULL;
char *pErr = NULL;
int padding = 0;
if (!(context->keyObject->accessRights & kAccessPermission_SSS_Use)) {
return kStatus_SSS_Fail;
}
/* Get the RSA Key. */
pKey = (EVP_PKEY *)keyObj->contents;
pRSA = EVP_PKEY_get1_RSA(pKey);
padding = openssl_get_padding(context->algorithm);
/* Encrypt the mesasage. */
ret = RSA_public_encrypt((int)srcLen, srcData, destData, pRSA, padding);
if (ret == -1) {
retval = kStatus_SSS_Fail;
ERR_load_crypto_strings();
pErr = SSS_MALLOC(150);
ERR_error_string(ERR_get_error(), pErr);
LOG_E("sss_openssl_asymmetric_encrypt");
goto exit;
}
else {
*destLen = ret;
}
exit:
return retval;
}
sss_status_t sss_openssl_asymmetric_decrypt(
sss_openssl_asymmetric_t *context, const uint8_t *srcData, size_t srcLen, uint8_t *destData, size_t *destLen)
{
sss_status_t retval = kStatus_SSS_Success;
int ret;
sss_openssl_object_t *keyObj = context->keyObject;
EVP_PKEY *pKey = NULL;
RSA *pRSA = NULL;
char *pErr = NULL;
int padding = 0;
if (!(context->keyObject->accessRights & kAccessPermission_SSS_Use)) {
return kStatus_SSS_Fail;
}
/* Get the RSA Key. */
pKey = (EVP_PKEY *)keyObj->contents;
pRSA = EVP_PKEY_get1_RSA(pKey);
padding = openssl_get_padding(context->algorithm);
/* Decrypt the mesasage. */
ret = RSA_private_decrypt((int)srcLen, srcData, destData, pRSA, padding);
if (ret == -1) {
retval = kStatus_SSS_Fail;
ERR_load_crypto_strings();
pErr = SSS_MALLOC(150);
ERR_error_string(ERR_get_error(), pErr);
LOG_E("sss_openssl_asymmetric_encrypt");
goto exit;
}
else {
*destLen = ret;
}
exit:
return retval;
}
void *openssl_get_hash_ptr_set_padding(sss_algorithm_t algorithm, uint32_t cipherType, EVP_PKEY_CTX *pKey_Ctx)
{
void *hashfPtr = NULL;
switch (algorithm) {
case kAlgorithm_SSS_SHA1:
case kAlgorithm_SSS_ECDSA_SHA1:
case kAlgorithm_SSS_RSASSA_PKCS1_V1_5_SHA1:
case kAlgorithm_SSS_RSASSA_PKCS1_PSS_MGF1_SHA1:
case kAlgorithm_SSS_RSAES_PKCS1_OAEP_SHA1: {
hashfPtr = (void *)EVP_sha1();
} break;
case kAlgorithm_SSS_SHA224:
case kAlgorithm_SSS_ECDSA_SHA224:
case kAlgorithm_SSS_RSASSA_PKCS1_V1_5_SHA224:
case kAlgorithm_SSS_RSASSA_PKCS1_PSS_MGF1_SHA224:
case kAlgorithm_SSS_RSAES_PKCS1_OAEP_SHA224: {
hashfPtr = (void *)EVP_sha224();
} break;
case kAlgorithm_SSS_SHA256:
case kAlgorithm_SSS_ECDSA_SHA256:
case kAlgorithm_SSS_RSASSA_PKCS1_V1_5_SHA256:
case kAlgorithm_SSS_RSASSA_PKCS1_PSS_MGF1_SHA256:
case kAlgorithm_SSS_RSAES_PKCS1_V1_5:
case kAlgorithm_SSS_RSAES_PKCS1_OAEP_SHA256:
case kAlgorithm_SSS_ECDAA: {
hashfPtr = (void *)EVP_sha256();
} break;
case kAlgorithm_SSS_SHA384:
case kAlgorithm_SSS_ECDSA_SHA384:
case kAlgorithm_SSS_RSASSA_PKCS1_V1_5_SHA384:
case kAlgorithm_SSS_RSASSA_PKCS1_PSS_MGF1_SHA384:
case kAlgorithm_SSS_RSAES_PKCS1_OAEP_SHA384: {
hashfPtr = (void *)EVP_sha384();
} break;
case kAlgorithm_SSS_SHA512:
case kAlgorithm_SSS_ECDSA_SHA512:
case kAlgorithm_SSS_RSASSA_PKCS1_V1_5_SHA512:
case kAlgorithm_SSS_RSASSA_PKCS1_PSS_MGF1_SHA512:
case kAlgorithm_SSS_RSAES_PKCS1_OAEP_SHA512: {
hashfPtr = (void *)EVP_sha512();
} break;
case kAlgorithm_SSS_RSASSA_PKCS1_V1_5_NO_HASH:
default:
hashfPtr = NULL;
}
if (cipherType == kSSS_CipherType_RSA || cipherType == kSSS_CipherType_RSA_CRT) {
EVP_PKEY_CTX_set_rsa_padding(pKey_Ctx, openssl_get_padding(algorithm));
}
else {
//No padding for ECC Sign
//EVP_CIPHER_CTX_set_padding(pKey_Ctx, 0);
}
return hashfPtr;
}
sss_status_t sss_openssl_asymmetric_sign_digest(
sss_openssl_asymmetric_t *context, uint8_t *digest, size_t digestLen, uint8_t *signature, size_t *signatureLen)
{
sss_status_t retval = kStatus_SSS_Success;
EVP_PKEY *pKey = NULL;
EVP_PKEY_CTX *pKey_Ctx = NULL;
void *hashfPtr = NULL;
int ret = 0;
if (!(context->keyObject->accessRights & kAccessPermission_SSS_Use)) {
return kStatus_SSS_Fail;
}
pKey = (EVP_PKEY *)context->keyObject->contents;
#if (OPENSSL_VERSION_NUMBER < 0x10100000L)
#else
if (context->keyObject->cipherType == kSSS_CipherType_EC_MONTGOMERY) {
EVP_MD_CTX *pKey_md_Ctx = NULL;
pKey_md_Ctx = (EVP_MD_CTX *)EVP_MD_CTX_create();
if (1 != EVP_DigestSignInit(pKey_md_Ctx, NULL, NULL, NULL, pKey)) {
retval = kStatus_SSS_Fail;
goto exit;
}
if (1 != EVP_DigestSign(pKey_md_Ctx, signature, signatureLen, digest, digestLen)) {
retval = kStatus_SSS_Fail;
}
goto exit;
}
#endif
/* Get the context from EVP_PKEY */
pKey_Ctx = EVP_PKEY_CTX_new(pKey, NULL);
/* Init the Signing context. */
if (1 != EVP_PKEY_sign_init(pKey_Ctx)) {
retval = kStatus_SSS_Fail;
goto exit;
}
/* Set the Signing MD. */
hashfPtr = openssl_get_hash_ptr_set_padding(context->algorithm, context->keyObject->cipherType, pKey_Ctx);
/*
* For RSA, null hash pointer is valid, as sign with no hash is available.
* Sign with no hash is invalid for ecc keys.
*/
if (context->keyObject->cipherType == kSSS_CipherType_EC_NIST_P ||
context->keyObject->cipherType == kSSS_CipherType_EC_NIST_K ||
context->keyObject->cipherType == kSSS_CipherType_EC_BRAINPOOL ||
context->keyObject->cipherType == kSSS_CipherType_EC_TWISTED_ED ||
context->keyObject->cipherType == kSSS_CipherType_EC_BARRETO_NAEHRIG) {
ENSURE_OR_GO_EXIT(NULL != hashfPtr);
}
/* Explicitly set the salt length to match the digest size (-1)
* #define RSA_PSS_SALTLEN_DIGEST -1, this is defined only in openssl 1.1
* Define it explicitly in this file.
*/
EVP_PKEY_CTX_set_rsa_pss_saltlen(pKey_Ctx, RSA_PSS_SALTLEN_DIGEST);
if (1 != EVP_PKEY_CTX_set_signature_md(pKey_Ctx, hashfPtr)) {
retval = kStatus_SSS_Fail;
goto exit;
}
/* Set the Signature length to 0. */
*signatureLen = 0;
/* Determine buffer length */
ret = EVP_PKEY_sign(pKey_Ctx, NULL, signatureLen, digest, digestLen);
if (ret <= 0) {
retval = kStatus_SSS_Fail;
goto exit;
}
/* Perfom Signing of the message. */
ret = EVP_PKEY_sign(pKey_Ctx, signature, signatureLen, digest, digestLen);
if (ret <= 0) {
retval = kStatus_SSS_Fail;
goto exit;
}
exit:
EVP_PKEY_CTX_free(pKey_Ctx);
pKey_Ctx = NULL;
return retval;
}
sss_status_t sss_openssl_asymmetric_verify_digest(
sss_openssl_asymmetric_t *context, uint8_t *digest, size_t digestLen, uint8_t *signature, size_t signatureLen)
{
sss_status_t retval = kStatus_SSS_Success;
EVP_PKEY *pKey = NULL;
EVP_PKEY_CTX *pKey_Ctx = NULL;
void *hashfPtr = NULL;
int ret = 0;
if (!(context->keyObject->accessRights & kAccessPermission_SSS_Use)) {
return kStatus_SSS_Fail;
}
pKey = (EVP_PKEY *)context->keyObject->contents;
#if (OPENSSL_VERSION_NUMBER < 0x10100000L)
#else
if (context->keyObject->cipherType == kSSS_CipherType_EC_MONTGOMERY) {
EVP_MD_CTX *pKey_md_Ctx = NULL;
pKey_md_Ctx = (EVP_MD_CTX *)EVP_MD_CTX_create();
if (1 != EVP_DigestVerifyInit(pKey_md_Ctx, NULL, NULL, NULL, pKey)) {
retval = kStatus_SSS_Fail;
goto exit;
}
if (1 != EVP_DigestVerify(pKey_md_Ctx, signature, signatureLen, digest, digestLen)) {
retval = kStatus_SSS_Fail;
}
goto exit;
}
#endif
/* Get the context from EVP_PKEY */
pKey_Ctx = EVP_PKEY_CTX_new(pKey, NULL);
/* Init the Verfying context. */
if (1 != EVP_PKEY_verify_init(pKey_Ctx)) {
retval = kStatus_SSS_Fail;
goto exit;
}
/* Set the Signing MD. */
hashfPtr = openssl_get_hash_ptr_set_padding(context->algorithm, context->keyObject->cipherType, pKey_Ctx);
/*
* For RSA, null hash pointer is valid, as sign with no hash is available.
* Sign with no hash is invalid for ecc keys.
*/
if (context->keyObject->cipherType == kSSS_CipherType_EC_NIST_P ||
context->keyObject->cipherType == kSSS_CipherType_EC_NIST_K ||
context->keyObject->cipherType == kSSS_CipherType_EC_BRAINPOOL ||
context->keyObject->cipherType == kSSS_CipherType_EC_TWISTED_ED ||
context->keyObject->cipherType == kSSS_CipherType_EC_BARRETO_NAEHRIG) {
ENSURE_OR_GO_EXIT(NULL != hashfPtr);
}
if (1 != EVP_PKEY_CTX_set_signature_md(pKey_Ctx, hashfPtr)) {
retval = kStatus_SSS_Fail;
goto exit;
}
/* Perfom Verification of the message. */
ret = EVP_PKEY_verify(pKey_Ctx, signature, signatureLen, digest, digestLen);
if (1 != ret) {
retval = kStatus_SSS_Fail;
goto exit;
}
exit:
EVP_PKEY_CTX_free(pKey_Ctx);
pKey_Ctx = NULL;
return retval;
}
sss_status_t sss_openssl_asymmetric_sign(
sss_openssl_asymmetric_t *context, uint8_t *srcData, size_t srcLen, uint8_t *destData, size_t *destLen)
{
sss_status_t retval = kStatus_SSS_Fail;
#if (OPENSSL_VERSION_NUMBER < 0x10100000L)
#else
EVP_MD_CTX *pKey_md_Ctx = NULL;
EVP_PKEY *pKey = NULL;
pKey = (EVP_PKEY *)context->keyObject->contents;
if (context->keyObject->cipherType == kSSS_CipherType_EC_TWISTED_ED) {
pKey_md_Ctx = (EVP_MD_CTX *)EVP_MD_CTX_create();
if (1 != EVP_DigestSignInit(pKey_md_Ctx, NULL, NULL, NULL, pKey)) {
goto exit;
}
if (1 != EVP_DigestSign(pKey_md_Ctx, destData, destLen, srcData, srcLen)) {
goto exit;
}
}
else {
goto exit;
}
retval = kStatus_SSS_Success;
#endif
exit:
return retval;
}
sss_status_t sss_openssl_asymmetric_verify(
sss_openssl_asymmetric_t *context, uint8_t *srcData, size_t srcLen, uint8_t *signature, size_t signatureLen)
{
sss_status_t retval = kStatus_SSS_Fail;
#if (OPENSSL_VERSION_NUMBER < 0x10100000L)
#else
EVP_MD_CTX *pKey_md_Ctx = NULL;
EVP_PKEY *pKey = NULL;
pKey = (EVP_PKEY *)context->keyObject->contents;
if (context->keyObject->cipherType == kSSS_CipherType_EC_TWISTED_ED) {
pKey_md_Ctx = (EVP_MD_CTX *)EVP_MD_CTX_create();
if (1 != EVP_DigestVerifyInit(pKey_md_Ctx, NULL, NULL, NULL, pKey)) {
goto exit;
}
if (1 != EVP_DigestVerify(pKey_md_Ctx, signature, signatureLen, srcData, srcLen)) {
goto exit;
}
}
else {
goto exit;
}
retval = kStatus_SSS_Success;
#endif
exit:
return retval;
}
void sss_openssl_asymmetric_context_free(sss_openssl_asymmetric_t *context)
{
memset(context, 0, sizeof(*context));
}
/* End: openssl_asym */
/* ************************************************************************** */
/* Functions : sss_openssl_symm */
/* ************************************************************************** */
sss_status_t sss_openssl_symmetric_context_init(sss_openssl_symmetric_t *context,
sss_openssl_session_t *session,
sss_openssl_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;
context->cache_data_len = 0;
context->cipher_ctx = NULL;
return retval;
}
sss_status_t sss_openssl_cipher_one_go(sss_openssl_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;
AES_KEY AESKey;
DES_key_schedule schedule;
DES_cblock DESKey;
switch (context->algorithm) {
case kAlgorithm_SSS_AES_ECB:
case kAlgorithm_SSS_AES_CBC: {
if (context->mode == kMode_SSS_Encrypt) {
if (AES_set_encrypt_key((uint8_t *)context->keyObject->contents,
(int)(context->keyObject->contents_size * 8),
&AESKey) < 0) {
retval = kStatus_SSS_Fail;
LOG_E("Key initialization failed");
goto exit;
}
}
else if (context->mode == kMode_SSS_Decrypt) {
if (AES_set_decrypt_key((uint8_t *)context->keyObject->contents,
(int)(context->keyObject->contents_size * 8),
&AESKey) < 0) {
retval = kStatus_SSS_Fail;
LOG_E("Key initialization failed");
goto exit;
}
}
} break;
case kAlgorithm_SSS_AES_CTR: {
if (AES_set_encrypt_key(
(uint8_t *)context->keyObject->contents, (int)(context->keyObject->contents_size * 8), &AESKey) < 0) {
retval = kStatus_SSS_Fail;
LOG_E("Key initialization failed");
goto exit;
}
} break;
case kAlgorithm_SSS_DES_CBC:
case kAlgorithm_SSS_DES_ECB:
case kAlgorithm_SSS_DES3_CBC:
case kAlgorithm_SSS_DES3_ECB: {
memcpy(DESKey, (const char *)context->keyObject->contents, context->keyObject->contents_size);
DES_set_key(&DESKey, &schedule);
break;
}
default:
return retval;
}
if (context->mode == kMode_SSS_Encrypt) {
switch (context->algorithm) {
case kAlgorithm_SSS_AES_ECB:
AES_ecb_encrypt(srcData, destData, &AESKey, AES_ENCRYPT);
break;
case kAlgorithm_SSS_AES_CBC:
AES_cbc_encrypt(srcData, destData, dataLen, &AESKey, iv, AES_ENCRYPT);
break;
case kAlgorithm_SSS_AES_CTR: {
unsigned char ecount_buf[16] = {
0,
};
unsigned int num = 0;
#if (OPENSSL_VERSION_NUMBER < 0x10100000L)
AES_ctr128_encrypt(srcData, destData, dataLen, &AESKey, iv, ecount_buf, &num);
#else
CRYPTO_ctr128_encrypt(srcData, destData, dataLen, &AESKey, iv, ecount_buf, &num, (block128_f)AES_encrypt);
#endif
} break;
case kAlgorithm_SSS_DES_ECB: {
#if (OPENSSL_VERSION_NUMBER < 0x10100000L)
DES_ecb_encrypt((const_DES_cblock *)srcData, (DES_cblock *)destData, &schedule, DES_ENCRYPT);
#else
size_t rem = dataLen;
int offset = 0;
if (dataLen % 8 != 0) {
LOG_E("Input should be 8 byte aligned for DES ECB");
return kStatus_SSS_Fail;
}
while ((rem > 0) && (rem % 8 == 0)) {
DES_ecb_encrypt(
(const_DES_cblock *)(srcData + offset), (DES_cblock *)(destData + offset), &schedule, DES_ENCRYPT);
offset = offset + 8;
rem = rem - 8;
}
#endif
} break;
case kAlgorithm_SSS_DES_CBC:
DES_cbc_encrypt(srcData, destData, (int)dataLen, &schedule, (DES_cblock *)iv, DES_ENCRYPT);
break;
default:
break;
}
}
else if (context->mode == kMode_SSS_Decrypt) {
switch (context->algorithm) {
case kAlgorithm_SSS_AES_ECB:
AES_ecb_encrypt(srcData, destData, &AESKey, AES_DECRYPT);
break;
case kAlgorithm_SSS_AES_CBC:
AES_cbc_encrypt(srcData, destData, dataLen, &AESKey, iv, AES_DECRYPT);
break;
case kAlgorithm_SSS_AES_CTR: {
unsigned char ecount_buf[16] = {
0,
};
unsigned int num = 0;
#if (OPENSSL_VERSION_NUMBER < 0x10100000L)
AES_ctr128_encrypt(srcData, destData, dataLen, &AESKey, iv, ecount_buf, &num);
#else
CRYPTO_ctr128_encrypt(srcData, destData, dataLen, &AESKey, iv, ecount_buf, &num, (block128_f)AES_encrypt);
#endif
} break;
case kAlgorithm_SSS_DES_ECB: {
#if (OPENSSL_VERSION_NUMBER < 0x10100000L)
DES_ecb_encrypt((const_DES_cblock *)srcData, (DES_cblock *)destData, &schedule, DES_DECRYPT);
#else
size_t rem = dataLen;
int offset = 0;
if (dataLen % 8 != 0) {
LOG_E("Input should be 8 byte aligned for DES ECB");
return kStatus_SSS_Fail;
}
while ((rem > 0) && (rem % 8 == 0)) {
DES_ecb_encrypt(
(const_DES_cblock *)(srcData + offset), (DES_cblock *)(destData + offset), &schedule, DES_DECRYPT);
offset = offset + 8;
rem = rem - 8;
}
#endif
} break;
case kAlgorithm_SSS_DES_CBC:
DES_cbc_encrypt(srcData, destData, (long)dataLen, &schedule, (DES_cblock *)iv, DES_DECRYPT);
break;
default:
break;
}
}
else {
return retval;
}
exit:
return kStatus_SSS_Success;
}
sss_status_t sss_openssl_cipher_init(sss_openssl_symmetric_t *context, uint8_t *iv, size_t ivLen)
{
sss_status_t retval = kStatus_SSS_Success;
const EVP_CIPHER *cipher_info = NULL;
if (context->algorithm == kAlgorithm_SSS_AES_ECB) {
switch (context->keyObject->keyBitLen) {
case 128:
cipher_info = EVP_aes_128_ecb();
break;
case 192:
cipher_info = EVP_aes_192_ecb();
break;
case 256:
cipher_info = EVP_aes_256_ecb();
break;
default:
goto exit;
}
}
else if (context->algorithm == kAlgorithm_SSS_AES_CBC) {
switch (context->keyObject->keyBitLen) {
case 128:
cipher_info = EVP_aes_128_cbc();
break;
case 192:
cipher_info = EVP_aes_192_cbc();
break;
case 256:
cipher_info = EVP_aes_256_cbc();
break;
default:
goto exit;
}
}
else if (context->algorithm == kAlgorithm_SSS_AES_CTR) {
switch (context->keyObject->keyBitLen) {
case 128:
cipher_info = EVP_aes_128_ctr();
break;
case 192:
cipher_info = EVP_aes_192_ctr();
break;
case 256:
cipher_info = EVP_aes_256_ctr();
break;
default:
goto exit;
}
}
/* Create and initialise the context */
context->cipher_ctx = EVP_CIPHER_CTX_new();
if (!(context->cipher_ctx)) {
retval = kStatus_SSS_InvalidArgument;
LOG_E(" Cipher initialization failed ");
goto exit;
}
if (context->mode == kMode_SSS_Encrypt) {
/* Initialise the encryption operation. IMPORTANT - ensure you use a key
* and IV size appropriate for your cipher
*/
if (1 != EVP_CipherInit(context->cipher_ctx, cipher_info, context->keyObject->contents, iv, 1)) {
retval = kStatus_SSS_InvalidArgument;
LOG_E("EncryptionCipher initialization failed !!!");
goto exit;
}
EVP_CIPHER_CTX_set_padding(context->cipher_ctx, 0);
}
else if (context->mode == kMode_SSS_Decrypt) {
/* Initialise the encryption operation. IMPORTANT - ensure you use a key
* and IV size appropriate for your cipher
*/
if (1 != EVP_CipherInit(context->cipher_ctx, cipher_info, context->keyObject->contents, iv, 0)) {
retval = kStatus_SSS_InvalidArgument;
LOG_E(" DecryptionCipher initialization failed");
goto exit;
}
EVP_CIPHER_CTX_set_padding(context->cipher_ctx, 0);
}
else {
retval = kStatus_SSS_InvalidArgument;
}
exit:
return retval;
}
sss_status_t sss_openssl_cipher_update(
sss_openssl_symmetric_t *context, const uint8_t *srcData, size_t srcLen, uint8_t *destData, size_t *destLen)
{
sss_status_t retval = kStatus_SSS_Fail;
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;
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);
if (1 !=
EVP_CipherUpdate(
context->cipher_ctx, (destData + output_offset), (int *)&blockoutLen, inputData, (int)inputData_len)) {
goto exit;
}
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;
inputData_len = CIPHER_BLOCK_SIZE;
ENSURE_OR_GO_EXIT(blockoutLen >= inputData_len);
if (1 != EVP_CipherUpdate(context->cipher_ctx,
(destData + output_offset),
(int *)&blockoutLen,
inputData,
(int)inputData_len)) {
goto exit;
}
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;
}
return retval;
}
sss_status_t sss_openssl_cipher_finish(
sss_openssl_symmetric_t *context, const uint8_t *srcData, size_t srcLen, uint8_t *destData, size_t *destLen)
{
sss_status_t retval = kStatus_SSS_Fail;
uint8_t srcdata_updated[2 * CIPHER_BLOCK_SIZE] = {
0,
};
size_t srcdata_updated_len = 0;
size_t outBuffSize = *destLen;
size_t blockoutLen = 0;
uint8_t dummyBuf[CIPHER_BLOCK_SIZE] = {
0,
};
int dummyBufLen = sizeof(dummyBuf);
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);
if (1 !=
EVP_CipherUpdate(context->cipher_ctx, destData, (int *)&blockoutLen, srcdata_updated, CIPHER_BLOCK_SIZE)) {
goto exit;
}
*destLen = blockoutLen;
outBuffSize -= blockoutLen;
}
if (srcdata_updated_len > CIPHER_BLOCK_SIZE) {
blockoutLen = outBuffSize;
ENSURE_OR_GO_EXIT(blockoutLen >= CIPHER_BLOCK_SIZE);
if (1 != EVP_CipherUpdate(context->cipher_ctx,
destData + CIPHER_BLOCK_SIZE,
(int *)&blockoutLen,
srcdata_updated + CIPHER_BLOCK_SIZE,
CIPHER_BLOCK_SIZE)) {
goto exit;
}
*destLen += blockoutLen;
outBuffSize -= blockoutLen;
}
/* All data processed using EVP_CipherUpdate call. EVP_CipherFinal call will be dummy call.
No encrypted/decrypted output will be generated */
if (1 != EVP_CipherFinal(context->cipher_ctx, dummyBuf, &dummyBufLen)) {
goto exit;
}
retval = kStatus_SSS_Success;
exit:
return retval;
}
sss_status_t sss_openssl_cipher_crypt_ctr(sss_openssl_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;
AES_KEY key;
if (AES_set_encrypt_key(
(uint8_t *)context->keyObject->contents, (int)(context->keyObject->contents_size * 8), &key) < 0) {
goto exit;
}
switch (context->keyObject->keyBitLen) {
case 128:
case 192:
case 256: {
unsigned int iLeft = (unsigned int)*szLeft;
#if (OPENSSL_VERSION_NUMBER < 0x10100000L)
AES_ctr128_encrypt(srcData, destData, size, &key, initialCounter, lastEncryptedCounter, &iLeft);
#else
CRYPTO_ctr128_encrypt(
srcData, destData, size, &key, initialCounter, lastEncryptedCounter, &iLeft, (block128_f)AES_encrypt);
#endif
*szLeft = iLeft;
break;
}
default:
goto exit;
}
retval = kStatus_SSS_Success;
exit:
return retval;
}
void sss_openssl_symmetric_context_free(sss_openssl_symmetric_t *context)
{
if (context->cipher_ctx != NULL) {
EVP_CIPHER_CTX_free((EVP_CIPHER_CTX *)context->cipher_ctx);
context->cipher_ctx = NULL;
}
memset(context, 0, sizeof(*context));
}
/* End: openssl_symm */
/* ************************************************************************** */
/* Functions : sss_openssl_aead */
/* ************************************************************************** */
sss_status_t sss_openssl_aead_context_init(sss_openssl_aead_t *context,
sss_openssl_session_t *session,
sss_openssl_object_t *keyObject,
sss_algorithm_t algorithm,
sss_mode_t mode)
{
sss_status_t retval = kStatus_SSS_Fail;
context->session = session;
context->keyObject = keyObject;
context->mode = mode;
if (algorithm == kAlgorithm_SSS_AES_GCM || algorithm == kAlgorithm_SSS_AES_CCM) {
context->algorithm = algorithm;
}
else {
LOG_E("AEAD improper algorithm passed!!!");
goto exit;
}
/* Create and initialise the context */
context->aead_ctx = EVP_CIPHER_CTX_new();
ENSURE_OR_GO_EXIT(context->aead_ctx != NULL);
context->pCcm_aad = NULL;
context->pCcm_data = NULL;
context->pCcm_iv = NULL;
context->pCcm_tag = NULL;
retval = sss_openssl_aead_init_ctx(context);
exit:
return retval;
}
static sss_status_t sss_openssl_aead_init_ctx(sss_openssl_aead_t *context)
{
sss_status_t retval = kStatus_SSS_Fail;
const EVP_CIPHER *aead_info = NULL;
int ret = 0;
if (context->algorithm == kAlgorithm_SSS_AES_GCM) {
switch (context->keyObject->keyBitLen) {
case 128:
aead_info = EVP_aes_128_gcm();
break;
case 192:
aead_info = EVP_aes_192_gcm();
break;
case 256:
aead_info = EVP_aes_256_gcm();
break;
default:
LOG_E("Improper key size!");
goto exit;
}
}
else if (context->algorithm == kAlgorithm_SSS_AES_CCM) {
switch (context->keyObject->keyBitLen) {
case 128:
aead_info = EVP_aes_128_ccm();
break;
case 192:
aead_info = EVP_aes_192_ccm();
break;
case 256:
aead_info = EVP_aes_256_ccm();
break;
default:
LOG_E("Improper key size!");
goto exit;
}
}
if (context->mode == kMode_SSS_Encrypt) {
/* Initialise the encryption operation. */
ret = EVP_EncryptInit_ex(context->aead_ctx, aead_info, NULL, NULL, NULL);
}
else if (context->mode == kMode_SSS_Decrypt) {
/* Initialise the decryption operation. */
ret = EVP_DecryptInit_ex(context->aead_ctx, aead_info, NULL, NULL, NULL);
}
ENSURE_OR_GO_EXIT(ret == 1);
retval = kStatus_SSS_Success;
exit:
return retval;
}
sss_status_t sss_openssl_aead_one_go(sss_openssl_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 = 0;
/* Set IV length if default 96 bits is not appropriate */
ret = EVP_CIPHER_CTX_ctrl(context->aead_ctx, EVP_CTRL_GCM_SET_IVLEN, nonceLen, NULL);
ENSURE_OR_GO_EXIT(ret == 1);
context->pCcm_data = NULL;
/* Check mode do the operation requested */
if (context->mode == kMode_SSS_Encrypt) {
retval = sss_openssl_aead_one_go_encrypt(
context, srcData, destData, size, nonce, nonceLen, aad, aadLen, tag, tagLen);
}
else if (context->mode == kMode_SSS_Decrypt) {
retval = sss_openssl_aead_one_go_decrypt(
context, srcData, destData, size, nonce, nonceLen, aad, aadLen, tag, tagLen);
}
exit:
return retval;
}
sss_status_t sss_openssl_aead_init(
sss_openssl_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;
int ret = 0;
if (context->algorithm == kAlgorithm_SSS_AES_GCM) {
ret = EVP_CIPHER_CTX_ctrl(context->aead_ctx, EVP_CTRL_GCM_SET_IVLEN, nonceLen, NULL);
ENSURE_OR_GO_EXIT(ret == 1);
context->cache_data_len = 0;
memset(context->cache_data, 0x00, sizeof(context->cache_data));
/* Initialise key and IV */
{
if (context->mode == kMode_SSS_Encrypt) {
ret = EVP_EncryptInit_ex(context->aead_ctx, NULL, NULL, context->keyObject->contents, nonce);
}
else {
ret = EVP_DecryptInit_ex(context->aead_ctx, NULL, NULL, context->keyObject->contents, nonce);
}
ENSURE_OR_GO_EXIT(ret == 1);
}
}
if (context->algorithm == kAlgorithm_SSS_AES_CCM) {
context->pCcm_iv = nonce;
context->ccm_ivLen = nonceLen;
context->ccm_tagLen = tagLen;
context->ccm_aadLen = aadLen;
context->ccm_dataTotalLen = payloadLen;
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 exit;
}
}
}
retval = kStatus_SSS_Success;
exit:
return retval;
}
sss_status_t sss_openssl_aead_update_aad(sss_openssl_aead_t *context, const uint8_t *aadData, size_t aadDataLen)
{
sss_status_t retval = kStatus_SSS_Fail;
int ret = 0;
int len = 0;
/* Provide AAD data */
if (context->algorithm == kAlgorithm_SSS_AES_GCM) {
if (context->mode == kMode_SSS_Decrypt) {
ret = EVP_DecryptUpdate(context->aead_ctx, NULL, &len, aadData, aadDataLen);
}
else {
ret = EVP_EncryptUpdate(context->aead_ctx, NULL, &len, aadData, aadDataLen);
}
ENSURE_OR_GO_EXIT(ret == 1);
}
else if (context->algorithm == kAlgorithm_SSS_AES_CCM) {
context->pCcm_aad = aadData;
context->ccm_aadLen = aadDataLen;
}
retval = kStatus_SSS_Success;
exit:
return retval;
}
sss_status_t sss_openssl_aead_update(
sss_openssl_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 = 0;
/*Note for OpenSSL AES_CCM Update data is called only once*/
if (context->algorithm == kAlgorithm_SSS_AES_CCM) {
if ((srcData != NULL) && (srcLen > 0)) {
retval = sss_openssl_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 =
aead_update(context, context->mode, inputData, inputData_len, (destData + output_offset), &blockoutLen);
ENSURE_OR_GO_CLEANUP(ret == 1);
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 = aead_update(
context, context->mode, inputData, inputData_len, (destData + output_offset), &blockoutLen);
ENSURE_OR_GO_CLEANUP(ret == 1);
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;
}
static sss_status_t sss_openssl_aead_ccm_update(sss_openssl_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;
}
static int aead_update(sss_openssl_aead_t *context,
sss_mode_t mode,
const uint8_t *srcData,
size_t srcLen,
uint8_t *destData,
size_t *destLen)
{
#if SSS_HAVE_TESTCOUNTERPART
int ret = 0;
int len = 0;
if (context->mode == kMode_SSS_Encrypt) {
ret = EVP_EncryptUpdate(context->aead_ctx, destData, &len, srcData, srcLen);
}
else if (context->mode == kMode_SSS_Decrypt) {
ret = EVP_DecryptUpdate(context->aead_ctx, destData, &len, srcData, srcLen);
}
*destLen = len;
#endif /*SSS_HAVE_TESTCOUNTERPART*/
return ret;
}
sss_status_t sss_openssl_aead_finish(sss_openssl_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
int ret = 0;
uint8_t srcdata_updated[2 * CIPHER_BLOCK_SIZE] = {
0,
};
size_t srcdata_updated_len = 0;
int len = 0;
if (context->algorithm == kAlgorithm_SSS_AES_CCM) { /* Check if finish has got source data */
if ((srcData != NULL) && (srcLen > 0)) {
retval = sss_openssl_aead_ccm_update(context, srcData, srcLen);
ENSURE_OR_GO_EXIT(retval == kStatus_SSS_Success);
}
retval = sss_openssl_aead_ccm_final(context, destData, destLen, tag, tagLen);
}
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 = aead_update(context, context->mode, srcdata_updated, srcdata_updated_len, destData, destLen);
ENSURE_OR_GO_EXIT(ret == 1);
if (context->mode == kMode_SSS_Encrypt) {
ret = EVP_EncryptFinal_ex(context->aead_ctx, destData, &len);
ENSURE_OR_GO_EXIT(ret == 1);
*destLen = len;
ret = EVP_CIPHER_CTX_ctrl(context->aead_ctx, EVP_CTRL_GCM_GET_TAG, 16, tag);
*tagLen = EVP_CTRL_GCM_GET_TAG;
}
else if (context->mode == kMode_SSS_Decrypt) {
ret = EVP_CIPHER_CTX_ctrl(context->aead_ctx, EVP_CTRL_CCM_SET_TAG, *tagLen, tag);
ENSURE_OR_GO_EXIT(ret == 1);
/* Finalise decrypt */
//ret = EVP_DecryptFinal_ex(context->aead_ctx, destData, &context->len);
}
//ENSURE_OR_GO_EXIT(ret == 1);
retval = kStatus_SSS_Success;
}
exit:
#endif /*SSS_HAVE_TESTCOUNTERPART*/
return retval;
}
static sss_status_t sss_openssl_aead_ccm_final(
sss_openssl_aead_t *context, uint8_t *destData, size_t *destLen, uint8_t *tag, size_t *tagLen)
{
sss_status_t retval = kStatus_SSS_Fail;
#if SSS_HAVE_TESTCOUNTERPART
context->pCcm_tag = tag;
if (context->mode == kMode_SSS_Decrypt) {
retval = sss_openssl_aead_ccm_Decryptfinal(context, destData, destLen);
}
else {
retval = sss_openssl_aead_ccm_Encryptfinal(context, destData, destLen);
if (retval == kStatus_SSS_Success) {
tag = context->pCcm_tag;
*tagLen = context->ccm_tagLen;
}
}
ENSURE_OR_GO_EXIT(retval == kStatus_SSS_Success);
*destLen = context->ccm_dataTotalLen;
retval = kStatus_SSS_Success;
exit:
#endif /*SSS_HAVE_TESTCOUNTERPART*/
return retval;
}
static sss_status_t sss_openssl_aead_ccm_Encryptfinal(sss_openssl_aead_t *context, uint8_t *destData, size_t *destLen)
{
sss_status_t retval = kStatus_SSS_Fail;
#if SSS_HAVE_TESTCOUNTERPART
int ret = 0;
int len = 0;
/*Set IV len */
ret = EVP_CIPHER_CTX_ctrl(context->aead_ctx, EVP_CTRL_CCM_SET_IVLEN, context->ccm_ivLen, NULL);
ENSURE_OR_GO_EXIT(ret == 1)
/* Set tag length */
ret = EVP_CIPHER_CTX_ctrl(context->aead_ctx, EVP_CTRL_CCM_SET_TAG, context->ccm_tagLen, NULL);
ENSURE_OR_GO_EXIT(ret == 1)
/* Initialise key and IV */
ret = EVP_EncryptInit_ex(context->aead_ctx, NULL, NULL, context->keyObject->contents, context->pCcm_iv);
ENSURE_OR_GO_EXIT(ret == 1);
/* Provide the total plain length */
ret = EVP_EncryptUpdate(context->aead_ctx, NULL, &len, NULL, context->ccm_dataTotalLen);
ENSURE_OR_GO_EXIT(ret == 1);
/* Provide any AAD data*/
ret = EVP_EncryptUpdate(context->aead_ctx, NULL, &len, context->pCcm_aad, context->ccm_aadLen);
ENSURE_OR_GO_EXIT(ret == 1);
/* Provide the message to be decrypted*/
ret = EVP_EncryptUpdate(context->aead_ctx, destData, &len, context->pCcm_data, context->ccm_dataTotalLen);
ENSURE_OR_GO_EXIT(ret == 1);
*destLen = len;
len = 0;
ret = EVP_CIPHER_CTX_ctrl(context->aead_ctx, EVP_CTRL_CCM_GET_TAG, context->ccm_tagLen, context->pCcm_tag);
ENSURE_OR_GO_EXIT(ret == 1);
//context->ccm_tagLen = len;
retval = kStatus_SSS_Success;
exit:
#endif /*SSS_HAVE_TESTCOUNTERPART*/
return retval;
}
static sss_status_t sss_openssl_aead_ccm_Decryptfinal(sss_openssl_aead_t *context, uint8_t *destData, size_t *destLen)
{
sss_status_t retval = kStatus_SSS_Fail;
#if SSS_HAVE_TESTCOUNTERPART
int ret = 0;
int len = 0;
int payloadlen = context->ccm_dataTotalLen;
/*Set IV len */
ret = EVP_CIPHER_CTX_ctrl(context->aead_ctx, EVP_CTRL_CCM_SET_IVLEN, context->ccm_ivLen, NULL);
ENSURE_OR_GO_EXIT(ret == 1)
/* Set expected tag value. */
ret = EVP_CIPHER_CTX_ctrl(context->aead_ctx, EVP_CTRL_CCM_SET_TAG, context->ccm_tagLen, context->pCcm_tag);
ENSURE_OR_GO_EXIT(ret == 1);
/* Initialise key and IV */
ret = EVP_DecryptInit_ex(context->aead_ctx, NULL, NULL, context->keyObject->contents, context->pCcm_iv);
ENSURE_OR_GO_EXIT(ret == 1);
/* Provide the total ciphertext length */
ret = EVP_DecryptUpdate(context->aead_ctx, NULL, &len, NULL, payloadlen);
ENSURE_OR_GO_EXIT(ret == 1);
/* Provide any AAD data*/
ret = EVP_DecryptUpdate(context->aead_ctx, NULL, &len, context->pCcm_aad, context->ccm_aadLen);
ENSURE_OR_GO_EXIT(ret == 1);
/* Provide the message to be decrypted*/
ret = EVP_DecryptUpdate(context->aead_ctx, destData, &len, context->pCcm_data, context->ccm_dataTotalLen);
ENSURE_OR_GO_EXIT(ret == 1);
*destLen = len;
retval = kStatus_SSS_Success;
exit:
#endif /*SSS_HAVE_TESTCOUNTERPART*/
return retval;
}
void sss_openssl_aead_context_free(sss_openssl_aead_t *context)
{
if (context->aead_ctx != NULL) {
if ((context->algorithm == kAlgorithm_SSS_AES_CCM) && (context->pCcm_data != NULL)) {
SSS_FREE(context->pCcm_data);
context->pCcm_data = NULL;
}
EVP_CIPHER_CTX_free((EVP_CIPHER_CTX *)context->aead_ctx);
context->aead_ctx = NULL;
}
memset(context, 0, sizeof(*context));
}
/* End: openssl_aead */
/* ************************************************************************** */
/* Functions : sss_openssl_mac */
/* ************************************************************************** */
sss_status_t sss_openssl_mac_context_init(sss_openssl_mac_t *context,
sss_openssl_session_t *session,
sss_openssl_object_t *keyObject,
sss_algorithm_t algorithm,
sss_mode_t mode)
{
sss_status_t retval = kStatus_SSS_Fail;
if (context != NULL) {
if (algorithm == kAlgorithm_SSS_CMAC_AES) {
context->cmac_ctx = CMAC_CTX_new();
}
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) {
#if (OPENSSL_VERSION_NUMBER < 0x10100000L)
context->hmac_ctx = SSS_MALLOC(sizeof(HMAC_CTX));
#else
context->hmac_ctx = HMAC_CTX_new();
#endif
if (context->hmac_ctx != NULL) {
#if (OPENSSL_VERSION_NUMBER < 0x10100000L)
HMAC_CTX_init(context->hmac_ctx);
#endif
}
}
context->session = session;
context->keyObject = keyObject;
context->mode = mode;
context->algorithm = algorithm;
retval = kStatus_SSS_Success;
}
return retval;
}
sss_status_t sss_openssl_mac_one_go(
sss_openssl_mac_t *context, const uint8_t *message, size_t messageLen, uint8_t *mac, size_t *macLen)
{
sss_status_t retval = kStatus_SSS_Fail;
int ret = 0;
unsigned int iMacLen;
const EVP_CIPHER *cipher_info = NULL;
uint8_t *key;
size_t keylen;
if ((context == NULL) || (message == NULL) || (mac == NULL) || (macLen == NULL)) {
goto cleanup;
}
if (context->keyObject->contents) {
key = context->keyObject->contents;
keylen = context->keyObject->contents_size;
}
else {
LOG_E("KeyObject key not created");
goto cleanup;
}
iMacLen = (unsigned int)*macLen;
if (context->algorithm == kAlgorithm_SSS_CMAC_AES) {
if (context->cmac_ctx == NULL) {
retval = kStatus_SSS_InvalidArgument;
}
else {
if (!(keylen == 16 || keylen == 24 || keylen == 32)) {
LOG_E("key bit not supported");
goto cleanup;
}
switch (keylen * 8) {
case 128:
cipher_info = EVP_aes_128_cbc();
break;
case 192:
cipher_info = EVP_aes_192_cbc();
break;
case 256:
cipher_info = EVP_aes_256_cbc();
break;
}
ret = CMAC_Init(
context->cmac_ctx, context->keyObject->contents, context->keyObject->contents_size, cipher_info, NULL);
if (ret == 1) {
ret = CMAC_Update(context->cmac_ctx, message, messageLen);
if (ret == 1) {
ret = CMAC_Final(context->cmac_ctx, mac, macLen);
if (ret == 1) {
retval = kStatus_SSS_Success;
}
}
}
}
}
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) {
iMacLen = (unsigned int)*macLen;
const EVP_MD *evp_md = NULL;
switch (context->algorithm) {
case kAlgorithm_SSS_HMAC_SHA1:
evp_md = EVP_sha1();
break;
case kAlgorithm_SSS_HMAC_SHA224:
evp_md = EVP_sha224();
break;
case kAlgorithm_SSS_HMAC_SHA256:
evp_md = EVP_sha256();
break;
case kAlgorithm_SSS_HMAC_SHA384:
evp_md = EVP_sha384();
break;
case kAlgorithm_SSS_HMAC_SHA512:
evp_md = EVP_sha512();
break;
default:
LOG_E("Invalid HMAC algorithm");
retval = kStatus_SSS_Fail;
goto cleanup;
}
if (NULL != HMAC(evp_md,
context->keyObject->contents,
(int)context->keyObject->contents_size,
message,
messageLen,
mac,
&iMacLen)) {
retval = kStatus_SSS_Success;
}
*macLen = iMacLen;
}
cleanup:
return retval;
}
sss_status_t sss_openssl_mac_init(sss_openssl_mac_t *context)
{
sss_status_t retval = kStatus_SSS_Fail;
const EVP_CIPHER *cipher_info = NULL;
int ret;
uint8_t *key;
size_t keylen;
if (context->keyObject->contents) {
key = context->keyObject->contents;
keylen = context->keyObject->contents_size;
}
else {
LOG_E("KeyObject key not created");
goto cleanup;
}
if (context->algorithm == kAlgorithm_SSS_CMAC_AES) {
if (!(keylen == 16 || keylen == 24 || keylen == 32)) {
LOG_E("key bit not supported");
goto cleanup;
}
switch (keylen * 8) {
case 128:
cipher_info = EVP_aes_128_cbc();
break;
case 192:
cipher_info = EVP_aes_192_cbc();
break;
case 256:
cipher_info = EVP_aes_256_cbc();
break;
}
if (context->cmac_ctx) {
ret = CMAC_Init(
context->cmac_ctx, context->keyObject->contents, context->keyObject->contents_size, cipher_info, NULL);
if (ret == 1) {
retval = kStatus_SSS_Success;
}
}
else {
LOG_W(
"cipher context not allocated call "
"sss_openssl_mac_context_init");
}
}
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) {
const EVP_MD *evp_md = NULL;
switch (context->algorithm) {
case kAlgorithm_SSS_HMAC_SHA1:
evp_md = EVP_sha1();
break;
case kAlgorithm_SSS_HMAC_SHA224:
evp_md = EVP_sha224();
break;
case kAlgorithm_SSS_HMAC_SHA256:
evp_md = EVP_sha256();
break;
case kAlgorithm_SSS_HMAC_SHA384:
evp_md = EVP_sha384();
break;
case kAlgorithm_SSS_HMAC_SHA512:
evp_md = EVP_sha512();
break;
default:
LOG_E("Invalid HMAC algorithm");
retval = kStatus_SSS_Fail;
goto cleanup;
}
ret = HMAC_Init_ex(
context->hmac_ctx, context->keyObject->contents, (int)context->keyObject->contents_size, evp_md, NULL);
if (ret == 1) {
retval = kStatus_SSS_Success;
}
else {
LOG_E(
"cipher context not allocated, call "
"sss_openssl_mac_context_init");
}
}
cleanup:
return retval;
}
sss_status_t sss_openssl_mac_update(sss_openssl_mac_t *context, const uint8_t *message, size_t messageLen)
{
sss_status_t retval = kStatus_SSS_Fail;
int ret;
if (message == NULL) {
return kStatus_SSS_InvalidArgument;
}
if (context->algorithm == kAlgorithm_SSS_CMAC_AES) {
CMAC_CTX *ctx;
ctx = context->cmac_ctx;
ret = CMAC_Update(ctx, message, messageLen);
if (ret == 1) {
retval = kStatus_SSS_Success;
}
}
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) {
ret = HMAC_Update(context->hmac_ctx, message, messageLen);
if (ret == 1) {
retval = kStatus_SSS_Success;
}
}
else {
//invalid alogortihm
}
return retval;
}
sss_status_t sss_openssl_mac_finish(sss_openssl_mac_t *context, uint8_t *mac, size_t *macLen)
{
int ret;
sss_status_t retval = kStatus_SSS_Fail;
if (mac == NULL || macLen == NULL) {
return kStatus_SSS_InvalidArgument;
}
if (context->algorithm == kAlgorithm_SSS_CMAC_AES) {
CMAC_CTX *ctx;
ctx = context->cmac_ctx;
ret = CMAC_Final(ctx, mac, macLen);
if (ret == 1) {
retval = kStatus_SSS_Success;
}
}
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) {
unsigned int iMacLen = (unsigned int)*macLen;
ret = HMAC_Final(context->hmac_ctx, mac, &iMacLen);
if (ret == 1) {
retval = kStatus_SSS_Success;
}
*macLen = iMacLen;
}
else {
//invalid alogortihm
}
return retval;
}
void sss_openssl_mac_context_free(sss_openssl_mac_t *context)
{
if (context != NULL) {
//sss_openssl_key_object_free(context->keyObject);
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) {
if (context->hmac_ctx != NULL) {
#if (OPENSSL_VERSION_NUMBER < 0x10100000L)
HMAC_CTX_cleanup((HMAC_CTX *)context->hmac_ctx);
#else
HMAC_CTX_free((HMAC_CTX *)context->hmac_ctx);
#endif
}
}
else if (context->algorithm == kAlgorithm_SSS_CMAC_AES) {
if (context->cmac_ctx != NULL) {
CMAC_CTX_free((CMAC_CTX *)context->cmac_ctx);
}
}
memset(context, 0, sizeof(*context));
}
}
/* End: openssl_mac */
/* ************************************************************************** */
/* Functions : sss_openssl_md */
/* ************************************************************************** */
sss_status_t sss_openssl_digest_context_init(
sss_openssl_digest_t *context, sss_openssl_session_t *session, sss_algorithm_t algorithm, sss_mode_t mode)
{
sss_status_t retval = kStatus_SSS_Fail;
ENSURE_OR_GO_CLEANUP(context);
context->session = session;
context->algorithm = algorithm;
context->mode = mode;
retval = kStatus_SSS_Success;
cleanup:
return retval;
}
sss_status_t sss_openssl_digest_one_go(
sss_openssl_digest_t *context, const uint8_t *message, size_t messageLen, uint8_t *digest, size_t *digestLen)
{
sss_status_t retval = kStatus_SSS_Fail;
int ret = 0;
unsigned int iDigestLen = (unsigned int)*digestLen;
const EVP_MD *md;
context->mdctx = EVP_MD_CTX_create();
if (context->mdctx == NULL) {
LOG_E("EVP_MD_CTX_create failed");
goto exit;
}
switch (context->algorithm) {
case kAlgorithm_SSS_SHA1:
md = EVP_get_digestbyname("SHA1");
*digestLen = 20;
break;
case kAlgorithm_SSS_SHA224:
md = EVP_get_digestbyname("SHA224");
*digestLen = 28;
break;
case kAlgorithm_SSS_SHA256:
md = EVP_get_digestbyname("SHA256");
*digestLen = 32;
break;
case kAlgorithm_SSS_SHA384:
md = EVP_get_digestbyname("SHA384");
*digestLen = 48;
break;
case kAlgorithm_SSS_SHA512:
md = EVP_get_digestbyname("SHA512");
*digestLen = 64;
break;
default:
LOG_E(" Algorithm mode not suported ");
goto exit;
}
if (md == NULL) {
goto exit;
}
ret = EVP_DigestInit_ex(context->mdctx, md, NULL);
if (ret != 1) {
LOG_E(" EVP_DigestInit_ex failed ");
goto exit;
}
ret = EVP_DigestUpdate(context->mdctx, message, messageLen);
if (ret != 1) {
LOG_E(" EVP_DigestUpdate failed ");
goto exit;
}
ret = EVP_DigestFinal_ex(context->mdctx, digest, &iDigestLen);
if (ret != 1) {
LOG_E(" EVP_DigestFinal_ex failed ");
goto exit;
}
*digestLen = iDigestLen;
EVP_MD_CTX_destroy(context->mdctx);
context->mdctx = NULL;
retval = kStatus_SSS_Success;
exit:
return retval;
}
sss_status_t sss_openssl_digest_init(sss_openssl_digest_t *context)
{
sss_status_t retval = kStatus_SSS_Fail;
const EVP_MD *md;
int ret = 0;
OpenSSL_add_all_algorithms();
context->mdctx = EVP_MD_CTX_create();
if (context->mdctx == NULL) {
LOG_E(" EVP_MD_CTX_create failed ");
goto exit;
}
switch (context->algorithm) {
case kAlgorithm_SSS_SHA1:
md = EVP_get_digestbyname("SHA1");
break;
case kAlgorithm_SSS_SHA224:
md = EVP_get_digestbyname("SHA224");
break;
case kAlgorithm_SSS_SHA256:
md = EVP_get_digestbyname("SHA256");
break;
case kAlgorithm_SSS_SHA384:
md = EVP_get_digestbyname("SHA384");
break;
case kAlgorithm_SSS_SHA512:
md = EVP_get_digestbyname("SHA512");
break;
default:
LOG_E(" Algorithm mode not suported ");
goto exit;
}
ret = EVP_DigestInit_ex(context->mdctx, md, NULL);
if (ret != 1) {
LOG_E("EVP_DigestInit_ex failed ");
goto exit;
}
retval = kStatus_SSS_Success;
exit:
return retval;
}
sss_status_t sss_openssl_digest_update(sss_openssl_digest_t *context, const uint8_t *message, size_t messageLen)
{
sss_status_t retval = kStatus_SSS_Fail;
int ret = 0;
ret = EVP_DigestUpdate(context->mdctx, message, messageLen);
if (ret != 1) {
LOG_E("EVP_DigestUpdate failed ");
goto exit;
}
retval = kStatus_SSS_Success;
exit:
return retval;
}
sss_status_t sss_openssl_digest_finish(sss_openssl_digest_t *context, uint8_t *digest, size_t *digestLen)
{
sss_status_t retval = kStatus_SSS_Fail;
int ret = 0;
unsigned int iDigestLen = (unsigned int)*digestLen;
ret = EVP_DigestFinal_ex(context->mdctx, digest, &iDigestLen);
if (ret != 1) {
LOG_E("EVP_DigestFinal_ex failed ");
goto exit;
}
*digestLen = iDigestLen;
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:
*digestLen = 0;
LOG_E("Algorithm mode not suported ");
goto exit;
}
retval = kStatus_SSS_Success;
exit:
return retval;
}
void sss_openssl_digest_context_free(sss_openssl_digest_t *context)
{
if (NULL != context->mdctx) {
#if (OPENSSL_VERSION_NUMBER < 0x10100000L)
EVP_MD_CTX_cleanup(context->mdctx);
#else
EVP_MD_CTX_destroy(context->mdctx);
#endif
}
memset(context, 0, sizeof(*context));
}
/* End: openssl_md */
/* ************************************************************************** */
/* Functions : sss_openssl_rng */
/* ************************************************************************** */
sss_status_t sss_openssl_rng_context_init(sss_openssl_rng_context_t *context, sss_openssl_session_t *session)
{
sss_status_t retval = kStatus_SSS_Fail;
ENSURE_OR_GO_CLEANUP(context);
context->session = session;
retval = kStatus_SSS_Success;
cleanup:
return retval;
}
sss_status_t sss_openssl_rng_get_random(sss_openssl_rng_context_t *context, uint8_t *random_data, size_t dataLen)
{
sss_status_t retval = kStatus_SSS_Fail;
if (random_data == NULL) {
goto exit;
}
#if (OPENSSL_VERSION_NUMBER < 0x10100000L)
if (0 == RAND_pseudo_bytes((unsigned char *)random_data, (int)dataLen)) {
LOG_E("Error in RAND_pseudo_bytes ");
goto exit;
}
#else
if (0 == RAND_bytes((unsigned char *)random_data, (int)dataLen)) {
LOG_E("Error in RAND_pseudo_bytes ");
goto exit;
}
#endif
retval = kStatus_SSS_Success;
exit:
return retval;
}
sss_status_t sss_openssl_rng_context_free(sss_openssl_rng_context_t *context)
{
sss_status_t retval = kStatus_SSS_Success;
memset(context, 0, sizeof(*context));
return retval;
}
/* End: openssl_rng */
/* ************************************************************************** */
/* Functions : Private sss openssl functions */
/* ************************************************************************** */
static sss_status_t sss_openssl_generate_ecp_key(sss_openssl_object_t *keyObject, size_t keyBitLen)
{
sss_status_t retval = kStatus_SSS_Success;
EVP_PKEY *pKey = NULL;
EC_KEY *pEC_Key = NULL;
EC_GROUP *pEC_Group = NULL;
int nid = 0;
int ret = 0;
/* Initilaize the EC Key. */
pEC_Key = EC_KEY_new();
if (pEC_Key == NULL) {
retval = kStatus_SSS_Fail;
LOG_E("Unable to initialize EC_Key");
goto exit;
}
if (keyObject->cipherType == kSSS_CipherType_EC_NIST_P) {
switch (keyBitLen) {
case 192:
nid = NID_X9_62_prime192v1;
break;
case 224:
nid = NID_secp224r1;
break;
case 256:
nid = NID_X9_62_prime256v1;
break;
case 384:
nid = NID_secp384r1;
break;
case 521:
nid = NID_secp521r1;
break;
default:
LOG_E("Key type EC_NIST_P not supported with key length 0x%X", keyBitLen);
retval = kStatus_SSS_Fail;
goto exit;
}
}
else if (keyObject->cipherType == kSSS_CipherType_EC_BRAINPOOL) {
switch (keyBitLen) {
case 192:
nid = NID_brainpoolP192r1;
break;
case 224:
nid = NID_brainpoolP224r1;
break;
case 320:
nid = NID_brainpoolP320r1;
break;
case 384:
nid = NID_brainpoolP384r1;
break;
case 160:
nid = NID_brainpoolP160r1;
break;
case 256:
nid = NID_brainpoolP256r1;
break;
case 512:
nid = NID_brainpoolP512r1;
break;
default:
LOG_E("Key type EC_BRAINPOOL not supported with key length 0x%X", keyBitLen);
retval = kStatus_SSS_Fail;
goto exit;
}
}
else if (keyObject->cipherType == kSSS_CipherType_EC_NIST_K) {
switch (keyBitLen) {
case 160:
nid = NID_secp160k1;
break;
case 192:
nid = NID_secp192k1;
break;
case 224:
nid = NID_secp224k1;
break;
case 256:
nid = NID_secp256k1;
break;
default:
LOG_E("Key type EC_NIST_K not supported with key length 0x%X", keyBitLen);
retval = kStatus_SSS_Fail;
goto exit;
}
}
#if (OPENSSL_VERSION_NUMBER < 0x10100000L)
#else
else if (keyObject->cipherType == kSSS_CipherType_EC_MONTGOMERY) {
switch (keyBitLen) {
case 256:
nid = NID_X25519;
break;
case 448:
nid = NID_X448;
break;
default:
LOG_E("Key type EC_MONTGOMERY not supported with key length 0x%X", keyBitLen);
retval = kStatus_SSS_Fail;
goto exit;
}
}
else if (keyObject->cipherType == kSSS_CipherType_EC_TWISTED_ED) {
switch (keyBitLen) {
case 256:
nid = NID_ED25519;
break;
default:
LOG_E("Key type EC_TWISTED_ED not supported with key length 0x%X", keyBitLen);
retval = kStatus_SSS_Fail;
goto exit;
}
}
#endif
else {
LOG_E("sss_openssl_generate_ecp_key: Invalid key type ");
}
#if (OPENSSL_VERSION_NUMBER < 0x10100000L)
#else
if (nid == NID_X448 || nid == NID_X25519 || nid == NID_ED25519) {
EVP_PKEY_CTX *pCtx = EVP_PKEY_CTX_new_id(nid, NULL);
if (1 != EVP_PKEY_keygen_init(pCtx)) {
retval = kStatus_SSS_Fail;
LOG_E("Unable to generate keys.");
}
/* Assign the EC Key to generic Key context. */
pKey = (EVP_PKEY *)keyObject->contents;
if (1 != EVP_PKEY_keygen(pCtx, &pKey)) {
retval = kStatus_SSS_Fail;
LOG_E("Unable to generate keys.");
}
EVP_PKEY_CTX_free(pCtx);
goto exit;
}
#endif
if (nid != 0) {
/* Get the Group by curve name. */
pEC_Group = EC_GROUP_new_by_curve_name(nid);
if (pEC_Group == NULL) {
retval = kStatus_SSS_Fail;
LOG_E("sss_openssl_generate_ecp_key: unable to get the group.");
goto exit;
}
EC_GROUP_set_asn1_flag(pEC_Group, OPENSSL_EC_NAMED_CURVE);
/* Set the group to ECKey context. */
if (EC_KEY_set_group(pEC_Key, pEC_Group) == 0) {
retval = kStatus_SSS_Fail;
LOG_E("sss_openssl_generate_ecp_key: unable set the group.");
EC_KEY_free(pEC_Key);
pEC_Key = NULL;
goto exit;
}
/* Generate the EC keys. */
ret = EC_KEY_generate_key(pEC_Key);
if (!ret) {
retval = kStatus_SSS_Fail;
LOG_E("Unable to generate keys.");
EC_KEY_free(pEC_Key);
pEC_Key = NULL;
goto exit;
}
/* Assign the EC Key to generic Key context. */
pKey = (EVP_PKEY *)keyObject->contents;
if (!EVP_PKEY_set1_EC_KEY(pKey, pEC_Key)) {
retval = kStatus_SSS_Fail;
LOG_E("Unable to assigning ECC key to EVP_PKEY context.");
EC_GROUP_free(pEC_Group);
EC_KEY_free(pEC_Key);
pEC_Key = NULL;
pEC_Group = NULL;
goto exit;
}
}
else {
LOG_E("No support for keyBitLen 0x%X", keyBitLen);
}
exit:
if (pEC_Group)
EC_GROUP_free(pEC_Group);
if (pEC_Key)
EC_KEY_free(pEC_Key);
return retval;
}
#ifdef _MSC_VER
#pragma warning(disable : 4127)
#endif
static sss_status_t sss_openssl_generate_rsa_key(sss_openssl_object_t *keyObject, size_t keyBitLen)
{
sss_status_t retval = kStatus_SSS_Success;
EVP_PKEY *pKey = NULL;
RSA *pRSA = NULL;
BIGNUM *pBigNum = NULL;
char *pBuffer = NULL;
unsigned long ulError = 0;
if (keyBitLen == 512 || keyBitLen == 1024 || keyBitLen == 1152 || keyBitLen == 2048 || keyBitLen == 3072 ||
keyBitLen == 4096) {
/* Load the error strings. */
ERR_load_CRYPTO_strings();
pRSA = RSA_new();
pBigNum = BN_new();
if (1 != BN_set_word(pBigNum, RSA_F4)) {
retval = kStatus_SSS_Fail;
LOG_E("sss_openssl_generate_rsa_key: BigNum creation Failed.");
goto exit;
}
/* Generate the Keys. */
if (1 != RSA_generate_key_ex(pRSA, (int)keyBitLen, pBigNum, NULL)) {
retval = kStatus_SSS_Fail;
ulError = ERR_get_error();
pBuffer = (char *)ERR_error_string(ulError, (char *)pBuffer);
LOG_E(" sss_openssl_generate_rsa_key");
#if (OPENSSL_VERSION_NUMBER < 0x10100000L)
ERR_free_strings();
#endif
BN_free(pBigNum);
goto exit;
}
BN_clear_free(pBigNum);
/* Assign the EC Key to generic Key context. */
pKey = (EVP_PKEY *)keyObject->contents;
if (!EVP_PKEY_set1_RSA(pKey, pRSA)) {
retval = kStatus_SSS_Fail;
LOG_E("Unable to assigning RSA key to EVP_PKEY context.");
BN_free(pBigNum);
RSA_free(pRSA);
goto exit;
}
}
else {
LOG_E("No support for keyBitLen", keyBitLen);
retval = kStatus_SSS_Fail;
}
exit:
RSA_free(pRSA);
return retval;
}
sss_status_t openssl_convert_to_bio(sss_openssl_object_t *keyObject, char *base64_format, int base64_format_len)
{
BIO *pBio_Pem = NULL;
EVP_PKEY *pKey = NULL;
char *pem_format = NULL;
char *start = NULL;
char *end = NULL;
sss_status_t ret = kStatus_SSS_Fail;
uint32_t objectType = keyObject->objectType;
switch (objectType) {
case kSSS_KeyPart_Public:
start = BEGIN_PUBLIC;
end = END_PUBLIC;
break;
case kSSS_KeyPart_Private:
case kSSS_KeyPart_Pair: {
if (keyObject->cipherType == kSSS_CipherType_RSA || keyObject->cipherType == kSSS_CipherType_RSA_CRT) {
start = BEGIN_RSA_PRIVATE;
end = END_RSA_PRIVATE;
break;
}
else if (keyObject->cipherType == kSSS_CipherType_EC_NIST_P ||
keyObject->cipherType == kSSS_CipherType_EC_NIST_K ||
keyObject->cipherType == kSSS_CipherType_EC_BRAINPOOL ||
keyObject->cipherType == kSSS_CipherType_EC_MONTGOMERY ||
keyObject->cipherType == kSSS_CipherType_EC_TWISTED_ED) {
start = BEGIN_EC_PRIVATE;
end = END_EC_PRIVATE;
break;
}
else {
goto exit;
}
}
default:
goto exit;
}
pem_format = (char *)SSS_CALLOC(1, base64_format_len + strlen(start) + strlen(end) + 1);
/* Convert Base64 to PEM format. */
snprintf(pem_format,
(strlen(base64_format) + strlen(start) + strlen(end) + 1),
"%s"
"%s"
"%s",
start,
base64_format,
end);
/* Assign the PEM_Format to BIO. */
pBio_Pem = BIO_new_mem_buf(pem_format, (int)strlen(pem_format));
if (pBio_Pem == NULL) {
LOG_E("Unable to assign the PEM to BIO buffer.");
goto exit;
}
if (objectType == kSSS_KeyPart_Public) {
/* Convert the BIO to PKEY format. */
pKey = PEM_read_bio_PUBKEY(pBio_Pem, NULL, NULL, NULL);
}
else {
pKey = PEM_read_bio_PrivateKey(pBio_Pem, NULL, NULL, NULL);
}
if (pKey == NULL) {
LOG_E("Unable to read the key from PEM.");
goto exit;
}
EVP_PKEY_free((EVP_PKEY *)keyObject->contents);
keyObject->contents = pKey;
ret = kStatus_SSS_Success;
exit:
BIO_free(pBio_Pem);
pBio_Pem = NULL;
if (pem_format)
SSS_FREE(pem_format);
return ret;
}
static sss_status_t sss_openssl_set_key(
sss_openssl_object_t *keyObject, const uint8_t *keyBuf, size_t keyBufLen, size_t keyBitLen)
{
sss_status_t retval = kStatus_SSS_Fail;
char *base64_format = NULL;
BIO *pBio_Mem = NULL, *pBio_64 = NULL;
BUF_MEM *pBufMem = NULL;
//EVP_PKEY *pKey = NULL;
sss_status_t ret = kStatus_SSS_Fail;
if (keyObject->objectType == kSSS_KeyPart_Default) {
if (keyBufLen > keyObject->contents_max_size) {
LOG_E("Not enough memory for key_size ", keyObject->contents_max_size);
goto exit;
}
else {
if (keyBuf != NULL) /* For Empty Certificate */
memcpy(keyObject->contents, keyBuf, keyBufLen);
keyObject->contents_size = keyBufLen;
}
}
else if ((keyObject->objectType == kSSS_KeyPart_Private) || (keyObject->objectType == kSSS_KeyPart_Public) ||
(keyObject->objectType == kSSS_KeyPart_Pair)) {
pBio_64 = BIO_new(BIO_f_base64());
if (pBio_64 == NULL) {
LOG_E("Unable to initialize Base64 format.");
goto exit;
}
BIO_set_flags(pBio_64, BIO_FLAGS_BASE64_NO_NL);
//BIO_set_close(pBio_64, BIO_NOCLOSE);
pBio_Mem = BIO_new(BIO_s_mem());
if (pBio_Mem == NULL) {
LOG_E("Unable to initialize Base64 mem format.");
goto exit;
}
//BIO_set_close(pBio_Mem, BIO_NOCLOSE);
pBio_64 = BIO_push(pBio_64, pBio_Mem);
BIO_write(pBio_64, keyBuf, (int)keyBufLen);
if (pBio_64 == NULL) {
LOG_E(" sss_openssl_set_key: key write failure.");
goto exit;
}
if (BIO_flush(pBio_64) < 1) {
LOG_E("sss_openssl_set_key: flushing failed.");
goto exit;
}
BIO_get_mem_ptr(pBio_64, &pBufMem);
base64_format = SSS_CALLOC(1, (pBufMem->length) + 1);
memcpy(base64_format, pBufMem->data, pBufMem->length);
base64_format[pBufMem->length] = '\0';
ret = openssl_convert_to_bio(keyObject, base64_format, (int)pBufMem->length);
if (ret != kStatus_SSS_Success) {
LOG_E(" sss_openssl_set_key: flushing failed.");
goto exit;
}
}
else {
goto exit;
}
keyObject->keyBitLen = keyBitLen;
retval = kStatus_SSS_Success;
exit:
BIO_free(pBio_Mem);
pBio_Mem = NULL;
BIO_free(pBio_64);
pBio_64 = NULL;
if (base64_format)
SSS_FREE(base64_format);
return retval;
}
static sss_status_t sss_openssl_hkdf_extract(const EVP_MD *md,
const uint8_t *salt,
size_t salt_len,
const uint8_t *ikm,
size_t ikm_len,
uint8_t *prk,
unsigned int *prk_len)
{
int hash_len;
unsigned char null_salt[EVP_MAX_MD_SIZE] = {'\0'};
sss_status_t retval = kStatus_SSS_Success;
hash_len = EVP_MD_size(md);
if (salt == NULL) {
salt = null_salt;
salt_len = hash_len;
}
unsigned int iPrkLen = *prk_len;
if (HMAC(md, salt, (int)salt_len, ikm, (int)ikm_len, prk, &iPrkLen) == NULL) {
retval = kStatus_SSS_Fail;
}
*prk_len = iPrkLen;
return retval;
}
static sss_status_t sss_openssl_hkdf_expand(const EVP_MD *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;
#if (OPENSSL_VERSION_NUMBER < 0x10100000L)
HMAC_CTX hmac;
#else
HMAC_CTX *hmac = NULL;
#endif
unsigned char T[EVP_MAX_MD_SIZE];
sss_status_t retval = kStatus_SSS_Success;
if (info_len == 0 || okm_len == 0 || okm == NULL) {
retval = kStatus_SSS_InvalidArgument;
goto exit;
}
hash_len = EVP_MD_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;
}
#if (OPENSSL_VERSION_NUMBER < 0x10100000L)
HMAC_CTX_init(&hmac);
#else
hmac = HMAC_CTX_new();
if (hmac == NULL) {
retval = kStatus_SSS_Fail;
goto exit;
}
#endif
#if (OPENSSL_VERSION_NUMBER < 0x10100000L)
if (!HMAC_Init_ex(&hmac, prk, (int)prk_len, md, NULL)) {
retval = kStatus_SSS_Fail;
goto exit;
}
/* Section 2.3. */
for (i = 1; i <= N; i++) {
unsigned char c = (unsigned char)i;
if (i > 1) {
if (!HMAC_Init_ex(&hmac, NULL, 0, NULL, NULL)) {
retval = kStatus_SSS_Fail;
goto exit;
}
if (!HMAC_Update(&hmac, T, T_len)) {
retval = kStatus_SSS_Fail;
goto exit;
}
}
if (!HMAC_Update(&hmac, info, info_len)) {
retval = kStatus_SSS_Fail;
goto exit;
}
if (!HMAC_Update(&hmac, &c, 1)) {
retval = kStatus_SSS_Fail;
goto exit;
}
if (!HMAC_Final(&hmac, T, NULL)) {
retval = kStatus_SSS_Fail;
goto exit;
}
memcpy(okm + where, T, (i != N) ? hash_len : (okm_len - where));
where += hash_len;
T_len = hash_len;
}
#else
if (!HMAC_Init_ex(hmac, prk, (int)prk_len, md, NULL)) {
retval = kStatus_SSS_Fail;
goto exit;
}
/* Section 2.3. */
for (i = 1; i <= N; i++) {
unsigned char c = (unsigned char)i;
if (i > 1) {
if (!HMAC_Init_ex(hmac, NULL, 0, NULL, NULL)) {
retval = kStatus_SSS_Fail;
goto exit;
}
if (!HMAC_Update(hmac, T, T_len)) {
retval = kStatus_SSS_Fail;
goto exit;
}
}
if (!HMAC_Update(hmac, info, info_len)) {
retval = kStatus_SSS_Fail;
goto exit;
}
if (!HMAC_Update(hmac, &c, 1)) {
retval = kStatus_SSS_Fail;
goto exit;
}
if (!HMAC_Final(hmac, T, NULL)) {
retval = kStatus_SSS_Fail;
goto exit;
}
memcpy(okm + where, T, (i != N) ? hash_len : (okm_len - where));
where += hash_len;
T_len = hash_len;
}
#endif
exit:
#if (OPENSSL_VERSION_NUMBER < 0x10100000L)
HMAC_CTX_cleanup(&hmac);
#else
HMAC_CTX_free(hmac);
#endif
return retval;
}
static sss_status_t sss_openssl_aead_one_go_encrypt(sss_openssl_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 = 0;
int len = 0;
size_t dest_len = 0;
/* Initialise key and IV */
ret = EVP_EncryptInit_ex(context->aead_ctx, NULL, NULL, context->keyObject->contents, nonce);
ENSURE_OR_GO_EXIT(ret == 1);
if (aad != NULL) {
/* Add AAD data.*/
ret = EVP_EncryptUpdate(context->aead_ctx, NULL, &len, aad, aadLen);
ENSURE_OR_GO_EXIT(ret == 1);
}
if (srcData != NULL) {
/* Encrypt plaintext */
ret = EVP_EncryptUpdate(context->aead_ctx, destData, &len, srcData, size);
ENSURE_OR_GO_EXIT(ret == 1);
dest_len = len;
}
/* Finalise the encryption */
ret = EVP_EncryptFinal_ex(context->aead_ctx, tag, &len);
ENSURE_OR_GO_EXIT(ret == 1);
/* Get the tag */
ret = EVP_CIPHER_CTX_ctrl(context->aead_ctx, EVP_CTRL_GCM_GET_TAG, EVP_CTRL_GCM_GET_TAG, tag);
ENSURE_OR_GO_EXIT(ret == 1);
*tagLen = EVP_CTRL_GCM_GET_TAG;
retval = kStatus_SSS_Success;
exit:
return retval;
}
static sss_status_t sss_openssl_aead_one_go_decrypt(sss_openssl_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 = 0;
int len = 0;
/* Initialise key and IV */
ret = EVP_DecryptInit_ex(context->aead_ctx, NULL, NULL, context->keyObject->contents, nonce);
ENSURE_OR_GO_EXIT(ret == 1);
/* Specify any AAD */
if (aad != NULL) {
ret = EVP_DecryptUpdate(context->aead_ctx, NULL, &len, aad, aadLen);
ENSURE_OR_GO_EXIT(ret == 1);
}
/* Decrypt ciphertext */
if (srcData != NULL) {
ret = EVP_DecryptUpdate(context->aead_ctx, destData, &len, srcData, size);
ENSURE_OR_GO_EXIT(ret == 1);
}
/* Set tag value. */
ret = EVP_CIPHER_CTX_ctrl(context->aead_ctx, EVP_CTRL_CCM_SET_TAG, 16, tag);
ENSURE_OR_GO_EXIT(ret == 1);
/* Finalise decrypt */
ret = EVP_DecryptFinal_ex(context->aead_ctx, destData, &len);
ENSURE_OR_GO_EXIT(ret == 1);
retval = kStatus_SSS_Success;
exit:
return retval;
}
#endif /* SSS_HAVE_OPENSSL */