# `Pkcs11ex.PKCS12`
[🔗](https://github.com/utaladriz/pkcs11ex/blob/v0.1.0/lib/pkcs11ex/pkcs12.ex#L1)

Read-only loader for PKCS#12 (`.p12` / `.pfx`) bundles.

**Never returns private key material**, even if the bundle contains one — only
a `:has_private_key` boolean. This is a deliberate design choice: `pkcs11ex`
does not sign with software keys (`specs.md` §10 Non-Goals). Use this loader
for trust-material extraction (`x5c` certs, trust anchors) and pair it with
`mix pkcs11ex.import_p12` (Phase 2) when you want to provision the key into a
PKCS#11 token.

## Implementation

v1 shells out to the `openssl pkcs12` CLI (passwords passed via env vars,
never command line). OTP's `:public_key` doesn't ship PKCS#12 support, and
rolling our own ASN.1 parser for the format's many encryption variants is a
significant undertaking. A native Rust replacement via the existing Rustler
bridge is on the roadmap; the public API is stable across the swap.

Requires `openssl` on `PATH`.

# `opts`

```elixir
@type opts() :: [password: binary(), max_chain: pos_integer()]
```

# `source`

```elixir
@type source() :: Path.t() | binary()
```

# `load`

```elixir
@spec load(source(), opts()) :: {:ok, Pkcs11ex.PKCS12.Bundle.t()} | {:error, term()}
```

Loads, parses, and returns a `Pkcs11ex.PKCS12.Bundle`.

`source` is either a filesystem path (string that resolves to a regular file)
or raw bundle bytes (binary that does not).

## Options

  * `:password` — bundle password. Required for encrypted bundles. Pass `nil`
    or omit only for the rare unencrypted bundle.
  * `:max_chain` — hard cap on chain length (default `8`). Bundles with more
    certificates fail with `:p12_chain_too_long`.

## Errors

Returns one of:
  * `:p12_invalid` — bundle bytes are malformed or unparseable.
  * `:p12_password_incorrect` — decryption failed.
  * `:p12_chain_too_long` — chain exceeded `:max_chain`.
  * `{:p12_unsupported_kdf, oid}` — bundle uses a KDF/cipher OID OpenSSL doesn't recognize.
  * `:openssl_not_found` — the `openssl` CLI is not on `PATH`.

# `load!`

```elixir
@spec load!(source(), opts()) :: Pkcs11ex.PKCS12.Bundle.t()
```

Same as `load/2` but raises `Pkcs11ex.Error` on failure.

---

*Consult [api-reference.md](api-reference.md) for complete listing*
