Botan 3.13.0
Crypto and TLS for C&
pkcs12.h
Go to the documentation of this file.
1/*
2* PKCS#12
3* (C) 2026 Damiano Mazzella
4*
5* Botan is released under the Simplified BSD License (see license.txt)
6*/
7
8#ifndef BOTAN_PKCS12_H_
9#define BOTAN_PKCS12_H_
10
11#include <botan/asn1_obj.h>
12#include <botan/pk_keys.h>
13#include <botan/secmem.h>
14#include <botan/x509cert.h>
15#include <memory>
16#include <optional>
17#include <span>
18#include <string>
19#include <string_view>
20#include <vector>
21
22namespace Botan {
23
25
26/**
27* Options controlling PKCS#12/PFX export.
28*
29* Use one of the static pseudo-constructors for the common cases:
30*
31* - @ref modern - PBES2-SHA256-AES256, SHA-256 MAC, 100 000 iterations
32* - @ref legacy_compat - PBE-SHA1-3DES, SHA-1 MAC, 2 048 iterations
33*
34* For custom configurations construct directly and use the @c with_*()
35* mutators (chainable). Any field not set explicitly defaults to the
36* "modern" value.
37*/
39 public:
40 /**
41 * @param password password protecting the file. Empty is allowed:
42 * PKCS#12 defines an encoding for an empty password, so
43 * it may be used with encryption and the MAC, although
44 * doing so offers no real protection.
45 * @param friendly_name optional friendly name attribute stored on the
46 * private key bag and on the matching end-entity
47 * certificate bag.
48 */
49 explicit PKCS12_Export_Options(std::string_view password, std::optional<std::string> friendly_name = {});
50
51 /**
52 * Modern defaults: PBES2-SHA256-AES256, SHA-256 MAC, 100 000 iterations.
53 */
54 static PKCS12_Export_Options modern(std::string_view password, std::optional<std::string> friendly_name = {});
55
56 /**
57 * Legacy-compatible defaults: PBE-SHA1-3DES, SHA-1 MAC, 2 048 iterations.
58 * Use when interoperability with old software (Java keytool pre-2019,
59 * older OpenSSL releases, Windows pre-Windows-10) is required.
60 */
61 static PKCS12_Export_Options legacy_compat(std::string_view password,
62 std::optional<std::string> friendly_name = {});
63
64 /// Override the friendly-name attribute (otherwise taken from the bundle).
66
67 /// Set number of KDF iterations.
69
70 /// Set the private key encryption algorithm (PKCS#12 PBE or PBES2 name).
72
73 /**
74 * Set the certificate encryption algorithm. Empty string (the default)
75 * means certificates are stored unencrypted (inside an unencrypted
76 * SafeContents); pass a non-empty algorithm to wrap them.
77 */
79
80 /// Set the digest used for the integrity MAC.
81 PKCS12_Export_Options& with_mac_digest(std::string algo);
82
83 /// Disable the integrity MAC. Generally not recommended.
85
86 const std::string& password() const { return m_password; }
87
88 const std::optional<std::string>& friendly_name() const { return m_friendly_name; }
89
90 size_t iterations() const { return m_iterations; }
91
92 const std::string& key_encryption_algo() const { return m_key_encryption_algo; }
93
94 /// Empty means: store certificates unencrypted.
95 const std::string& cert_encryption_algo() const { return m_cert_encryption_algo; }
96
97 const std::string& mac_digest() const { return m_mac_digest; }
98
99 bool include_mac() const { return m_include_mac; }
100
101 private:
102 std::string m_password;
103 std::optional<std::string> m_friendly_name;
104 size_t m_iterations = 100000;
105 std::string m_key_encryption_algo = "PBES2-SHA256-AES256";
106 std::string m_cert_encryption_algo;
107 std::string m_mac_digest = "SHA-256";
108 bool m_include_mac = true;
109};
110
111/**
112* PKCS#12/PFX bundle: parsed contents, mutable container, and exporter.
113*
114* PKCS#12 is a file format for storing cryptographic objects (private keys
115* and X.509 certificates) together, typically protected by a password.
116*
117* The class can be used both to inspect an existing PFX and to build a new
118* one. Construction from bytes parses an existing file; the default
119* constructor produces an empty bundle that the caller populates with
120* mutators (@ref add_key, @ref add_certificate, ...) before calling
121* @ref export_to to serialize.
122*
123* @code
124* // Parse
125* Botan::PKCS12 p12(pfx_bytes, "password");
126* if(!p12.private_keys().empty()) {
127* const auto& key = p12.private_keys().front();
128* // ...
129* }
130* if(auto ee = p12.end_entity_certificate()) {
131* // ...
132* }
133*
134* // Build
135* Botan::PKCS12 out;
136* out.set_friendly_name("My Bundle");
137* out.add_key(my_key);
138* out.add_certificate(my_cert);
139* for(const auto& ca : ca_chain) {
140* out.add_certificate(ca);
141* }
142* const auto blob = out.export_to(
143* Botan::PKCS12_Export_Options::modern("password"), rng);
144* @endcode
145*/
146class BOTAN_PUBLIC_API(3, 13) PKCS12 final {
147 public:
148 /// Construct an empty bundle.
149 PKCS12() = default;
150
151 /**
152 * Parse a PKCS#12/PFX file.
153 *
154 * @param data the PFX file contents
155 * @param password the password to decrypt the file
156 * @throws Decoding_Error if parsing fails
157 * @throws Invalid_Authentication_Tag if MAC verification fails
158 */
159 PKCS12(std::span<const uint8_t> data, std::string_view password);
160
161 /**
162 * Private keys stored in the bundle, in the order they appear in the
163 * PFX (for a parsed file) or in insertion order (for a built one).
164 * PKCS#12 allows multiple keys per file; parsing currently surfaces all
165 * KeyBag / PKCS8ShroudedKeyBag entries.
166 */
167 const std::vector<std::shared_ptr<Private_Key>>& private_keys() const { return m_private_keys; }
168
169 /**
170 * Certificates stored in the bundle, in the order they appear in the
171 * PFX or in insertion order. The end-entity certificate (if any) is
172 * not separated from CA/intermediate certificates at storage level;
173 * use @ref end_entity_certificate to obtain it.
174 */
175 const std::vector<X509_Certificate>& certificates() const { return m_certificates; }
176
177 /**
178 * @return the first certificate whose subjectPublicKeyInfo matches one
179 * of the stored private keys, or @c nullopt if none match
180 * (e.g. a certificate-only or key-only bundle).
181 */
182 std::optional<X509_Certificate> end_entity_certificate() const;
183
184 /**
185 * Convenience helper: every certificate except the one returned by
186 * @ref end_entity_certificate. Returned in storage order.
187 */
188 std::vector<X509_Certificate> ca_certificates() const;
189
190 /**
191 * Friendly-name attribute attached to the private key / end-entity
192 * certificate bag, if present.
193 */
194 const std::optional<std::string>& friendly_name() const { return m_friendly_name; }
195
196 /**
197 * localKeyId attribute attached to the private key / end-entity
198 * certificate bag, if present.
199 */
200 const std::optional<std::vector<uint8_t>>& local_key_id() const { return m_local_key_id; }
201
202 /**
203 * OIDs of bag types encountered during parsing but not handled by this
204 * implementation (e.g. SecretBag). Empty for normal files and for
205 * bundles constructed in-memory.
206 */
207 const std::vector<OID>& unknown_bag_types() const { return m_unknown_bag_types; }
208
209 /// Add a private key. PKCS#12 supports multiple keys per file.
210 void add_key(std::shared_ptr<Private_Key> key);
211
212 /// Add a certificate. End-entity vs CA is determined at export time
213 /// by matching against stored keys.
214 void add_certificate(X509_Certificate cert);
215
216 /// Set (or replace) the friendly-name attribute.
217 void set_friendly_name(std::string name);
218
219 /// Clear the friendly-name attribute.
220 void clear_friendly_name();
221
222 /// Set (or replace) the localKeyId attribute.
223 void set_local_key_id(std::vector<uint8_t> id);
224
225 /// Clear the localKeyId attribute.
226 void clear_local_key_id();
227
228 /**
229 * Serialize the bundle as a PKCS#12/PFX file.
230 *
231 * @param options export options (password, algorithms, ...).
232 * @param rng RNG used to generate salts, IVs and (if requested) the
233 * localKeyId when none is set explicitly.
234 * @throws Invalid_Argument if @p options is internally inconsistent
235 * (e.g. an unsupported algorithm is requested).
236 * @throws Invalid_Argument if a stored private key does not match any
237 * stored certificate (this implementation requires the
238 * end-entity cert to be present when a key is exported).
239 */
240 std::vector<uint8_t> export_to(const PKCS12_Export_Options& options, RandomNumberGenerator& rng) const;
241
242 private:
243 std::vector<std::shared_ptr<Private_Key>> m_private_keys;
244 std::vector<X509_Certificate> m_certificates;
245 std::optional<std::string> m_friendly_name;
246 std::optional<std::vector<uint8_t>> m_local_key_id;
247 std::vector<OID> m_unknown_bag_types;
248};
249
250} // namespace Botan
251
252#endif
#define BOTAN_PUBLIC_API(maj, min)
Definition api.h:21
const std::optional< std::string > & friendly_name() const
Definition pkcs12.h:88
PKCS12_Export_Options & without_mac()
Disable the integrity MAC. Generally not recommended.
Definition pkcs12.cpp:440
PKCS12_Export_Options & with_mac_digest(std::string algo)
Set the digest used for the integrity MAC.
Definition pkcs12.cpp:435
static PKCS12_Export_Options modern(std::string_view password, std::optional< std::string > friendly_name={})
Definition pkcs12.cpp:401
const std::string & key_encryption_algo() const
Definition pkcs12.h:92
PKCS12_Export_Options & with_friendly_name(std::string name)
Override the friendly-name attribute (otherwise taken from the bundle).
Definition pkcs12.cpp:415
static PKCS12_Export_Options legacy_compat(std::string_view password, std::optional< std::string > friendly_name={})
Definition pkcs12.cpp:406
size_t iterations() const
Definition pkcs12.h:90
const std::string & password() const
Definition pkcs12.h:86
bool include_mac() const
Definition pkcs12.h:99
const std::string & cert_encryption_algo() const
Empty means: store certificates unencrypted.
Definition pkcs12.h:95
PKCS12_Export_Options & with_cert_encryption_algo(std::string algo)
Definition pkcs12.cpp:430
PKCS12_Export_Options & with_iterations(size_t n)
Set number of KDF iterations.
Definition pkcs12.cpp:420
const std::string & mac_digest() const
Definition pkcs12.h:97
PKCS12_Export_Options(std::string_view password, std::optional< std::string > friendly_name={})
Definition pkcs12.cpp:398
PKCS12_Export_Options & with_key_encryption_algo(std::string algo)
Set the private key encryption algorithm (PKCS#12 PBE or PBES2 name).
Definition pkcs12.cpp:425
const std::optional< std::vector< uint8_t > > & local_key_id() const
Definition pkcs12.h:200
const std::optional< std::string > & friendly_name() const
Definition pkcs12.h:194
const std::vector< std::shared_ptr< Private_Key > > & private_keys() const
Definition pkcs12.h:167
PKCS12()=default
Construct an empty bundle.
const std::vector< OID > & unknown_bag_types() const
Definition pkcs12.h:207
const std::vector< X509_Certificate > & certificates() const
Definition pkcs12.h:175