Unable to use OpenSSL methods

Dear All,
I have been working on the development of Trusted Applications on Trusty TEE (using Jetson AGX Xavier). I am extending the basic functionalities of crypto-service from Hwkey-agent to generate asymmetrical keys, encrypt and decrypt ciphers using those keys. But, I am unable to get the project compiled correctly.

I have tried different implementations to get to the bottom of the errors.

Using PEM Format:

...
#include <openssl/bn.h>
#include <openssl/pem.h>
#include <openssl/ssl.h>
#include <openssl/rsa.h>
#include <openssl/evp.h>
#include <openssl/bio.h>
#include <openssl/err.h>

static int padding = RSA_PKCS1_PADDING;
static RSA *createRSA(unsigned char *key, int public)
{
    RSA *rsa = NULL;
    BIO *keybio;
    keybio = BIO_new_mem_buf(key, -1);
    if (keybio == NULL)
    {
        TLOGE("Failed to create key BIO");
        return 0;
    }
    if (public)
    {
        rsa = PEM_read_bio_RSA_PUBKEY(keybio, &rsa, NULL, NULL);
    }
    else
    {
        rsa = PEM_read_bio_RSAPrivateKey(keybio, &rsa, NULL, NULL);
    }
    if (rsa == NULL)
    {
        TLOGE("Failed to create RSA");
    }

    return rsa;
}

static int public_encrypt(unsigned char *data, int data_len, unsigned char *key, unsigned char *encrypted)
{
    RSA *rsa = createRSA(key, 1);
    int result = RSA_public_encrypt(data_len, data, encrypted, rsa, padding);
    return result;
}
static int private_decrypt(unsigned char *enc_data, int data_len, unsigned char *key, unsigned char *decrypted)
{
    RSA *rsa = createRSA(key, 0);
    int result = RSA_private_decrypt(data_len, enc_data, decrypted, rsa, padding);
    return result;
}

static int private_encrypt(unsigned char *data, int data_len, unsigned char *key, unsigned char *encrypted)
{
    RSA *rsa = createRSA(key, 0);
    int result = RSA_private_encrypt(data_len, data, encrypted, rsa, padding);
    return result;
}
static int public_decrypt(unsigned char *enc_data, int data_len, unsigned char *key, unsigned char *decrypted)
{
    RSA *rsa = createRSA(key, 1);
    int result = RSA_public_decrypt(data_len, enc_data, decrypted, rsa, padding);
    return result;
}

static void printLastError(char *msg)
{
    TLOGE("%s ERROR:\n", msg);
}

static int testing_openssl(void)
{
    char plainText[2048 / 8] = "Hello this is a test"; //key length : 2048
    char publicKey[] = "-----BEGIN PUBLIC KEY-----\n"
                       "...."
                       "-----END PUBLIC KEY-----\n";

    char privateKey[] = "-----BEGIN RSA PRIVATE KEY-----\n"
                       " ...."
                        "-----END RSA PRIVATE KEY-----\n";

    unsigned char encrypted[4098] = {};
    unsigned char decrypted[4098] = {};

    int encrypted_length = public_encrypt(plainText, strlen(plainText), publicKey, encrypted);
    if (encrypted_length == -1)
    {
        printLastError("Public Encrypt failed ");
        return 0;
    }
    TLOGE("Encrypted length =%d\n", encrypted_length);

    int decrypted_length = private_decrypt(encrypted, encrypted_length, privateKey, decrypted);
    if (decrypted_length == -1)
    {
        printLastError("Private Decrypt failed ");
        return 0;
    }
    TLOGE("Decrypted Text =%s\n", decrypted);
    TLOGE("Decrypted Length =%d\n", decrypted_length);

    encrypted_length = private_encrypt(plainText, strlen(plainText), privateKey, encrypted);
    if (encrypted_length == -1)
    {
        printLastError("Private Encrypt failed");
        return 0;
    }
    TLOGE("Encrypted length =%d\n", encrypted_length);

    decrypted_length = public_decrypt(encrypted, encrypted_length, publicKey, decrypted);
    if (decrypted_length == -1)
    {
        printLastError("Public Decrypt failed");
        return 0;
    }
    TLOGE("Decrypted Text =%s\n", decrypted);
    TLOGE("Decrypted Length =%d\n", decrypted_length);
}
void crypto_srv_process_req(iovec_t *ipc_msg, int len)
{
	crypto_srv_msg_t *msg = ipc_msg[0].base;
	uint8_t *payload = ipc_msg[1].base;
	int payload_len = msg->payload_len;
	uint8_t *data = NULL;
	uint8_t *key_in_ekb;
	AES_KEY aes_key;
	int aes_enc_flag;
	int idx;
	uint8_t* info;
	int test;
	test = testing_openssl();

	
	info = get_root_key();
	key_in_ekb = ekb_get_key(EKB_USER_KEY_DISK_ENCRYPTION);
	if (key_in_ekb == NULL) {
		TLOGE("%s: get key in ekb failed\n", __func__);
		return;
	}

	data = malloc(CRYPTO_SRV_PAYLOAD_SIZE);
	if (data == NULL) {
		TLOGE("%s: malloc failed\n", __func__);
		return;
	}
	memcpy(data, payload, payload_len);
	memcpy(msg->root_key, info, 8*16);
	if (msg->cmd == CRYPTO_SRV_CMD_ENCRYPT) {
		AES_set_encrypt_key(key_in_ekb, AES_KEY_128_SIZE * 8, &aes_key);
		aes_enc_flag = AES_ENCRYPT;
	} else {
		AES_set_decrypt_key(key_in_ekb, AES_KEY_128_SIZE * 8, &aes_key);
		aes_enc_flag = AES_DECRYPT;
	}

	for (idx = 0; idx < payload_len; idx += AES_BLOCK_SIZE)
		AES_cbc_encrypt(data + idx, payload + idx, AES_BLOCK_SIZE,
				&aes_key, msg->iv, aes_enc_flag);

	free(data);
}

While compiling this code I get an error related to undefined reference to the gettid method.

linking t194ref/build-t186/user_tasks/nvidia-sample/hwkey-agent/hwkey-agent.syms.elf
/home/lgiori/l4t-gcc/gcc-linaro-7.3.1-2018.05-x86_64_arm-linux-gnueabihf/bin/arm-linux-gnueabihf-ld.bfd: warning: section `.bss' type changed to PROGBITS
./t194ref/build-t186/user_tasks/nvidia-sample/hwkey-agent/lib/lib/openssl-stubs.mod.o: In function `rand_pool_add_nonce_data':
/trusty/trusty/trusty/lib/lib/openssl-stubs/rand.c:88: undefined reference to `gettid'
make/xbin.mk:149: recipe for target 't194ref/build-t186/user_tasks/nvidia-sample/hwkey-agent/hwkey-agent.syms.elf' failed
make[2]: *** [t194ref/build-t186/user_tasks/nvidia-sample/hwkey-agent/hwkey-agent.syms.elf] Error 1
make[2]: Leaving directory '/home/lgiori/l4t-gcc/Linux_for_Tegra/source/public/atf_and_trusty/trusty/trusty'
lk/common/engine.mk:28: recipe for target 'make-make' failed
make[1]: *** [make-make] Error 2
make[1]: Leaving directory '/home/lgiori/l4t-gcc/Linux_for_Tegra/source/public/atf_and_trusty/trusty/trusty'
makefile:27: recipe for target 't186' failed
make: *** [t186] Error 2
Generating Trusted OS Partition Image File
Generate TOS Image File for boot-wrapper.

While looking for a solution inside the forum. I stumbled upon this thread that proposed a solution using DER format keys. So I implemented the steps mentioned in the solution.

Using DER Format:

static int enc_d2i(void)
{
    RSA *rsa;
    char plainText[2048 / 8] = "Hello this is a test";
    unsigned char encrypted[4098] = {};
    const unsigned char *private_key[594] = {...}; // loading DER key in hex format from hexdump
    EVP_PKEY *prvKey = EVP_PKEY_new();
    prvKey = d2i_PrivateKey(EVP_PKEY_RSA, prvKey, *private_key, sizeof(private_key));
    rsa = EVP_PKEY_get1_RSA(prvKey);
    int result = RSA_private_encrypt(sizeof(plainText), (const unsigned char *)plainText, encrypted, rsa, padding);
    return result;

}
void crypto_srv_process_req(iovec_t *ipc_msg, int len)
{
	....
	int test;
	test = enc_d2i();
	....

I still face the same error as before.

Some investigations:

    - gettid()

I did try some solutions to the reference to gettid() by redefining the method instead of the extern pid_t gettid().

#include<sys/syscall.h>
pid_t gettid() { return syscall(SYS_gettid); }

#include <linux/unistd.h>
pid_t gettid(void){ return syscall(__NR_gettid); }

But this only created other dependency issues and functions override.

    - Which function uses gettid?

After isolation parts of the code it seems that d2i_PrivateKey is the own that spawns the error with gettid. I tried to look for substitutes for it but I couldn’t.

Questions:
Is there any solution to this issue?
Are there any known implementations to OpenSSL with rsa keys manipulations?

I have been stuck for a almost a week now and I would be grateful if you can help me solving this issue so I can continue on with my project.
Thank you in advance for your help!

hello n3k0m4,

for your reference,
please check below for the steps to install necessary packages,

(1) Please enable deb-src in /etc/apt/source.llist. then execute, $ sudo apt-get update
(2) Install build packages, so we can rebuild the OpenSSL deb package, for example, to enable native AF_ALG support.

$ mkdir openssl-build
$ cd openssl-build
$ sudo apt-get install build-essential pkg-config ubuntu-dev-tools debhelper
$ sudo apt-get build-dep openssl
$ apt-get source openssl
$ cd openssl-1.1.1
$ sed -i "s/CONFARGS  =/CONFARGS  = enable-engine enable-dso enable-afalgeng/" debian/rules
$ dch -i "Enabled AF_ALG support"
$ debuild
$ cd ..
$ sudo dpkg -i ./*.deb

Hello JerryChang,
I would like to thank you for your quick reply.
The errors I am getting are in the host machine that compiles the TAs and then flash the board. So I followed the snippet of code you wrote and installed the OpenSSL. But, I still have the same issue while compiling (Undefined reference to gettid() method).
Should I install those inside of the board too and try again? Could you also, if possible, explain to me how will this AF_ALG support help get trough the problem?
Thanks again.

The above might actually be correct since you are inside of the bootloader (which 32-bit might apply to), but I would be certain that if you are cross-compiling, then be certain that you are using the correct tool version and target architecture. I admit I have not compiled bootloader code in a long time, so perhaps that part is still 32-bit.

hello n3k0m4,

please share the details steps to reproduce this cross-compile failure.
thanks

Hello JerryChang,
Thank you for your quick reply.
The snippets of code are added inside hwkey-agent/crypto_service.c .
Concerning the compilation, I am using this script:

export CROSS_COMPILE=/home/lgiori/l4t-gcc/gcc-linaro-7.3.1-2018.05-x86_64_aarch64-linux-gnu/bin/aarch64-linux-gnu-
export CROSS_COMPILE_AARCH64=/home/lgiori/l4t-gcc/gcc-linaro-7.3.1-2018.05-x86_64_aarch64-linux-gnu/bin/aarch64-linux-gnu-
export CROSS_COMPILE_ARM=/home/lgiori/l4t-gcc/gcc-linaro-7.3.1-2018.05-x86_64_arm-linux-gnueabihf/bin/arm-linux-gnueabihf-

## Compile ATF and TOS
cd /trusty/atf/arm-trusted-firmware
make BUILD_BASE=./t194ref CROSS_COMPILE="${CROSS_COMPILE_AARCH64}" DEBUG=0 LOG_LEVEL=20 PLAT=tegra SPD=trusty TARGET_SOC=t194 V=0

cd /trusty/trusty/trusty
make t186 PROJECT=t186 TARGET=t186 BUILDROOT=./t194ref TOOLCHAIN_PREFIX="${CROSS_COMPILE_AARCH64}" ARCH_arm_TOOLCHAIN_PREFIX="${CROSS_COMPILE_ARM}" ARCH_arm64_TOOLCHAIN_PREFIX="${CROSS_COMPILE_AARCH64}" DEBUG=1 DEBUG_LVL=0 DEFAULT_OTE_APP_DEBUGLEVEL=1 NOECHO=@ TRUSTY_VARIANT=l4t-public TRUSTY_MULTI_GUEST_CONFIGURATION= TARGET_SOC=t194

## Copy Generate files into
cp /trusty/atf/arm-trusted-firmware/t194ref/tegra/t194/release/bl31.bin /home/lgiori/l4t-gcc/Linux_for_Tegra/nv_tegra/tos-scripts
cp /trusty/trusty/trusty/t194ref/build-t186/lk.bin /home/lgiori/l4t-gcc/Linux_for_Tegra/nv_tegra/tos-scripts

## Generate TOS image
cd /home/lgiori/l4t-gcc/Linux_for_Tegra/nv_tegra/tos-scripts
./gen_tos_part_img.py --monitor bl31.bin --os lk.bin tos_t194.img
## Replace the TOS image
cp tos_t194.img /home/lgiori/l4t-gcc/Linux_for_Tegra/bootloader/

## Place XAVIER in recovery mode
echo "==================================================="
echo "Place XAVIER in recovery mode AND "
echo cd /home/lgiori/l4t-gcc/Linux_for_Tegra/
echo sudo ./flash.sh -k secure-os jetson-xavier mmcblk0p1
echo "==================================================="

Please let me know if this is enough to reproduce the issue.
I am happy to provide more details if needed.
Thanks,

thanks, please also let us know which version of L4T source releases you’re using.

I remember having the latest version pulled from the Jetson Download center. Could please tell me how to get the version so we can be sure ?

here’s the latest public sources, see 32.6.1 Driver Details.

I actually have the 32.5.1 version.

could you please moving to the latest release for confirmation, thanks

I am using sdkmanager to update the versions I am using. It might take a few minutes.
Once everything is done I will test the compilation and get back to you.
Thanks

Hello JerryChang,
I have updated the versions using the sdkmanager. I have also tried to compile the TAs but got the same error about undefined reference to gettid().
Thanks for waiting on my reply.

hello n3k0m4,

this failed to call gettid() while requesting it as part of seed for random. the failure is caused by gettid() not available in Trusty.
hence, please check you’re using the latest Trusty sources, it’s now use current time stamp to seed random for openssl.
for example,
$L4T_Sources/r32.6.1/Linux_for_Tegra/source/public/atf_and_trusty/trusty/lib/lib/openssl-stubs/rand.c

int rand_pool_add_nonce_data(RAND_POOL *pool)
{
    struct {
        uint64_t time;
    } rinfo;;

    /*
     * Add a high resolution timestamp to
     * ensure that the nonce is unique with high probability for
     * different process instances.
     */
    (void)gettime(1, 1, &rinfo.time);

    return rand_pool_add(pool, (unsigned char *)&rinfo, sizeof(rinfo), 0);
}

Hello JerryChang,
Thanks for your reply. I am actually confused because from sdkmanager it seems that I installed Jetpack 4.6 which includes the latest version of l4t but I still get the error.
Is it possible to show me how can I upgrade the l4t version manually (what are the archives I need to download and how to install them).
This is the old script I wrote to get the everything set up manually without sdkmanager. It would be helpful if you can point to me what I need to modify.

## Checking for the existing files
#xavier_dir=$(find / -name xavier-framework 2>/dev/null)
if [ -z $(find / -name xavier-framework 2>/dev/null) ];
    then
    ## Export a base folder for installation
    echo "====================================="
    echo "[*] CREATE BASE FOLDER"
    echo "====================================="
    export XAVIER=$HOME/xavier-framework
    mkdir -p $XAVIER
fi
export XAVIER=$HOME/xavier-framework
if [ ! -d $XAVIER/l4t-gcc ];
    then
        cd $XAVIER
        mkdir l4t-gcc
fi
if [ $(ls $XAVIER/l4t-gcc | grep gcc-linaro*.tar.xz | wc -l) -lt 2 ];
    then
        if [ ! -d $XAVIER/l4t-gcc/gcc-linaro-7.3.1-2018.05-x86_64_aarch64-linux-gnu ] && [ ! -d $XAVIER/l4t-gcc/gcc-linaro-7.3.1-2018.05-x86_64_arm-linux-gnueabihf ];
            then
                ## Get ARCH64 and ARM Cross Compiler
                echo "====================================="
                echo "[*] INSTALL CROSS COMPILER"
                echo "====================================="
                cd $XAVIER/l4t-gcc
                rm -rf gcc-linaro*;
                wget http://releases.linaro.org/components/toolchain/binaries/7.3-2018.05/arm-linux-gnueabihf/gcc-linaro-7.3.1-2018.05-x86_64_arm-linux-gnueabihf.tar.xz
                wget http://releases.linaro.org/components/toolchain/binaries/7.3-2018.05/aarch64-linux-gnu/gcc-linaro-7.3.1-2018.05-x86_64_aarch64-linux-gnu.tar.xz
                echo "====================================="
                echo "[*] PLEASE WAIT WHILE INSTALLING CROSS COMPILER"
                echo "====================================="
                tar xf gcc-linaro-7.3.1-2018.05-x86_64_aarch64-linux-gnu.tar.xz
                tar xf gcc-linaro-7.3.1-2018.05-x86_64_arm-linux-gnueabihf.tar.xz
                rm *.xz
                cd $XAVIER
        fi
            ## Export 
            echo "====================================="
            echo "[*] CONFIGURE CROSS COMPILER"
            echo "====================================="
            export CROSS_COMPILE=$XAVIER/l4t-gcc/gcc-linaro-7.3.1-2018.05-x86_64_aarch64-linux-gnu/bin/aarch64-linux-gnu-
            export CROSS_COMPILE_AARCH64=$XAVIER/l4t-gcc/gcc-linaro-7.3.1-2018.05-x86_64_aarch64-linux-gnu/bin/aarch64-linux-gnu-
            export CROSS_COMPILE_ARM=$XAVIER/l4t-gcc/gcc-linaro-7.3.1-2018.05-x86_64_arm-linux-gnueabihf/bin/arm-linux-gnueabihf-

fi
        


## Get BPS Public Sources 
echo "====================================="
echo "[*] INSTALL XAVIER JESTON PUBLIC SOURCES"
echo "====================================="

if [ ! -d $XAVIER/Linux_for_Tegra ];
    then 
        if [ ! -e $XAVIER/public_sources.tbz2 ];
            then
                #wget https://developer.nvidia.com/embedded/l4t/r32_release_v5.1/r32_release_v5.1/t186/tegra186_linux_r32.5.1_aarch64.tbz2
                wget https://developer.nvidia.com/embedded/l4t/r32_release_v5.1/r32_release_v5.1/sources/t186/public_sources.tbz2
        fi
        tar xf *.tbz2
        rm *.tbz2

        cd $XAVIER/Linux_for_Tegra/source/public
        tar xf atf_src.tbz2
        mkdir atf_and_trusty
        mkdir atf_and_trusty/atf
        mkdir atf_and_trusty/trusty
        tar xpf atf_src.tbz2 -C atf_and_trusty/atf/
        tar xpf trusty_src.tbz2 -C atf_and_trusty/trusty/
fi



## Compile ATF and TOS
echo "====================================="
echo "[*] CROSS COMPILE ATF AND TRUSTY"
echo "====================================="

export Trusty=$XAVIER/Linux_for_Tegra/source/public/atf_and_trusty/trusty/trusty
export Arm_firm=$XAVIER/Linux_for_Tegra/source/public/atf_and_trusty/atf/arm-trusted-firmware

cd $Arm_firm
make BUILD_BASE=./t194ref CROSS_COMPILE="${CROSS_COMPILE_AARCH64}" DEBUG=0 LOG_LEVEL=20 PLAT=tegra SPD=trusty TARGET_SOC=t194 V=0

cd $Trusty
make t186 PROJECT=t186 TARGET=t186 BUILDROOT=./t194ref TOOLCHAIN_PREFIX="${CROSS_COMPILE_AARCH64}" ARCH_arm_TOOLCHAIN_PREFIX="${CROSS_COMPILE_ARM}" ARCH_arm64_TOOLCHAIN_PREFIX="${CROSS_COMPILE_AARCH64}" DEBUG=0 DEBUG_LVL=0 DEFAULT_OTE_APP_DEBUGLEVEL=1 NOECHO=@ TRUSTY_VARIANT=l4t-public TRUSTY_MULTI_GUEST_CONFIGURATION= TARGET_SOC=t194



cd $Trusty
if [ ! -d  "output" ];
    then
        mkdir output
fi
rm -rf $Trusty/output/*
cp $Trusty/t194ref/build-t186/lk.bin $Trusty/output
cp $Arm_firm/t194ref/tegra/t194/release/bl31.bin $Trusty/output

echo "====================================="
echo "[*] FLASH "
echo "====================================="

Thanks you,

please refer to JetPack Archive | NVIDIA Developer for the public sources of each JetPack release.
so, the linkage to the public_sources.tbz2 should be .../l4t/r32_release_v6.1/sources/t186/public_sources.tbz2

Hello JerryChang,
I updated the version and the compilation issue is solved but now I am facing another problem where all custom application I created are not working…
Example:
The test application containing OpenSSL key generation (Port: hwkey-agentt.srv.crypto) gives this when I try to run it.
tipc_connect: can’t connect to tipc service “hwkey-agentt.srv.crypto” (err=107)

It is the same for all the other applications that I developed. They were working before and now return the same err=107

NB: The projects are added in the t186-l4t.mk and no errors in the compilation.
Also, I have faced this issue before and found no solution but when I flashed the board from 0 using sdkmanager it worked

hello n3k0m4,

could you please share bootloader logs, we would like to check those BL31 logs for reference,
thanks

Hello,
Here are the logs pulled from the UART console about BL31:

TICE:  BL31: v1.3(release):
NOTICE:  BL31: Built : 10:28:59, Aug 17 2021
initializing trusty (Built: 11:50:46 Aug 17 2021 )
Initializing Trusted OS SMC handler
ipc-unittest-main: 1519: Welcome to IPC unittest!!!
ipc-unittest-main: 1531: waiting forever
ipc-unittest-srv: 329: Init unittest services!!!
hwkey-agent: 41: hwkey-agent is running!!
hwkey-agent: 315: key_mgnt_processing .......
hwkey-agent: 162: ekb_verification: EKB_CMAC verification is not match.
hwkey-agent: 368: key_mgnt_processing: failed (-7)
hwkey-agent: 45: main: Failed to verify or extract EKB (-7).
exit called, thread 0xffffffffea8f2d58, name trusty_app_2_92b92883-f96a-4177
luks-srv: 40: luks-srv is running!!
hwkey-agent: 40: hwkey-agent is running!!
hwkey-agent: 232: key_mgnt_processing .......
hwkey-agent: 263: ssk_dk_copy 186 ssk_dk_copy 136
ioctl_map_eks_to_user: ERROR: ioctl called more than once
hwkey-agent: 92: get_ekb: failed to map EKB memory (-17)
hwkey-agent: 139: ekb_verification: failed to get EKB (-1). Exiting
hwkey-agent: 277: key_mgnt_processing: failed (-1)
hwkey-agent: 45: main: Failed to verify or extract EKB (-1).
exit called, thread 0xffffffffea907228, name trusty_app_4_92b92883-f96a-4177
Hello World 1
HelloWorld: 41: Hello World 1 is running!!
HelloWorld: 160: Init helloworld-srv IPC services!!
Data Provider Service
Data-provider: 41: Data Provider is running!!
Data-provider: 168: Init helloworld-srv IPC services!!
HelloWorld: 21: HelloWorld-SRV: CONNECTED!.
HelloWorld: 51: The end of Get_data()!!
Data-provider: 38: Data from Data Provider 65

This is the first time I get the error from hwkey-agent.
Thanks,

hello n3k0m4,

there’s verification failure.

since it’s Trusty uses the Encrypted Keyblob (EKB) mechanism to provision keys and other confidential data.
did you create an Encrypted Binary Blob (EKB) file by the EKB generation tool, and also update the EKB partition?
please refer to Tool for EKB Generation for using python script, gen_ekb.py. thanks