Compare commits

...
Sign in to create a new pull request.

2 commits

Author SHA1 Message Date
Jakub Jelen
8752f78be1 2.7.0-3 2026-06-23 15:26:03 +02:00
Jakub Jelen
c5bcf99184 Use low-level AES operations to prevent session leak (#2487009) 2026-06-23 15:25:54 +02:00
2 changed files with 235 additions and 3 deletions

View file

@ -0,0 +1,228 @@
diff --git a/aes_cmac/aes.c b/aes_cmac/aes.c
index 5b5f45f..696a289 100644
--- a/aes_cmac/aes.c
+++ b/aes_cmac/aes.c
@@ -170,77 +170,15 @@ cleanup:
#else
-static const EVP_CIPHER *aes_ecb(uint16_t key_len) {
- switch (key_len) {
- case 16:
- return EVP_aes_128_ecb();
- case 24:
- return EVP_aes_192_ecb();
- case 32:
- return EVP_aes_256_ecb();
- default:
- return NULL;
- }
-}
-
-static const EVP_CIPHER *aes_cbc(uint16_t key_len) {
- switch (key_len) {
- case 16:
- return EVP_aes_128_cbc();
- case 24:
- return EVP_aes_192_cbc();
- case 32:
- return EVP_aes_256_cbc();
- default:
- return NULL;
- }
-}
-
-static int aes_encrypt_ex(const EVP_CIPHER *cipher, const uint8_t *in,
- uint8_t *out, uint16_t len, const uint8_t *iv,
- aes_context *ctx) {
- if (EVP_EncryptInit_ex(ctx->ctx, cipher, NULL, ctx->key, iv) != 1) {
- return -1;
- }
- if (EVP_CIPHER_CTX_set_padding(ctx->ctx, 0) != 1) {
- return -2;
- }
- int update_len = len;
- if (EVP_EncryptUpdate(ctx->ctx, out, &update_len, in, len) != 1) {
- return -3;
- }
- int final_len = len - update_len;
- if (EVP_EncryptFinal_ex(ctx->ctx, out + update_len, &final_len) != 1) {
- return -4;
- }
- if (update_len + final_len != len) {
- return -5;
- }
- return 0;
-}
-
-static int aes_decrypt_ex(const EVP_CIPHER *cipher, const uint8_t *in,
- uint8_t *out, uint16_t len, const uint8_t *iv,
- aes_context *ctx) {
- if (EVP_DecryptInit_ex(ctx->ctx, cipher, NULL, ctx->key, iv) != 1) {
- return -1;
- }
- if (EVP_CIPHER_CTX_set_padding(ctx->ctx, 0) != 1) {
- return -2;
- }
- int update_len = len;
- if (EVP_DecryptUpdate(ctx->ctx, out, &update_len, in, len) != 1) {
- return -3;
- }
- int final_len = len - update_len;
- if (EVP_DecryptFinal_ex(ctx->ctx, out + update_len, &final_len) != 1) {
- return -4;
- }
- if (update_len + final_len != len) {
- return -5;
- }
- return 0;
-}
+/*
+ * Use the low-level AES API (AES_set_encrypt_key / AES_ecb_encrypt /
+ * AES_cbc_encrypt) instead of the EVP API. The low-level functions
+ * operate directly on an AES_KEY struct with pre-computed round keys
+ * and do not depend on OpenSSL's global library context. This means
+ * they continue to work after OPENSSL_cleanup() has been called,
+ * which is critical for SCP03 session close during application
+ * teardown.
+ */
#endif
@@ -266,17 +204,15 @@ int aes_set_key(const uint8_t *key, uint16_t key_len, aes_context *ctx) {
#else
- if (key == NULL || aes_ecb(key_len) == NULL) {
+ if (key == NULL || (key_len != 16 && key_len != 24 && key_len != 32)) {
return -1;
}
- if (!ctx->ctx) {
- ctx->ctx = EVP_CIPHER_CTX_new();
- if (!ctx->ctx) {
- return -2;
- }
+ if (AES_set_encrypt_key(key, key_len * 8, &ctx->enc_key) != 0) {
+ return -2;
+ }
+ if (AES_set_decrypt_key(key, key_len * 8, &ctx->dec_key) != 0) {
+ return -3;
}
- ctx->key_len = key_len;
- memcpy(ctx->key, key, key_len);
#endif
@@ -295,23 +231,18 @@ int aes_load_key(const char *key, aes_context *ctx) {
const uint8_t default_mac[] = {0x59, 0x2f, 0xd4, 0x83, 0xf7, 0x59,
0xe2, 0x99, 0x09, 0xa0, 0x4c, 0x45,
0x05, 0xd2, 0xce, 0x0a};
- ctx->key_len = sizeof(default_enc);
- if (key == NULL || aes_ecb(ctx->key_len) == NULL) {
+ const uint8_t *k;
+
+ if (key == NULL)
return -1;
- }
- if (!ctx->ctx) {
- ctx->ctx = EVP_CIPHER_CTX_new();
- if (!ctx->ctx) {
- return -2;
- }
- }
if (!strcmp(key, "default_enc"))
- memcpy(ctx->key, default_enc, ctx->key_len);
+ k = default_enc;
else if (!strcmp(key, "default_mac"))
- memcpy(ctx->key, default_mac, ctx->key_len);
+ k = default_mac;
else
- memset(ctx->key, 0, ctx->key_len);
- return 0;
+ return -1;
+
+ return aes_set_key(k, sizeof(default_enc), ctx);
#endif
}
@@ -334,8 +265,8 @@ int aes_encrypt(const uint8_t *in, uint8_t *out, aes_context *ctx) {
#else
- return aes_encrypt_ex(aes_ecb(ctx->key_len), in, out, AES_BLOCK_SIZE, NULL,
- ctx);
+ AES_ecb_encrypt(in, out, &ctx->enc_key, AES_ENCRYPT);
+ return 0;
#endif
}
@@ -359,8 +290,8 @@ int aes_decrypt(const uint8_t *in, uint8_t *out, aes_context *ctx) {
#else
- return aes_decrypt_ex(aes_ecb(ctx->key_len), in, out, AES_BLOCK_SIZE, NULL,
- ctx);
+ AES_ecb_encrypt(in, out, &ctx->dec_key, AES_DECRYPT);
+ return 0;
#endif
}
@@ -388,7 +319,10 @@ int aes_cbc_encrypt(const uint8_t *in, uint8_t *out, uint16_t len,
#else
- return aes_encrypt_ex(aes_cbc(ctx->key_len), in, out, len, iv, ctx);
+ uint8_t _iv[AES_BLOCK_SIZE];
+ memcpy(_iv, iv, AES_BLOCK_SIZE);
+ AES_cbc_encrypt(in, out, len, &ctx->enc_key, _iv, AES_ENCRYPT);
+ return 0;
#endif
}
@@ -416,7 +350,10 @@ int aes_cbc_decrypt(const uint8_t *in, uint8_t *out, uint16_t len,
#else
- return aes_decrypt_ex(aes_cbc(ctx->key_len), in, out, len, iv, ctx);
+ uint8_t _iv[AES_BLOCK_SIZE];
+ memcpy(_iv, iv, AES_BLOCK_SIZE);
+ AES_cbc_encrypt(in, out, len, &ctx->dec_key, _iv, AES_DECRYPT);
+ return 0;
#endif
}
@@ -484,7 +421,7 @@ void aes_destroy(aes_context *ctx) {
#else
- EVP_CIPHER_CTX_free(ctx->ctx);
+ /* AES_KEY has no resources to free, just zero the key material */
#endif
diff --git a/aes_cmac/aes.h b/aes_cmac/aes.h
index 798cb15..ba0ef97 100644
--- a/aes_cmac/aes.h
+++ b/aes_cmac/aes.h
@@ -30,7 +30,7 @@
#include <bcrypt.h>
#include <ntstatus.h>
#else
-#include <openssl/evp.h>
+#include <openssl/aes.h>
#endif
#ifndef AES_BLOCK_SIZE // Defined in openssl/aes.h
@@ -51,9 +51,8 @@ typedef struct {
PBYTE pbKeyECBObj;
size_t cbKeyObj;
#else
- EVP_CIPHER_CTX *ctx;
- uint16_t key_len;
- uint8_t key[32];
+ AES_KEY enc_key;
+ AES_KEY dec_key;
#endif
} aes_context;

View file

@ -2,7 +2,7 @@
Name: yubihsm-shell
Version: 2.7.0
Release: 2%{?dist}
Release: 3%{?dist}
Summary: Tools to interact with YubiHSM 2
# Automatically converted from old format: ASL 2.0 - review is highly recommended.
@ -13,6 +13,8 @@ Source1: https://developers.yubico.com/%{name}/Releases/%{name}-%{version}.tar.g
Source2: gpgkey-9588EA0F.gpg
# https://github.com/Yubico/yubihsm-shell/pull/411
Patch2: yubihsm-shell-2.5.0-pcsc-lite.patch
# https://github.com/Yubico/yubihsm-shell/pull/528
Patch3: yubihsm-shell-2.7.0-session-leak.patch
BuildRequires: cmake
BuildRequires: cppcheck
@ -45,8 +47,7 @@ Development libraries for working with yubihsm 2.
%prep
gpgv2 --quiet --keyring %{SOURCE2} %{SOURCE1} %{SOURCE0}
%setup -q
%patch 2 -p1
%autosetup -p1
%build
@ -112,6 +113,9 @@ chrpath --delete $RPM_BUILD_ROOT%{_libdir}/pkcs11/yubihsm_pkcs11.so
%changelog
* Tue Jun 23 2026 Jakub Jelen <jjelen@redhat.com> - 2.7.0-3
- Use low-level AES operations to prevent session leak (#2487009)
* Fri Jul 25 2025 Fedora Release Engineering <releng@fedoraproject.org> - 2.7.0-2
- Rebuilt for https://fedoraproject.org/wiki/Fedora_43_Mass_Rebuild