/* Copyright 2019 NXP * SPDX-License-Identifier: Apache-2.0 */ #include "sss_interface.h" #include #include #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 #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; }