CMS Signatures & Encryption
CMS Signatures & Encryption
Section titled “CMS Signatures & Encryption”This guide covers the Cryptographic Message Syntax (CMS) implementation for signing and encrypting data.
1. What is CMS?
Section titled “1. What is CMS?”Cryptographic Message Syntax (CMS) is a standard format (RFC 5652) for signing and encrypting data. It supports classical algorithms (ECDSA, RSA, Ed25519, Ed448), post-quantum (ML-DSA, SLH-DSA, ML-KEM), and hybrid modes.
Standards
Section titled “Standards”| Standard | Description |
|---|---|
| RFC 5652 | Cryptographic Message Syntax (CMS) |
| RFC 8419 | EdDSA (Ed25519/Ed448) in CMS |
| RFC 9629 | Using Key Encapsulation Mechanisms in CMS |
| RFC 9814 | SLH-DSA in CMS |
| RFC 9880 | ML-KEM for CMS |
| RFC 9882 | ML-DSA in CMS |
| FIPS 203 | ML-KEM (Kyber) |
| FIPS 204 | ML-DSA (Dilithium) |
| FIPS 205 | SLH-DSA (SPHINCS+) |
Content Types
Section titled “Content Types”| Type | OID | Description |
|---|---|---|
| SignedData | 1.2.840.113549.1.7.2 | Digital signatures |
| EnvelopedData | 1.2.840.113549.1.7.3 | Encrypted data |
2. CLI Commands
Section titled “2. CLI Commands”cms sign
Section titled “cms sign”Create a CMS SignedData signature.
qpki cms sign --data <file> --cert <cert> --key <key> --out <output> [flags]Flags:
| Flag | Default | Description |
|---|---|---|
--data | (required) | File to sign |
--cert | Signer certificate (PEM) | |
--key | Private key (PEM, or use —hsm-config) | |
--credential | Credential ID (alternative to —cert/—key) | |
--cred-dir | ./credentials | Credentials directory |
--out, -o | (required) | Output file (.p7s) |
--hash | (auto) | Hash algorithm. Auto-selected for ML-DSA per RFC 9882. Options: sha256, sha384, sha512, sha3-256, sha3-384, sha3-512 |
--detached | true | Create detached signature (content not included) |
--include-certs | true | Include signer certificate in output |
--hsm-config | HSM configuration file (YAML) | |
--key-label | HSM key label (CKA_LABEL) | |
--key-id | HSM key ID (CKA_ID, hex) | |
--passphrase | Key passphrase |
Examples:
# Sign with credential (recommended)qpki cms sign --data document.pdf --credential signer --out document.p7s
qpki cms sign --data document.pdf --cert signer.crt --key signer.key --out document.p7s
qpki cms sign --data document.pdf --cert signer.crt --key signer.key --detached=false --out document.p7s
qpki cms sign --data document.pdf --cert signer.crt --key signer.key --hash sha512 --out document.p7s
qpki cms sign --data document.pdf --cert signer.crt \ --hsm-config ./hsm.yaml --key-label "signing-key" --out document.p7scms verify
Section titled “cms verify”Verify a CMS SignedData signature.
qpki cms verify <signature-file> [flags]Flags:
| Flag | Default | Description |
|---|---|---|
--data | Original data file (for detached signatures) | |
--ca | CA certificate for chain verification |
Examples:
# Verify detached signatureqpki cms verify document.p7s --data document.pdf --ca ca.crt
qpki cms verify document.p7s --ca ca.crt
qpki cms verify document.p7s --data document.pdfcms encrypt
Section titled “cms encrypt”Encrypt data using CMS EnvelopedData.
qpki cms encrypt --recipient <cert> --in <file> --out <file> [flags]Flags:
| Flag | Short | Default | Description |
|---|---|---|---|
--recipient | -r | (required) | Recipient certificate(s), repeatable |
--in | -i | (required) | Input file to encrypt |
--out | -o | (required) | Output file (.p7m) |
--content-enc | aes-256-gcm | Content encryption (aes-256-gcm, aes-256-cbc, aes-128-gcm) |
Supported key types:
- RSA: Uses RSA-OAEP with SHA-256
- EC: Uses ECDH with AES Key Wrap (HSM supported via CKM_ECDH1_DERIVE)
- ML-KEM: Uses ML-KEM encapsulation with AES Key Wrap (post-quantum)
Examples:
# Encrypt for a single recipientqpki cms encrypt --recipient bob.crt --in secret.txt --out secret.p7m
qpki cms encrypt --recipient alice.crt --recipient bob.crt --in data.txt --out data.p7m
qpki cms encrypt --recipient bob.crt --in data.txt --out data.p7m --content-enc aes-256-cbccms decrypt
Section titled “cms decrypt”Decrypt CMS EnvelopedData.
qpki cms decrypt --key <key> --in <file> --out <file> [flags]Flags:
| Flag | Short | Default | Description |
|---|---|---|---|
--key | -k | Private key file (PEM) | |
--cert | -c | Certificate for recipient matching | |
--credential | Credential ID (searches ALL versions for matching key) | ||
--cred-dir | ./credentials | Credentials directory | |
--in | -i | (required) | Input file (.p7m) |
--out | -o | (required) | Output file |
--passphrase | Key passphrase |
Examples:
# Decrypt with credential (searches all versions)qpki cms decrypt --credential recipient --in secret.p7m --out secret.txt
qpki cms decrypt --key bob.key --in secret.p7m --out secret.txt
qpki cms decrypt --key bob.key --passphrase "secret" --in data.p7m --out data.txt
qpki cms decrypt --key bob.key --cert bob.crt --in data.p7m --out data.txtNote: When using
--credential, QPKI searches all versions of the credential for a matching decryption key. This is essential after key rotation: data encrypted with an old key (before rotation) can still be decrypted.
cms info
Section titled “cms info”Display detailed information about a CMS message.
qpki cms info <file>Output includes:
- Content type (SignedData or EnvelopedData)
- Version, algorithms, signature/encryption details
- Signer information (for SignedData)
- Recipient information (for EnvelopedData)
- Embedded certificates
Examples:
# Display SignedData infoqpki cms info signature.p7s
qpki cms info encrypted.p7m3. Signing Profiles
Section titled “3. Signing Profiles”Create a signing certificate for CMS signatures.
Option A: Credential-based
Section titled “Option A: Credential-based”# ECDSAqpki credential enroll --ca-dir ./ca --cred-dir ./credentials \ --profile ec/signing --var cn="Document Signer" --id signer
qpki credential enroll --ca-dir ./ca --cred-dir ./credentials \ --profile ml/signing --var cn="PQC Signer" --id pqc-signer
qpki credential enroll --ca-dir ./ca --cred-dir ./credentials \ --profile slh/signing --var cn="Archive Signer" --id archive-signer
qpki credential enroll --ca-dir ./ca --cred-dir ./credentials \ --profile hybrid/catalyst/signing --var cn="Hybrid Signer" --id hybrid-signer
qpki cms sign --data doc.pdf \ --cert ./credentials/signer/certificates.pem \ --key ./credentials/signer/private-keys.pem --out doc.p7sOption B: CSR-based
Section titled “Option B: CSR-based”# 1. Generate keyqpki key gen --algorithm ecdsa-p256 --out signer.key
qpki csr gen --key signer.key --cn "Document Signer" --out signer.csr
qpki cert issue --ca-dir ./ca --profile ec/signing --csr signer.csr --out signer.crt
qpki cms sign --data doc.pdf --cert signer.crt --key signer.key --out doc.p7s4. Encryption Profiles
Section titled “4. Encryption Profiles”Create an encryption certificate for CMS EnvelopedData.
Option A: Credential-based
Section titled “Option A: Credential-based”# ECDH (classical)qpki credential enroll --ca-dir ./ca --cred-dir ./credentials \ --profile ec/encryption --var cn="Recipient" --id recipient
qpki credential enroll --ca-dir ./ca --cred-dir ./credentials \ --profile ml/encryption --var cn="PQC Recipient" --id pqc-recipient
qpki cms encrypt --recipient ./credentials/recipient/certificates.pem \ --in secret.txt --out secret.p7mOption B: CSR-based
Section titled “Option B: CSR-based”# 1. Generate keyqpki key gen --algorithm ecdsa-p384 --out recipient.key
qpki csr gen --key recipient.key --cn "Recipient" --out recipient.csr
qpki cert issue --ca-dir ./ca --profile ec/encryption --csr recipient.csr --out recipient.crt
qpki cms encrypt --recipient recipient.crt --in secret.txt --out secret.p7m5. Algorithm Support
Section titled “5. Algorithm Support”Signature Algorithms
Section titled “Signature Algorithms”| Algorithm | Key Type | Use Case |
|---|---|---|
| ECDSA-SHA256/384/512 | EC P-256/384/521 | Classical (recommended) |
| RSA-SHA256/384/512 | RSA 2048-4096 | Legacy compatibility |
| Ed25519 | Ed25519 | Modern classical (~128-bit security) |
| Ed448 | Ed448 | Modern classical (~224-bit security) |
| ML-DSA-44/65/87 | ML-DSA | Post-quantum |
| SLH-DSA-* | SLH-DSA | Hash-based PQC |
Key Encapsulation
Section titled “Key Encapsulation”| Algorithm | Key Type | Use Case |
|---|---|---|
| RSA-OAEP | RSA | Classical |
| ECDH + AES-KW | EC | Classical (recommended) |
| ML-KEM-512/768/1024 | ML-KEM | Post-quantum |
Content Encryption
Section titled “Content Encryption”| Algorithm | Key Size | Mode |
|---|---|---|
| AES-256-GCM | 256-bit | AEAD (default) |
| AES-128-GCM | 128-bit | AEAD |
| AES-256-CBC | 256-bit | CBC |
5.1 RFC 9882 Compliance (ML-DSA)
Section titled “5.1 RFC 9882 Compliance (ML-DSA)”QPKI implements RFC 9882 recommendations for ML-DSA in CMS:
Automatic Digest Selection
Section titled “Automatic Digest Selection”When signing with ML-DSA certificates, the digest algorithm is automatically selected based on the ML-DSA security level if not explicitly specified:
| ML-DSA Variant | Security Level | Auto-Selected Digest |
|---|---|---|
| ML-DSA-44 | NIST Level 1 | SHA-256 |
| ML-DSA-65 | NIST Level 3 | SHA-384 |
| ML-DSA-87 | NIST Level 5 | SHA-512 |
Example:
# Sign with ML-DSA (see Section 3 for certificate creation)qpki cms sign --data doc.pdf --cert signer.crt --key signer.key --out doc.p7s
qpki cms sign --data doc.pdf --cert signer.crt --key signer.key --hash sha256 --out doc.p7sVerification Warnings
Section titled “Verification Warnings”During verification, QPKI checks if the digest algorithm matches the ML-DSA security level and issues warnings for suboptimal combinations:
# Verify a signature - warning shown if digest doesn't match ML-DSA levelqpki cms verify doc.p7s --data doc.pdf --ca ca.crt
# WARNING: ML-DSA-87 signature uses SHA-256 (RFC 9882 recommends SHA-512 for NIST Level 5)Supported Digest Algorithms
Section titled “Supported Digest Algorithms”| Algorithm | OID | Notes |
|---|---|---|
| SHA-256 | 2.16.840.1.101.3.4.2.1 | Default for ML-DSA-44, classical |
| SHA-384 | 2.16.840.1.101.3.4.2.2 | Default for ML-DSA-65 |
| SHA-512 | 2.16.840.1.101.3.4.2.3 | Default for ML-DSA-87 |
| SHA3-256 | 2.16.840.1.101.3.4.2.8 | SHA-3 family |
| SHA3-384 | 2.16.840.1.101.3.4.2.9 | SHA-3 family |
| SHA3-512 | 2.16.840.1.101.3.4.2.10 | SHA-3 family |
5.2 RFC 8419 Compliance (EdDSA)
Section titled “5.2 RFC 8419 Compliance (EdDSA)”QPKI implements RFC 8419 for EdDSA algorithms (Ed25519 and Ed448) in CMS:
Supported Algorithms
Section titled “Supported Algorithms”| Algorithm | OID | Security Level | Mode |
|---|---|---|---|
| Ed25519 | 1.3.101.112 | ~128 bits | Pure (no pre-hash) |
| Ed448 | 1.3.101.113 | ~224 bits | Pure (no pre-hash) |
Pure Mode Signing
Section titled “Pure Mode Signing”Both Ed25519 and Ed448 operate in “pure” mode per RFC 8419:
- Data is signed directly without pre-hashing
- Parameters field is absent in AlgorithmIdentifier
- Ed448 uses empty context string (
"")
Example:
# Sign with Ed448 (see Section 3 for certificate creation)qpki cms sign --data doc.pdf --cert signer.crt --key signer.key --out doc.p7s
qpki cms verify doc.p7s --data doc.pdf --ca ca.crtEd25519 vs Ed448
Section titled “Ed25519 vs Ed448”| Feature | Ed25519 | Ed448 |
|---|---|---|
| Security | ~128 bits | ~224 bits |
| Signature size | 64 bytes | 114 bytes |
| Public key size | 32 bytes | 57 bytes |
| Performance | Faster | Slower |
| Use case | General purpose | Higher security requirements |
5.3 RFC 9814 Compliance (SLH-DSA)
Section titled “5.3 RFC 9814 Compliance (SLH-DSA)”QPKI implements RFC 9814 for SLH-DSA (SPHINCS+) algorithms in CMS:
Supported Algorithms
Section titled “Supported Algorithms”| Algorithm | OID | Security | Mode |
|---|---|---|---|
| SLH-DSA-SHA2-128s | 2.16.840.1.101.3.4.3.20 | NIST Level 1 | Small signatures |
| SLH-DSA-SHA2-128f | 2.16.840.1.101.3.4.3.21 | NIST Level 1 | Fast signing |
| SLH-DSA-SHA2-192s | 2.16.840.1.101.3.4.3.22 | NIST Level 3 | Small signatures |
| SLH-DSA-SHA2-192f | 2.16.840.1.101.3.4.3.23 | NIST Level 3 | Fast signing |
| SLH-DSA-SHA2-256s | 2.16.840.1.101.3.4.3.24 | NIST Level 5 | Small signatures |
| SLH-DSA-SHA2-256f | 2.16.840.1.101.3.4.3.25 | NIST Level 5 | Fast signing |
| SLH-DSA-SHAKE-128s | 2.16.840.1.101.3.4.3.26 | NIST Level 1 | Small signatures |
| SLH-DSA-SHAKE-128f | 2.16.840.1.101.3.4.3.27 | NIST Level 1 | Fast signing |
| SLH-DSA-SHAKE-192s | 2.16.840.1.101.3.4.3.28 | NIST Level 3 | Small signatures |
| SLH-DSA-SHAKE-192f | 2.16.840.1.101.3.4.3.29 | NIST Level 3 | Fast signing |
| SLH-DSA-SHAKE-256s | 2.16.840.1.101.3.4.3.30 | NIST Level 5 | Small signatures |
| SLH-DSA-SHAKE-256f | 2.16.840.1.101.3.4.3.31 | NIST Level 5 | Fast signing |
Digest Auto-Selection
Section titled “Digest Auto-Selection”Per RFC 9814, the digest algorithm is auto-selected based on SLH-DSA security level:
| Security Level | Digest Algorithm |
|---|---|
| 128-bit (Level 1) | SHA-256 |
| 192-bit (Level 3) | SHA-512 |
| 256-bit (Level 5) | SHA-512 |
Pure Mode Signing
Section titled “Pure Mode Signing”All SLH-DSA variants operate in “pure” mode:
- Data is signed directly without pre-hashing
- Parameters field is absent in AlgorithmIdentifier
- Empty context string per RFC 9814
Example:
# Sign with SLH-DSA (see Section 3 for certificate creation)qpki cms sign --data doc.pdf --cert signer.crt --key signer.key --out doc.p7s
qpki cms verify doc.p7s --data doc.pdf --ca ca.crtSHA2 vs SHAKE Variants
Section titled “SHA2 vs SHAKE Variants”| Feature | SHA2 variants | SHAKE variants |
|---|---|---|
| Hash function | SHA-256/SHA-512 | SHAKE128/SHAKE256 |
| Interoperability | Wider support | Newer standard |
| Performance | Similar | Similar |
| Use case | General purpose | SHAKE-based systems |
6. OpenSSL Interoperability
Section titled “6. OpenSSL Interoperability”# Verify a CMS signature (classical algorithms only)openssl cms -verify -in signature.p7s -content document.pdf -CAfile ca.crt
openssl cms -decrypt -in encrypted.p7m -inkey recipient.key -out decrypted.txt
openssl cms -sign -in document.pdf -signer signer.crt -inkey signer.key -out signature.p7sNote: OpenSSL 3.6+ supports ML-KEM for CMS encryption/decryption (RFC 9629). For ML-DSA and SLH-DSA signatures, use
qpki cmscommands.
7. Use Cases
Section titled “7. Use Cases”Document Signing
Section titled “Document Signing”# Sign a contractqpki cms sign --data contract.pdf --cert signer.crt --key signer.key --out contract.p7s
qpki cms verify contract.p7s --data contract.pdf --ca ca.crtSecure Email (S/MIME)
Section titled “Secure Email (S/MIME)”# Encrypt for recipientqpki cms encrypt --recipient alice@example.com.crt --in message.txt --out message.p7m
qpki cms decrypt --key alice.key --in message.p7m --out message.txtPost-Quantum Document Protection
Section titled “Post-Quantum Document Protection”# Encrypt with ML-KEM (quantum-resistant)qpki cms encrypt --recipient bob-mlkem.crt --in sensitive.doc --out sensitive.p7m8. Hybrid Encryption (PQC Transition)
Section titled “8. Hybrid Encryption (PQC Transition)”For quantum-safe encryption during the post-quantum transition, use multiple recipients with different key types. This creates an EnvelopedData with two RecipientInfos, providing defense-in-depth security.
Concept
Section titled “Concept”┌─────────────────────────────────────────────────────────────┐│ EnvelopedData │├─────────────────────────────────────────────────────────────┤│ RecipientInfo[0]: KeyAgreeRecipientInfo (ECDH) ││ └─ Wrapped CEK using ECDH + AES-KW ││ ││ RecipientInfo[1]: KEMRecipientInfo (ML-KEM) ││ └─ Wrapped CEK using ML-KEM encapsulation ││ ││ EncryptedContentInfo: ││ └─ AES-256-GCM(CEK, plaintext) │└─────────────────────────────────────────────────────────────┘# Create encryption credentials for both algorithmsqpki credential enroll --ca-dir /path/to/ca --profile ec/encryption \ --var cn="Alice (Classical)"qpki credential enroll --ca-dir /path/to/pqc-ca --profile ml/encryption \ --var cn="Alice (PQC)"
qpki cms encrypt \ --recipient alice-ec.crt \ --recipient alice-mlkem.crt \ --in secret.txt --out secret.p7m
qpki cms decrypt --key alice-ec.key --in secret.p7m --out decrypted.txtqpki cms decrypt --key alice-mlkem.key --in secret.p7m --out decrypted.txtSecurity Model
Section titled “Security Model”| Threat | Classical (ECDH) | Post-Quantum (ML-KEM) | Hybrid |
|---|---|---|---|
| Classical computer | Protected | Protected | Protected |
| Quantum computer | Vulnerable | Protected | Protected |
| Bug in ML-KEM | N/A | Vulnerable | Protected |
| Bug in ECDH | Vulnerable | N/A | Protected |
Key insight: An attacker must break BOTH algorithms to decrypt the message, providing “belt and suspenders” security during the PQC transition.
9. HSM Support
Section titled “9. HSM Support”CMS operations support HSM-stored keys for both signing and decryption.
Signing with HSM
Section titled “Signing with HSM”export HSM_PIN="****"
qpki cms sign --data document.pdf --cert signer.crt \ --hsm-config ./hsm.yaml --key-label "signing-key" --out document.p7sDecryption with HSM (ECDH)
Section titled “Decryption with HSM (ECDH)”For EC encryption certificates, decryption uses ECDH key derivation via CKM_ECDH1_DERIVE:
export HSM_PIN="****"
qpki cms decrypt --in secret.p7m --out secret.txt \ --hsm-config ./hsm.yaml --key-label "encryption-key"Requirements for HSM decryption:
- EC keys must have
CKA_DERIVEattribute (QPKI sets this automatically) - HSM must support
CKM_ECDH1_DERIVEmechanism