Repository navigation
feat(engine): generate HSM AES keys with a GENERATE_KEY ctrl command - #806
Closed
Christian Walter (walterchris) wants to merge 1 commit into
Closed
Christian Walter (walterchris) wants to merge 1 commit into
Christian Walter (walterchris) wants to merge 1 commit into
Conversation
Contributor
There was a problem hiding this comment.
🔵 Needs a closer look
The unsafe OpenSSL callback bridge and HSM key-persistence lifecycle warrant final human review despite no confirmed blocking defects.
No open issues 🎉
What changed in this PR
Adds HSM-backed AES key generation to the OpenSSL 1.1.1 engine through GENERATE_KEY, using masked key files instead of opaque symmetric keys.
Changes:
- Adds string control-command registration and AES, AES-GCM, and AES-XTS key generation with masked-blob export and HSM key cleanup.
- Extends key URIs with AES kinds and optional
bits=, including cipher-size validation. - Documents the command and adds unit, C-API, CLI, and hardware-smoke coverage.
| File | Description |
|---|---|
plugins/ossl_engine/integration-tests/openssl-cli/testfiles/generate_key/generate_key.sh |
Tests CLI generation, file permissions, and invalid arguments. |
plugins/ossl_engine/integration-tests/openssl-cli/src/engine_cli_tests.rs |
Registers the generation CLI suite. |
plugins/ossl_engine/integration-tests/openssl-capi/src/engine_capi_tests.rs |
Tests command invocation and generated-key round trips. |
plugins/ossl_engine/inc/azihsm_ossl_engine.h |
Defines the command name and documents usage. |
plugins/ossl_engine/azihsm_ossl_engine/src/uri.rs |
Parses AES kinds and optional key sizes. |
plugins/ossl_engine/azihsm_ossl_engine/src/keyload.rs |
Rejects all AES kinds as private keys. |
plugins/ossl_engine/azihsm_ossl_engine/src/hkdf.rs |
Reuses the shared AES-size constant. |
plugins/ossl_engine/azihsm_ossl_engine/src/engine_impl.rs |
Registers and dispatches GENERATE_KEY. |
plugins/ossl_engine/azihsm_ossl_engine/src/context/tests.rs |
Adds generation, persistence, and cipher-compatibility tests. |
plugins/ossl_engine/azihsm_ossl_engine/src/aes.rs |
Implements generation, export, cleanup, and size checks. |
plugins/ossl_engine/azihsm_ossl_engine_sys/wrapper.h |
Exposes the string-command flag to Rust bindings. |
plugins/ossl_engine/azihsm_ossl_engine_sys/build.rs |
Allows binding generation for ENGINE_CMD_BASE. |
plugins/ossl_engine/azihsm_ossl_engine_core/src/engine.rs |
Adds control-command registration, dispatch, and validation tests. |
Review effort: Balanced
Christian Walter (walterchris)
force-pushed
the
engine/magic-numbers
branch
from
October 26, 2026 20:42
b7b0a99 to
24cc55a
Compare
Christian Walter (walterchris)
force-pushed
the
engine/aes-keygen
branch
from
October 26, 2026 20:43
6aa25b1 to
9ec5b9a
Compare
Christian Walter (walterchris)
force-pushed
the
engine/magic-numbers
branch
from
October 26, 2026 22:41
24cc55a to
bba7ce9
Compare
Christian Walter (walterchris)
force-pushed
the
engine/aes-keygen
branch
2 times, most recently
from
October 27, 2026 08:38
5d79dc2 to
4bb6759
Compare
Christian Walter (walterchris)
changed the base branch from
engine/magic-numbers
to
main
October 27, 2026 08:38
Christian Walter (walterchris)
force-pushed
the
engine/aes-keygen
branch
from
October 27, 2026 08:44
4bb6759 to
b6eb64d
Compare
Christian Walter (walterchris)
force-pushed
the
engine/aes-keygen
branch
from
October 27, 2026 09:44
b6eb64d to
d3a96ac
Compare
Christian Walter (walterchris)
force-pushed
the
engine/aes-keygen
branch
from
October 27, 2026 10:23
d3a96ac to
a2e27fa
Compare
OpenSSL 1.1.1 has no object for an opaque symmetric key, so AES keys
cannot be generated through an OpenSSL key API. GENERATE_KEY, the
engine's first ctrl command, generates one in the HSM and writes its
masked key file, the form AZIHSM_CTRL_SET_KEY_URI attaches:
ENGINE_ctrl_cmd_string(e, AZIHSM_CMD_GENERATE_KEY,
"azihsm:///keys/k.bin;type=aes", 0);
openssl engine -t -post 'GENERATE_KEY:azihsm:///keys/k.bin;type=aes' <engine>
The type is aes (128, 192 or 256 bits; default 256, as in the
provider), aes-gcm (256) or aes-xts (512). The URI grammar gains these
types and a bits= attribute for AES keys; AZIHSM_CTRL_SET_KEY_URI takes
the same URI and refuses one whose bits= disagrees with the cipher.
Core gains string ctrl command registration (Engine::set_ctrl,
CtrlHandler); any other kind of ENGINE_ctrl call fails.
Signed-off-by: Christian Walter <christian.walter@9elements.com>
Christian Walter (walterchris)
force-pushed
the
engine/aes-keygen
branch
from
October 27, 2026 11:36
a2e27fa to
8939d16
Compare
Collaborator
Author
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.


OpenSSL 1.1.1 has no opaque symmetric keys (the provider's AES keygen needs OpenSSL 3.5's
EVP_SKEY), so the engine generates AES keys with its own ctrl command and hands them over as masked key files, the formAZIHSM_CTRL_SET_KEY_URIalready attaches.Usage
type=bits=aesaes-gcmaes-xtsKinds, sizes and the 256-bit default follow the provider's AES generate (
plugins/ossl_prov/src/azihsm_ossl_skeymgmt_aes.c).Changes
Engine::set_ctrl/CtrlHandler/string_cmdregister string ctrl commands. Any otherENGINE_ctrlcall (unknown number, nonzeroi, a callback, a NULL argument) fails.GENERATE_KEY(aes::generate_key) validates the URI and size before touching the HSM, generates the key, exports the masked blob (zeroized), deletes the HSM key and writes the file with the existing hardened writer (0600, atomic replace).type=aes-gcm|aes-xtsandbits=(AES keys only).AZIHSM_CTRL_SET_KEY_URI: acceptsbits=and refuses a mismatch with the cipher before touching the HSM.AZIHSM_CMD_GENERATE_KEYand usage.AES_KEY_BITSis shared by HKDF and keygen.Testing
All in the u2004 container (OpenSSL 1.1.1f):
#[ignore]hardware smoke): every type and size writes a 0600 blob that unmasks to that kind and size; CBC keys match the SDK's AES-CBC through the engine cipher, by the generating URI and bytype=aes; GCM/XTS keys and abits=mismatch do not attach to AES-CBC; a rerun replaces the blob; bad types, sizes and paths fail without a file.openssl engine -t -postfor every type and size (mode 600); bad arguments print[Failure]and write nothing.cargo +nightly fmt --check, clippy (4 configs), unit: core 55, engine 58, resiliency 31; CLI 10/10; C-API 12/12.