Skip to content

feat(engine): generate HSM AES keys with a GENERATE_KEY ctrl command - #806

Closed
Christian Walter (walterchris) wants to merge 1 commit into
mainfrom
engine/aes-keygen
Closed

Christian Walter (walterchris) wants to merge 1 commit into
mainfrom
engine/aes-keygen

Conversation

@walterchris

@walterchris Christian Walter (walterchris) commented Oct 23, 2026 •

Copy link
Copy Markdown
Collaborator

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 form AZIHSM_CTRL_SET_KEY_URI already attaches.

Usage

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>
type= bits=
aes 128, 192, 256 (default 256)
aes-gcm 256
aes-xts 512

Kinds, sizes and the 256-bit default follow the provider's AES generate (plugins/ossl_prov/src/azihsm_ossl_skeymgmt_aes.c).

Changes

  • core: Engine::set_ctrl / CtrlHandler / string_cmd register string ctrl commands. Any other ENGINE_ctrl call (unknown number, nonzero i, a callback, a NULL argument) fails.
  • engine: 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).
  • URI: type=aes-gcm|aes-xts and bits= (AES keys only).
  • AZIHSM_CTRL_SET_KEY_URI: accepts bits= and refuses a mismatch with the cipher before touching the HSM.
  • Header: AZIHSM_CMD_GENERATE_KEY and usage.
  • AES_KEY_BITS is shared by HKDF and keygen.

Testing

All in the u2004 container (OpenSSL 1.1.1f):

  • Unit (mock, plus an #[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 by type=aes; GCM/XTS keys and a bits= mismatch do not attach to AES-CBC; a rerun replaces the blob; bad types, sizes and paths fail without a file.
  • Core: registration, by name and by number, and the rejected call shapes.
  • C-API: the command name from the header; generated CBC keys round-trip; GCM/XTS keys are written; bad arguments fail.
  • CLI: openssl engine -t -post for 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.

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🔵 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

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟡 Changes recommended

Command-table validation accepts malformed terminators that can cause invalid memory access in OpenSSL.

1 open issue

Review effort: Balanced

Comment thread plugins/ossl_engine/azihsm_ossl_engine_core/src/engine.rs Outdated
Comment thread plugins/ossl_engine/azihsm_ossl_engine/src/context/tests.rs Dismissed
Comment thread plugins/ossl_engine/integration-tests/openssl-capi/src/engine_capi_tests.rs Dismissed

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟡 Changes recommended

Command-table validation permits interior nameless entries that can cause OpenSSL command-name queries to crash.

1 open issue
1 resolved since last review

Review effort: Balanced

Comment thread plugins/ossl_engine/azihsm_ossl_engine_core/src/engine.rs Outdated

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🔵 Needs a closer look

The unresolved command-table pointer-safety issue needs correction, and the new OpenSSL control path and HSM key lifecycle warrant final human validation.

1 open issue
1 resolved since last review

Review effort: Balanced

Comment thread plugins/ossl_engine/azihsm_ossl_engine_core/src/engine.rs Outdated
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>

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🔵 Needs a closer look

The new OpenSSL FFI dispatch and HSM key lifecycle need final human validation because runtime behavior was not independently verified during review.

No open issues 🎉

1 resolved since last review

Review effort: Balanced

@walterchris

Copy link
Copy Markdown
Collaborator Author

TesseraHSM/tessera-sw#5

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants