Skip to content

feat: add configuration file to provider V2#220

Open
jenstopp wants to merge 21 commits intomainfrom
feat/add-configuration-file-v2
Open

feat: add configuration file to provider V2#220
jenstopp wants to merge 21 commits intomainfrom
feat/add-configuration-file-v2

Conversation

@jenstopp
Copy link
Collaborator

@jenstopp jenstopp commented Feb 27, 2026

This is a updated PR of #115 rebased and working on top of main.

Running the provider now requires having the credentials loaded via files; they are not hardcoded anymore:

# Create the two credential files at the default paths:
mkdir -p /var/lib/azihsm

printf '\x70\xFC\xF7\x30\xB8\x76\x42\x38\xB8\x35\x80\x10\xCE\x8A\x3F\x76' \
    | tee /var/lib/azihsm/credentials_id.bin > /dev/null

printf '\xDB\x3D\xC7\x7F\xC2\x2E\x43\x00\x80\xD4\x1B\x31\xB6\xF0\x48\x00' \
    | tee /var/lib/azihsm/credentials_pin.bin > /dev/null

Also make sure to remove any existing bmk.bin / muk.bin files from CWD as they will not work with the new OBK. Each of the files will be generated on first use.

Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

This PR updates the OpenSSL provider V2 initialization flow to load HSM credentials from on-disk files (instead of hardcoded values) and to parse provider configuration (key file paths + API revision) from openssl.cnf with environment-variable support for credential paths.

Changes:

  • Add binary credential loading (ID/PIN) from configured file paths and cleanse credentials after use.
  • Add provider config parsing for BMK/MUK/OBK paths and API revision, with defaults and file: prefix handling.
  • Extend AZIHSM_CONFIG with credential path fields and API revision fields/constants.

Reviewed changes

Copilot reviewed 4 out of 4 changed files in this pull request and generated 6 comments.

File Description
plugins/ossl_prov/src/azihsm_ossl_hsm.c Load credentials from fixed-size binary files and use them when opening a session.
plugins/ossl_prov/src/azihsm_ossl_base.c Parse config from core params + env vars; validate API revision before opening device/session.
plugins/ossl_prov/inc/azihsm_ossl_base.h.in Add config constants/fields for credential paths and API revision (template header).
plugins/ossl_prov/inc/azihsm_ossl_base.h Add config constants/fields for credential paths and API revision (generated header).

Copilot AI review requested due to automatic review settings March 2, 2026 16:10
@jenstopp jenstopp force-pushed the feat/add-configuration-file-v2 branch from 0836aa7 to 48a2b66 Compare March 2, 2026 16:10
Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

Copilot reviewed 4 out of 4 changed files in this pull request and generated 3 comments.

@jenstopp jenstopp linked an issue Mar 2, 2026 that may be closed by this pull request
Copilot AI review requested due to automatic review settings March 2, 2026 22:29
@jenstopp jenstopp force-pushed the feat/add-configuration-file-v2 branch from de5414f to 7d174cf Compare March 2, 2026 22:29
Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

Copilot reviewed 4 out of 4 changed files in this pull request and generated 6 comments.

@jenstopp jenstopp linked an issue Mar 2, 2026 that may be closed by this pull request
Copilot AI review requested due to automatic review settings March 2, 2026 23:39
Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

Copilot reviewed 13 out of 13 changed files in this pull request and generated 6 comments.

@jenstopp jenstopp force-pushed the feat/add-configuration-file-v2 branch from c38b655 to 7fc7b24 Compare March 5, 2026 13:56
Copilot AI review requested due to automatic review settings March 5, 2026 14:02
Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

Copilot reviewed 14 out of 14 changed files in this pull request and generated 3 comments.

@jenstopp jenstopp force-pushed the feat/add-configuration-file-v2 branch from 23b00d0 to 45cc4a6 Compare March 9, 2026 21:52
Copilot AI review requested due to automatic review settings March 9, 2026 22:08
Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

Copilot reviewed 14 out of 14 changed files in this pull request and generated 2 comments.

Copilot AI review requested due to automatic review settings March 10, 2026 10:32
jenstopp and others added 15 commits March 10, 2026 14:00
- Add explicit <stdbool.h>, <stdint.h> to azihsm_ossl_base.h.in and
  <stdio.h> to azihsm_ossl_base.c (avoid relying on transitive includes)
- Remove unused static core_get_params global (-Wunused-but-set-variable)
- Harden load_credentials_from_file() with open()+fstat()+read() to
  ensure the path is a regular file of the expected size before reading
- Add azihsm_path_is_safe() rejecting NULL, empty, and ".." credential
  paths from env vars; change parse_provider_config() to OSSL_STATUS
  to propagate failures to OSSL_provider_init()

Signed-off-by: Jens Topp <jens.topp@9elements.com>
- Replace single `read()` call with a loop that retries on `EINTR` and
  accumulates partial reads
- Split `fstat()` failure from the file-type/size check — each case now
  has a distinct error message
- Fix formatting
- Add missing headers
- Validate all key-material paths (`bmk`, `muk`, `obk`, `pota_private_key`,
  `pota_public_key`) with `azihsm_path_is_safe` before use
- Add missing `return OSSL_FAILURE` after invalid `api-revision` format error

Signed-off-by: Jens Topp <jens.topp@9elements.com>
The previous code embedded a fixed 48-byte OBK (DEFAULT_OBK, the sequence
0x01..0x30) and a fixed P-384 key pair (POTA_PRIVATE_KEY_DER /
POTA_PUBLIC_KEY_DER) directly in the source as static arrays.

Replace the fallbacks with first-use generation:

- OBK: generate_and_save_obk() fills 48 bytes with RAND_bytes() and writes
  them to the configured obk_path (mode 0600) on first start. Subsequent
  starts load the persisted file, producing the same MOBK on every
  EstablishCredential call.

- POTA key pair: generate_and_save_pota_keypair() generates a fresh P-384
  key pair with EVP_EC_gen(), encodes the private key as SEC1 DER
  (d2i_AutoPrivateKey-compatible) and the public key as SubjectPublicKeyInfo
  DER, and writes both files (mode 0600). Subsequent starts load the persisted
  pair and produce a valid ECDSA-SHA384 endorsement signature.

The three static arrays, the three default_* boolean guards, and the
conditional free_buffer() branches are all removed. All key buffers are now
always heap-allocated, making the cleanup paths uniform.

Signed-off-by: Jens Topp <jens.topp@9elements.com>
Signed-off-by: Jens Topp <jens.topp@9elements.com>
Five independent read-file implementations and four independent
write-file implementations existed across the provider sources.
The versions in azihsm_ossl_hsm.c had full ERR_raise_data
coverage.

Extract these two implementations into a new shared module:

  azihsm_file_load(path, buffer)
    - ENOENT treated as success (file not yet created)
    - 64 KB size limit
    - Full ERR_raise_data at every error path (errno + path in message)

  azihsm_file_write(path, data, len)
    - write() loop handles short writes and EINTR
    - O_NOFOLLOW, mode 0600
    - Unlinks partial file on failure
    - Full ERR_raise_data at every error path

Callers updated:
  - azihsm_ossl_hsm.c: remove load_file_to_buffer(); reduce
    write_buffer_to_file() to a thin struct azihsm_buffer wrapper
  - azihsm_ossl_mac.c, kdf.c, store.c: remove local read_file() /
    read_key_file(); replace call sites with azihsm_file_load()
  - azihsm_ossl_keymgmt_ec.c, keymgmt_rsa.c: replace all lines of
    inline fopen/fseek/ftell/fread with azihsm_file_load(); replace
    all inline open/fdopen/fwrite with
    azihsm_ossl_write_masked_key_to_file()
  - azihsm_ossl_masked_key.c: reduce write_masked_key_to_file() body
    to a one-line delegate to azihsm_file_write()

Signed-off-by: Jens Topp <jens.topp@9elements.com>
Signed-off-by: Jens Topp <jens.topp@9elements.com>
Signed-off-by: Jens Topp <jens.topp@9elements.com>
Change all seven hardcoded /var/lib/azihsm/ default paths to CWD-relative
equivalents (e.g. ./bmk.bin) so the provider works out of the box without
any system-wide directory setup. Missing key files are still auto-generated
on first use.

Add a Configuration section to the README documenting the three-tier config
priority (openssl.cnf → env vars → defaults), the full openssl.cnf structure
required to load the provider and override key paths, all supported parameters
with their new defaults, and both invocation styles (provider-path vs
OPENSSL_CONF).

Update the Installation section to replace the mandatory /var/lib/azihsm
directory creation step with an optional note pointing to the Configuration
section.

Signed-off-by: Jens Topp <jens.topp@9elements.com>
Remove auto-generation of OBK and POTA keys on first use. These are
security-sensitive files that should be managed explicitly, not created
silently. The provider now returns a descriptive error when either is
absent (caller source), including the expected format, size, and the
openssl command needed to generate the missing material.

Update the README configuration table with format details for OBK and
POTA paths, and replace the "auto-generated on first use" note with
explicit descriptions of which files are auto-managed (BMK, MUK) and
which must be provided (OBK, POTA, credentials).

Signed-off-by: Jens Topp <jens.topp@9elements.com>
Signed-off-by: Jens Topp <jens.topp@9elements.com>
Signed-off-by: Jens Topp <jens.topp@9elements.com>
Signed-off-by: Jens Topp <jens.topp@9elements.com>
Signed-off-by: Jens Topp <jens.topp@9elements.com>
Signed-off-by: Christian Walter <christian.walter@9elements.com>
Signed-off-by: Christian Walter <christian.walter@9elements.com>
Copilot AI review requested due to automatic review settings March 10, 2026 13:00
@walterchris walterchris force-pushed the feat/add-configuration-file-v2 branch from 0a3988c to df75378 Compare March 10, 2026 13:00
Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

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

Copilot was unable to review this pull request because the user who requested the review is ineligible. To be eligible to request a review, you need a paid Copilot license, or your organization must enable Copilot code review.

Signed-off-by: Christian Walter <christian.walter@9elements.com>
@walterchris
Copy link
Collaborator

Credentials PIN should be read from the ENV vars and not as a file.

Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

Copilot reviewed 16 out of 16 changed files in this pull request and generated 3 comments.


You can also share your feedback on Copilot code review. Take the survey.

Signed-off-by: Christian Walter <christian.walter@9elements.com>
Copilot AI review requested due to automatic review settings March 12, 2026 09:24
@walterchris walterchris force-pushed the feat/add-configuration-file-v2 branch from 7d7df2f to 54802e2 Compare March 12, 2026 09:24
Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

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

Copilot was unable to review this pull request because the user who requested the review is ineligible. To be eligible to request a review, you need a paid Copilot license, or your organization must enable Copilot code review.

Signed-off-by: Christian Walter <christian.walter@9elements.com>
Comment on lines +399 to +402
if (!((pair[0] >= '0' && pair[0] <= '9') || (pair[0] >= 'a' && pair[0] <= 'f') ||
(pair[0] >= 'A' && pair[0] <= 'F')) ||
!((pair[1] >= '0' && pair[1] <= '9') || (pair[1] >= 'a' && pair[1] <= 'f') ||
(pair[1] >= 'A' && pair[1] <= 'F')))

Check notice

Code scanning / CodeQL

Complex condition Note

Complex condition: too many logical operations in this expression.

Copilot Autofix

AI 6 minutes ago

In general, to fix this kind of problem, you extract the complex boolean expression into one or more helper constructs: a small static function (e.g., is_hex_digit), or intermediate boolean variables with descriptive names. Then the original if uses these helpers, reducing the number of chained logical operators and improving readability.

For this specific code, the best approach without changing functionality is to introduce a small static int is_hex_char(char c) helper in the same file and then replace the complex if condition with calls to this helper. This eliminates the repeated range logic, makes the intent obvious, and removes the complex condition entirely. The helper should return nonzero if c is a valid hex digit (0-9, a-f, A-F). Then the condition becomes if (!is_hex_char(pair[0]) || !is_hex_char(pair[1])), which is short and clear. No new headers or external libraries are needed; we just add a static function definition above hex_decode_credentials within plugins/ossl_prov/src/azihsm_ossl_base.c and change the if body starting around lines 398–403 accordingly.

Suggested changeset 1
plugins/ossl_prov/src/azihsm_ossl_base.c

Autofix patch

Autofix patch
Run the following command in your local git repository to apply this patch
cat << 'EOF' | git apply
diff --git a/plugins/ossl_prov/src/azihsm_ossl_base.c b/plugins/ossl_prov/src/azihsm_ossl_base.c
--- a/plugins/ossl_prov/src/azihsm_ossl_base.c
+++ b/plugins/ossl_prov/src/azihsm_ossl_base.c
@@ -373,6 +373,13 @@
  *
  * Returns OSSL_SUCCESS on success, OSSL_FAILURE on error.
  */
+static int is_hex_char(char c)
+{
+    return ((c >= '0' && c <= '9') ||
+            (c >= 'a' && c <= 'f') ||
+            (c >= 'A' && c <= 'F'));
+}
+
 static OSSL_STATUS hex_decode_credentials(const char *env_name, const char *hex_str, uint8_t *out)
 {
     size_t len = strlen(hex_str);
@@ -396,10 +403,7 @@
         char pair[3] = { hex_str[i * 2], hex_str[i * 2 + 1], '\0' };
 
         /* Validate both nibbles are hex digits */
-        if (!((pair[0] >= '0' && pair[0] <= '9') || (pair[0] >= 'a' && pair[0] <= 'f') ||
-              (pair[0] >= 'A' && pair[0] <= 'F')) ||
-            !((pair[1] >= '0' && pair[1] <= '9') || (pair[1] >= 'a' && pair[1] <= 'f') ||
-              (pair[1] >= 'A' && pair[1] <= 'F')))
+        if (!is_hex_char(pair[0]) || !is_hex_char(pair[1]))
         {
             ERR_raise_data(
                 ERR_LIB_PROV,
EOF
@@ -373,6 +373,13 @@
*
* Returns OSSL_SUCCESS on success, OSSL_FAILURE on error.
*/
static int is_hex_char(char c)
{
return ((c >= '0' && c <= '9') ||
(c >= 'a' && c <= 'f') ||
(c >= 'A' && c <= 'F'));
}

static OSSL_STATUS hex_decode_credentials(const char *env_name, const char *hex_str, uint8_t *out)
{
size_t len = strlen(hex_str);
@@ -396,10 +403,7 @@
char pair[3] = { hex_str[i * 2], hex_str[i * 2 + 1], '\0' };

/* Validate both nibbles are hex digits */
if (!((pair[0] >= '0' && pair[0] <= '9') || (pair[0] >= 'a' && pair[0] <= 'f') ||
(pair[0] >= 'A' && pair[0] <= 'F')) ||
!((pair[1] >= '0' && pair[1] <= '9') || (pair[1] >= 'a' && pair[1] <= 'f') ||
(pair[1] >= 'A' && pair[1] <= 'F')))
if (!is_hex_char(pair[0]) || !is_hex_char(pair[1]))
{
ERR_raise_data(
ERR_LIB_PROV,
Copilot is powered by AI and may make mistakes. Always verify output.
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.

De-duplicate read_file function in the OSSL provider Change hardcoded POTA endorsement keys to config-based

4 participants