Skip to content

feat: openssl tls.key_file pkcs11:#11611

Open
itzwam wants to merge 8 commits intofluent:masterfrom
itzwam:pkcs11
Open

feat: openssl tls.key_file pkcs11:#11611
itzwam wants to merge 8 commits intofluent:masterfrom
itzwam:pkcs11

Conversation

@itzwam
Copy link

@itzwam itzwam commented Mar 23, 2026

implements #10506

Summary by CodeRabbit

  • New Features

    • TLS can load private keys from PKCS#11 (pkcs11:) URIs, enabling hardware-backed keys (HSM) alongside existing PEM file support.
    • Key/certificate matching validation remains performed after key installation.
  • Bug Fixes

    • Missing or empty PIN for PKCS#11 URIs now emits a warning instead of hard-failing, improving robustness when PINs are managed externally.
    • Attempts to use PKCS#11 without platform support now produce an error.

@coderabbitai
Copy link

coderabbitai bot commented Mar 23, 2026

Note

Reviews paused

It looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the reviews.auto_review.auto_pause_after_reviewed_commits setting.

Use the following commands to manage reviews:

  • @coderabbitai resume to resume automatic reviews.
  • @coderabbitai review to trigger a single review.

Use the checkboxes below for quick actions:

  • ▶️ Resume reviews
  • 🔍 Trigger review
📝 Walkthrough

Walkthrough

Adds PKCS#11 URI handling to OpenSSL TLS key loading: when key_file starts with pkcs11: the code uses the OpenSSL ENGINE API to load the private key (ENGINE_by_id("pkcs11"), ENGINE_init, ENGINE_load_private_key, SSL_CTX_use_PrivateKey), while preserving PEM file loading for other key_file values and updating error/cleanup paths.

Changes

Cohort / File(s) Summary
TLS OpenSSL key loader
src/tls/openssl.c
Detect pkcs11: URIs and route private-key loading through OpenSSL ENGINE (ENGINE_by_id("pkcs11"), ENGINE_init, ENGINE_load_private_key, SSL_CTX_use_PrivateKey); error/warn when ENGINE unavailable or PIN missing; ensure ENGINE/EVP_PKEY cleanup on failure; keep existing SSL_CTX_use_PrivateKey_file branch for non-pkcs11: keys and retain SSL_CTX_check_private_key validation.

Sequence Diagram(s)

sequenceDiagram
    participant App as Application
    participant TLS as tls_context_create
    participant OpenSSL as OpenSSL
    participant Engine as ENGINE("pkcs11")
    participant Token as PKCS#11 Token

    App->>TLS: tls_context_create(key_file, key_passwd)
    TLS->>OpenSSL: create SSL_CTX / load certificate
    alt key_file starts with "pkcs11:"
        TLS->>TLS: warn if key_passwd empty
        TLS->>OpenSSL: ENGINE_by_id("pkcs11")
        OpenSSL->>Engine: ENGINE_init()
        TLS->>Engine: ENGINE_load_private_key(pkcs11_uri, key_passwd)
        Engine->>Token: access token / PIN prompt
        Token-->>Engine: EVP_PKEY
        Engine-->>OpenSSL: EVP_PKEY
        OpenSSL->>OpenSSL: SSL_CTX_use_PrivateKey(EVP_PKEY)
        OpenSSL->>Engine: ENGINE_finish() / ENGINE_free()
        OpenSSL->>OpenSSL: EVP_PKEY_free()
    else Standard PEM file
        TLS->>OpenSSL: set password callback if provided
        OpenSSL->>OpenSSL: SSL_CTX_use_PrivateKey_file(path)
    end
    OpenSSL->>OpenSSL: SSL_CTX_check_private_key()
    OpenSSL-->>TLS: success / error
    TLS-->>App: return result
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

Suggested reviewers

  • edsiper
  • cosmo0920

Poem

🐰 I sniffed a key that whispered "pkcs11",
I nudged the ENGINE, gave it a spin,
A PIN, a hop, the EVP danced free,
Old PEM trails hummed on beside me,
I wiped my paws and munched a carrot. 🥕

🚥 Pre-merge checks | ✅ 2 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (2 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly identifies the main change: adding PKCS#11 support to OpenSSL TLS key file handling, which aligns with the changeset that adds pkcs11: prefix detection and ENGINE-based key loading.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link

@chatgpt-codex-connector chatgpt-codex-connector bot left a comment

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 979ffa13b5

ℹ️ About Codex in GitHub

Codex has been enabled to automatically review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 2

🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@src/tls/openssl.c`:
- Around line 958-964: The key loading branch using SSL_CTX_use_PrivateKey_file
logs the error into err_buf and calls flb_error but then continues execution,
causing a later misleading SSL_CTX_check_private_key error; after the flb_error
call in the failure path of SSL_CTX_use_PrivateKey_file, immediately jump to the
existing error cleanup path (use goto error) so the function exits with the
original key load failure rather than proceeding to SSL_CTX_check_private_key.
- Around line 924-950: The PKCS#11 branch uses deprecated ENGINE APIs
(ENGINE_by_id, ENGINE_init, ENGINE_load_private_key, ENGINE_finish) and
currently logs errors without OpenSSL error context; update the error logging
calls around ENGINE_by_id, ENGINE_init, ENGINE_load_private_key and
SSL_CTX_use_PrivateKey to append the OpenSSL error string using
ERR_error_string_n(err, err_buf, sizeof err_buf) (err_buf is already in scope)
so each flb_error includes the descriptive OpenSSL error, and keep note to plan
a future migration from ENGINE APIs to the Provider API for OpenSSL 3+/4.0
compatibility.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: dc2c62df-ca9e-4215-9f23-5fb683f32b97

📥 Commits

Reviewing files that changed from the base of the PR and between 40fff8e and 979ffa1.

📒 Files selected for processing (1)
  • src/tls/openssl.c

itzwam and others added 3 commits March 23, 2026 20:44
Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com>
Signed-off-by: toinux <26522723+itzwam@users.noreply.github.com>
Copy link
Author

@itzwam itzwam left a comment

Choose a reason for hiding this comment

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

Fixed most of the code suggestions

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@src/tls/openssl.c`:
- Around line 918-955: The OPENSSL_NO_ENGINE guard currently logs an error and
does a goto but leaves the ENGINE-related identifiers (ENGINE, ENGINE_by_id,
ENGINE_init, ENGINE_load_private_key, EVP_PKEY, SSL_CTX_use_PrivateKey,
EVP_PKEY_free, ENGINE_finish, ENGINE_free) unguarded, causing compile failures;
wrap the entire ENGINE usage block (the code that declares ENGINE *e, calls
ENGINE_by_id/ENGINE_init/ENGINE_load_private_key and uses EVP_PKEY and
SSL_CTX_use_PrivateKey, then frees with EVP_PKEY_free/ENGINE_finish/ENGINE_free)
inside an `#else` ... `#endif` so that when OPENSSL_NO_ENGINE is defined only the
flb_error and goto error are compiled, and when it is not defined the existing
ENGINE code is compiled as before.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 37c7bde4-337e-43b4-9df6-81b125b4f2b3

📥 Commits

Reviewing files that changed from the base of the PR and between 4d7de5b and e539b41.

📒 Files selected for processing (1)
  • src/tls/openssl.c

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 2

♻️ Duplicate comments (1)
src/tls/openssl.c (1)

918-958: ⚠️ Potential issue | 🔴 Critical

The OPENSSL_NO_ENGINE guard is still incomplete.

Line 919 only gates the runtime error path. Lines 928-958 still reference ENGINE symbols outside an #else, so a no-engine build will fail at compile time before it can ever hit goto error.

🔧 Proposed fix
         if (strncmp(key_file, "pkcs11:", 7) == 0) {
 `#ifdef` OPENSSL_NO_ENGINE
             flb_error("[tls] pkcs11_key_file '%s': requires OpenSSL ENGINE support",
                         key_file);
             goto error;
-#endif
+#else
             /* PKCS#11 URI detected */
             if (!key_passwd || strlen(key_passwd) == 0) {
                 flb_warn("[tls] PKCS#11 URI may fail without a PIN/password (tls_key_passwd)");
             }
             ENGINE *e = ENGINE_by_id("pkcs11");
@@
             EVP_PKEY_free(pkey);
             ENGINE_finish(e);
             ENGINE_free(e);
+#endif
         }
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/tls/openssl.c` around lines 918 - 958, The code references ENGINE symbols
(ENGINE, ENGINE_by_id, ENGINE_init, ENGINE_load_private_key, ENGINE_finish,
ENGINE_free, EVP_PKEY, SSL_CTX_use_PrivateKey) even when OPENSSL_NO_ENGINE is
defined, causing compile errors; wrap the entire PKCS#11 branch that uses ENGINE
(from the ENGINE *e = ENGINE_by_id(...) through ENGINE_free(e) and related
EVP_PKEY handling) inside the complementary `#ifndef` OPENSSL_NO_ENGINE (or move
it into the `#else` block of the existing guard) so that when OPENSSL_NO_ENGINE is
defined the compiler sees only the error/warn path and not any ENGINE symbols.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@src/tls/openssl.c`:
- Around line 920-921: The log currently prints key_file verbatim which can leak
sensitive PKCS#11 URI query attributes; modify the logging in src/tls/openssl.c
(the flb_error calls that reference pkcs11_key_file/key_file, including the
block around lines 943-950) to first detect when key_file is a PKCS#11 URI
(scheme "pkcs11:"), parse its query string and produce a sanitized copy that
removes or replaces sensitive query parameters (at minimum "pin-value" and
"pin-source") before passing to flb_error; for non-pkcs11 paths log the original
value. Implement the sanitizer as a small helper (e.g., sanitize_pkcs11_uri) and
use it in all places that currently log key_file so the emitted message contains
the sanitized URI instead of the raw one.
- Around line 968-971: Cache the OpenSSL error value before it is consumed: call
ERR_get_error() once into a local unsigned long (e.g., "err") and pass that
cached value to ERR_error_string_n(err, err_buf, sizeof(err_buf)-1) and to the
flb_error() formatting call instead of calling ERR_get_error() twice; update the
block around the check (where ret != 1, involving err_buf, ERR_error_string_n,
and flb_error) to reuse that single cached error value and preserve correct
error/message pairing for key_file.

---

Duplicate comments:
In `@src/tls/openssl.c`:
- Around line 918-958: The code references ENGINE symbols (ENGINE, ENGINE_by_id,
ENGINE_init, ENGINE_load_private_key, ENGINE_finish, ENGINE_free, EVP_PKEY,
SSL_CTX_use_PrivateKey) even when OPENSSL_NO_ENGINE is defined, causing compile
errors; wrap the entire PKCS#11 branch that uses ENGINE (from the ENGINE *e =
ENGINE_by_id(...) through ENGINE_free(e) and related EVP_PKEY handling) inside
the complementary `#ifndef` OPENSSL_NO_ENGINE (or move it into the `#else` block of
the existing guard) so that when OPENSSL_NO_ENGINE is defined the compiler sees
only the error/warn path and not any ENGINE symbols.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 71520a4a-dbee-4634-af20-8b2a2c33b6eb

📥 Commits

Reviewing files that changed from the base of the PR and between e539b41 and 9f377b3.

📒 Files selected for processing (1)
  • src/tls/openssl.c

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

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant