openssl/openssl
CMS / PKCS family
Active contributors: Tomas Mraz, Stephen Henson (historical), Pauli, Matt Caswell, slontis
Purpose
OpenSSL implements the Cryptographic Message Syntax (CMS, RFC 5652 and friends) plus the older PKCS family it generalises:
- CMS (
crypto/cms/) — signed-data, enveloped-data, authenticated-enveloped-data, digested-data, encrypted-data, compressed-data. Used by S/MIME, PKCS#7-derived protocols, ASIC-S, RPC-Sec-GSS, … - PKCS#7 (
crypto/pkcs7/) — the predecessor of CMS, kept for compatibility with old S/MIME, code-signing, and applications that still use the legacy PKCS#7 schema. - PKCS#12 (
crypto/pkcs12/) — the password-protected key+cert bundle (.p12/.pfx).
Each maps onto an ASN.1 schema (see subsystems/asn1) and uses BIO chains for streaming I/O.
Directory layout
crypto/
├── cms/
│ ├── cms_asn1.c -- the CMS ASN.1 templates
│ ├── cms_lib.c -- common helpers; BIO chain assembly; MIME I/O
│ ├── cms_sd.c -- SignedData (sign/verify)
│ ├── cms_env.c -- EnvelopedData (encrypt/decrypt)
│ ├── cms_enc.c -- the inner content-encryption helpers
│ ├── cms_dh.c -- KARI / KAGreement (DH/ECDH key agreement recipient info)
│ ├── cms_ec.c -- ECDH KARI specifics
│ ├── cms_rsa.c -- KTRI for RSA, RSA-OAEP
│ ├── cms_kari.c -- generic KARI driver
│ ├── cms_pwri.c -- PasswordRecipientInfo
│ ├── cms_smime.c -- the SMIME read/write entry points
│ ├── cms_io.c -- BER indefinite streaming I/O
│ ├── cms_att.c -- attribute helpers
│ ├── cms_ess.c -- ESS extensions (signing certificate, content hint, signed receipt request)
│ ├── cms_cd.c -- CompressedData
│ ├── cms_dd.c -- DigestedData
│ └── cms_local.h, cms_err.c
├── pkcs7/
│ ├── pk7_asn1.c, pk7_lib.c, pk7_smime.c, pk7_doit.c, pk7_attr.c, pk7_mime.c, pk7_local.h, pk7_err.c
├── pkcs12/
│ ├── p12_asn.c -- PKCS#12 schema
│ ├── p12_init.c, p12_add.c, p12_attr.c, p12_crpt.c, p12_decr.c, p12_kiss.c, p12_mutl.c, p12_npas.c, p12_p8d.c, p12_p8e.c, p12_local.h, p12_err.c, p12_sbag.c, p12_utl.c
└── ess/
└── ess_lib.c, ess_asn1.c, ess_err.c -- the ESS structures shared with CMS/PKCS#7CMS overview
The CMS surface revolves around an CMS_ContentInfo * and a small set of high-level operations:
| Operation | Function |
|---|---|
| Sign | CMS_sign(signer_cert, signer_key, additional_certs, content_bio, flags) |
| Verify | CMS_verify(cms, certs, store, content_bio, output_bio, flags) |
| Encrypt | CMS_encrypt(recipient_certs, content_bio, cipher, flags) |
| Decrypt | CMS_decrypt(cms, recipient_key, recipient_cert, dcont, output_bio, flags) |
| Compress / decompress | CMS_compress / CMS_uncompress |
Flags include CMS_DETACHED, CMS_BINARY, CMS_NOCERTS, CMS_NOCRL, CMS_NOATTR, CMS_TEXT, CMS_STREAM, CMS_USE_KEYID, CMS_PARTIAL, CMS_KEY_PARAM, CMS_DEBUG_DECRYPT, CMS_NO_SIGNING_TIME, CMS_AUTH_DATA_OAEP_LABEL_REQUIRED, …
For composing signed-and-then-enveloped or partial structures, CMS_PARTIAL plus CMS_add1_signer, CMS_add0_recipient_key, CMS_add0_recipient_password, etc. let the caller assemble piece-by-piece, ending with CMS_final to compute the actual signatures and encryptions.
Signed-data
A SignedData has the high-level shape:
SignedData ::= SEQUENCE {
version CMSVersion,
digestAlgorithms SET OF DigestAlgorithmIdentifier,
encapContentInfo EncapsulatedContentInfo, -- inner content (or a reference to it for detached)
certificates [0] IMPLICIT CertificateSet OPTIONAL,
crls [1] IMPLICIT RevocationInfoChoices OPTIONAL,
signerInfos SET OF SignerInfo
}OpenSSL's signer flow:
sequenceDiagram
participant App
participant SD as cms_sd.c
participant Inner as Inner content BIO
participant MD as EVP_MD via provider
App->>SD: CMS_sign(cert, key, certs, content_bio, flags)
SD->>SD: build CMS_SignerInfo + signed attributes (signing time, content type, message digest)
SD->>MD: digest content_bio
SD->>SD: sign signed attributes (or content for !CMS_NOATTR & detached cases)
SD-->>App: CMS_ContentInfo *
App->>SD: SMIME_write_CMS / i2d_CMS_bio_streamStreaming: with CMS_STREAM, the function returns a CMS_ContentInfo not yet fully serialised; the caller wraps it with BIO_new_CMS (which chains a content-feeding BIO over the output BIO) and writes the content bytes through. The CMS BIO finalises the structure when freed. This avoids buffering the entire content in memory.
Enveloped-data and recipient infos
EnvelopedData supports several recipient-info kinds, each with its own helper file:
| RecipientInfo kind | File | Use |
|---|---|---|
| KEKRecipientInfo (symmetric KEK) | cms_lib.c, cms_env.c |
KEK shared by recipient + sender. |
| KeyTransRecipientInfo (KTRI) | cms_rsa.c |
RSA / RSA-OAEP transport. |
| KeyAgreeRecipientInfo (KARI) | cms_kari.c, cms_dh.c, cms_ec.c |
DH/ECDH agreement. |
| PasswordRecipientInfo (PWRI) | cms_pwri.c |
PBKDF2-derived KEK from a passphrase. |
| OtherRecipientInfo | passes through | for extensions. |
Encrypt:
CMS_ContentInfo *cms = CMS_encrypt(
sk_X509_recipients, /* the recipients' certs */
content_bio, /* bytes to encrypt */
EVP_aes_256_gcm(), /* content-encryption alg */
CMS_BINARY | CMS_STREAM);Per-recipient cipher params (RSA-OAEP, ECDH KDF, …) are configured before CMS_encrypt via CMS_PARTIAL plus CMS_RecipientInfo_* setters, or after by walking CMS_get0_RecipientInfos.
ASIC-S, S/MIME, "MIME"
cms_smime.c reads and writes S/MIME-formatted messages: the multipart/signed and application/pkcs7-mime container formats. The "MIME" here is a tiny in-tree implementation, not a full MIME library — just enough to handle CMS payloads. Signature verification of a multipart/signed bundle requires the verifier to canonicalise CRLF the way the signer did; flags CMS_TEXT and CMS_BINARY control this.
ESS extensions
The signing-certificate-v2 attribute (RFC 5126/5035) and other ESS attributes used by RFC 3161 timestamps live in crypto/ess/. CMS pulls them in through cms_ess.c.
PKCS#7
PKCS#7 is the predecessor of CMS. The schema and operations are conceptually similar but the wire format differs (and PKCS#7 lacks AEAD support). OpenSSL keeps the PKCS#7 implementation in crypto/pkcs7/ mostly for parsing legacy code-signing artifacts, S/MIME v2, and similar; new code should use CMS.
The API mirror: PKCS7_sign, PKCS7_verify, PKCS7_encrypt, PKCS7_decrypt, SMIME_write_PKCS7, SMIME_read_PKCS7. Internally PKCS#7 is simpler — a single recipient-info kind (PKCS7_RECIP_INFO), no AEAD, no compressed-data.
PKCS#12
PKCS#12 (.p12 / .pfx) is the password-protected key+cert bundle used everywhere from S/MIME identity import to TLS server-key bundles.
PKCS12 *p12 = PKCS12_create(
"passphrase", "Friendly Name",
private_key, cert, ca_chain,
/* nid_key */ -1, /* nid_cert */ -1,
/* iter */ 0, /* mac_iter */ -1, /* keytype */ 0);
i2d_PKCS12_fp(fp, p12);
/* later: */
PKCS12 *p12 = d2i_PKCS12_fp(fp, NULL);
EVP_PKEY *key = NULL; X509 *cert = NULL; STACK_OF(X509) *ca = NULL;
PKCS12_parse(p12, "passphrase", &key, &cert, &ca);PKCS#12 is layered: a PFX wrapper holds an outer signed/MAC'd AuthSafe of SafeContents, each of which holds bags (key bag, cert bag, secret bag, CRL bag, …). The bag encryption uses PBKDF1 (legacy) or PBKDF2 (modern, post-3.0) plus a content-encryption alg. The MAC is HMAC-SHA1 by default but -macalg chooses SHA-256 etc.
The default MAC iteration count and PBES2 cipher were modernised in 3.0; old applications that need PKCS12 compatible with Windows XP-era importers can fall back via PKCS12_create_ex.
Common pitfalls
- CRLF sensitivity. S/MIME signed text messages are signed after canonicalisation. Ferrying them through systems that mangle line endings breaks signatures.
- Wrong CMS_BINARY / CMS_TEXT. Pass
CMS_BINARYwhen the content is bytes, not text. - Detached signatures need
CMS_DETACHEDon both sign and verify. - PKCS#12 iteration counts. The default is now strong enough; the legacy
MAC iterationsfield is small (1in some SDKs); consultdoc/man3/PKCS12_create.pod. - PKCS#7 vs CMS. Don't use PKCS#7 for new designs.
Integration points
- CMS is used by
apps/openssl cmsandapps/openssl smime. Some scripts expect CMS output by default; others want PKCS#7. - PKCS#12 is loaded by
apps/openssl pkcs12and byOSSL_STOREautomatically when given a.p12file. - CMP (RFC 4210) uses CMS-style message protection; see features/cmp.
- Timestamps wrap a TimeStampToken (a CMS SignedData) in their RFC 3161 response — see
crypto/ts/.
Entry points for modification
- New CMS recipient info kind: extend
CMS_RecipientInfo(cms_lib.c), add a per-kind file, register in the dispatcher. - New content-encryption mode: ensure the EVP cipher you want to support is exposed by a provider; CMS's content-encryption uses
EVP_CIPHERdirectly. - New PKCS#12 bag type: extend
crypto/pkcs12/p12_asn.candp12_kiss.c.
Documentation
doc/man3/CMS_sign.pod,CMS_verify.pod,CMS_encrypt.pod,CMS_decrypt.pod,CMS_compress.pod,CMS_uncompress.pod,CMS_get0_SignerInfos.pod,CMS_RecipientInfo_*.doc/man3/PKCS12_create.pod,PKCS12_parse.pod,PKCS12_newpass.pod.doc/man3/PKCS7_sign.pod,PKCS7_verify.pod,SMIME_*.doc/man7/ossl-guide-cms.pod(where present).
Built by Factory AutoWiki from public repository content. It is a generated preview for codebase exploration, not source-maintained documentation.