# PKCS Loaders
Five top-level functions extract X.509 certificates and/or PKCS#8 private keys from
container formats (PKCS#7, PKCS#12). All functions accept DER, BER, or CER input;
the encoding is detected automatically.
## Functions
### load_der_pkcs7_certificates
```python
load_der_pkcs7_certificates(data: bytes) -> list[Certificate]
```
Parse a DER or BER PKCS#7 SignedData blob and return its embedded certificates.
BER indefinite-length encodings (common in PKCS#7 files from older tools) are handled
transparently. Non-certificate entries in the CertificateSet are silently skipped.
Raises `ValueError` if the outer ContentInfo contentType is not id-signedData, or on any
ASN.1 structural error.
### load_pem_pkcs7_certificates
```python
load_pem_pkcs7_certificates(data: bytes) -> list[Certificate]
```
Decode PEM block(s) in `data` (any label accepted: `PKCS7`, `CMS`, `CERTIFICATE`, etc.),
then extract certificates from each PKCS#7 payload. All certificates across all blocks are
returned as a single flat list.
Raises `ValueError` if no PEM block is found, or if any block fails to parse as PKCS#7
SignedData.
### load_pkcs12_certificates
```python
load_pkcs12_certificates(data: bytes, password: bytes = None) -> list[Certificate]
```
Extract certificates from a PKCS#12 / PFX archive. Non-certificate bag types
(`keyBag`, `pkcs8ShroudedKeyBag`, `crlBag`, `secretBag`) are silently skipped.
`password` is the archive password as raw bytes (UTF-8, no NUL terminator). Pass `b""`
or omit for no-password archives.
Encrypted bags are supported when built with the `openssl` Cargo feature
(PBES2/PBKDF2/AES-256-CBC) and optionally `deprecated-pkcs12-algorithms` (legacy 3DES).
Without the `openssl` feature a `ValueError` is raised when any encrypted bag is
encountered.
### load_pkcs12_keys
```python
load_pkcs12_keys(data: bytes, password: bytes = None) -> list[bytes]
```
Extract PKCS#8 private keys from a PKCS#12 archive. Returns a list of raw DER-encoded
`OneAsymmetricKey` blobs, one per `keyBag` (unencrypted) and `pkcs8ShroudedKeyBag`
(decrypted with the `openssl` feature) entry. `certBag`, `crlBag`, and `secretBag`
entries are silently skipped.
### load_pkcs12
```python
load_pkcs12(data: bytes, password: bytes = None) -> tuple[list[Certificate], list[bytes]]
```
Extract both certificates and private keys from a PKCS#12 archive in a single call.
Returns `(certs, keys)` where `certs` is a `list[Certificate]` and `keys` is a `list[bytes]`
of DER-encoded PKCS#8 structures.
### create_pkcs12
```python
create_pkcs12(
certificates: list[Certificate | bytes],
private_key: PrivateKey | bytes | None = None,
password: bytes | None = None,
) -> bytes
```
Build a DER-encoded PKCS#12 PFX archive. Each element of `certificates` may be a
`Certificate` object or raw DER `bytes`; both types may appear in the same list.
`private_key` may be a `PrivateKey` object or DER-encoded PKCS#8 `bytes`.
When `password` is `None` or omitted, the archive is written without encryption.
When `password` is provided and the library is built with the `openssl` Cargo feature,
bags are encrypted with PBES2/PBKDF2-SHA256/AES-256-CBC using 600,000 iterations.
Without the `openssl` feature, supplying a password raises `ValueError`.
Raises `TypeError` for unrecognised element types in `certificates` or for an
unrecognised `private_key` type.
## Usage
```python
import synta
# ── PKCS#7 SignedData (DER or BER) ───────────────────────────────────────────
# amazon-roots.p7b uses BER indefinite-length encoding (0x30 0x80…); both are
# handled transparently — no caller-visible difference.
data = open("bundle.p7b", "rb").read()
certs = synta.load_der_pkcs7_certificates(data)
for cert in certs:
print(cert.subject)
# ── PKCS#7 SignedData (PEM-wrapped) ──────────────────────────────────────────
pem = open("bundle.pem", "rb").read()
certs = synta.load_pem_pkcs7_certificates(pem)
# ── PKCS#12 — certificates only ──────────────────────────────────────────────
data = open("archive.p12", "rb").read()
certs = synta.load_pkcs12_certificates(data) # unencrypted
certs = synta.load_pkcs12_certificates(data, b"s3cr3t") # password-protected
print(f"found {len(certs)} certificate(s)")
for cert in certs:
print(cert.subject, cert.not_before, "–", cert.not_after)
# ── PKCS#12 — private keys only ──────────────────────────────────────────────
# Returns a list[bytes] of DER-encoded OneAsymmetricKey (PKCS#8) structures.
keys = synta.load_pkcs12_keys(data, b"s3cr3t")
for key_der in keys:
from cryptography.hazmat.primitives.serialization import load_der_private_key
key = load_der_private_key(key_der, None)
# ── PKCS#12 — both certificates and keys in one call ─────────────────────────
certs, keys = synta.load_pkcs12(data, b"s3cr3t")
```
### Creating PKCS#12 Archives
```python
import synta
# ── Certificate objects directly ─────────────────────────────────────────────
certs = synta.load_pkcs12_certificates(open("src.p12", "rb").read())
pfx = synta.create_pkcs12(certs) # no password
open("bundle.p12", "wb").write(pfx)
# ── With a password (openssl feature required) ────────────────────────────────
try:
pfx = synta.create_pkcs12(certs, password=b"s3cr3t")
except ValueError:
# Raised when password is provided without the openssl Cargo feature
pass
# ── With a cert and a PrivateKey object ──────────────────────────────────────
certs, keys = synta.load_pkcs12(open("src.p12", "rb").read())
key = synta.PrivateKey.from_der(keys[0])
pfx = synta.create_pkcs12(certs, private_key=key, password=b"s3cr3t")
# ── Raw DER bytes also accepted ───────────────────────────────────────────────
pfx = synta.create_pkcs12(
[cert.to_der() for cert in certs],
private_key=keys[0], # bytes from load_pkcs12_keys
)
# ── Roundtrip verification ────────────────────────────────────────────────────
parsed_back = synta.load_pkcs12_certificates(pfx, None)
assert len(parsed_back) == len(certs)
```
**Encryption support:** when `password` is provided and the library is built with
`--features openssl`, bags are encrypted with PBES2/PBKDF2-SHA256/AES-256-CBC using
600,000 iterations. Without the `openssl` feature, supplying a non-`None` password raises
`ValueError`.
See also [PKI Blocks](pki-blocks.md) for format-agnostic reading, and [PEM/DER](pem-der.md)
for PEM encode/decode helpers.