blob: 7f6b75a15c43ccb862408eb0de0d4a44159cd5a5 [file] [log] [blame]
/* Copyright 2019 NXP
* SPDX-License-Identifier: Apache-2.0
*/
#include "sss_interface.h"
#include <stdlib.h>
#include <string.h>
#include "nxEnsure.h"
#include "nxLog_App.h"
#if defined(SSS_USE_FTR_FILE)
#include "fsl_sss_ftr.h"
#else
#include "fsl_sss_ftr_default.h"
#endif
#include "mbedtls/base64.h"
#if USE_SSS_DLL
#include <windows.h>
#endif
#if USE_SSS_DLL
HMODULE hDll = NULL;
#endif
/* Declare gSESession in the server and client application file
and assign session context to it
*/
extern sss_session_t *gSESession;
int init_done = 0;
sss_session_t *gPSession = NULL;
sss_key_store_t gkeyStore = {
0,
};
sss_object_t priv_key_keyObject = {
0,
};
unsigned int PRIV_KEY_ID = 0;
unsigned int PRIV_KEY_LEN = 0;
#define CERT_ID 0x2345
#define MAGIC_NO \
{ \
0xA5, 0xA6, 0xB5, 0xB6 \
}
#if USE_SSS_DLL
static pFunc_sss_key_store_context_init pSSSkeyStoreContextInit = NULL;
static pFunc_sss_key_store_context_free pSSSkeyStoreContextFree = NULL;
static pFunc_sss_key_store_allocate pSSSkeyStoreAllocate = NULL;
static pFunc_sss_key_object_get_handle pSSSKeyObjectGethandle = NULL;
static pFunc_sss_key_object_init pSSSkeyObjectInit = NULL;
static pFunc_sss_key_object_free pSSSkeyObjectFree = NULL;
static pFunc_sss_key_object_allocate_handle pSSSKeyObjectAllocatehandle = NULL;
static pFunc_sss_asymmetric_context_init pSSSAssymCtxInit = NULL;
static pFunc_sss_asymmetric_context_free pSSSAssymCtxFree = NULL;
static pFunc_sss_asymmetric_decrypt pSSSAssymDecrypt = NULL;
static pFunc_sss_asymmetric_encrypt pSSSAssymEncrypt = NULL;
static pFunc_sss_asymmetric_sign pSSSAssymSign = NULL;
static pFunc_sss_key_store_get_key pSSSKeyStoreGetKey = NULL;
#endif
int sss_interface_init()
{
sss_status_t status = kStatus_SSS_Fail;
int ret = -1;
LOG_I("function - %s", __FUNCTION__);
if (init_done || gSESession == NULL) {
return 0;
}
gPSession = gSESession;
#if USE_SSS_DLL
hDll = LoadLibrary("sssapisw.dll");
ENSURE_OR_GO_EXIT(hDll != NULL);
#endif
#if USE_SSS_DLL
pSSSkeyStoreContextInit = (pFunc_sss_key_store_context_init)GetProcAddress(hDll, "sss_key_store_context_init");
pSSSkeyStoreContextFree = (pFunc_sss_key_store_context_free)GetProcAddress(hDll, "sss_key_store_context_free");
pSSSkeyStoreAllocate = (pFunc_sss_key_store_allocate)GetProcAddress(hDll, "sss_key_store_allocate");
pSSSkeyObjectInit = (pFunc_sss_key_object_init)GetProcAddress(hDll, "sss_key_object_init");
pSSSkeyObjectFree = (pFunc_sss_key_object_free)GetProcAddress(hDll, "sss_key_object_free");
pSSSKeyObjectAllocatehandle =
(pFunc_sss_key_object_allocate_handle)GetProcAddress(hDll, "sss_key_object_allocate_handle");
pSSSKeyObjectGethandle = (pFunc_sss_key_object_get_handle)GetProcAddress(hDll, "sss_key_object_get_handle");
pSSSAssymCtxInit = (pFunc_sss_asymmetric_context_init)GetProcAddress(hDll, "sss_asymmetric_context_init");
pSSSAssymCtxFree = (pFunc_sss_asymmetric_context_free)GetProcAddress(hDll, "sss_asymmetric_context_free");
pSSSAssymDecrypt = (pFunc_sss_asymmetric_decrypt)GetProcAddress(hDll, "sss_asymmetric_decrypt");
pSSSAssymEncrypt = (pFunc_sss_asymmetric_encrypt)GetProcAddress(hDll, "sss_asymmetric_encrypt");
pSSSAssymSign = (pFunc_sss_asymmetric_sign)GetProcAddress(hDll, "sss_asymmetric_sign_digest");
pSSSKeyStoreGetKey = (pFunc_sss_key_store_get_key)GetProcAddress(hDll, "sss_key_store_get_key");
#endif
#if USE_SSS_DLL
ENSURE_OR_GO_EXIT(pSSSkeyStoreContextInit != NULL);
status = pSSSkeyStoreContextInit(&gkeyStore, gPSession);
#else
status = sss_key_store_context_init(&gkeyStore, gPSession);
#endif
ENSURE_OR_GO_EXIT(status == kStatus_SSS_Success);
#if USE_SSS_DLL
ENSURE_OR_GO_EXIT(pSSSkeyStoreAllocate != NULL);
status = pSSSkeyStoreAllocate(&gkeyStore, __LINE__);
#else
status = sss_key_store_allocate(&gkeyStore, __LINE__);
#endif
ENSURE_OR_GO_EXIT(status == kStatus_SSS_Success);
/*
ENSURE_OR_GO_EXIT(pSSSkeyObjectInit != NULL);
status = pSSSkeyObjectInit(&priv_key_keyObject, &gkeyStore);
ENSURE_OR_GO_EXIT(status == kStatus_SSS_Success);
ENSURE_OR_GO_EXIT(pSSSKeyObjectAllocatehandle != NULL);
status = pSSSKeyObjectAllocatehandle(&priv_key_keyObject,
0x123456,
kSSS_KeyPart_Pair,
kSSS_CipherType_RSA,
2048,
kKeyObject_Mode_Persistent);
ENSURE_OR_GO_EXIT(status == kStatus_SSS_Success);
*/
ret = 0;
init_done = 1;
exit:
return ret;
}
void sss_interface_deinit(sss_session_t *session)
{
LOG_I("function - %s", __FUNCTION__);
#if USE_SSS_DLL
ENSURE_OR_RETURN(pSSSkeyStoreContextFree != NULL);
pSSSkeyStoreContextFree(&gkeyStore);
#else
sss_key_store_context_free(&gkeyStore);
#endif
return;
}
int sss_interface_rsa_decrypt_data(
unsigned char *input, unsigned int inlen, unsigned char *output, unsigned int *outLen)
{
int ret = -1;
sss_status_t status = kStatus_SSS_Fail;
sss_asymmetric_t assymContext = {
0,
};
sss_object_t keyObject = {
0,
};
unsigned int inoffset = 0;
unsigned int outoffset = 0;
size_t outLenTemp = *outLen;
LOG_I("function - %s", __FUNCTION__);
#if USE_SSS_DLL
ENSURE_OR_GO_EXIT(pSSSkeyObjectInit != NULL);
status = pSSSkeyObjectInit(&keyObject, &gkeyStore);
#else
status = sss_key_object_init(&keyObject, &gkeyStore);
#endif
ENSURE_OR_GO_EXIT(status == kStatus_SSS_Success);
#if USE_SSS_DLL
ENSURE_OR_GO_EXIT(pSSSKeyObjectGethandle != NULL);
status = pSSSKeyObjectGethandle(&keyObject, PRIV_KEY_ID);
#else
status = sss_key_object_get_handle(&keyObject, PRIV_KEY_ID);
#endif
ENSURE_OR_GO_EXIT(status == kStatus_SSS_Success);
#if USE_SSS_DLL
ENSURE_OR_GO_EXIT(pSSSAssymCtxInit != NULL);
status =
pSSSAssymCtxInit(&assymContext, gPSession, &keyObject, kAlgorithm_SSS_RSAES_PKCS1_OAEP_SHA1, kMode_SSS_Decrypt);
#else
status = sss_asymmetric_context_init(
&assymContext, gPSession, &keyObject, kAlgorithm_SSS_RSAES_PKCS1_OAEP_SHA1, kMode_SSS_Decrypt);
#endif
ENSURE_OR_GO_EXIT(status == kStatus_SSS_Success);
while (inoffset < inlen) {
size_t inDataLen = (inlen < PRIV_KEY_LEN) ? inlen : PRIV_KEY_LEN;
#if USE_SSS_DLL
ENSURE_OR_GO_EXIT(pSSSAssymDecrypt != NULL);
status = pSSSAssymDecrypt(
&assymContext, (const uint8_t *)input + inoffset, inDataLen, (uint8_t *)output + outoffset, &outLenTemp);
#else
status = sss_asymmetric_decrypt(
&assymContext, (const uint8_t *)input + inoffset, inDataLen, (uint8_t *)output + outoffset, &outLenTemp);
#endif
ENSURE_OR_GO_EXIT(status == kStatus_SSS_Success);
outoffset = outoffset + outLenTemp;
inoffset = inoffset + inDataLen;
}
*outLen = outoffset;
ret = 0;
exit:
#if USE_SSS_DLL
ENSURE_OR_GO_EXIT(pSSSkeyObjectFree != NULL);
pSSSkeyObjectFree(&keyObject);
#else
sss_key_object_free(&keyObject);
#endif
#if USE_SSS_DLL
ENSURE_OR_GO_EXIT(pSSSAssymCtxFree != NULL);
pSSSAssymCtxFree(&assymContext);
#else
sss_asymmetric_context_free(&assymContext);
#endif
return ret;
}
/* Not used by OPC UA stack */
int sss_interface_rsa_encrypt_data(
unsigned char *input, unsigned int inlen, unsigned char *output, unsigned int *outLen)
{
int ret = -1;
sss_status_t status = kStatus_SSS_Fail;
sss_asymmetric_t assymContext = {
0,
};
sss_object_t keyObject = {
0,
};
size_t outputLen = *outLen;
LOG_I("function - %s", __FUNCTION__);
#if USE_SSS_DLL
ENSURE_OR_GO_EXIT(pSSSkeyObjectInit != NULL);
status = pSSSkeyObjectInit(&keyObject, &gkeyStore);
#else
status = sss_key_object_init(&keyObject, &gkeyStore);
#endif
ENSURE_OR_GO_EXIT(status == kStatus_SSS_Success);
#if USE_SSS_DLL
ENSURE_OR_GO_EXIT(pSSSKeyObjectGethandle != NULL);
status = pSSSKeyObjectGethandle(&keyObject, PRIV_KEY_ID);
#else
status = sss_key_object_get_handle(&keyObject, PRIV_KEY_ID);
#endif
ENSURE_OR_GO_EXIT(status == kStatus_SSS_Success);
#if USE_SSS_DLL
ENSURE_OR_GO_EXIT(pSSSAssymCtxInit != NULL);
status =
pSSSAssymCtxInit(&assymContext, gPSession, &keyObject, kAlgorithm_SSS_RSAES_PKCS1_OAEP_SHA1, kMode_SSS_Encrypt);
#else
status = sss_asymmetric_context_init(
&assymContext, gPSession, &keyObject, kAlgorithm_SSS_RSAES_PKCS1_OAEP_SHA1, kMode_SSS_Encrypt);
#endif
ENSURE_OR_GO_EXIT(status == kStatus_SSS_Success);
#if USE_SSS_DLL
ENSURE_OR_GO_EXIT(pSSSAssymEncrypt != NULL);
status = pSSSAssymEncrypt(&assymContext, input, inlen, output, &outputLen);
#else
status = sss_asymmetric_encrypt(&assymContext, (const uint8_t *)input, inlen, (uint8_t *)output, &outputLen);
#endif
ENSURE_OR_GO_EXIT(status == kStatus_SSS_Success);
*outLen = outputLen;
ret = 0;
exit:
#if USE_SSS_DLL
ENSURE_OR_GO_EXIT(pSSSkeyObjectFree != NULL);
pSSSkeyObjectFree(&keyObject);
#else
sss_key_object_free(&keyObject);
#endif
#if USE_SSS_DLL
ENSURE_OR_GO_EXIT(pSSSAssymCtxFree != NULL);
pSSSAssymCtxFree(&assymContext);
#else
sss_asymmetric_context_free(&assymContext);
#endif
return ret;
}
int sss_interface_rsa_sign_data(unsigned char *input, unsigned int inlen, unsigned char *output, unsigned int *outLen)
{
int ret = -1;
sss_status_t status = kStatus_SSS_Fail;
sss_asymmetric_t assymContext = {
0,
};
sss_object_t keyObject = {
0,
};
sss_algorithm_t algorithm = kAlgorithm_None;
size_t outputLen = *outLen;
LOG_I("function - %s", __FUNCTION__);
#if USE_SSS_DLL
ENSURE_OR_GO_EXIT(pSSSkeyObjectInit != NULL);
status = pSSSkeyObjectInit(&keyObject, &gkeyStore);
#else
status = sss_key_object_init(&keyObject, &gkeyStore);
#endif
ENSURE_OR_GO_EXIT(status == kStatus_SSS_Success);
#if USE_SSS_DLL
ENSURE_OR_GO_EXIT(pSSSKeyObjectGethandle != NULL);
status = pSSSKeyObjectGethandle(&keyObject, PRIV_KEY_ID);
#else
status = sss_key_object_get_handle(&keyObject, PRIV_KEY_ID);
#endif
ENSURE_OR_GO_EXIT(status == kStatus_SSS_Success);
switch (inlen) {
case 20:
algorithm = kAlgorithm_SSS_RSASSA_PKCS1_V1_5_SHA1;
break;
case 28:
algorithm = kAlgorithm_SSS_RSASSA_PKCS1_V1_5_SHA224;
break;
case 32:
algorithm = kAlgorithm_SSS_RSASSA_PKCS1_V1_5_SHA256;
break;
case 48:
algorithm = kAlgorithm_SSS_RSASSA_PKCS1_PSS_MGF1_SHA384;
break;
case 64:
algorithm = kAlgorithm_SSS_RSASSA_PKCS1_V1_5_SHA512;
break;
default:
LOG_E("%s - Invalid input length", __FUNCTION__);
goto exit;
}
#if USE_SSS_DLL
ENSURE_OR_GO_EXIT(pSSSAssymCtxInit != NULL);
status = pSSSAssymCtxInit(&assymContext, gPSession, &keyObject, algorithm, kMode_SSS_Sign);
#else
status = sss_asymmetric_context_init(&assymContext, gPSession, &keyObject, algorithm, kMode_SSS_Sign);
#endif
ENSURE_OR_GO_EXIT(status == kStatus_SSS_Success);
#if USE_SSS_DLL
ENSURE_OR_GO_EXIT(pSSSAssymSign != NULL);
status = pSSSAssymSign(&assymContext, input, inlen, output, &outputLen);
#else
status = sss_asymmetric_sign_digest(&assymContext, (uint8_t *)input, inlen, (uint8_t *)output, &outputLen);
#endif
ENSURE_OR_GO_EXIT(status == kStatus_SSS_Success);
*outLen = outputLen;
ret = 0;
exit:
#if USE_SSS_DLL
ENSURE_OR_GO_EXIT(pSSSkeyObjectFree != NULL);
pSSSkeyObjectFree(&keyObject);
#else
sss_key_object_free(&keyObject);
#endif
#if USE_SSS_DLL
ENSURE_OR_GO_EXIT(pSSSAssymCtxFree != NULL);
pSSSAssymCtxFree(&assymContext);
#else
sss_asymmetric_context_free(&assymContext);
#endif
return ret;
}
int sss_interface_rsa_get_key_size()
{
return PRIV_KEY_LEN;
}
int sss_interface_read_certificate(unsigned char **cert_buf, size_t *cert_buf_len)
{
int ret = -1;
sss_status_t status = kStatus_SSS_Fail;
sss_object_t certObject = {
0,
};
unsigned char buf[2048] = {
0,
};
size_t buf_len = sizeof(buf);
size_t buf_len_bits = sizeof(buf) * 8;
LOG_I("function - %s", __FUNCTION__);
#if USE_SSS_DLL
ENSURE_OR_GO_EXIT(pSSSkeyObjectInit != NULL);
status = pSSSkeyObjectInit(&certObject, &gkeyStore);
#else
status = sss_key_object_init(&certObject, &gkeyStore);
#endif
ENSURE_OR_GO_EXIT(status == kStatus_SSS_Success);
#if USE_SSS_DLL
ENSURE_OR_GO_EXIT(pSSSKeyObjectGethandle != NULL);
status = pSSSKeyObjectGethandle(&certObject, CERT_ID);
#else
status = sss_key_object_get_handle(&certObject, CERT_ID);
#endif
ENSURE_OR_GO_EXIT(status == kStatus_SSS_Success);
#if USE_SSS_DLL
ENSURE_OR_GO_EXIT(pSSSKeyStoreGetKey != NULL);
status = pSSSKeyStoreGetKey(&gkeyStore, &certObject, buf, &buf_len, &buf_len_bits);
#else
status = sss_key_store_get_key(&gkeyStore, &certObject, buf, &buf_len, &buf_len_bits);
#endif
ENSURE_OR_GO_EXIT(status == kStatus_SSS_Success);
*cert_buf = (unsigned char *)SSS_MALLOC(buf_len);
memcpy(*cert_buf, buf, buf_len);
*cert_buf_len = buf_len;
ret = 0;
exit:
#if USE_SSS_DLL
ENSURE_OR_GO_EXIT(pSSSkeyObjectFree != NULL);
pSSSkeyObjectFree(&certObject);
#else
sss_key_object_free(&certObject);
#endif
return ret;
}
#define IGNORE_TAG 1
#define MODULUS 2
#define PUBLIC_EXP 3
#define PRIVATE_EXP 4
#define PRIME1 5
#define PRIME2 6
#define EXP1 7
#define EXP2 8
#define COEFFICIENT 9
#define END 10
int sss_interface_is_ref_key(unsigned char *pem_key, unsigned int pem_key_len)
{
int ret = -1;
unsigned char base64decode[2048] = {
0,
};
size_t outLen = sizeof(base64decode);
char magic_no[4] = MAGIC_NO;
int mbedtls_ret = 0;
unsigned int i = 0;
unsigned int length = 0;
int state = 0;
mbedtls_ret = mbedtls_base64_decode(base64decode,
outLen,
&outLen,
pem_key + 32 /*Remove '-----BEGIN RSA PRIVATE KEY-----' and '-----END RSA PRIVATE KEY-----'*/
,
pem_key_len - 63);
ENSURE_OR_GO_EXIT(mbedtls_ret == 0);
if (memcmp(base64decode + outLen - 4, magic_no, 4) != 0) {
goto exit;
}
i = 0;
if (base64decode[i++] == 0x30) {
/* Verify the length */
if (base64decode[i] == 0x81) {
i++;
length = base64decode[i++];
}
else if (base64decode[i] == 0x82) {
i++;
length = base64decode[i + 1] | base64decode[i] << 8;
i = i + 2;
}
else {
length = base64decode[i++];
}
if (length != outLen - i) {
goto exit;
}
}
state = IGNORE_TAG;
while (i < outLen) {
if (base64decode[i++] == 0x02) {
if (base64decode[i] == 0x81) {
i++;
length = base64decode[i++];
}
else if (base64decode[i] == 0x82) {
i++;
length = base64decode[i + 1] | base64decode[i] << 8;
i = i + 2;
}
else {
length = base64decode[i++];
}
switch (state) {
case IGNORE_TAG:
case PUBLIC_EXP:
case PRIVATE_EXP:
case PRIME1:
case EXP1:
case EXP2:
case COEFFICIENT: {
i = i + length;
if (state == IGNORE_TAG)
state = MODULUS;
else if (state == PUBLIC_EXP)
state = PRIVATE_EXP;
else if (state == PRIVATE_EXP)
state = PRIME1;
else if (state == PRIME1)
state = PRIME2;
else if (state == EXP1)
state = EXP2;
else if (state == EXP2)
state = COEFFICIENT;
else if (state == COEFFICIENT)
state = END;
else
goto exit;
} break;
case MODULUS: {
PRIV_KEY_LEN = length;
if (base64decode[i] == 0x00) {
PRIV_KEY_LEN = PRIV_KEY_LEN - 1;
}
i = i + length;
state = PUBLIC_EXP;
} break;
case PRIME2: {
unsigned int j = 0;
while (j < length) {
PRIV_KEY_ID |= base64decode[i + length - j - 1] << (8 * j);
j++;
}
i = i + length;
state = EXP1;
} break;
default: {
PRIV_KEY_LEN = 0;
PRIV_KEY_ID = 0;
goto exit;
}
}
}
else {
goto exit;
}
}
ret = 1;
exit:
return ret;
}