hsmCompatVerify RSA EC Examples - dogtagpki/pki GitHub Wiki

RSA/EC Key Archival and Recovery with hsmCompatVerify

1. Overview

This document demonstrates end-to-end RSA and EC private key archival and recovery using the hsmCompatVerify KRA simulator tool.

Key Points:

  • hsmCompatVerify is a standalone KRA simulator - no CA/KRA instances needed

  • Demonstrates traditional (non-PQC) key archival workflow

  • Uses RSA-2048 or EC (nistp256) for key generation

  • Tests both client-side and server-side operations

  • Supports HSM/PKCS#11 token testing

2. Prerequisites

2.1. Software Requirements

Component Version

NSS

3.44+ (recommended 3.48+)

JSS

4.10+

hsmCompatVerify

Merged in Dogtag PKI master

2.2. Test Environment

  • Working directory: ~/demo/kra-compat

  • NSS database password: Secret.123

  • All commands run from ~/demo/kra-compat

3. Demo Setup

3.1. Create Directory Structure

$ mkdir -p ~/demo/kra-compat/client-nssdb ~/demo/kra-compat/pkiserv-nssdb
$ cd ~/demo/kra-compat
Note
All commands below assume you are in the ~/demo/kra-compat directory.

3.2. Initialize NSS Databases

Initialize NSS security databases for both client and server.

3.2.1. Client NSS Database

# Create password file
$ echo "Secret.123" > client-nssdb/password.txt

# Initialize NSS database
$ certutil -N -d client-nssdb/ -f client-nssdb/password.txt

3.2.2. Server NSS Database

# Create password file
$ echo "Secret.123" > pkiserv-nssdb/password.txt

# Initialize NSS database
$ certutil -N -d pkiserv-nssdb/ -f pkiserv-nssdb/password.txt

4. Step 0: Setup (Create CA, Transport, and Storage Certificates)

This step creates the necessary certificates for the KRA simulator. It only needs to be run once.

$ hsmCompatVerifyServ --setup-only \
  --pkiserv-db-path pkiserv-nssdb \
  --pkiserv-passwd-file pkiserv-nssdb/password.txt \
  --hsm-token "" \
  --hsm-token-passwd-file pkiserv-nssdb/password.txt \
  --ca-nickname "test CA Signing Certificate" \
  --transport-nickname "test KRA Transport Certificate" \
  --storage-nickname "test KRA Storage Certificate" \
  --verbose

Expected Output:

  • RSA-4096 CA certificate created (self-signed)

  • RSA-2048 Transport certificate created

  • RSA-2048 Storage certificate created

  • PEM files exported to pkiserv-nssdb/ directory:

    • kra_transport.pem

    • kra_storage.pem

Verify:

$ ls -1 pkiserv-nssdb/*.pem
pkiserv-nssdb/kra_storage.pem
pkiserv-nssdb/kra_transport.pem

$ certutil -L -d pkiserv-nssdb
Certificate Nickname                                         Trust Attributes
test CA Signing Certificate                                  CTu,Cu,Cu
test KRA Transport Certificate                               u,u,u
test KRA Storage Certificate                                 u,u,u

5. Step 1: Client-Side Archival

Generate an RSA-2048 user key pair and wrap it for archival using the KRA transport certificate.

$ hsmCompatVerifyClnt \
  --client-db-path client-nssdb \
  --client-passwd-file client-nssdb/password.txt \
  --transport-cert pkiserv-nssdb/kra_transport.pem \
  --output client-nssdb/test-rsa \
  --algorithm RSA \
  --key-length 2048 \
  --keywrap-alg "AES KeyWrap/Wrapped" \
  --rsa-keywrap RSA-OAEP \
  --verbose

Expected Output Files:

client-nssdb/test-rsa-wrapped-session.bin  (256 bytes - RSA-OAEP wrapped session key)
client-nssdb/test-rsa-wrapped-private.bin  (1224 bytes - AES-KWP wrapped RSA private key)
client-nssdb/test-rsa-public.der           (294 bytes - RSA public key)

Verify:

$ ls -lh client-nssdb/test-rsa-*
-rw-r--r--. 1 user user  294 client-nssdb/test-rsa-public.der
-rw-r--r--. 1 user user 1.2K client-nssdb/test-rsa-wrapped-private.bin
-rw-r--r--. 1 user user  256 client-nssdb/test-rsa-wrapped-session.bin

What Happened:

  1. Client generated RSA-2048 key pair in NSS database

  2. Generated 32-byte AES-256 session key

  3. RSA private key wrapped with AES-256 session key using AES-KWP

  4. Session key wrapped with KRA transport public key using RSA-OAEP

  5. Three output files created for transmission to KRA

6. Step 2: Server-Side Archival

Unwrap the user’s private key from transport wrapping, re-wrap with storage key, and create LDIF entry.

$ hsmCompatVerifyServ \
  --pkiserv-db-path pkiserv-nssdb \
  --client-db-path client-nssdb \
  --pkiserv-passwd-file pkiserv-nssdb/password.txt \
  --hsm-token "" \
  --hsm-token-passwd-file pkiserv-nssdb/password.txt \
  --wrapped-session client-nssdb/test-rsa-wrapped-session.bin \
  --wrapped-private client-nssdb/test-rsa-wrapped-private.bin \
  --public-key client-nssdb/test-rsa-public.der \
  --ca-nickname "test CA Signing Certificate" \
  --transport-nickname "test KRA Transport Certificate" \
  --storage-nickname "test KRA Storage Certificate" \
  --subject-dn "CN=Test User RSA" \
  --archive-only \
  --ldif-file client-nssdb/kra-archived-key.ldif \
  --keywrap-alg "AES KeyWrap/Wrapped" \
  --rsa-keywrap RSA-OAEP \
  --verbose

Expected Output:

  • Session key unwrapped using transport private key (RSA-OAEP decryption)

  • RSA private key unwrapped successfully

  • New session key generated for storage wrapping

  • RSA private key re-wrapped with storage session key

  • Session key wrapped with storage public key

  • LDIF file created: client-nssdb/kra-archived-key.ldif (contains certificate + wrapped key data)

Verify:

$ ls -lh client-nssdb/kra-archived-key.ldif
-rw-r--r--. 1 user user 4.8K client-nssdb/kra-archived-key.ldif

What Happened:

  1. KRA unwrapped session key using transport private key (RSA-OAEP)

  2. User’s private key unwrapped from transport wrapping (AES-KWP)

  3. User certificate generated and signed by CA

  4. KRA generated new session key for storage

  5. User’s private key re-wrapped for long-term storage (AES-KWP)

  6. Session key wrapped with storage public key (RSA-OAEP)

  7. LDIF entry created containing certificate and wrapped key metadata

7. Step 3: Server-Side Recovery

Read archived key from LDIF, unwrap with storage key, and export to PKCS#12 file for user.

$ hsmCompatVerifyServ \
  --pkiserv-db-path pkiserv-nssdb \
  --client-db-path client-nssdb \
  --pkiserv-passwd-file pkiserv-nssdb/password.txt \
  --hsm-token "" \
  --hsm-token-passwd-file pkiserv-nssdb/password.txt \
  --ldif-file client-nssdb/kra-archived-key.ldif \
  --ca-nickname "test CA Signing Certificate" \
  --transport-nickname "test KRA Transport Certificate" \
  --storage-nickname "test KRA Storage Certificate" \
  --p12-output client-nssdb/recovered-user-rsa.p12 \
  --recovery-passwd "Secret.123" \
  --recover-only \
  --verbose

Expected Output:

  • Loaded certificate + wrapped keys from LDIF

  • Session key unwrapped using storage private key (RSA-OAEP decryption)

  • RSA private key unwrapped successfully

  • PKCS#12 file created: client-nssdb/recovered-user-rsa.p12

Verify:

$ ls -lh client-nssdb/recovered-user-rsa.p12
-rw-------. 1 user user 2.8K client-nssdb/recovered-user-rsa.p12

What Happened:

  1. KRA loaded archived key entry from LDIF

  2. KRA unwrapped session key using storage private key (RSA-OAEP)

  3. User’s private key unwrapped from storage (AES-KWP)

  4. PKCS#12 file created with user’s certificate and private key

  5. PKCS#12 encrypted with AES-256-CBC + PBKDF2 (default non-legacy mode)

8. Verification

8.1. Inspect PKCS#12 Contents

$ pk12util -l client-nssdb/recovered-user-rsa.p12 -W Secret.123

Expected Output:

Key(shrouded):
    Friendly Name: CN=Test User RSA

    Encryption algorithm: AES-256-CBC
        Parameters:
            Iteration Count: 10000 (from PBKDF2)
            IV: [16 bytes]

Certificate:
    Data:
        Subject: "CN=Test User RSA"
        Issuer: "CN=test CA Signing Certificate"
        Serial Number: ...
        Public Key Algorithm: RSA
        Public Key Size: 2048 bits

8.2. Import Test with p12tool

Import the recovered PKCS#12 file into a fresh database to verify round-trip success.

# Create fresh test database
$ mkdir -p test-import
$ echo "Secret.123" > test-import/password.txt
$ certutil -N -d test-import -f test-import/password.txt

# Create p12tool password file
$ echo "Secret.123" > p12.pwd

# Import PKCS#12 using p12tool
$ p12tool -i client-nssdb/recovered-user-rsa.p12 \
  -d test-import \
  -w p12.pwd \
  -k test-import/password.txt

# Verify import
$ certutil -L -d test-import
$ certutil -K -d test-import

Expected Result:

PKCS12 IMPORT SUCCESSFUL
Certificate and private key imported successfully

$ certutil -L -d test-import
Certificate Nickname                                         Trust Attributes
CN=Test User RSA                                             u,u,u
test CA Signing Certificate                                  ,,

$ certutil -K -d test-import
< 0> rsa      xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx   CN=Test User RSA

9. Alternative: EC Key Archival

You can also test EC key archival by changing the algorithm:

9.1. Client-Side EC Key Generation

$ hsmCompatVerifyClnt \
  --client-db-path client-nssdb \
  --client-passwd-file client-nssdb/password.txt \
  --transport-cert pkiserv-nssdb/kra_transport.pem \
  --output client-nssdb/test-ec \
  --algorithm EC \
  --curve nistp256 \
  --keywrap-alg "AES KeyWrap/Wrapped" \
  --rsa-keywrap RSA-OAEP \
  --verbose

Expected Output Files:

client-nssdb/test-ec-wrapped-session.bin  (256 bytes)
client-nssdb/test-ec-wrapped-private.bin  (48 bytes - EC private key is smaller)
client-nssdb/test-ec-public.der           (91 bytes - EC public key)

9.2. Server-Side EC Archival and Recovery

# Archive
$ hsmCompatVerifyServ \
  --pkiserv-db-path pkiserv-nssdb \
  --client-db-path client-nssdb \
  --pkiserv-passwd-file pkiserv-nssdb/password.txt \
  --hsm-token "" \
  --hsm-token-passwd-file pkiserv-nssdb/password.txt \
  --wrapped-session client-nssdb/test-ec-wrapped-session.bin \
  --wrapped-private client-nssdb/test-ec-wrapped-private.bin \
  --public-key client-nssdb/test-ec-public.der \
  --ca-nickname "test CA Signing Certificate" \
  --transport-nickname "test KRA Transport Certificate" \
  --storage-nickname "test KRA Storage Certificate" \
  --subject-dn "CN=Test User EC" \
  --archive-only \
  --ldif-file client-nssdb/kra-archived-key-ec.ldif \
  --keywrap-alg "AES KeyWrap/Wrapped" \
  --rsa-keywrap RSA-OAEP \
  --verbose

# Recover
$ hsmCompatVerifyServ \
  --pkiserv-db-path pkiserv-nssdb \
  --client-db-path client-nssdb \
  --pkiserv-passwd-file pkiserv-nssdb/password.txt \
  --hsm-token "" \
  --hsm-token-passwd-file pkiserv-nssdb/password.txt \
  --ldif-file client-nssdb/kra-archived-key-ec.ldif \
  --ca-nickname "test CA Signing Certificate" \
  --transport-nickname "test KRA Transport Certificate" \
  --storage-nickname "test KRA Storage Certificate" \
  --p12-output client-nssdb/recovered-user-ec.p12 \
  --recovery-passwd "Secret.123" \
  --recover-only \
  --verbose

10. Key Highlights

10.1. KRA Workflow

  1. Client generates RSA or EC key pair

  2. Client wraps private key using KRA transport public key (RSA-OAEP + AES-KWP)

  3. KRA archives by unwrapping with transport and re-wrapping with storage key

  4. KRA recovers by unwrapping from storage and exporting to PKCS#12

10.2. Cryptographic Operations

  • RSA-OAEP: Session key wrapping with transport/storage public keys

  • AES-256-KWP: Private key wrapping (RFC 5649, FIPS-compliant)

  • PBKDF2 + AES-256-CBC: PKCS#12 encryption (non-legacy mode)

10.3. Key Wrap Algorithm Options

This demo uses --keywrap-alg "AES KeyWrap/Wrapped" (AES-KWP, RFC 5649) which is recommended for FIPS compliance.

Available Key Wrap Modes:

Algorithm Description PKCS#11 Mechanism

AES KeyWrap/Wrapped

AES-256-KWP (RFC 5649)

CKM_AES_KEY_WRAP_KWP (0x210B)

AES KeyWrap/Padding

AES-256-KWP (alternative)

CKM_AES_KEY_WRAP_PAD (0x210A)

AES KeyWrap/NoPadding

AES Key Wrap (8-byte aligned)

CKM_AES_KEY_WRAP (0x2109)

AES/CBC/PKCS5Padding

AES-CBC with IV

CKM_AES_CBC_PAD (0x1085)

Important: The same --keywrap-alg must be used in both hsmCompatVerifyClnt and hsmCompatVerifyServ.

10.4. RSA Key Wrap Options

This demo uses --rsa-keywrap RSA-OAEP which is recommended for better security.

Available RSA Wrap Modes:

Mode Description

RSA-OAEP

RSA-OAEP (recommended, better security)

RSA

RSA PKCS#1 v1.5 (legacy compatibility)

Important: The same --rsa-keywrap must be used in both hsmCompatVerifyClnt and hsmCompatVerifyServ.

10.5. Drop-In Compatibility

  • Works with existing KRA workflow

  • RSA CA for certificate signing

  • RSA transport and storage keys (required for key wrapping)

  • No server-side code changes needed

  • User keys can be RSA or EC

11. HSM Testing

The tool supports HSM/PKCS#11 token testing by specifying the HSM token name:

11.1. Setup with HSM

$ hsmCompatVerifyServ --setup-only \
  --pkiserv-db-path pkiserv-nssdb \
  --pkiserv-passwd-file pkiserv-nssdb/password.txt \
  --hsm-token "MyHSM" \
  --hsm-token-passwd-file hsm-password.txt \
  --ca-nickname "test CA Signing Certificate" \
  --transport-nickname "test KRA Transport Certificate" \
  --storage-nickname "test KRA Storage Certificate" \
  --verbose

This will create CA, transport, and storage keys on the HSM token named "MyHSM".

11.2. Verification with HSM

$ hsmCompatVerifyServ \
  --pkiserv-db-path pkiserv-nssdb \
  --client-db-path client-nssdb \
  --pkiserv-passwd-file pkiserv-nssdb/password.txt \
  --hsm-token "MyHSM" \
  --hsm-token-passwd-file hsm-password.txt \
  --wrapped-session client-nssdb/test-rsa-wrapped-session.bin \
  --wrapped-private client-nssdb/test-rsa-wrapped-private.bin \
  --public-key client-nssdb/test-rsa-public.der \
  --ca-nickname "test CA Signing Certificate" \
  --transport-nickname "test KRA Transport Certificate" \
  --storage-nickname "test KRA Storage Certificate" \
  --subject-dn "CN=Test User RSA" \
  --p12-output client-nssdb/recovered-user-rsa.p12 \
  --recovery-passwd "Secret.123" \
  --verbose

12. Troubleshooting

12.1. NSS Version Check

$ rpm -q nss
nss-3.90.0-1.fc38.x86_64

12.2. JSS Version Check

$ rpm -q jss
jss-5.5.0-1.fc38.x86_64

12.3. Common Issues

Issue: hsmCompatVerifyServ or hsmCompatVerifyClnt not found

Solution: Ensure tools are in PATH or use full path to binaries


Issue: Transport certificate not found

Solution: Verify the transport certificate was exported during setup:

$ ls -l pkiserv-nssdb/kra_transport.pem

Issue: PKCS#12 import fails

Solution: Verify password and database are correct. Use p12tool for importing PKCS#12 files.


Issue: Key wrap algorithm mismatch

Solution: Ensure the same --keywrap-alg is used in both client and server commands


Issue: RSA keywrap type mismatch

Solution: Ensure the same --rsa-keywrap is used in both client and server commands

13. Legacy PKCS#12 Format

By default, hsmCompatVerifyServ creates non-legacy PKCS#12 files using AES-256-CBC + PBKDF2. For compatibility with older systems, you can use legacy format:

$ hsmCompatVerifyServ \
  --recover-only \
  --ldif-file client-nssdb/kra-archived-key.ldif \
  --p12-output client-nssdb/recovered-user-legacy.p12 \
  --recovery-passwd "Secret.123" \
  --legacyPKCS12 \
  --verbose

This will create a PKCS#12 file using PBE_SHA1_DES3_CBC (not FIPS-compliant).

14. References

⚠️ **GitHub.com Fallback** ⚠️