Skip to content

Commit 74d9f71

Browse files
authored
Merge pull request #398 from tropicsquare/ETR01SDK-337-Add-openssl-crypto-backend
ETR01SDK-337: Add OpenSSL crypto backend
2 parents 293d022 + 100d132 commit 74d9f71

File tree

15 files changed

+683
-1
lines changed

15 files changed

+683
-1
lines changed

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
2424
- ESP-IDF HAL for Espressif SoCs.
2525
- Missing secure memory zeroing to `lt_in__session_start()` and `lt_hkdf()` (internal function).
2626
- Missing check of `lt_handle_t.l3.session_status` in `lt_in__ecc_key_generate()`.
27+
- CAL: support for OpenSSL.
2728

2829
### Fixed
2930
- `lt_print_bytes` function now returns `LT_PARAM_ERR` when incorrect parameters are passed instead of `LT_FAIL`.

cal/openssl/CMakeLists.txt

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
cmake_minimum_required(VERSION 3.21.0)
2+
3+
set(LT_CAL_SRCS
4+
${CMAKE_CURRENT_SOURCE_DIR}/lt_openssl_common.c
5+
${CMAKE_CURRENT_SOURCE_DIR}/lt_openssl_aesgcm.c
6+
${CMAKE_CURRENT_SOURCE_DIR}/lt_openssl_sha256.c
7+
${CMAKE_CURRENT_SOURCE_DIR}/lt_openssl_hmac_sha256.c
8+
${CMAKE_CURRENT_SOURCE_DIR}/lt_openssl_x25519.c
9+
)
10+
11+
set(LT_CAL_INC_DIRS
12+
${CMAKE_CURRENT_SOURCE_DIR}
13+
)
14+
15+
# export generic names for parent to consume
16+
set(LT_CAL_SRCS ${LT_CAL_SRCS} PARENT_SCOPE)
17+
set(LT_CAL_INC_DIRS ${LT_CAL_INC_DIRS} PARENT_SCOPE)

cal/openssl/libtropic_openssl.h

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
#ifndef LT_OPENSSL_H
2+
#define LT_OPENSSL_H
3+
4+
/**
5+
* @file lt_openssl.h
6+
* @brief OpenSSL public declarations.
7+
* @copyright Copyright (c) 2020-2025 Tropic Square s.r.o.
8+
*
9+
* @license For the license see LICENSE.md in the root directory of this source tree.
10+
*/
11+
12+
#include <openssl/evp.h>
13+
14+
/**
15+
* @brief Context structure for OpenSSL.
16+
*
17+
*/
18+
typedef struct lt_ctx_openssl_t {
19+
/** @private @brief AES-GCM context for encryption. */
20+
EVP_CIPHER_CTX *aesgcm_encrypt_ctx;
21+
/** @private @brief AES-GCM context for decryption. */
22+
EVP_CIPHER_CTX *aesgcm_decrypt_ctx;
23+
/** @private @brief SHA-256 context. */
24+
EVP_MD_CTX *sha256_ctx;
25+
} lt_ctx_openssl_t;
26+
27+
#endif // LT_OPENSSL_H

cal/openssl/lt_openssl_aesgcm.c

Lines changed: 259 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,259 @@
1+
/**
2+
* @file lt_openssl_aesgcm.c
3+
* @copyright Copyright (c) 2020-2025 Tropic Square s.r.o.
4+
*
5+
* @license For the license see LICENSE.md in the root directory of this source tree.
6+
*/
7+
8+
#include <inttypes.h>
9+
#include <openssl/err.h>
10+
#include <openssl/evp.h>
11+
#include <stdint.h>
12+
#include <stdlib.h>
13+
#include <string.h>
14+
15+
#include "libtropic_common.h"
16+
#include "libtropic_logging.h"
17+
#include "libtropic_openssl.h"
18+
#include "lt_aesgcm.h"
19+
20+
lt_ret_t lt_aesgcm_encrypt_init(void *ctx, const uint8_t *key, const uint32_t key_len)
21+
{
22+
if (key_len != TR01_AES256_KEY_LEN) {
23+
LT_LOG_ERROR("Invalid AES-GCM key length: got %" PRIu32 " bytes, expected %d bytes", key_len,
24+
TR01_AES256_KEY_LEN);
25+
return LT_PARAM_ERR;
26+
}
27+
28+
lt_ctx_openssl_t *_ctx = (lt_ctx_openssl_t *)ctx;
29+
unsigned long err_code;
30+
31+
// Initialize AES-GCM encryption context.
32+
_ctx->aesgcm_encrypt_ctx = EVP_CIPHER_CTX_new();
33+
if (!_ctx->aesgcm_encrypt_ctx) {
34+
err_code = ERR_get_error();
35+
LT_LOG_ERROR("Failed to allocate AES-GCM encryption context, err_code=%lu (%s)", err_code,
36+
ERR_error_string(err_code, NULL));
37+
return LT_CRYPTO_ERR;
38+
}
39+
40+
// Set cipher type.
41+
if (!EVP_EncryptInit_ex(_ctx->aesgcm_encrypt_ctx, EVP_aes_256_gcm(), NULL, NULL, NULL)) {
42+
err_code = ERR_get_error();
43+
LT_LOG_ERROR("Failed to initialize AES-GCM encryption context with cipher type, err_code=%lu (%s)", err_code,
44+
ERR_error_string(err_code, NULL));
45+
return LT_CRYPTO_ERR;
46+
}
47+
48+
// Set IV length.
49+
if (!EVP_CIPHER_CTX_ctrl(_ctx->aesgcm_encrypt_ctx, EVP_CTRL_GCM_SET_IVLEN, TR01_L3_IV_SIZE, NULL)) {
50+
err_code = ERR_get_error();
51+
LT_LOG_ERROR("Failed to initialize AES-GCM encryption context with IV length, err_code=%lu (%s)", err_code,
52+
ERR_error_string(err_code, NULL));
53+
return LT_CRYPTO_ERR;
54+
}
55+
56+
// Set encryption key.
57+
if (!EVP_EncryptInit_ex(_ctx->aesgcm_encrypt_ctx, NULL, NULL, key, NULL)) {
58+
err_code = ERR_get_error();
59+
LT_LOG_ERROR("Failed to initialize AES-GCM encryption context with key, err_code=%lu (%s)", err_code,
60+
ERR_error_string(err_code, NULL));
61+
return LT_CRYPTO_ERR;
62+
}
63+
64+
return LT_OK;
65+
}
66+
67+
lt_ret_t lt_aesgcm_decrypt_init(void *ctx, const uint8_t *key, const uint32_t key_len)
68+
{
69+
if (key_len != TR01_AES256_KEY_LEN) {
70+
LT_LOG_ERROR("Invalid AES-GCM key length: got %" PRIu32 " bytes, expected %d bytes", key_len,
71+
TR01_AES256_KEY_LEN);
72+
return LT_PARAM_ERR;
73+
}
74+
75+
lt_ctx_openssl_t *_ctx = (lt_ctx_openssl_t *)ctx;
76+
unsigned long err_code;
77+
78+
// Initialize AES-GCM decryption context.
79+
_ctx->aesgcm_decrypt_ctx = EVP_CIPHER_CTX_new();
80+
if (!_ctx->aesgcm_decrypt_ctx) {
81+
err_code = ERR_get_error();
82+
LT_LOG_ERROR("Failed to allocate AES-GCM decryption context, err_code=%lu (%s)", err_code,
83+
ERR_error_string(err_code, NULL));
84+
return LT_CRYPTO_ERR;
85+
}
86+
87+
// Set cipher type.
88+
if (!EVP_DecryptInit_ex(_ctx->aesgcm_decrypt_ctx, EVP_aes_256_gcm(), NULL, NULL, NULL)) {
89+
err_code = ERR_get_error();
90+
LT_LOG_ERROR("Failed to initialize AES-GCM decryption context with cipher type, err_code=%lu (%s)", err_code,
91+
ERR_error_string(err_code, NULL));
92+
return LT_CRYPTO_ERR;
93+
}
94+
95+
// Set IV length.
96+
if (!EVP_CIPHER_CTX_ctrl(_ctx->aesgcm_decrypt_ctx, EVP_CTRL_GCM_SET_IVLEN, TR01_L3_IV_SIZE, NULL)) {
97+
err_code = ERR_get_error();
98+
LT_LOG_ERROR("Failed to initialize AES-GCM decryption context with IV length, err_code=%lu (%s)", err_code,
99+
ERR_error_string(err_code, NULL));
100+
return LT_CRYPTO_ERR;
101+
}
102+
103+
// Set decryption key.
104+
if (!EVP_DecryptInit_ex(_ctx->aesgcm_decrypt_ctx, NULL, NULL, key, NULL)) {
105+
err_code = ERR_get_error();
106+
LT_LOG_ERROR("Failed to initialize AES-GCM decryption context with key, err_code=%lu (%s)", err_code,
107+
ERR_error_string(err_code, NULL));
108+
return LT_CRYPTO_ERR;
109+
}
110+
111+
return LT_OK;
112+
}
113+
114+
lt_ret_t lt_aesgcm_encrypt(void *ctx, const uint8_t *iv, const uint32_t iv_len, const uint8_t *add,
115+
const uint32_t add_len, const uint8_t *plaintext, const uint32_t plaintext_len,
116+
uint8_t *ciphertext, const uint32_t ciphertext_len)
117+
{
118+
if (iv_len != TR01_L3_IV_SIZE) {
119+
LT_LOG_ERROR("Invalid AES-GCM IV length: got %" PRIu32 " bytes, expected %d bytes", iv_len, TR01_L3_IV_SIZE);
120+
return LT_PARAM_ERR;
121+
}
122+
123+
lt_ctx_openssl_t *_ctx = (lt_ctx_openssl_t *)ctx;
124+
unsigned long err_code;
125+
int out_len;
126+
127+
// Set IV.
128+
if (!EVP_EncryptInit_ex(_ctx->aesgcm_encrypt_ctx, NULL, NULL, NULL, iv)) {
129+
err_code = ERR_get_error();
130+
LT_LOG_ERROR("Failed to set AES-GCM encryption IV, err_code=%lu (%s)", err_code,
131+
ERR_error_string(err_code, NULL));
132+
return LT_CRYPTO_ERR;
133+
}
134+
135+
// Process AAD (Additional Authenticated Data).
136+
if (!EVP_EncryptUpdate(_ctx->aesgcm_encrypt_ctx, NULL, &out_len, add, (int)add_len)) {
137+
err_code = ERR_get_error();
138+
LT_LOG_ERROR("Failed to process AES-GCM AAD, err_code=%lu (%s)", err_code, ERR_error_string(err_code, NULL));
139+
return LT_CRYPTO_ERR;
140+
}
141+
142+
// Encrypt plaintext.
143+
if (!EVP_EncryptUpdate(_ctx->aesgcm_encrypt_ctx, ciphertext, &out_len, plaintext, (int)plaintext_len)) {
144+
err_code = ERR_get_error();
145+
LT_LOG_ERROR("Failed to encrypt AES-GCM plaintext, err_code=%lu (%s)", err_code,
146+
ERR_error_string(err_code, NULL));
147+
return LT_CRYPTO_ERR;
148+
}
149+
150+
// Check that all plaintext data was processed.
151+
if (out_len != (int)(ciphertext_len - TR01_L3_TAG_SIZE)) {
152+
LT_LOG_ERROR("AES-GCM encryption length mismatch! Current: %d bytes, expected: %" PRIu32 " bytes", out_len,
153+
ciphertext_len - TR01_L3_TAG_SIZE);
154+
return LT_CRYPTO_ERR;
155+
}
156+
157+
// Finalize encryption.
158+
if (!EVP_EncryptFinal_ex(_ctx->aesgcm_encrypt_ctx, ciphertext + out_len, &out_len)) {
159+
err_code = ERR_get_error();
160+
LT_LOG_ERROR("Failed to finalize AES-GCM encryption, err_code=%lu (%s)", err_code,
161+
ERR_error_string(err_code, NULL));
162+
return LT_CRYPTO_ERR;
163+
}
164+
165+
// Get the tag.
166+
if (!EVP_CIPHER_CTX_ctrl(_ctx->aesgcm_encrypt_ctx, EVP_CTRL_GCM_GET_TAG, TR01_L3_TAG_SIZE,
167+
ciphertext + plaintext_len)) {
168+
err_code = ERR_get_error();
169+
LT_LOG_ERROR("Failed to get AES-GCM encryption tag, err_code=%lu (%s)", err_code,
170+
ERR_error_string(err_code, NULL));
171+
return LT_CRYPTO_ERR;
172+
}
173+
174+
return LT_OK;
175+
}
176+
177+
lt_ret_t lt_aesgcm_decrypt(void *ctx, const uint8_t *iv, const uint32_t iv_len, const uint8_t *add,
178+
const uint32_t add_len, const uint8_t *ciphertext, const uint32_t ciphertext_len,
179+
uint8_t *plaintext, const uint32_t plaintext_len)
180+
{
181+
if (iv_len != TR01_L3_IV_SIZE) {
182+
LT_LOG_ERROR("Invalid AES-GCM IV length: got %" PRIu32 " bytes, expected %d bytes", iv_len, TR01_L3_IV_SIZE);
183+
return LT_PARAM_ERR;
184+
}
185+
186+
lt_ctx_openssl_t *_ctx = (lt_ctx_openssl_t *)ctx;
187+
unsigned long err_code;
188+
int out_len;
189+
190+
// Set IV.
191+
if (!EVP_DecryptInit_ex(_ctx->aesgcm_decrypt_ctx, NULL, NULL, NULL, iv)) {
192+
err_code = ERR_get_error();
193+
LT_LOG_ERROR("Failed to set AES-GCM decryption IV, err_code=%lu (%s)", err_code,
194+
ERR_error_string(err_code, NULL));
195+
return LT_CRYPTO_ERR;
196+
}
197+
198+
// Process AAD (Additional Authenticated Data).
199+
if (!EVP_DecryptUpdate(_ctx->aesgcm_decrypt_ctx, NULL, &out_len, add, (int)add_len)) {
200+
err_code = ERR_get_error();
201+
LT_LOG_ERROR("Failed to process AES-GCM AAD, err_code=%lu (%s)", err_code, ERR_error_string(err_code, NULL));
202+
return LT_CRYPTO_ERR;
203+
}
204+
205+
// Decrypt ciphertext.
206+
if (!EVP_DecryptUpdate(_ctx->aesgcm_decrypt_ctx, plaintext, &out_len, ciphertext,
207+
(int)(ciphertext_len - TR01_L3_TAG_SIZE))) {
208+
err_code = ERR_get_error();
209+
LT_LOG_ERROR("Failed to decrypt AES-GCM ciphertext, err_code=%lu (%s)", err_code,
210+
ERR_error_string(err_code, NULL));
211+
return LT_CRYPTO_ERR;
212+
}
213+
214+
// Check that all ciphertext data was processed.
215+
if (out_len != (int)(plaintext_len)) {
216+
LT_LOG_ERROR("AES-GCM decryption length mismatch! Current: %d bytes, expected: %" PRIu32 " bytes", out_len,
217+
plaintext_len);
218+
return LT_CRYPTO_ERR;
219+
}
220+
221+
// Set expected tag value.
222+
if (!EVP_CIPHER_CTX_ctrl(_ctx->aesgcm_decrypt_ctx, EVP_CTRL_GCM_SET_TAG, TR01_L3_TAG_SIZE,
223+
(void *)(ciphertext + ciphertext_len - TR01_L3_TAG_SIZE))) {
224+
err_code = ERR_get_error();
225+
LT_LOG_ERROR("Failed to set AES-GCM decryption tag, err_code=%lu (%s)", err_code,
226+
ERR_error_string(err_code, NULL));
227+
return LT_CRYPTO_ERR;
228+
}
229+
230+
// Finalize decryption.
231+
if (EVP_DecryptFinal_ex(_ctx->aesgcm_decrypt_ctx, plaintext + out_len, &out_len) <= 0) {
232+
err_code = ERR_get_error();
233+
LT_LOG_ERROR("Failed to finalize AES-GCM decryption, err_code=%lu (%s)", err_code,
234+
ERR_error_string(err_code, NULL));
235+
return LT_CRYPTO_ERR;
236+
}
237+
238+
return LT_OK;
239+
}
240+
241+
lt_ret_t lt_aesgcm_encrypt_deinit(void *ctx)
242+
{
243+
lt_ctx_openssl_t *_ctx = (lt_ctx_openssl_t *)ctx;
244+
245+
EVP_CIPHER_CTX_free(_ctx->aesgcm_encrypt_ctx);
246+
_ctx->aesgcm_encrypt_ctx = NULL;
247+
248+
return LT_OK;
249+
}
250+
251+
lt_ret_t lt_aesgcm_decrypt_deinit(void *ctx)
252+
{
253+
lt_ctx_openssl_t *_ctx = (lt_ctx_openssl_t *)ctx;
254+
255+
EVP_CIPHER_CTX_free(_ctx->aesgcm_decrypt_ctx);
256+
_ctx->aesgcm_decrypt_ctx = NULL;
257+
258+
return LT_OK;
259+
}

cal/openssl/lt_openssl_common.c

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
/**
2+
* @file lt_openssl_common.c
3+
* @copyright Copyright (c) 2020-2025 Tropic Square s.r.o.
4+
*
5+
* @license For the license see LICENSE.md in the root directory of this source tree.
6+
*/
7+
8+
#include <openssl/evp.h>
9+
#include <stdbool.h>
10+
11+
#include "libtropic_openssl.h"
12+
#include "lt_aesgcm.h"
13+
#include "lt_crypto_common.h"
14+
#include "lt_sha256.h"
15+
16+
lt_ret_t lt_crypto_ctx_init(void *ctx)
17+
{
18+
lt_ctx_openssl_t *_ctx = (lt_ctx_openssl_t *)ctx;
19+
20+
_ctx->aesgcm_encrypt_ctx = NULL;
21+
_ctx->aesgcm_decrypt_ctx = NULL;
22+
_ctx->sha256_ctx = NULL;
23+
24+
return LT_OK;
25+
}
26+
27+
lt_ret_t lt_crypto_ctx_deinit(void *ctx)
28+
{
29+
lt_ret_t ret1 = lt_aesgcm_encrypt_deinit(ctx);
30+
lt_ret_t ret2 = lt_aesgcm_decrypt_deinit(ctx);
31+
lt_ret_t ret3 = lt_sha256_deinit(ctx);
32+
33+
if (ret1 != LT_OK) {
34+
return ret1;
35+
}
36+
if (ret2 != LT_OK) {
37+
return ret2;
38+
}
39+
if (ret3 != LT_OK) {
40+
return ret3;
41+
}
42+
43+
return LT_OK;
44+
}

0 commit comments

Comments
 (0)