feat(ex): Add client server example to use keys stored in TPM

- Encrypt the private key using the key stored in TPM
   and remove the unencrypted private key from the filesystem
 - Used the encrypted key intermittently for software-based
   encryption/decryption

Change-Id: I46fc24102365292d9af6b51c582e3a3f74b2af5e
This commit is contained in:
Divya Prasanth Prabhakaran 2021-08-03 17:26:02 +05:30 committed by Julius Pfrommer
parent 78e07988db
commit 379ee51171
10 changed files with 1608 additions and 3 deletions

View File

@ -41,6 +41,32 @@ jobs:
./configure
sudo make install
cmd_action: unit_tests_encryption LIBRESSL
- name: TPM Tool Build
cmd_deps: |
sudo apt-get install -y -qq acl autoconf autoconf-archive automake build-essential cmake doxygen gcc git iproute2 libcurl4-openssl-dev libjson-c-dev libcmocka0 libcmocka-dev libgcrypt20-dev libglib2.0-dev libini-config-dev libmbedtls-dev libssl-dev libsqlite3-dev libtool libyaml-dev pkg-config procps python3-pip sqlite3 udev uthash-dev
cd ${HOME}
git clone https://github.com/tpm2-software/tpm2-tss.git
cd ${HOME}/tpm2-tss
git checkout 2.4.6
./bootstrap && ./configure --with-udevrulesdir=/etc/udev/rules.d --with-udevrulesprefix=70-
make -j$(nproc)
sudo make install
sudo ldconfig
sudo udevadm control --reload-rules && sudo udevadm trigger
sudo apt-get install -y -qq tpm2-tools opensc
cd ${HOME}
git clone https://github.com/tpm2-software/tpm2-pkcs11.git
cd ${HOME}/tpm2-pkcs11
git checkout 1.6.0
./bootstrap && ./configure
make -j$(nproc)
sudo make install
sudo ldconfig
sudo cp ${HOME}/tpm2-pkcs11/src/pkcs11.h /usr/include
cd ${HOME}/tpm2-pkcs11/tools/
sudo pip3 install pyasn1_modules
pip3 install .
cmd_action: build_tpm_tool
- name: Release Build
cmd_deps: sudo apt-get install -y -qq libmbedtls-dev
cmd_action: build_release

View File

@ -214,6 +214,31 @@ else()
endif()
endif()
# TPM Security
set(UA_ENABLE_ENCRYPTION_TPM2 "OFF" CACHE STRING "TPM encryption support")
SET_PROPERTY(CACHE UA_ENABLE_ENCRYPTION_TPM2 PROPERTY STRINGS "PKCS11" "KEYSTORE" "OFF")
if(UA_ENABLE_ENCRYPTION_TPM2 STREQUAL "OFF")
set(UA_ENABLE_TPM2_SECURITY OFF)
set(UA_ENABLE_TPM2_KEYSTORE OFF)
elseif(UA_ENABLE_ENCRYPTION_TPM2 STREQUAL "PKCS11")
set(UA_ENABLE_TPM2_SECURITY ON)
elseif(UA_ENABLE_ENCRYPTION_TPM2 STREQUAL "KEYSTORE")
set(UA_ENABLE_TPM2_KEYSTORE ON)
endif()
if(UA_ENABLE_TPM2_SECURITY)
if(NOT UA_ENABLE_PUBSUB_ENCRYPTION)
message(FATAL_ERROR "TPM2 encryption cannot be used with disabled UA_ENABLE_PUBSUB_ENCRYPTION")
endif()
endif()
if(UA_ENABLE_TPM2_KEYSTORE)
if(NOT UA_ENABLE_ENCRYPTION)
message(FATAL_ERROR "TPM2 Keystore cannot be used with disabled UA_ENABLE_ENCRYPTION")
endif()
endif()
# Namespace Zero
set(UA_NAMESPACE_ZERO "REDUCED" CACHE STRING "Completeness of the generated namespace zero (minimal/reduced/full)")
SET_PROPERTY(CACHE UA_NAMESPACE_ZERO PROPERTY STRINGS "MINIMAL" "REDUCED" "FULL")
@ -308,9 +333,6 @@ endif()
option(UA_FORCE_WERROR "Force compilation with -Werror" ON)
option(UA_ENABLE_TPM2_SECURITY "Enable encryption using TPM hardware" OFF)
mark_as_advanced(UA_ENABLE_TPM2_SECURITY)
#General PubSub setup
option(UA_ENABLE_PUBSUB "Enable the PubSub protocol" OFF)
@ -1473,6 +1495,9 @@ if(UA_BUILD_TOOLS)
if(UA_ENABLE_JSON_ENCODING)
add_subdirectory(tools/ua2json)
endif()
if(UA_ENABLE_TPM2_KEYSTORE)
add_subdirectory(tools/tpm_keystore)
endif()
endif()
########################

View File

@ -289,6 +289,11 @@ Detailed SDK Features
- ``MBEDTLS`` Encryption support using mbed TLS
- ``OPENSSL`` Encryption support using OpenSSL
- ``LIBRESSL`` EXPERIMENTAL: Encryption support using LibreSSL
**UA_ENABLE_ENCRYPTION_TPM2**
Enable TPM hardware for encryption. The possible options are:
- ``OFF`` No TPM encryption support. (default)
- ``PKCS11`` Encryption support using tpm2_pkcs11
- ``KEYSTORE`` Encryption of keys using TPM
**UA_NAMESPACE_ZERO**

View File

@ -172,6 +172,12 @@ if(UA_ENABLE_ENCRYPTION OR UA_ENABLE_ENCRYPTION STREQUAL "MBEDTLS" OR UA_ENABLE_
add_example(client_encryption encryption/client_encryption.c)
target_include_directories(server_encryption PRIVATE "${PROJECT_SOURCE_DIR}/examples")
target_include_directories(client_encryption PRIVATE "${PROJECT_SOURCE_DIR}/examples")
if(UA_ENABLE_TPM2_KEYSTORE)
add_example(server_encryption_tpm_keystore encryption/server_encryption_tpm_keystore.c)
add_example(client_encryption_tpm_keystore encryption/client_encryption_tpm_keystore.c)
target_link_libraries(server_encryption_tpm_keystore tpm2_pkcs11 ssl crypto)
target_link_libraries(client_encryption_tpm_keystore tpm2_pkcs11 ssl crypto)
endif()
endif()
if (NOT (BUILD_SHARED_LIBS AND WIN32))

View File

@ -0,0 +1,135 @@
1. TESTED ENVIRONMENT:
Apollo Lake processor-1.60GHz
OS - Ubuntu - 20.04.2 LTS
Kernel - 5.4.0-74-generic
2. ENVIRONMENT SETUP:
Follow the below steps in both Server and Client.
Install required packages:
sudo apt -y install acl autoconf autoconf-archive automake build-essential cmake doxygen gcc git iproute2 libcurl4-openssl-dev libjson-c-dev libcmocka0 libcmocka-dev libglib2.0-dev libini-config-dev libmbedtls-dev libssl-dev libsqlite3-dev libtool libyaml-dev pkg-config procps python3-pip sqlite3 udev uthash-dev
Install the netifaces dependency
sudo pip install netifaces
Install the TPM2 Software Stack library:
cd ${HOME}
git clone https://github.com/tpm2-software/tpm2-tss.git
cd ${HOME}/tpm2-tss
git checkout 2.4.6
./bootstrap
./configure --with-udevrulesdir=/etc/udev/rules.d --with-udevrulesprefix=70-
make -j$(nproc)
sudo make install
sudo ldconfig
sudo udevadm control --reload-rules && sudo udevadm trigger
Install the TPM2 Tools (tpm2-tools):
cd ${HOME}
git clone https://github.com/tpm2-software/tpm2-tools.git
cd tpm2-tools
git checkout 4.3.2
./bootstrap
./configure
make -j$(nproc)
sudo make install
sudo apt install opensc
Install adaptation of PKCS#11 for TPM2 (tpm2-pkcs11):
cd ${HOME}
git clone https://github.com/tpm2-software/tpm2-pkcs11.git
cd ${HOME}/tpm2-pkcs11
git checkout 1.6.0
./bootstrap
./configure
make -j$(nproc)
sudo make install
sudo ldconfig
cp ${HOME}/tpm2-pkcs11/src/pkcs11.h /usr/include
Install the required python packages:
cd ${HOME}/tpm2-pkcs11/tools/
sudo pip3 install pyasn1_modules
pip3 install .
Create an directory to create slot
cd ${HOME}/
mkdir pkcs11_store
Set environment variable for TCTI connection and path for database. If TPM hardware is not installed skip the below section:
cd ${HOME}/
echo 'export TPM2TOOLS_TCTI="device:/dev/tpm0"' >> .bashrc
echo 'export TPM2_PKCS11_STORE="'${HOME}'/pkcs11_store"' >> .bashrc
echo 'PATH=$PATH:'${HOME}'/pkcs11_store:'${HOME}'/tpm2-pkcs11/tools' >> .bashrc
source .bashrc
Creates the tpm2_pkcs11.sqlite3 database
pid="$(tpm2_ptool init | grep id | cut -d' ' -f 2-2)"
Create a token
tpm2_ptool addtoken --pid=$pid --sopin=123456 --userpin=123456 --label=opcua
The details of the options used in this command are:
--pid - The primary object id to associate with this token.
--sopin - The Administrator pin. This pin is used for object recovery.
--userpin - The user pin. This pin is used for authentication of object.
--label - An unique label to identify the profile in use.
--path - The location of the store directory.
Create the AES key
tpm2_ptool addkey --label=opcua --key-label=tpm_encrypt_key --userpin=123456 --algorithm=aes128
3. GENERATE AND ENCRYPT SERVER AND CLIENT KEYS
Verify if the TPM supports the following capbilities (https://github.com/tpm2-software/tpm2-tools/blob/master/man/tpm2_getcap.1.md):
tpm2_getcap algorithms | grep 'aes\|cbc'
tpm2_getcap commands | grep 'TPM2_CC_EncryptDecrypt\|TPM2_CC_VerifySignature'
# If above capbilities are not available, the application will not execute properly
Create encryption and signing key in both the server and client node filesystems.
cd open62541/tools/tpm_keystore/
In server,
python3 ../certs/create_self-signed.py -u urn:open62541.server.application
In client,
python3 ../certs/create_self-signed.py -u urn:unconfigured:application -c client
Seal the encryption and signing key files using the key available in TPM
gcc cert_encrypt_tpm.c -o cert_encrypt_tpm -ltpm2_pkcs11 -lssl -lcrypto
./cert_encrypt_tpm -s<slotID> -p<userPin> -l<keyLable> -f<keyToBeEncrypted> -o<keyToStoreEncryptedData>
In server,
./cert_encrypt_tpm -s1 -p123456 -ltpm_encrypt_key -fserver_cert.der -oserver_cert_sealed.der
./cert_encrypt_tpm -s1 -p123456 -ltpm_encrypt_key -fserver_key.der -oserver_key_sealed.der
In client,
./cert_encrypt_tpm -s1 -p123456 -ltpm_encrypt_key -fclient_cert.der -oclient_cert_sealed.der
./cert_encrypt_tpm -s1 -p123456 -ltpm_encrypt_key -fclient_key.der -oclient_key_sealed.der
Delete the original encryption and signing key
In Server, rm server_key.der server_cert.der
In Client, rm client_key.der client_cert.der
4. BUILD AND RUN SERVER AND CLIENT APPLICATION
To run client and server applications over Ethernet in two nodes connected in peer-to-peer network
cd ../../
mkdir build && cd build
cmake -DUA_BUILD_EXAMPLES=ON -DUA_BUILD_TOOLS=ON -DUA_ENABLE_ENCRYPTION=MBEDTLS -DUA_ENABLE_ENCRYPTION_TPM2=KEYSTORE ..
make -j$(nproc)
The binaries are generated in build/bin/ folder
./bin/examples/server_encryption_tpm_keystore <server-certificate.der> <server-private-key.der> <slot_id> <user_pin> <key_lable>
./bin/examples/client_encryption_tpm_keystore <opc.tcp://host:port> <client-certificate.der> <client-private-key.der> <slot_id> <user_pin> <key_lable>
Eg:
In Server,
./bin/examples/server_encryption_tpm_keystore ../tools/tpm_keystore/server_cert_sealed.der ../tools/tpm_keystore/server_key_sealed.der 1 123456 tpm_encrypt_key
In Client,
./bin/examples/client_encryption_tpm_keystore opc.tcp://localhost:4840 ../tools/tpm_keystore/client_cert_sealed.der ../tools/tpm_keystore/client_key_sealed.der 1 123456 tpm_encrypt_key
NOTE: Ignore the following warnings and error displayed during the run,
WARNING:fapi:src/tss2-fapi/api/Fapi_List.c:226:Fapi_List_Finish() Profile of path not provisioned: /HS/SRK
ERROR:fapi:src/tss2-fapi/api/Fapi_List.c:81:Fapi_List() ErrorCode (0x00060034) Entities_List
WARNING: Listing FAPI token objects failed: "fapi:Provisioning was not executed."
Please see https://github.com/tpm2-software/tpm2-pkcs11/blob/master/docs/FAPI.md for more details
WARNING: Getting tokens from fapi backend failed.

View File

@ -0,0 +1,435 @@
/* This work is licensed under a Creative Commons CCZero 1.0 Universal License.
* See http://creativecommons.org/publicdomain/zero/1.0/ for more information.
*
* Copyright 2021 (c) Kalycito Infotech Private Limited
*
*/
#include <open62541/client_config_default.h>
#include <open62541/client_highlevel.h>
#include <open62541/plugin/log_stdout.h>
#include <open62541/plugin/securitypolicy.h>
#include <stdlib.h>
#include <openssl/evp.h>
#include <pkcs11.h>
#include "common.h"
#define MIN_ARGS 7
static void get_MAC(const uint8_t *message, size_t message_len, unsigned char **message_digest,
unsigned int *message_digest_len)
{
EVP_MD_CTX *md_ctx;
if((md_ctx = EVP_MD_CTX_new()) == NULL) {
UA_LOG_ERROR(UA_Log_Stdout, UA_LOGCATEGORY_SECURITYPOLICY, "Error while EVP_MD_CTX_new");
return;
}
if(1 != EVP_DigestInit_ex(md_ctx, EVP_sha256(), NULL)) {
UA_LOG_ERROR(UA_Log_Stdout, UA_LOGCATEGORY_SECURITYPOLICY, "Error while EVP_DigestInit_ex");
return;
}
if(1 != EVP_DigestUpdate(md_ctx, message, message_len)) {
UA_LOG_ERROR(UA_Log_Stdout, UA_LOGCATEGORY_SECURITYPOLICY, "Error while EVP_DigestUpdate");
return;
}
if((*message_digest = (unsigned char *)OPENSSL_malloc((size_t)EVP_MD_size(EVP_sha256()))) == NULL) {
UA_LOG_ERROR(UA_Log_Stdout, UA_LOGCATEGORY_SECURITYPOLICY, "Error while OPENSSL_malloc");
return;
}
if(1 != EVP_DigestFinal_ex(md_ctx, *message_digest, message_digest_len)) {
UA_LOG_ERROR(UA_Log_Stdout, UA_LOGCATEGORY_SECURITYPOLICY, "Error while EVP_DigestFinal_ex");
return;
}
EVP_MD_CTX_free(md_ctx);
}
/* If object is found the object_handle is set */
static UA_Boolean
find_object_by_label(CK_SESSION_HANDLE hSession, char *label, unsigned long *object_handle) {
UA_StatusCode rv = UA_STATUSCODE_GOOD;
UA_Boolean rtnval = UA_FALSE;
unsigned long foundCount = 0;
do
{
CK_OBJECT_HANDLE hObject = 0;
rv = (UA_StatusCode)C_FindObjects(hSession, &hObject, 1, &foundCount );
if (rv == UA_STATUSCODE_GOOD) {
/* This will show the labels and values */
CK_ATTRIBUTE attrTemplate[] = {
{CKA_LABEL, NULL_PTR, 0}
};
rv = (UA_StatusCode)C_GetAttributeValue(hSession, hObject, attrTemplate, 1);
if (attrTemplate[0].ulValueLen > 0)
attrTemplate[0].pValue = (char *)UA_malloc(attrTemplate[0].ulValueLen);
rv = (UA_StatusCode)C_GetAttributeValue(hSession, hObject, attrTemplate, 1);
if (attrTemplate[0].ulValueLen > 0) {
char * val = (char *)UA_malloc(attrTemplate[0].ulValueLen + 1);
strncpy(val, (const char*)attrTemplate[0].pValue, attrTemplate[0].ulValueLen);
val[attrTemplate[0].ulValueLen] = '\0';
if (strcasecmp(val, (char *)label) == 0) rtnval = true;
UA_free(val);
*object_handle = hObject;
}
if (attrTemplate[0].pValue)
UA_free(attrTemplate[0].pValue);
} else {
rtnval = UA_FALSE;
UA_LOG_ERROR(UA_Log_Stdout, UA_LOGCATEGORY_SECURITYPOLICY,
"Error from tpm2_pkcs11 - refer https://github.com/tpm2-software/tpm2-pkcs11/blob/master/src/pkcs11.h "
"C_FindObjects failed = 0x%.8lx", (long unsigned int)rv);
}
} while( rv == UA_STATUSCODE_GOOD && foundCount > 0 && !rtnval);
return rtnval;
}
static UA_StatusCode
decrypt_data(unsigned long slotNum, unsigned char *pin, char *label, UA_ByteString *in_data,
UA_ByteString **decrypted_data, UA_ByteString * iv_data, uint64_t orginal_data_length) {
UA_StatusCode rv = UA_STATUSCODE_GOOD;
UA_ByteString *out_data = *decrypted_data;
unsigned long *pSlotList = NULL;
unsigned long slotID = 0;
unsigned long int ulSlotCount = 0;
unsigned long hSession;
CK_SESSION_INFO sessionInfo;
unsigned long hObject = 0;
unsigned char *ptr_encrypted_data = NULL;
unsigned long encrypted_data_length = 0;
unsigned char *data_clear = NULL;
unsigned long clear_data_length = 0;
unsigned long declen = 16;
unsigned char iv[iv_data->length];
UA_Boolean key_object_found = UA_FALSE;
CK_OBJECT_CLASS key_class = CKO_SECRET_KEY;
CK_KEY_TYPE key_type = CKK_AES;
CK_ATTRIBUTE attrTemplate[] = {
{CKA_CLASS, &key_class, sizeof(key_class)},
{CKA_KEY_TYPE, &key_type, sizeof(key_type)},
{CKA_LABEL, (void *)label, strlen(label)}
};
if (iv_data && iv_data->length > 0 && iv_data->data) {
rv = (UA_StatusCode)C_Initialize(NULL_PTR);
if (rv != UA_STATUSCODE_GOOD) {
UA_LOG_ERROR(UA_Log_Stdout, UA_LOGCATEGORY_SECURITYPOLICY,
"Error from tpm2_pkcs11 - refer https://github.com/tpm2-software/tpm2-pkcs11/blob/master/src/pkcs11.h "
"C_Initialize failed = 0x%.8lX", (long unsigned int)rv);
goto cleanup;
}
} else {
UA_LOG_ERROR(UA_Log_Stdout, UA_LOGCATEGORY_SECURITYPOLICY,
"The initializtion vector is not valid");
goto cleanup;
}
rv = (UA_StatusCode)C_GetSlotList(CK_TRUE, NULL, &ulSlotCount);
if ((rv == UA_STATUSCODE_GOOD) && (ulSlotCount > 0)) {
pSlotList = (unsigned long*)UA_malloc(ulSlotCount * sizeof (unsigned long));
if (pSlotList == NULL) {
UA_LOG_ERROR(UA_Log_Stdout, UA_LOGCATEGORY_SECURITYPOLICY,
"System error: Unable to allocate memory");
goto cleanup;
}
rv = (UA_StatusCode)C_GetSlotList(CK_TRUE, pSlotList, &ulSlotCount);
if (rv != UA_STATUSCODE_GOOD) {
UA_LOG_ERROR(UA_Log_Stdout, UA_LOGCATEGORY_SECURITYPOLICY,
"Error from tpm2_pkcs11 - refer https://github.com/tpm2-software/tpm2-pkcs11/blob/master/src/pkcs11.h "
"GetSlotList failed: Unable to get slot list = 0x%.8lX", (long unsigned int)rv);
goto cleanup;
}
} else {
UA_LOG_ERROR(UA_Log_Stdout, UA_LOGCATEGORY_SECURITYPOLICY,
"Error from tpm2_pkcs11 - refer https://github.com/tpm2-software/tpm2-pkcs11/blob/master/src/pkcs11.h "
"GetSlotList failed: Unable to get slot count = 0x%.8lX", (long unsigned int)rv);
goto cleanup;
}
for (unsigned long int i = 0; i < ulSlotCount; i++) {
slotID = pSlotList[i];
if (slotID == slotNum) {
CK_TOKEN_INFO token_info;
rv = (UA_StatusCode)C_GetTokenInfo(slotID, &token_info);
if (rv != UA_STATUSCODE_GOOD) {
UA_LOG_ERROR(UA_Log_Stdout, UA_LOGCATEGORY_SECURITYPOLICY,
"Error from tpm2_pkcs11 - refer https://github.com/tpm2-software/tpm2-pkcs11/blob/master/src/pkcs11.h "
"C_GetTokenInfo failed = 0x%.8lX", (long unsigned int)rv);
goto cleanup;
}
break;
}
}
rv = (UA_StatusCode)C_OpenSession(slotID, CKF_SERIAL_SESSION | CKF_RW_SESSION, (CK_VOID_PTR) NULL, NULL, &hSession);
if (rv != UA_STATUSCODE_GOOD) {
UA_LOG_ERROR(UA_Log_Stdout, UA_LOGCATEGORY_SECURITYPOLICY,
"Error from tpm2_pkcs11 - refer https://github.com/tpm2-software/tpm2-pkcs11/blob/master/src/pkcs11.h "
"C_OpenSession failed = 0x%.8lX", (long unsigned int)rv);
goto cleanup;
}
rv = (UA_StatusCode)C_GetSessionInfo(hSession, &sessionInfo);
if (rv != UA_STATUSCODE_GOOD) {
UA_LOG_ERROR(UA_Log_Stdout, UA_LOGCATEGORY_SECURITYPOLICY,
"Error from tpm2_pkcs11 - refer https://github.com/tpm2-software/tpm2-pkcs11/blob/master/src/pkcs11.h "
"C_GetSessionInfo failed = 0x%.8lX", (long unsigned int)rv);
goto cleanup;
}
if(sessionInfo.state != CKS_RW_USER_FUNCTIONS) {
/* Logs a user into a token */
rv = (UA_StatusCode)C_Login(hSession, CKU_USER, pin, strlen((const char *)pin));
if (rv != UA_STATUSCODE_GOOD) {
UA_LOG_ERROR(UA_Log_Stdout, UA_LOGCATEGORY_SECURITYPOLICY,
"Error from tpm2_pkcs11 - refer https://github.com/tpm2-software/tpm2-pkcs11/blob/master/src/pkcs11.h "
"C_Login failed = 0x%.8lX", (long unsigned int)rv);
goto cleanup;
}
}
rv = (UA_StatusCode)C_FindObjectsInit(hSession, attrTemplate, sizeof(attrTemplate)/sizeof (CK_ATTRIBUTE));
if (rv == UA_STATUSCODE_GOOD) {
key_object_found = find_object_by_label(hSession, label, &hObject);
if (key_object_found == UA_FALSE){
UA_LOG_ERROR(UA_Log_Stdout, UA_LOGCATEGORY_SECURITYPOLICY, "Error: key object not found");
goto cleanup;
}
rv = (UA_StatusCode)C_FindObjectsFinal(hSession);
if (rv != UA_STATUSCODE_GOOD) {
UA_LOG_ERROR(UA_Log_Stdout, UA_LOGCATEGORY_SECURITYPOLICY,
"Error from tpm2_pkcs11 - refer https://github.com/tpm2-software/tpm2-pkcs11/blob/master/src/pkcs11.h "
"C_FindObjectsFinal failed = 0x%.8lX", (long unsigned int)rv);
goto cleanup;
}
} else {
UA_LOG_ERROR(UA_Log_Stdout, UA_LOGCATEGORY_SECURITYPOLICY,
"Error from tpm2_pkcs11 - refer https://github.com/tpm2-software/tpm2-pkcs11/blob/master/src/pkcs11.h "
"C_FindObjectsInit failed = 0x%.8lX", (long unsigned int)rv);
goto cleanup;
}
for (size_t i=0; i < iv_data->length; i++) {
iv[i] = *((CK_BYTE *)(iv_data->data + i));
}
CK_MECHANISM mechanism = {CKM_AES_CBC, iv, sizeof(iv)};
encrypted_data_length = in_data->length;
clear_data_length = encrypted_data_length;
ptr_encrypted_data = (CK_BYTE *)(UA_malloc(encrypted_data_length * sizeof(CK_BYTE)));
memset(ptr_encrypted_data, 0, encrypted_data_length);
memcpy(ptr_encrypted_data, (CK_BYTE *)(in_data->data), in_data->length);
rv = (UA_StatusCode)C_DecryptInit(hSession, &mechanism, hObject);
if (rv != UA_STATUSCODE_GOOD) {
UA_LOG_ERROR(UA_Log_Stdout, UA_LOGCATEGORY_SECURITYPOLICY,
"Error from tpm2_pkcs11 - refer https://github.com/tpm2-software/tpm2-pkcs11/blob/master/src/pkcs11.h "
"C_DecryptInit failed = 0x%.8lX", (long unsigned int)rv);
goto cleanup;
}
data_clear = (CK_BYTE *)UA_malloc(clear_data_length * sizeof(CK_BYTE));
memset(data_clear, 0, clear_data_length);
unsigned long part_number = 0;
while (rv == UA_STATUSCODE_GOOD && part_number * 16 < clear_data_length - 16) {
rv = (UA_StatusCode)C_DecryptUpdate(hSession, ptr_encrypted_data + part_number * 16,
16, &data_clear[part_number*16], &declen);
if (rv != UA_STATUSCODE_GOOD) {
UA_LOG_ERROR(UA_Log_Stdout, UA_LOGCATEGORY_SECURITYPOLICY,
"Error from tpm2_pkcs11 - refer https://github.com/tpm2-software/tpm2-pkcs11/blob/master/src/pkcs11.h "
"C_Decryptupdate failed = 0x%.8lX", (long unsigned int)rv);
goto cleanup;
}
part_number++;
}
rv = (UA_StatusCode)C_DecryptFinal(hSession, &data_clear[part_number *16], &declen);
if (rv != UA_STATUSCODE_GOOD) {
UA_LOG_ERROR(UA_Log_Stdout, UA_LOGCATEGORY_SECURITYPOLICY,
"Error from tpm2_pkcs11 - refer https://github.com/tpm2-software/tpm2-pkcs11/blob/master/src/pkcs11.h "
"C_DecryptFinal failed = 0x%.8lX", (long unsigned int)rv);
goto cleanup;
}
if (orginal_data_length > clear_data_length)
orginal_data_length = 0;
if (out_data->data) {
UA_free(out_data->data);
out_data->length = 0;
}
out_data->data = (UA_Byte *)UA_malloc(orginal_data_length);
memcpy(out_data->data, data_clear, orginal_data_length);
out_data->length = orginal_data_length;
C_Logout(hSession);
C_CloseSession(hSession);
C_Finalize(NULL);
cleanup:
if (data_clear)
UA_free(data_clear);
if (pSlotList)
UA_free(pSlotList);
if (ptr_encrypted_data)
UA_free(ptr_encrypted_data);
return rv;
}
static UA_StatusCode
decrypt(unsigned long slotNum, unsigned char *pin, char *label,
UA_ByteString *in_data, UA_ByteString **decrypted_data) {
UA_StatusCode rv = UA_STATUSCODE_GOOD;
/* For decrypt
Calculate the HMAC of the output without the 32 byte (256 bit) md_value
Check the calcualted md with the md from the input
if they match continue to decrypt the input */
unsigned char *md_value = NULL;
unsigned int md_len;
unsigned int expected_md_len = 32;
UA_ByteString *enc_data = UA_ByteString_new();
UA_ByteString *iv_data = UA_ByteString_new();
/* Get the HMAC */
get_MAC(in_data->data, in_data->length - expected_md_len, &md_value, &md_len);
if (memcmp(in_data->data + in_data->length - expected_md_len, md_value, md_len) == 0) {
/* Get the iv that was appended to the encrypted data
find the iv. It was packed in the first 16 bytes of the last 56 in the file */
UA_ByteString_allocBuffer(iv_data, 16);
uint8_t * ptr_in_data = (uint8_t *)(in_data->data);
memcpy(iv_data->data, ptr_in_data + in_data->length - sizeof(uint64_t) - expected_md_len - iv_data->length, iv_data->length);
/* Find the data length in output */
uint64_t clear_data_length;
clear_data_length = *((uint64_t *)(ptr_in_data + in_data->length - sizeof(uint64_t) - expected_md_len));
/* Remove the extra 56 bytes that were added at the end of the encrypted data */
UA_ByteString_allocBuffer(enc_data, in_data->length - sizeof(uint64_t) - expected_md_len - iv_data->length);
memcpy(enc_data->data, ptr_in_data, enc_data->length);
rv = (UA_StatusCode)decrypt_data(slotNum, pin, label, enc_data, decrypted_data, iv_data, clear_data_length);
if(rv != UA_STATUSCODE_GOOD) {
UA_LOG_ERROR(UA_Log_Stdout, UA_LOGCATEGORY_SECURITYPOLICY, "decrypt_data failed");
}
UA_ByteString_delete(iv_data);
UA_ByteString_delete(enc_data);
} else {
UA_LOG_ERROR(UA_Log_Stdout, UA_LOGCATEGORY_SECURITYPOLICY, "HMAC does not match");
return EXIT_FAILURE;
}
if(md_value) OPENSSL_free(md_value);
return rv;
}
int main(int argc, char* argv[]) {
if(argc < MIN_ARGS) {
UA_LOG_FATAL(UA_Log_Stdout, UA_LOGCATEGORY_USERLAND,
"Arguments are missing. The required arguments are "
"<opc.tcp://host:port> "
"<client-certificate.der> <client-private-key.der> "
"<slotId> <userPin> <keyLable> "
"[<trustlist1.crl>, ...]");
return EXIT_FAILURE;
}
char *keyLabel = NULL;
unsigned long slotId = 0;
unsigned char *userpin = NULL;
UA_ByteString privateKey = UA_BYTESTRING_NULL;
UA_ByteString certificate = UA_BYTESTRING_NULL;
UA_ByteString *encrypt_out_data = NULL;
UA_ByteString *certificate_out_data = NULL;
const char *endpointUrl = argv[1];
/* Load certificate and private key */
UA_ByteString certificate_in_date = loadFile(argv[2]);
UA_ByteString encrypt_in_data = loadFile(argv[3]);
slotId = (unsigned long)atoi(argv[4]);
userpin = (unsigned char*)argv[5];
keyLabel = argv[6];
encrypt_out_data = (UA_ByteString *)UA_malloc(sizeof(UA_ByteString));
encrypt_out_data->data = NULL;
encrypt_out_data->length = 0;
UA_StatusCode rv = decrypt(slotId, userpin, keyLabel, &encrypt_in_data, &encrypt_out_data);
if (rv != UA_STATUSCODE_GOOD) {
fprintf(stderr, "Decrypt failed for RSA privare key");
return EXIT_FAILURE;
}
privateKey.data = encrypt_out_data->data;
privateKey.length = encrypt_out_data->length;
certificate_out_data = (UA_ByteString *)UA_malloc(sizeof(UA_ByteString));
certificate_out_data->data = NULL;
certificate_out_data->length = 0;
rv = decrypt(slotId, userpin, keyLabel, &certificate_in_date, &certificate_out_data);
if (rv != UA_STATUSCODE_GOOD) {
UA_LOG_ERROR(UA_Log_Stdout, UA_LOGCATEGORY_SECURITYPOLICY, "Decrypt failed for certificate");
return EXIT_FAILURE;
}
certificate.data = certificate_out_data->data;
certificate.length = certificate_out_data->length;
/* Load the trustList. Load revocationList is not supported now */
size_t trustListSize = 0;
if(argc > MIN_ARGS)
trustListSize = (size_t)argc-MIN_ARGS;
UA_STACKARRAY(UA_ByteString, trustList, trustListSize+1);
for(size_t trustListCount = 0; trustListCount < trustListSize; trustListCount++)
trustList[trustListCount] = loadFile(argv[trustListCount+7]);
UA_ByteString *revocationList = NULL;
size_t revocationListSize = 0;
UA_Client *client = UA_Client_new();
UA_ClientConfig *cc = UA_Client_getConfig(client);
cc->securityMode = UA_MESSAGESECURITYMODE_SIGNANDENCRYPT;
UA_ClientConfig_setDefaultEncryption(cc, certificate, privateKey,
trustList, trustListSize,
revocationList, revocationListSize);
if (encrypt_out_data) {
if (encrypt_out_data->data)
UA_free(encrypt_out_data->data);
UA_free(encrypt_out_data);
}
UA_ByteString_clear(&certificate_in_date);
UA_ByteString_clear(&encrypt_in_data);
for(size_t deleteCount = 0; deleteCount < trustListSize; deleteCount++) {
UA_ByteString_clear(&trustList[deleteCount]);
}
/* Secure client connect */
cc->securityMode = UA_MESSAGESECURITYMODE_SIGNANDENCRYPT; /* require encryption */
UA_StatusCode retval = UA_Client_connect(client, endpointUrl);
if(retval != UA_STATUSCODE_GOOD) {
UA_Client_delete(client);
return EXIT_FAILURE;
}
UA_Variant value;
UA_Variant_init(&value);
/* NodeId of the variable holding the current time */
const UA_NodeId nodeId = UA_NODEID_NUMERIC(0, UA_NS0ID_SERVER_SERVERSTATUS_CURRENTTIME);
retval = UA_Client_readValueAttribute(client, nodeId, &value);
if(retval == UA_STATUSCODE_GOOD &&
UA_Variant_hasScalarType(&value, &UA_TYPES[UA_TYPES_DATETIME])) {
UA_DateTime raw_date = *(UA_DateTime *) value.data;
UA_DateTimeStruct dts = UA_DateTime_toStruct(raw_date);
UA_LOG_INFO(UA_Log_Stdout, UA_LOGCATEGORY_USERLAND, "date is: %u-%u-%u %u:%u:%u.%03u\n",
dts.day, dts.month, dts.year, dts.hour, dts.min, dts.sec, dts.milliSec);
}
/* Clean up */
UA_Variant_clear(&value);
UA_Client_delete(client);
return retval == UA_STATUSCODE_GOOD ? EXIT_SUCCESS : EXIT_FAILURE;
}

View File

@ -0,0 +1,432 @@
/* This work is licensed under a Creative Commons CCZero 1.0 Universal License.
* See http://creativecommons.org/publicdomain/zero/1.0/ for more information.
*
* Copyright 2021 (c) Kalycito Infotech Private Limited
*
*/
#include <open62541/client_highlevel.h>
#include <open62541/plugin/log_stdout.h>
#include <open62541/plugin/securitypolicy.h>
#include <open62541/server.h>
#include <open62541/server_config_default.h>
#include <signal.h>
#include <stdlib.h>
#include <openssl/evp.h>
#include <pkcs11.h>
#include "common.h"
static void get_MAC(const uint8_t *message, size_t message_len, unsigned char **message_digest,
unsigned int *message_digest_len)
{
EVP_MD_CTX *md_ctx;
if((md_ctx = EVP_MD_CTX_new()) == NULL) {
UA_LOG_ERROR(UA_Log_Stdout, UA_LOGCATEGORY_SECURITYPOLICY, "Error while EVP_MD_CTX_new");
return;
}
if(1 != EVP_DigestInit_ex(md_ctx, EVP_sha256(), NULL)) {
UA_LOG_ERROR(UA_Log_Stdout, UA_LOGCATEGORY_SECURITYPOLICY, "Error while EVP_DigestInit_ex");
return;
}
if(1 != EVP_DigestUpdate(md_ctx, message, message_len)) {
UA_LOG_ERROR(UA_Log_Stdout, UA_LOGCATEGORY_SECURITYPOLICY, "Error while EVP_DigestUpdate");
return;
}
if((*message_digest = (unsigned char *)OPENSSL_malloc((size_t)EVP_MD_size(EVP_sha256()))) == NULL) {
UA_LOG_ERROR(UA_Log_Stdout, UA_LOGCATEGORY_SECURITYPOLICY, "Error while OPENSSL_malloc");
return;
}
if(1 != EVP_DigestFinal_ex(md_ctx, *message_digest, message_digest_len)) {
UA_LOG_ERROR(UA_Log_Stdout, UA_LOGCATEGORY_SECURITYPOLICY, "Error while EVP_DigestFinal_ex");
return;
}
EVP_MD_CTX_free(md_ctx);
}
/* If object is found the object_handle is set */
static UA_Boolean
find_object_by_label(CK_SESSION_HANDLE hSession, char *label, unsigned long *object_handle) {
UA_StatusCode rv = UA_STATUSCODE_GOOD;
UA_Boolean rtnval = UA_FALSE;
unsigned long foundCount = 0;
do
{
CK_OBJECT_HANDLE hObject = 0;
rv = (UA_StatusCode)C_FindObjects(hSession, &hObject, 1, &foundCount );
if (rv == UA_STATUSCODE_GOOD) {
/* This will show the labels and values */
CK_ATTRIBUTE attrTemplate[] = {
{CKA_LABEL, NULL_PTR, 0}
};
rv = (UA_StatusCode)C_GetAttributeValue(hSession, hObject, attrTemplate, 1);
if (attrTemplate[0].ulValueLen > 0)
attrTemplate[0].pValue = (char *)UA_malloc(attrTemplate[0].ulValueLen);
rv = (UA_StatusCode)C_GetAttributeValue(hSession, hObject, attrTemplate, 1);
if (attrTemplate[0].ulValueLen > 0) {
char * val = (char *)UA_malloc(attrTemplate[0].ulValueLen + 1);
strncpy(val, (const char*)attrTemplate[0].pValue, attrTemplate[0].ulValueLen);
val[attrTemplate[0].ulValueLen] = '\0';
if (strcasecmp(val, (char *)label) == 0) rtnval = true;
UA_free(val);
*object_handle = hObject;
}
if (attrTemplate[0].pValue)
UA_free(attrTemplate[0].pValue);
} else {
rtnval = UA_FALSE;
UA_LOG_ERROR(UA_Log_Stdout, UA_LOGCATEGORY_SECURITYPOLICY,
"Error from tpm2_pkcs11 - refer https://github.com/tpm2-software/tpm2-pkcs11/blob/master/src/pkcs11.h "
"C_FindObjects failed = 0x%.8lx", (long unsigned int)rv);
}
} while( rv == UA_STATUSCODE_GOOD && foundCount > 0 && !rtnval);
return rtnval;
}
static UA_StatusCode
decrypt_data(unsigned long slotNum, unsigned char *pin, char *label, UA_ByteString *in_data,
UA_ByteString **decrypted_data, UA_ByteString * iv_data, uint64_t orginal_data_length) {
UA_StatusCode rv = UA_STATUSCODE_GOOD;
UA_ByteString *out_data = *decrypted_data;
unsigned long *pSlotList = NULL;
unsigned long slotID = 0;
unsigned long int ulSlotCount = 0;
unsigned long hSession;
CK_SESSION_INFO sessionInfo;
unsigned long hObject = 0;
unsigned char *ptr_encrypted_data = NULL;
unsigned long encrypted_data_length = 0;
unsigned char *data_clear = NULL;
unsigned long clear_data_length = 0;
unsigned long declen = 16;
unsigned char iv[iv_data->length];
UA_Boolean key_object_found = UA_FALSE;
CK_OBJECT_CLASS key_class = CKO_SECRET_KEY;
CK_KEY_TYPE key_type = CKK_AES;
CK_ATTRIBUTE attrTemplate[] = {
{CKA_CLASS, &key_class, sizeof(key_class)},
{CKA_KEY_TYPE, &key_type, sizeof(key_type)},
{CKA_LABEL, (void *)label, strlen(label)}
};
if (iv_data && iv_data->length > 0 && iv_data->data) {
rv = (UA_StatusCode)C_Initialize(NULL_PTR);
if (rv != UA_STATUSCODE_GOOD) {
UA_LOG_ERROR(UA_Log_Stdout, UA_LOGCATEGORY_SECURITYPOLICY,
"Error from tpm2_pkcs11 - refer https://github.com/tpm2-software/tpm2-pkcs11/blob/master/src/pkcs11.h "
"C_Initialize failed: Error = 0x%.8lX", (long unsigned int)rv);
goto cleanup;
}
} else {
UA_LOG_ERROR(UA_Log_Stdout, UA_LOGCATEGORY_SECURITYPOLICY,
"The initializtion vector is not valid");
goto cleanup;
}
rv = (UA_StatusCode)C_GetSlotList(CK_TRUE, NULL, &ulSlotCount);
if ((rv == UA_STATUSCODE_GOOD) && (ulSlotCount > 0)) {
pSlotList = (unsigned long*)UA_malloc(ulSlotCount * sizeof (unsigned long));
if (pSlotList == NULL) {
UA_LOG_ERROR(UA_Log_Stdout, UA_LOGCATEGORY_SECURITYPOLICY,
"System error: Unable to allocate memory");
goto cleanup;
}
rv = (UA_StatusCode)C_GetSlotList(CK_TRUE, pSlotList, &ulSlotCount);
if (rv != UA_STATUSCODE_GOOD) {
UA_LOG_ERROR(UA_Log_Stdout, UA_LOGCATEGORY_SECURITYPOLICY,
"Error from tpm2_pkcs11 - refer https://github.com/tpm2-software/tpm2-pkcs11/blob/master/src/pkcs11.h "
"GetSlotList failed: Error unable to get slot list = 0x%.8lX", (long unsigned int)rv);
goto cleanup;
}
} else {
UA_LOG_ERROR(UA_Log_Stdout, UA_LOGCATEGORY_SECURITYPOLICY,
"GetSlotList failed: Error unable to get slot count = 0x%.8lX", (long unsigned int)rv);
goto cleanup;
}
for (unsigned long int i = 0; i < ulSlotCount; i++) {
slotID = pSlotList[i];
if (slotID == slotNum) {
CK_TOKEN_INFO token_info;
rv = (UA_StatusCode)C_GetTokenInfo(slotID, &token_info);
if (rv != UA_STATUSCODE_GOOD) {
UA_LOG_ERROR(UA_Log_Stdout, UA_LOGCATEGORY_SECURITYPOLICY,
"Error from tpm2_pkcs11 - refer https://github.com/tpm2-software/tpm2-pkcs11/blob/master/src/pkcs11.h "
"C_GetTokenInfo failed = 0x%.8lX", (long unsigned int)rv);
goto cleanup;
}
break;
}
}
rv = (UA_StatusCode)C_OpenSession(slotID, CKF_SERIAL_SESSION | CKF_RW_SESSION, (CK_VOID_PTR) NULL, NULL, &hSession);
if (rv != UA_STATUSCODE_GOOD) {
UA_LOG_ERROR(UA_Log_Stdout, UA_LOGCATEGORY_SECURITYPOLICY,
"Error from tpm2_pkcs11 - refer https://github.com/tpm2-software/tpm2-pkcs11/blob/master/src/pkcs11.h "
"C_OpenSession failed = 0x%.8lX", (long unsigned int)rv);
goto cleanup;
}
rv = (UA_StatusCode)C_GetSessionInfo(hSession, &sessionInfo);
if (rv != UA_STATUSCODE_GOOD) {
UA_LOG_ERROR(UA_Log_Stdout, UA_LOGCATEGORY_SECURITYPOLICY,
"Error from tpm2_pkcs11 - refer https://github.com/tpm2-software/tpm2-pkcs11/blob/master/src/pkcs11.h "
"C_GetSessionInfo failed = 0x%.8lX", (long unsigned int)rv);
goto cleanup;
}
if(sessionInfo.state != CKS_RW_USER_FUNCTIONS) {
/* Logs a user into a token */
rv = (UA_StatusCode)C_Login(hSession, CKU_USER, pin, strlen((const char *)pin));
if (rv != UA_STATUSCODE_GOOD) {
UA_LOG_ERROR(UA_Log_Stdout, UA_LOGCATEGORY_SECURITYPOLICY,
"Error from tpm2_pkcs11 - refer https://github.com/tpm2-software/tpm2-pkcs11/blob/master/src/pkcs11.h "
"C_Login failed = 0x%.8lX", (long unsigned int)rv);
goto cleanup;
}
}
rv = (UA_StatusCode)C_FindObjectsInit(hSession, attrTemplate, sizeof(attrTemplate)/sizeof (CK_ATTRIBUTE));
if (rv == UA_STATUSCODE_GOOD) {
key_object_found = find_object_by_label(hSession, label, &hObject);
if (key_object_found == UA_FALSE){
UA_LOG_ERROR(UA_Log_Stdout, UA_LOGCATEGORY_SECURITYPOLICY, "Error: key object not found");
goto cleanup;
}
rv = (UA_StatusCode)C_FindObjectsFinal(hSession);
if (rv != UA_STATUSCODE_GOOD) {
UA_LOG_ERROR(UA_Log_Stdout, UA_LOGCATEGORY_SECURITYPOLICY,
"Error from tpm2_pkcs11 - refer https://github.com/tpm2-software/tpm2-pkcs11/blob/master/src/pkcs11.h "
"C_FindObjectsFinal failed = 0x%.8lX", (long unsigned int)rv);
goto cleanup;
}
} else {
UA_LOG_ERROR(UA_Log_Stdout, UA_LOGCATEGORY_SECURITYPOLICY,
"Error from tpm2_pkcs11 - refer https://github.com/tpm2-software/tpm2-pkcs11/blob/master/src/pkcs11.h "
"C_FindObjectsInit failed = 0x%.8lX", (long unsigned int)rv);
goto cleanup;
}
for (size_t i=0; i < iv_data->length; i++) {
iv[i] = *((CK_BYTE *)(iv_data->data + i));
}
CK_MECHANISM mechanism = {CKM_AES_CBC, iv, sizeof(iv)};
encrypted_data_length = in_data->length;
clear_data_length = encrypted_data_length;
ptr_encrypted_data = (CK_BYTE *)(UA_malloc(encrypted_data_length * sizeof(CK_BYTE)));
memset(ptr_encrypted_data, 0, encrypted_data_length);
memcpy(ptr_encrypted_data, (CK_BYTE *)(in_data->data), in_data->length);
rv = (UA_StatusCode)C_DecryptInit(hSession, &mechanism, hObject);
if (rv != UA_STATUSCODE_GOOD) {
UA_LOG_ERROR(UA_Log_Stdout, UA_LOGCATEGORY_SECURITYPOLICY,
"Error from tpm2_pkcs11 - refer https://github.com/tpm2-software/tpm2-pkcs11/blob/master/src/pkcs11.h "
"C_DecryptInit failed = 0x%.8lX", (long unsigned int)rv);
goto cleanup;
}
data_clear = (CK_BYTE *)UA_malloc(clear_data_length * sizeof(CK_BYTE));
memset(data_clear, 0, clear_data_length);
unsigned long part_number = 0;
while (rv == UA_STATUSCODE_GOOD && part_number * 16 < clear_data_length - 16) {
rv = (UA_StatusCode)C_DecryptUpdate(hSession, ptr_encrypted_data + part_number * 16,
16, &data_clear[part_number*16], &declen);
if (rv != UA_STATUSCODE_GOOD) {
UA_LOG_ERROR(UA_Log_Stdout, UA_LOGCATEGORY_SECURITYPOLICY,
"Error from tpm2_pkcs11 - refer https://github.com/tpm2-software/tpm2-pkcs11/blob/master/src/pkcs11.h "
"C_Decryptupdate failed = 0x%.8lX", (long unsigned int)rv);
goto cleanup;
}
part_number++;
}
rv = (UA_StatusCode)C_DecryptFinal(hSession, &data_clear[part_number *16], &declen);
if (rv != UA_STATUSCODE_GOOD) {
UA_LOG_ERROR(UA_Log_Stdout, UA_LOGCATEGORY_SECURITYPOLICY,
"Error from tpm2_pkcs11 - refer https://github.com/tpm2-software/tpm2-pkcs11/blob/master/src/pkcs11.h "
"C_DecryptFinal failed = 0x%.8lX", (long unsigned int)rv);
goto cleanup;
}
if (orginal_data_length > clear_data_length)
orginal_data_length = 0;
if (out_data->data) {
UA_free(out_data->data);
out_data->length = 0;
}
out_data->data = (UA_Byte *)UA_malloc(orginal_data_length);
memcpy(out_data->data, data_clear, orginal_data_length);
out_data->length = orginal_data_length;
C_Logout(hSession);
C_CloseSession(hSession);
C_Finalize(NULL);
cleanup:
if (data_clear)
UA_free(data_clear);
if (pSlotList)
UA_free(pSlotList);
if (ptr_encrypted_data)
UA_free(ptr_encrypted_data);
return rv;
}
static UA_StatusCode
decrypt(unsigned long slotNum, unsigned char *pin, char *label,
UA_ByteString *in_data, UA_ByteString **decrypted_data) {
UA_StatusCode rv = UA_STATUSCODE_GOOD;
/* For decrypt
Calculate the HMAC of the output without the 32 byte (256 bit) md_value
Check the calcualted md with the md from the input
if they match continue to decrypt the input */
unsigned char *md_value = NULL;
unsigned int md_len;
unsigned int expected_md_len = 32;
UA_ByteString *enc_data = UA_ByteString_new();
UA_ByteString *iv_data = UA_ByteString_new();
/* Get the HMAC */
get_MAC(in_data->data, in_data->length - expected_md_len, &md_value, &md_len);
if (memcmp(in_data->data + in_data->length - expected_md_len, md_value, md_len) == 0) {
/* Get the iv that was appended to the encrypted data
find the iv. It was packed in the first 16 bytes of the last 56 in the file */
UA_ByteString_allocBuffer(iv_data, 16);
uint8_t * ptr_in_data = (uint8_t *)(in_data->data);
memcpy(iv_data->data, ptr_in_data + in_data->length - sizeof(uint64_t) - expected_md_len - iv_data->length, iv_data->length);
/* Find the data length in output */
uint64_t clear_data_length;
clear_data_length = *((uint64_t *)(ptr_in_data + in_data->length - sizeof(uint64_t) - expected_md_len));
/* Remove the extra 56 bytes that were added at the end of the encrypted data */
UA_ByteString_allocBuffer(enc_data, in_data->length - sizeof(uint64_t) - expected_md_len - iv_data->length);
memcpy(enc_data->data, ptr_in_data, enc_data->length);
rv = (UA_StatusCode)decrypt_data(slotNum, pin, label, enc_data, decrypted_data, iv_data, clear_data_length);
if(rv != UA_STATUSCODE_GOOD) {
UA_LOG_ERROR(UA_Log_Stdout, UA_LOGCATEGORY_SECURITYPOLICY, "decrypt_data failed");
}
UA_ByteString_delete(iv_data);
UA_ByteString_delete(enc_data);
} else {
UA_LOG_ERROR(UA_Log_Stdout, UA_LOGCATEGORY_SECURITYPOLICY, "HMAC does not match");
return EXIT_FAILURE;
}
if(md_value) OPENSSL_free(md_value);
return rv;
}
UA_Boolean running = true;
static void stopHandler(int sig) {
UA_LOG_INFO(UA_Log_Stdout, UA_LOGCATEGORY_USERLAND, "received ctrl-c");
running = false;
}
int main(int argc, char* argv[]) {
signal(SIGINT, stopHandler);
signal(SIGTERM, stopHandler);
if(argc < 6) {
UA_LOG_FATAL(UA_Log_Stdout, UA_LOGCATEGORY_USERLAND,
"Missing arguments. Arguments are "
"<server-certificate.der> <private-key.der> "
"<slotId> <userPin> <keyLable> "
"[<trustlist1.crl>, ...]");
return EXIT_FAILURE;
}
char *keyLabel = NULL;
unsigned long slotId = 0;
unsigned char *userpin = NULL;
UA_ByteString privateKey = UA_BYTESTRING_NULL;
UA_ByteString certificate = UA_BYTESTRING_NULL;
UA_ByteString *certificate_out_data = NULL;
UA_ByteString *encrypt_out_data = NULL;
/* Load certificate and private key */
UA_ByteString certificate_in_date = loadFile(argv[1]);
UA_ByteString encrypt_in_data = loadFile(argv[2]);
slotId = (unsigned long)atoi(argv[3]);
userpin = (unsigned char*)argv[4];
keyLabel = argv[5];
encrypt_out_data = (UA_ByteString *)UA_malloc(sizeof(UA_ByteString));
encrypt_out_data->data = NULL;
encrypt_out_data->length = 0;
UA_StatusCode rv = decrypt(slotId, userpin, keyLabel, &encrypt_in_data, &encrypt_out_data);
if (rv != UA_STATUSCODE_GOOD) {
UA_LOG_ERROR(UA_Log_Stdout, UA_LOGCATEGORY_SECURITYPOLICY, "Decrypt failed for RSA privare key");
return EXIT_FAILURE;
}
privateKey.data = encrypt_out_data->data;
privateKey.length = encrypt_out_data->length;
certificate_out_data = (UA_ByteString *)UA_malloc(sizeof(UA_ByteString));
certificate_out_data->data = NULL;
certificate_out_data->length = 0;
rv = decrypt(slotId, userpin, keyLabel, &certificate_in_date, &certificate_out_data);
if (rv != UA_STATUSCODE_GOOD) {
UA_LOG_ERROR(UA_Log_Stdout, UA_LOGCATEGORY_SECURITYPOLICY, "Decrypt failed for certificate");
return EXIT_FAILURE;
}
certificate.data = certificate_out_data->data;
certificate.length = certificate_out_data->length;
/* Load the trustlist */
size_t trustListSize = 0;
if(argc > 6)
trustListSize = (size_t)argc-6;
UA_STACKARRAY(UA_ByteString, trustList, trustListSize+1);
for(size_t i = 0; i < trustListSize; i++)
trustList[i] = loadFile(argv[i+6]);
/* Loading of an issuer list, not used in this application */
size_t issuerListSize = 0;
UA_ByteString *issuerList = NULL;
/* Loading of a revocation list currently unsupported */
UA_ByteString *revocationList = NULL;
size_t revocationListSize = 0;
UA_Server *server = UA_Server_new();
UA_ServerConfig *config = UA_Server_getConfig(server);
UA_StatusCode retval =
UA_ServerConfig_setDefaultWithSecurityPolicies(config, 4840,
&certificate, &privateKey,
trustList, trustListSize,
issuerList, issuerListSize,
revocationList, revocationListSize);
#ifdef UA_ENABLE_WEBSOCKET_SERVER
UA_ServerConfig_addNetworkLayerWS(UA_Server_getConfig(server), 7681, 0, 0, &certificate, &privateKey);
#endif
if (encrypt_out_data) {
if (encrypt_out_data->data)
UA_free(encrypt_out_data->data);
UA_free(encrypt_out_data);
}
UA_ByteString_clear(&certificate_in_date);
UA_ByteString_clear(&encrypt_in_data);
for(size_t i = 0; i < trustListSize; i++)
UA_ByteString_clear(&trustList[i]);
if(retval != UA_STATUSCODE_GOOD)
goto cleanup;
retval = UA_Server_run(server, &running);
cleanup:
UA_Server_delete(server);
return retval == UA_STATUSCODE_GOOD ? EXIT_SUCCESS : EXIT_FAILURE;
}

View File

@ -38,6 +38,19 @@ function build_docs {
make doc
}
#######################
# Build TPM tool #
#######################
function build_tpm_tool {
mkdir -p build; cd build; rm -rf *
cmake -DUA_BUILD_TOOLS=ON \
-DUA_ENABLE_ENCRYPTION=MBEDTLS \
-DUA_ENABLE_ENCRYPTION_TPM2=KEYSTORE \
..
make ${MAKEOPTS}
}
#########################
# Build Release Version #
#########################

View File

@ -0,0 +1,4 @@
set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/bin)
add_executable(cert_encrypt_tpm cert_encrypt_tpm.c)
target_link_libraries(cert_encrypt_tpm tpm2_pkcs11 ssl crypto)

View File

@ -0,0 +1,524 @@
/* This work is licensed under a Creative Commons CCZero 1.0 Universal License.
* See http://creativecommons.org/publicdomain/zero/1.0/ for more information.
*
* Copyright (c) 2021 Kalycito Infotech Private Limited
*/
/* gcc cert_encrypt_tpm.c -o cert_encrypt_tpm -ltpm2_pkcs11 -lssl -lcrypto */
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <strings.h>
#include <stdint.h>
#include <stdbool.h>
#include <openssl/evp.h>
#include "pkcs11.h"
typedef enum { B_FALSE, B_TRUE } boolean_t;
typedef struct binary_data binary_data;
struct binary_data {
long length;
void *data;
};
void usage(void);
void get_MAC_error(void);
void get_MAC_error(void) {
printf("%s\n", "Error while getting the message digest");
return;
}
/* If message is binary do not use strlen(message) for message_len. */
static void get_MAC(const uint8_t *message, size_t message_len, unsigned char **message_digest,
unsigned int *message_digest_len)
{
EVP_MD_CTX *md_ctx;
if((md_ctx = EVP_MD_CTX_new()) == NULL)
get_MAC_error();
if(1 != EVP_DigestInit_ex(md_ctx, EVP_sha256(), NULL))
get_MAC_error();
if(1 != EVP_DigestUpdate(md_ctx, message, message_len))
get_MAC_error();
if((*message_digest = (unsigned char *)OPENSSL_malloc((size_t)EVP_MD_size(EVP_sha256()))) == NULL)
get_MAC_error();
if(1 != EVP_DigestFinal_ex(md_ctx, *message_digest, message_digest_len))
get_MAC_error();
EVP_MD_CTX_free(md_ctx);
}
/* If object is found the object_handle is set */
static boolean_t
find_object_by_label(CK_SESSION_HANDLE hSession, unsigned char *label, CK_OBJECT_HANDLE *object_handle) {
CK_RV rv;
boolean_t rtnval = B_FALSE;
CK_ULONG foundCount = 0;
do
{
CK_OBJECT_HANDLE hObject = 0;
rv = C_FindObjects( hSession, &hObject, 1, &foundCount );
if (rv == CKR_OK) {
/* This will show the labels and values */
CK_ATTRIBUTE attrTemplate[] = {
{CKA_LABEL, NULL_PTR, 0}
};
rv = C_GetAttributeValue(hSession, hObject, attrTemplate, 1);
if (attrTemplate[0].ulValueLen > 0)
attrTemplate[0].pValue = (char *)malloc(attrTemplate[0].ulValueLen);
rv = C_GetAttributeValue(hSession, hObject, attrTemplate, 1);
if (attrTemplate[0].ulValueLen > 0) {
char * val = (char *)malloc(attrTemplate[0].ulValueLen + 1);
strncpy(val, (const char*)attrTemplate[0].pValue, attrTemplate[0].ulValueLen);
val[attrTemplate[0].ulValueLen] = '\0';
printf("Label is <%s>\n", val);
if (strcasecmp(val, (char *)label) == 0) rtnval = B_TRUE;
free(val);
*object_handle = hObject;
}
if (attrTemplate[0].pValue)
free(attrTemplate[0].pValue);
} else {
rtnval = B_FALSE;
printf("Error from tpm2_pkcs11 - refer https://github.com/tpm2-software/tpm2-pkcs11/blob/master/src/pkcs11.h "
"C_FindObjects failed = 0x%.8lx\n", rv);
}
} while( CKR_OK == rv && foundCount > 0 && !rtnval);
return rtnval;
}
/* The encrypted_data is a binary_data struct that will contain
the length and contents of the encrypted data */
static CK_RV encrypt(int slotNum, unsigned char *pin, unsigned char *label,
binary_data *in_data, binary_data **encrypted_data, binary_data * iv_data) {
static CK_SLOT_ID_PTR pSlotList = NULL_PTR;
static CK_SLOT_ID slotID;
CK_SESSION_HANDLE hSession;
CK_ULONG ulSlotCount = 0;
unsigned int expected_md_len = 32;
binary_data *out_data = *encrypted_data;
uint32_t i;
CK_RV rv;
CK_BYTE *data_encrypted;
CK_ULONG clear_data_length;
CK_ULONG encrypted_data_length = 0;
CK_ULONG enclen = 16;
CK_BYTE iv[iv_data->length];
CK_OBJECT_HANDLE hObject = 0;
boolean_t key_object_found;
CK_OBJECT_CLASS key_class = CKO_SECRET_KEY;
CK_KEY_TYPE key_type = CKK_AES;
CK_ATTRIBUTE attrTemplate[] = {
{CKA_CLASS, &key_class, sizeof(key_class)},
{CKA_KEY_TYPE, &key_type, sizeof(key_type)},
{CKA_LABEL, (void *)label, strlen((char*)label)}
};
if (iv_data && iv_data->length > 0 && iv_data->data) {
rv = C_Initialize(NULL_PTR);
if (rv != CKR_OK) {
printf("Error from tpm2_pkcs11 - refer https://github.com/tpm2-software/tpm2-pkcs11/blob/master/src/pkcs11.h "
"C_Initialize failed = 0x%.8lX\n", rv);
goto cleanup;
}
} else {
printf("The initializtion vector is not valid\n");
goto cleanup;
}
rv = C_GetSlotList(CK_TRUE, NULL_PTR, &ulSlotCount);
if ((rv == CKR_OK) && (ulSlotCount > 0)) {
pSlotList = (CK_SLOT_ID_PTR)malloc(ulSlotCount * sizeof (CK_SLOT_ID));
if (pSlotList == NULL) {
printf("System error: unable to allocate memory\n");
goto cleanup;
}
rv = C_GetSlotList(CK_TRUE, pSlotList, &ulSlotCount);
if (rv != CKR_OK) {
printf("Error from tpm2_pkcs11 - refer https://github.com/tpm2-software/tpm2-pkcs11/blob/master/src/pkcs11.h "
"GetSlotList failed: Unable to get slot list for processing = 0x%.8lX\n", rv);
goto cleanup;
}
} else {
printf("Error from tpm2_pkcs11 - refer https://github.com/tpm2-software/tpm2-pkcs11/blob/master/src/pkcs11.h "
"GetSlotList failed: Unable to get slot count = 0x%.8lX\n", rv);
goto cleanup;
}
for (i = 0; i < ulSlotCount; i++) {
slotID = pSlotList[i];
if (slotID == (CK_SLOT_ID)slotNum) {
CK_TOKEN_INFO token_info;
rv = C_GetTokenInfo(slotID, &token_info);
if (rv != CKR_OK) {
printf("Error from tpm2_pkcs11 - refer https://github.com/tpm2-software/tpm2-pkcs11/blob/master/src/pkcs11.h "
"C_GetTokenInfo failed = 0x%.8lX\n", rv);
goto cleanup;
}
break;
}
}
rv = C_OpenSession(slotID, CKF_SERIAL_SESSION | CKF_RW_SESSION, (CK_VOID_PTR) NULL, NULL, &hSession);
if (rv != CKR_OK) {
printf("Error from tpm2_pkcs11 - refer https://github.com/tpm2-software/tpm2-pkcs11/blob/master/src/pkcs11.h "
"C_OpenSession failed = 0x%.8lX\n", rv);
goto cleanup;
}
rv = C_Login(hSession, CKU_USER, pin, strlen((const char *)pin));
if (rv != CKR_OK) {
printf("Error from tpm2_pkcs11 - refer https://github.com/tpm2-software/tpm2-pkcs11/blob/master/src/pkcs11.h "
"C_Login failed = 0x%.8lX\n", rv);
goto cleanup;
}
rv = C_FindObjectsInit(hSession, attrTemplate, sizeof(attrTemplate)/sizeof (CK_ATTRIBUTE));
if (rv == CKR_OK) {
key_object_found = find_object_by_label(hSession, label, &hObject);
if (key_object_found == false){
printf("Error: key object not found\n");
goto cleanup;
}
rv = C_FindObjectsFinal(hSession);
if (CKR_OK != rv) {
printf("Error from tpm2_pkcs11 - refer https://github.com/tpm2-software/tpm2-pkcs11/blob/master/src/pkcs11.h "
"C_FindObjectsFinal failed = 0x%.8lX\n", rv);
goto cleanup;
}
} else {
printf("Error from tpm2_pkcs11 - refer https://github.com/tpm2-software/tpm2-pkcs11/blob/master/src/pkcs11.h "
"C_FindObjectsInit failed = 0x%.8lX\n", rv);
goto cleanup;
}
for (i=0; i < iv_data->length; i++) {
iv[i] = *((CK_BYTE *)((uint32_t*)iv_data->data + i));
}
CK_MECHANISM mechanism = {CKM_AES_CBC, iv, sizeof(iv)};
clear_data_length = (CK_ULONG)in_data->length;
/* The data to encrypt must be a multiple of 16, required for AES to work */
if (clear_data_length % 16) {
clear_data_length += 16 - (clear_data_length % 16);
}
/* Add 16 bytes because encrypt final does not accept the data bytes */
clear_data_length +=16;
CK_BYTE_PTR ptr_clear_data;
ptr_clear_data = (CK_BYTE *)(malloc(clear_data_length * sizeof(CK_BYTE)));
memset(ptr_clear_data, 0, clear_data_length);
/* Copy the data into the bytes that will be encrypted */
memcpy(ptr_clear_data, (CK_BYTE *)(in_data->data), (size_t)in_data->length);
rv = C_EncryptInit(hSession, &mechanism, hObject);
if (CKR_OK != rv) {
printf("Error from tpm2_pkcs11 - refer https://github.com/tpm2-software/tpm2-pkcs11/blob/master/src/pkcs11.h "
"C_EncryptInit failed = 0x%.8lX\n", rv);
goto cleanup;
}
/* For AES expect the encrypted size to be the same size as the clear data */
encrypted_data_length = clear_data_length;
data_encrypted = (CK_BYTE *)malloc(encrypted_data_length * sizeof(CK_BYTE));
memset(data_encrypted, 0, encrypted_data_length);
/* Keep track of how many parts have been encrypted */
int part_number = 0;
while (rv == CKR_OK && part_number * 16 < (int)encrypted_data_length - 16) {
rv = C_EncryptUpdate(hSession, ptr_clear_data + part_number * 16,
16, &data_encrypted[part_number*16], &enclen);
if (CKR_OK != rv) {
printf("Error from tpm2_pkcs11 - refer https://github.com/tpm2-software/tpm2-pkcs11/blob/master/src/pkcs11.h "
"C_Encryptupdate failed = 0x%.8lX\n", rv);
goto cleanup;
}
part_number++;
}
C_EncryptFinal(hSession, &data_encrypted[part_number *16 ], &enclen);
if (CKR_OK != rv) {
printf("Error from tpm2_pkcs11 - refer https://github.com/tpm2-software/tpm2-pkcs11/blob/master/src/pkcs11.h "
"C_EncryptFinal failed = 0x%.8lX\n", rv);
goto cleanup;
}
/* Add 56 more bytes. 16 bytes will hold the iv
The next 8 bytes will be an unsigned long (uint64_t) that indicates the original data length
The last 32 bytes are for the HMAC */
long out_data_length = (long)(encrypted_data_length + (long unsigned int)iv_data->length + sizeof(uint64_t) + expected_md_len);
if (out_data->data) {
free(out_data->data);
out_data->length = 0;
}
out_data->data = (void *)malloc((size_t)out_data_length);
out_data->length = out_data_length;
uint8_t * ptr_out_data = (uint8_t *)(out_data->data);
memset(ptr_out_data, 255, (size_t)out_data_length);
/* Copy the encrypted bytes, leaving the last 56 bytes alone */
memcpy(out_data->data, data_encrypted, encrypted_data_length);
/* Copy the iv into the bytes after the encrypted data */
for (i=0; i < iv_data->length; i++) {
memcpy((uint64_t *)(ptr_out_data + encrypted_data_length +i), &iv[i], 1);
}
/* In the next 8 bytes, write the original input data length
before it was forced to be a multiple of 16
This is so decrypt can know how much clear data there was */
*((uint64_t *)(ptr_out_data + out_data_length - sizeof(uint64_t) - expected_md_len)) = (uint64_t)in_data->length;
/* Calculate the HMAC of the output */
unsigned char *md_value;
unsigned int md_len;
/* Append the HMAC */
get_MAC(ptr_out_data, (size_t)out_data_length - expected_md_len, &md_value, &md_len);
for (i=0; i < md_len; i++) {
memcpy((uint64_t *)(ptr_out_data + out_data_length - expected_md_len + i), &md_value[i], 1);
}
if(md_value) OPENSSL_free(md_value);
C_Logout(hSession);
C_CloseSession(hSession);
C_Finalize(NULL);
cleanup:
if (pSlotList)
free(pSlotList);
if (ptr_clear_data)
free(ptr_clear_data);
if (data_encrypted)
free(data_encrypted);
return rv;
}
static binary_data* read_input_file(const char * filename) {
binary_data *data = (binary_data*)malloc(sizeof(binary_data));
if (data != NULL) {
data->length = 0;
void *buff = NULL;
long end_position;
/* Open the file for reading in binary mode */
FILE *f_in = fopen(filename, "rb");
if (f_in != NULL) {
/* Go to the end of the file */
const int seek_end_value = fseek(f_in, 0, SEEK_END);
if (seek_end_value != -1) {
/* Get the position in the file (in bytes). This is the length. */
end_position = ftell(f_in);
if (end_position != -1) {
/* Go back to the beginning of the file */
const int seek_start_value = fseek(f_in, 0, SEEK_SET);
if (seek_start_value != -1) {
/* Allocate enough space to read the whole file */
buff = (void*)malloc((size_t)end_position);
if (buff != NULL) {
/* Read the whole file to buffer */
const long length = (const long)fread(buff, 1, (size_t)end_position, f_in);
if (length == end_position) {
data->length = end_position;
data->data = buff;
fclose(f_in);
return data;
}
free(buff);
}
}
}
}
fclose(f_in);
}
free(data);
}
return NULL;
}
static boolean_t write_output_file(const char * filename, binary_data* data) {
boolean_t rv = B_FALSE;
if (data && data->length > 0 && data->data) {
FILE * f_out = fopen(filename, "wb");
size_t num_to_write = (size_t)data->length;
if (f_out) {
size_t num_written = fwrite(data->data, sizeof(uint8_t), num_to_write, f_out);
if (num_written == (size_t)data->length) {
rv = B_TRUE;
} else {
printf("fwrite() failed: wrote only %zu out of %zu elements.\n",
num_written, data->length);
}
fclose(f_out);
}
}
return rv;
}
static void process_command_line(int argc, char** argv, unsigned char** slot, unsigned char** pin,
unsigned char** label, unsigned char** in_file, unsigned char** out_file) {
int i;
unsigned char *slotptr = NULL;
unsigned char *pinptr = NULL;
unsigned char *labelptr = NULL;
unsigned char *in_fileptr = NULL;
unsigned char *out_fileptr = NULL;
for(i=1;i<argc;i++)
{
if(argv[i][0] == '-')
{
switch(argv[i][1])
{
case 's' :
if (*slot) free(*slot);
slotptr = (unsigned char*)argv[i] + 2;
*slot = (unsigned char *)malloc(strlen((const char*)slotptr) + 1);
(*slot)[strlen((const char*)slotptr)] = '\0';
strcpy((char*)*slot, (const char*)slotptr);
break;
case 'p' :
if (*pin) free(*pin);
pinptr = (unsigned char*)argv[i] + 2;
*pin = (unsigned char *)malloc(strlen((const char*)pinptr) + 1);
(*pin)[strlen((const char*)pinptr)] = '\0';
strcpy((char*)*pin, (const char*)pinptr);
break;
case 'l' :
if (*label) free(*label);
labelptr = (unsigned char*)argv[i] + 2;
*label = (unsigned char *)malloc(strlen((const char*)labelptr) + 1);
(*label)[strlen((const char*)labelptr)] = '\0';
strcpy((char*)*label, (const char*)labelptr);
break;
case 'f' :
if (*in_file) free(*in_file);
in_fileptr = (unsigned char*)argv[i] + 2;
*in_file = (unsigned char *)malloc(strlen((const char*)in_fileptr) + 1);
(*in_file)[strlen((const char*)in_fileptr)] = '\0';
strcpy((char*)*in_file, (const char*)in_fileptr);
break;
case 'o' :
if (*out_file) free(*out_file);
out_fileptr = (unsigned char*)argv[i] + 2;
*out_file = (unsigned char *)malloc(strlen((const char*)out_fileptr) + 1);
(*out_file)[strlen((const char*)out_fileptr)] = '\0';
strcpy((char*)*out_file, (const char*)out_fileptr);
break;
case 'h' :
break;
default :
printf("Unknown option %s\n",argv[i]);
}
} else {
printf("Unknown option %s\n",argv[i]);
}
}
}
/*
* **Usage function**
* The usage function gives the information to run the application.
* ./cert_encrypt_tpm -s<slotNo.> -p<pin> -l<key_lable> -f<input_file> -o<output_file>
* For more options, use ./cert_encrypt_tpm --help
*/
void usage(void)
{
printf("The slot number must be provided using the -s parameter\n"
"The pin for the token must be provided using the -p parameter\n"
"A label for the key object must be provided using the -l parameter\n"
"A file that contains the data to be encrypted must be provided using the -f parameter\n"
"A file to write the encrypted data must be provided using the -o parameter\n");
}
int main(int argc, char** argv)
{
unsigned char *slot = (unsigned char *)malloc(1);
slot[0] = '\0';
unsigned char *pin = (unsigned char *)malloc(1);
pin[0] = '\0';
unsigned char *label = (unsigned char *)malloc(1);
label[0] = '\0';
unsigned char *in_file = (unsigned char *)malloc(1);
in_file[0] = '\0';
unsigned char *out_file = (unsigned char *)malloc(1);
out_file[0] = '\0';
int slotNum = 0;
binary_data *in_data = NULL;
binary_data *out_data = NULL;
binary_data *iv_data = NULL;
unsigned char iv[] = {5, 9, 3, 6, 21, 0, 21, 4, 7, 42, 9, 2, 1, 8, 17, 16};
CK_RV rv = CKR_OK;
if((argc == 2) && (strcmp(argv[1], "--help") == 0 || strcmp(argv[1], "-h")) == 0)
{
usage();
return 0;
}
process_command_line(argc, argv, &slot, &pin, &label, &in_file, &out_file);
printf("\n");
if (slot[0] != '\0') {
slotNum = atoi((const char*)slot);
} else {
usage();
return 0;
}
if (pin[0] == '\0' || label[0] == '\0' || in_file[0] == '\0' || out_file[0] == '\0') {
usage();
return 0;
}
/* Put iv array in a struct that has data and length */
iv_data = (binary_data *)malloc(sizeof(binary_data));
iv_data->length = sizeof(iv);
iv_data->data = malloc(sizeof(iv));
for (unsigned long i=0; i < sizeof(iv); i++) {
*((unsigned char *)((unsigned long)iv_data->data + i)) = iv[i];
}
if (slotNum > 0 && pin[0] != '\0' && label[0] != '\0'
&& in_file[0] != '\0' && out_file[0] != '\0') {
boolean_t rv_write_file = B_FALSE;
/* Get the data from the input file. This data will be encrypted */
in_data = read_input_file((const char*)in_file);
out_data = (binary_data *)malloc(sizeof(binary_data));
out_data->length = 0;
out_data->data = NULL;
rv = encrypt(slotNum, pin, label, in_data, &out_data, iv_data);
if (rv != CKR_OK){
printf("Encryption failed\n");
}
if (out_data && out_data->data && out_data->length > 0) {
/* Write the encrypted data to the output file */
rv_write_file = write_output_file((const char*)out_file, out_data);
}
if (!rv_write_file) {
printf("%s\n", "Failed to write to output file");
}
}
if (slot) free(slot);
if (pin) free(pin);
if (label) free(label);
if (in_file) free(in_file);
if (out_file) free(out_file);
if (in_data) {
if (in_data->data) free(in_data->data);
free(in_data);
}
if (out_data) {
if (out_data->data) free(out_data->data);
free(out_data);
}
if (iv_data) {
if (iv_data->data) free(iv_data->data);
free(iv_data);
}
return 0;
}