# 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,
cipher: str | None = None,
mac_algorithm: str | 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`.
**`cipher`** selects the symmetric cipher for private-key encryption inside the archive.
Accepted values:
| `"aes256"` | AES-256-CBC | Default |
| `"aes128"` | AES-128-CBC | |
Raises `ValueError` for unknown or unsupported values (e.g. `"3des"`).
**`mac_algorithm`** selects the HMAC algorithm for the integrity MAC and PBKDF2 PRF.
Accepted values:
| `"sha256"` | HMAC-SHA-256 | Default |
| `"sha384"` | HMAC-SHA-384 | |
| `"sha512"` | HMAC-SHA-512 | |
Raises `ValueError` for unknown or unsupported values (e.g. `"sha1"`).
When `password` is `None` or omitted, the archive is written without encryption and
`cipher` / `mac_algorithm` have no effect. When `password` is provided and the library is
built with the `openssl` Cargo feature, bags are encrypted with PBES2/PBKDF2 using
600,000 iterations and the selected cipher and MAC algorithm. 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")
# ── Custom cipher and MAC algorithm ──────────────────────────────────────────
pfx = synta.create_pkcs12(
certs,
private_key=key,
password=b"s3cr3t",
cipher="aes128",
mac_algorithm="sha384",
)
# ── 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 using 600,000 iterations
(AES-256-CBC / HMAC-SHA-256 by default). 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.