Common Public Key Standards and Their Use with OpenSSL
This post outlines several commonly adopted standards for working with public keys in cryptographic systems. It highlights their primary purposes, relevant use cases and gives examples of how to generate or work with these standards using OpenSSL commands.
This post does not cover specific file formats (e.g., PEM, DER, or JWK), for more information on file formats, please refer to:
Common Cryptographic File Formats
An overview of PEM, DER, JWK, and JWKS, covering usage details, file extensions, and import/export examples with OpenSSL and Web Crypto API.
PKCS #8
- Purpose: Defines a generic, algorithm-agnostic format for private keys.
- Context: Used wherever private keys need to be stored or exchanged in a standardized manner, supporting RSA, EC, DSA, and others in a single format.
- Typical Extensions:
.pem
(PEM-encoded) - Formal Definition: historically RFC 5208, but obsoleted by RFC 5958.
Example (PEM format):
-----BEGIN PRIVATE KEY-----
MIIEvQIBADANBgkqhkiG9...
-----END PRIVATE KEY-----
Generate an RSA private key in PKCS #8 format:
openssl genpkey -algorithm RSA -out private_key.pem
SPKI (SubjectPublicKeyInfo)
- Purpose: Defines a standard, algorithm-agnostic format for public keys, as part of the X.509 certificate structure.
- Context: Commonly extracted from certificates or derived from a PKCS #8 private key. By taking a PKCS #8 private key (which includes both algorithm parameters and the private key material), one can produce the corresponding public key in SPKI format, ensuring consistent algorithm identification and key data representation.
- Typical Extensions:
.pem
(PEM-encoded) - Formal Definition: Defined within X.509 RFC 5280 (see SubjectPublicKeyInfo section)
Example (PEM public key):
-----BEGIN PUBLIC KEY-----
MIIBIjANBgkq...
-----END PUBLIC KEY-----
Generate a public key from a private key in PKCS #8 format with OpenSSL:
openssl rsa -pubout -in private_key.pem -out public_key.pem
It is not trivial to extract the public key from a private key in PKCS #8 format using the Web Crypto API. If you are interested in this process, you can refer to the article below for a guide:
Deriving an RSA Public Key from a Private Key Using the Web Crypto API
Learn how to derive an RSA public key from a private key using the Web Crypto API by exporting the private key in JWK format and re-importing key components.
PKCS #10 (Certificate Signing Request - CSR)
- Purpose: A request for a certificate, including a public key (SPKI) and identifying information like the requested subject’s name.
- Context: Submitted to a certificate authority to obtain an X.509 certificate.
- Typical Extensions:
.csr
, sometimes.pem
(Note:.csr
files are typically PEM-encoded.) - Formal Definition:: RFC 2986
- PKCS #10 was defined in the context of the original PKCS standards by RSA Labs
- It was not formally standardized by the IETF, but the format is widely used in practice
- RFC 2986 is basically a re-publication of the original PKCS #10 specification
Example (PEM-encoded CSR):
-----BEGIN CERTIFICATE REQUEST-----
MIICzDCCAbQCAQAwCzEJMAcGA1UEAwwAM...
... (This request includes the public key and the subject details such as CN, O, L, ST, C)
-----END CERTIFICATE REQUEST-----
Generate a CSR with OpenSSL and an existing private key (the private key is used to create the public key in the CSR and to sign the CSR):
The signature algorithm is defined by PKCS #1, when using RSA, which is the default for OpenSSL.
openssl req -new -key private_key.pem -out request.csr
You can view the contents (mainly Subject, SPKI and Signature) of a CSR with:
openssl req -in request.csr -noout -text
X.509
What It Is:
X.509 is a standard defining the format of public key certificates. These certificates bind a public key to an identity (e.g., a server name or a person). The X.509 structure also uses ASN.1. Many PKCS standards build on or interact with X.509 certificates.
Formal Definition: RFC 5280
Example (PEM):
-----BEGIN CERTIFICATE-----
MIIDazCCAlOgA...
-----END CERTIFICATE-----
Generate a self-signed certificate using a CSR (Certificate Signing Request) and a private key:
openssl req -new -key private_key.pem -out request.csr
openssl x509 -req -in request.csr -signkey private_key.pem -out cert.pem
Generate a self-signed certificate with OpenSSL and an RSA private key (PKCS #8 format):
openssl req -new -x509 -key private_key.pem -out cert.pem -days 365
You can also create a self signed certificate without a private key, openssl will generate a new key for you:
openssl req -new -x509 -keyout private_key.pem -out cert.pem -days 365
# this will ask for a password, because the private key will be encrypted with AES256 per default
# you can create a private key without password with the -nodes (No DES) option
openssl req -new -x509 -keyout private_key.pem -out cert.pem -days 365 -nodes # no DES encryption, option name is a bit misleading, because nowadays AES is used
You can view the contents of a certificate with:
openssl x509 -in cert.pem -noout -text
PKCS #12 (PFX)
- Purpose: Binary container for private keys, certificates, and optionally a chain of certificates, often encrypted with a password.
- Context: Used to transport and back up key+certificate pairs securely, commonly in Windows environments or when importing keys into browsers or servers.
- Typical Extensions:
.p12
,.pfx
- (Binary format, no direct PEM example.)
- Formal Definition: RFC 7292
Generate a PKCS #12 file from a private key and certificate:
openssl pkcs12 -export -inkey private_key.pem -in cert.pem -out keystore.p12
You can view the contents of a PKCS #12 file with:
openssl pkcs12 -info -nodes -in keystore.p12 # no DES (-nodes) option to avoid password prompt, remove it if the private key is encrypted
You can extract the private key and certificate from a PKCS #12 file with:
# Extract the private key (unencrypted)
openssl pkcs12 -in keystore.p12 -out private_key.pem -nodes -nocerts # remove no DES (-nodes) option if the private key is encrypted
# Extract the certificate
openssl pkcs12 -in keystore.p12 -out cert.pem -nokeys -clcerts
CMS (Cryptographic Message Syntax)
- Purpose: CMS is the IETF’s standard syntax for cryptographically protected messages. It supports digital signatures, message digests, and encryption. CMS is effectively the evolution of PKCS #7 in an IETF standards track.
- Context: CMS is widely used in secure email (S/MIME), secure file transfer, and other scenarios requiring signed or encrypted data interchange.
- Typical Extensions: While CMS can be encapsulated in various file extensions (
.p7s
,.p7m
, or sometimes.cms
), it often appears in contexts where PKCS #7 formats were traditionally used. - Structure: A CMS object (like PKCS #7) can contain certificates, signer info, and encrypted data. However, private keys are not typically included. The data can be encoded in binary (DER) or ASCII-armored (PEM).
- Formal Definition: RFC 5652
- CMS was derived from PKCS #7 but became an IETF standard.
Example (PEM) Although PEM labels vary in practice, you might see:
-----BEGIN CMS-----
MIIGCSqGSIb3DQEHAaCCA...
-----END CMS-----
Create a Signed CMS Message:
openssl cms -sign \
-in data.txt \
-signer cert.pem \
-inkey private_key.pem \
-out signed.cms \
-nodetach \
-outform PEM
Verify a CMS Message:
Since we are using a self signed certificate the signer and the CA are the same, normally you would use a root CA certificate to verify the signature.
openssl cms -verify \
-in signed.cms \
-CAfile cert.pem \
-out verified_data.txt
Encrypt Data Using CMS:
openssl cms -encrypt \
-in data.txt \
-out encrypted.cms \
-outform PEM \
cert.pem
Decrypt Data Using CMS:
openssl cms -decrypt \
-in encrypted.cms \
-recip cert.pem \
-inkey private_key.pem \
-out decrypted_data.txt
S/MIME (Secure/Multipurpose Internet Mail Extensions)
- Purpose: S/MIME provides a standard for public key encryption and signing of MIME data, typically used in email. It leverages CMS (formerly PKCS #7) as its core cryptographic structure.
- Context: S/MIME is the de-facto standard for secure email. It adds cryptographic enhancements to MIME messages, allowing for end-to-end encryption and digital signatures in email clients.
- Typical Extensions / Usage: S/MIME messages often appear as
.p7s
attachments for detached signatures, or.p7m
for enveloped (encrypted) data within email clients. - Structure (No Private Key): The actual S/MIME messages will contain CMS/PKCS #7 structures but do not embed private keys. Certificates for the sender or the encryption recipient may be included to facilitate trust. (typically not PEM encoded)
- Formal Definition: RFC 5751
Example
MIME-Version: 1.0
Content-Type: multipart/signed; protocol="application/x-pkcs7-signature"; micalg="sha-256"; boundary="----abc1"
This is an S/MIME signed message
------abc1
Content-Type: text/plain
(SOME DATA)
------abc1
Content-Type: application/x-pkcs7-signature; name="smime.p7s"
Content-Transfer-Encoding: base64
Content-Disposition: attachment; filename="smime.p7s"
MIIGGgYJK...
------abc1--
Create a Signed S/MIME Message
openssl smime -sign \
-in data.txt \
-text \
-signer cert.pem \
-inkey private_key.pem \
-out signed.p7m
Verify a Signed S/MIME Message
- Since the generated p7m file includes the signer's public key certificate, it is self contained and can be verified without explicitly providing the CA certificate.
- In a real-world scenario, you would need the CA certificate to make sure the signer's certificate is trusted, since we are using a self signed certificate here, we skip the validation of the signer's certificate chain with
-noverify
.
openssl smime -verify \
-noverify \
-in signed.p7m \
-out verified_message.txt
Encrypt a Message for S/MIME
openssl smime -encrypt \
-in data.txt \
-out encrypted.p7m \
cert.pem
Decrypt an Encrypted S/MIME Message
openssl smime -decrypt \
-in encrypted.p7m \
-recip cert.pem \
-inkey private_key.pem \
-out decrypted_data.txt
Other Notable Standards
PKCS #1
- Purpose: Defines the RSA cryptography standard, including the mathematical properties of RSA keys, as well as the encoding, encryption, and signature schemes (e.g., RSAES-OAEP, RSASSA-PSS).
- Key Handling: Primarily defines how to work with RSA keys and their operations, not how to store them. While PKCS #1 private key structures can still appear in legacy deployments, modern environments often use PKCS #8 for key storage.
- Relevance: PKCS #1 is actively maintained and forms the basis for RSA usage in various protocols. While the PKCS #1 format is considered legacy (modern systems use PKCS #8 for private key storage), the standard itself is still fundamental for specifying RSA algorithm behavior, padding, and signature schemes.
- Typical Usage: Referenced whenever RSA signatures or encryption must be performed, ensuring interoperability and consistent algorithm definitions.
- Formal Definition: RFC 8017
Legacy Example (RSA Private Key, PEM):
this format is considered legacy and not recommended for new deployments, newer systems use PKCS #8 for storing private keys
-----BEGIN RSA PRIVATE KEY-----
MIIEowIBAAKCAQEA...
-----END RSA PRIVATE KEY-----
PKCS #3 (Diffie-Hellman Parameters)
- Purpose: Specifies parameters for Diffie-Hellman key exchange.
- Context: Used to share and standardize DH parameters, less common today but still used in some legacy systems.
- Typical Extensions:
.pem
- Formal Definition: RFC 2631
Example (PEM):
-----BEGIN DH PARAMETERS-----
MIGHAoGBALWo...
-----END DH PARAMETERS-----
PKCS #7 (Cryptographic Message Syntax)
- Purpose: Defines a format for signed or encrypted data, and can bundle certificates.
- Context: Used to distribute certificates or signed messages without revealing private keys.
- Typical Extensions:
.p7b
,.p7c
- (No private key included, typically a binary or PEM-encoded structure with certificates and signatures.)
- Formal Definition: RFC 2315
Example (PEM):
-----BEGIN PKCS7-----
MIIBIjANBgkq...
-----END PKCS7-----
Generate a PKCS #7 file with OpenSSL (-nocrl for no Certificate Revocation List, which is ):
openssl crl2pkcs7 -nocrl -certfile cert.pem -out certs.p7b
Inspect the contents of a PKCS #7 file:
openssl pkcs7 -in certs.p7b -print_certs -text