8#include <botan/pkcs12.h>
10#include <botan/asn1_obj.h>
11#include <botan/ber_dec.h>
12#include <botan/data_src.h>
13#include <botan/der_enc.h>
14#include <botan/exceptn.h>
15#include <botan/hash.h>
17#include <botan/mem_ops.h>
18#include <botan/pkcs8.h>
20#include <botan/internal/charset.h>
21#include <botan/internal/fmt.h>
22#include <botan/internal/pkcs12_kdf.h>
23#include <botan/internal/pkcs12_pbe.h>
33constexpr size_t PKCS12_MAX_NESTING = 10;
37 X509_Certificate cert;
38 std::vector<uint8_t> local_key_id;
39 std::string friendly_name;
46void encode_bmpstring(
DER_Encoder& enc, std::string_view str) {
54std::string resolve_mac_hash(
const OID& oid) {
73 throw Decoding_Error(
fmt(
"Unsupported PKCS#12 MAC digest: {}", oid.to_formatted_string()));
83 static const std::array<std::string_view, 4> supported_key_algos = {
86 "PBES2-SHA256-AES256",
87 "PBES2-SHA256-AES128",
89 if(std::find(supported_key_algos.begin(), supported_key_algos.end(), opts.key_encryption_algo()) ==
90 supported_key_algos.end()) {
91 throw Invalid_Argument(
fmt(
"PKCS#12: unsupported key encryption algorithm '{}'", opts.key_encryption_algo()));
93 if(!opts.cert_encryption_algo().empty()) {
94 if(std::find(supported_key_algos.begin(), supported_key_algos.end(), opts.cert_encryption_algo()) ==
95 supported_key_algos.end()) {
97 fmt(
"PKCS#12: unsupported cert encryption algorithm '{}'", opts.cert_encryption_algo()));
104 if(opts.include_mac()) {
105 static const std::array<std::string_view, 6> supported_mac_digests = {
106 "SHA-1",
"SHA-224",
"SHA-256",
"SHA-384",
"SHA-512",
"SHA-512-256"};
107 if(std::find(supported_mac_digests.begin(), supported_mac_digests.end(), opts.mac_digest()) ==
108 supported_mac_digests.end()) {
112 throw Invalid_Argument(
fmt(
"PKCS#12: MAC digest '{}' is not available in this build", opts.mac_digest()));
124void verify_mac(std::span<const uint8_t> auth_safe_data,
125 std::span<const uint8_t> mac_value,
126 std::span<const uint8_t> mac_salt,
128 const std::string& hash_name,
129 std::string_view password,
130 bool openssl_empty_pwd_compat) {
132 const size_t mac_key_len = hmac->output_length();
135 if(openssl_empty_pwd_compat && password.empty()) {
137 pkcs12_kdf({mac_key.data(), mac_key_len}, {}, {mac_salt.data(), mac_salt.size()}, iterations, 3, *hash);
140 kdf.derive_key(mac_key.data(), mac_key_len, password.data(), password.size(), mac_salt.data(), mac_salt.size());
143 hmac->set_key(mac_key);
144 hmac->update(auth_safe_data);
154void parse_bag_attributes(
BER_Decoder& decoder, std::string& friendly_name, std::vector<uint8_t>& local_key_id) {
155 if(!decoder.more_items()) {
163 while(attrs.more_items()) {
166 attr_seq.
decode(attr_oid);
169 if(attr_oid == friendly_name_oid) {
172 friendly_name = str.
value();
173 }
else if(attr_oid == local_key_id_oid) {
186 std::shared_ptr<Private_Key> key;
187 std::vector<uint8_t> local_key_id;
188 std::string friendly_name;
195 std::string_view password,
196 std::vector<ParsedCert>& cert_entries,
197 std::vector<ParsedKey>& key_entries,
198 std::vector<OID>& unknown_bag_types,
199 bool openssl_empty_pwd_compat,
201 if(depth >= PKCS12_MAX_NESTING) {
202 throw Decoding_Error(
"PKCS#12: SafeContentsBag nesting too deep");
210 while(decoder.more_items()) {
212 std::string bag_friendly_name;
213 std::vector<uint8_t> bag_key_id;
220 bool pushed_cert =
false;
221 bool pushed_key =
false;
223 if(bag_type == cert_bag_oid) {
226 cert_bag.
decode(cert_type);
228 if(cert_type == x509_cert_oid) {
229 std::vector<uint8_t> cert_data;
237 cert_bag.discard_remaining();
241 }
else if(bag_type == shrouded_key_bag_oid) {
243 std::vector<uint8_t> encrypted_key;
246 shrouded.
decode(pbe_algo);
250 auto decrypted =
pkcs12_pbe_decrypt(encrypted_key, password, pbe_algo, openssl_empty_pwd_compat);
252 key_entries.push_back({std::shared_ptr<Private_Key>(
PKCS8::load_key(src)), {}, {}});
254 }
else if(bag_type == key_bag_oid) {
256 bag_value.raw_bytes(key_data);
257 bag_value.verify_end();
259 key_entries.push_back({std::shared_ptr<Private_Key>(
PKCS8::load_key(src)), {}, {}});
261 }
else if(bag_type == safe_contents_bag_oid) {
264 nested_sc, password, cert_entries, key_entries, unknown_bag_types, openssl_empty_pwd_compat, depth + 1);
265 nested_sc.verify_end();
266 bag_value.verify_end();
268 unknown_bag_types.push_back(bag_type);
269 bag_value.discard_remaining();
274 parse_bag_attributes(bag_seq, bag_friendly_name, bag_key_id);
276 if(pushed_cert && !cert_entries.empty()) {
277 if(!bag_key_id.empty()) {
278 cert_entries.back().local_key_id = bag_key_id;
280 if(!bag_friendly_name.empty()) {
281 cert_entries.back().friendly_name = bag_friendly_name;
283 }
else if(pushed_key && !key_entries.empty()) {
284 if(!bag_key_id.empty()) {
285 key_entries.back().local_key_id = bag_key_id;
287 if(!bag_friendly_name.empty()) {
288 key_entries.back().friendly_name = bag_friendly_name;
292 bag_seq.verify_end();
299void parse_authenticated_safe(std::span<const uint8_t> data,
300 std::string_view password,
301 std::vector<ParsedCert>& cert_entries,
302 std::vector<ParsedKey>& key_entries,
303 std::vector<OID>& unknown_bag_types,
304 bool openssl_empty_pwd_compat) {
311 while(seq.more_items()) {
314 content_info.
decode(content_type);
316 if(content_type == pkcs7_data_oid) {
317 std::vector<uint8_t> safe_contents_data;
324 parse_safe_contents(sc_seq, password, cert_entries, key_entries, unknown_bag_types, openssl_empty_pwd_compat);
326 safe_contents.verify_end();
327 content_info.verify_end();
328 }
else if(content_type == pkcs7_enc_data_oid) {
336 throw Decoding_Error(
fmt(
"PKCS#12: unsupported EncryptedData version: {}", version));
340 OID enc_content_type;
342 enc_content_info.decode(enc_content_type);
343 enc_content_info.decode(enc_algo);
345 if(enc_content_type != pkcs7_data_oid) {
347 fmt(
"PKCS#12: EncryptedData contentType must be Data, got {}", enc_content_type.to_formatted_string()));
350 std::vector<uint8_t> encrypted_content;
351 const BER_Object enc_content_obj = enc_content_info.get_next_object();
354 const std::span<const uint8_t> raw(enc_content_obj.bits(), enc_content_obj.length());
355 encrypted_content.reserve(raw.size());
357 while(chunks.more_items()) {
358 std::vector<uint8_t> chunk;
360 encrypted_content.insert(encrypted_content.end(), chunk.begin(), chunk.end());
364 encrypted_content.assign(enc_content_obj.bits(), enc_content_obj.bits() + enc_content_obj.length());
366 throw Decoding_Error(
"PKCS#12: Expected [0] context-specific for encrypted content");
369 enc_content_info.verify_end();
370 enc_data.verify_end();
377 parse_safe_contents(sc_seq, password, cert_entries, key_entries, unknown_bag_types, openssl_empty_pwd_compat);
379 safe_contents.verify_end();
380 content.verify_end();
381 content_info.verify_end();
384 fmt(
"PKCS#12: unsupported AuthenticatedSafe content type {}", content_type.to_formatted_string()));
409 opts.m_iterations = 2048;
410 opts.m_key_encryption_algo =
"PBE-SHA1-3DES";
411 opts.m_mac_digest =
"SHA-1";
416 m_friendly_name = std::move(name);
426 m_key_encryption_algo = std::move(algo);
431 m_cert_encryption_algo = std::move(algo);
436 m_mac_digest = std::move(algo);
441 m_include_mac =
false;
450 std::vector<ParsedCert> cert_entries;
451 std::vector<ParsedKey> key_entries;
463 std::vector<uint8_t> auth_safe_content;
466 auth_safe_info.
decode(auth_safe_type);
469 if(auth_safe_type != pkcs7_data_oid) {
481 bool openssl_empty_pwd_compat =
false;
488 std::vector<uint8_t> mac_value;
489 digest_info.
decode(digest_algo);
493 std::vector<uint8_t> mac_salt;
494 size_t iterations = 1;
497 mac_data.
decode(iterations);
501 throw Decoding_Error(
fmt(
"PKCS#12 MAC has invalid iteration count: {}", iterations));
504 const std::string hash_name = resolve_mac_hash(digest_algo.
oid());
511 verify_mac(auth_safe_content, mac_value, mac_salt, iterations, hash_name, password,
false);
513 if(!password.empty()) {
516 verify_mac(auth_safe_content, mac_value, mac_salt, iterations, hash_name, password,
true);
517 openssl_empty_pwd_compat =
true;
521 parse_authenticated_safe(
522 auth_safe_content, password, cert_entries, key_entries, m_unknown_bag_types, openssl_empty_pwd_compat);
525 m_private_keys.reserve(key_entries.size());
526 for(
auto& ke : key_entries) {
527 m_private_keys.push_back(std::move(ke.key));
532 if(!key_entries.empty()) {
533 if(!key_entries.front().friendly_name.empty()) {
534 m_friendly_name = key_entries.front().friendly_name;
536 if(!key_entries.front().local_key_id.empty()) {
537 m_local_key_id = key_entries.front().local_key_id;
544 std::optional<size_t> end_entity_idx;
545 if(!cert_entries.empty() && !m_private_keys.empty()) {
546 const auto& first_key = m_private_keys.front();
547 const auto& first_key_id = key_entries.empty() ? std::vector<uint8_t>{} : key_entries.front().local_key_id;
549 if(!first_key_id.empty()) {
550 for(
size_t i = 0; i < cert_entries.size(); ++i) {
557 if(!end_entity_idx) {
558 const auto key_spki = first_key->subject_public_key();
559 for(
size_t i = 0; i < cert_entries.size(); ++i) {
561 if(cert_entries[i].cert.subject_public_key_info() == key_spki) {
572 m_certificates.reserve(cert_entries.size());
574 m_certificates.push_back(std::move(cert_entries[*end_entity_idx].cert));
575 if(!m_friendly_name && !cert_entries[*end_entity_idx].
friendly_name.empty()) {
576 m_friendly_name = cert_entries[*end_entity_idx].friendly_name;
578 if(!m_local_key_id && !cert_entries[*end_entity_idx].
local_key_id.empty()) {
579 m_local_key_id = cert_entries[*end_entity_idx].local_key_id;
581 for(
size_t i = 0; i < cert_entries.size(); ++i) {
582 if(i != *end_entity_idx) {
586 if(!m_friendly_name && !cert_entries[i].
friendly_name.empty()) {
587 m_friendly_name = cert_entries[i].friendly_name;
589 m_certificates.push_back(std::move(cert_entries[i].cert));
593 for(
auto& ce : cert_entries) {
594 if(!m_friendly_name && !ce.friendly_name.empty()) {
595 m_friendly_name = ce.friendly_name;
597 m_certificates.push_back(std::move(ce.cert));
603 pfx.
verify_end(
"PKCS#12: trailing data after PFX");
607 if(m_certificates.size() < 2) {
611 std::vector<X509_Certificate> result;
612 result.reserve(m_certificates.size() - 1);
617 const auto ee_spki = ee->subject_public_key_info();
618 bool skipped =
false;
619 for(
const auto& c : m_certificates) {
620 if(!skipped && c.subject_public_key_info() == ee_spki) {
630 for(
size_t i = 1; i < m_certificates.size(); ++i) {
631 result.push_back(m_certificates[i]);
638 if(m_certificates.empty() || m_private_keys.empty()) {
641 const auto& first_key = m_private_keys.front();
642 const auto key_spki = first_key->subject_public_key();
643 for(
const auto& c : m_certificates) {
645 if(c.subject_public_key_info() == key_spki) {
659 m_private_keys.push_back(std::move(key));
663 m_certificates.push_back(std::move(cert));
667 m_friendly_name = std::move(name);
671 m_friendly_name.reset();
675 m_local_key_id = std::move(
id);
679 m_local_key_id.reset();
683 if(m_private_keys.empty() && m_certificates.empty()) {
684 throw Invalid_Argument(
"PKCS#12::export_to requires at least a key or certificate");
687 validate_options(options);
692 std::optional<size_t> end_entity_idx;
693 if(!m_private_keys.empty() && !m_certificates.empty()) {
694 const auto& first_key = m_private_keys.front();
695 const auto key_spki = first_key->subject_public_key();
696 for(
size_t i = 0; i < m_certificates.size(); ++i) {
698 if(m_certificates[i].subject_public_key_info() == key_spki) {
706 if(!end_entity_idx) {
707 throw Invalid_Argument(
"PKCS#12::export_to: private key does not match any certificate");
727 }
else if(end_entity_idx) {
728 local_key_id = m_certificates[*end_entity_idx].subject_public_key_bitstring_sha1();
729 }
else if(!m_private_keys.empty()) {
733 const auto pub_bits = m_private_keys.front()->public_key_bits();
734 sha1->update(pub_bits);
741 if(!has_fn && !has_id) {
746 enc.start_sequence();
747 enc.encode(friendly_name_oid);
754 enc.start_sequence();
755 enc.encode(local_key_id_oid);
765 std::vector<uint8_t> cert_safe_contents;
766 if(!m_certificates.empty()) {
772 cert_bags.
encode(cert_bag_oid);
776 cert_bags.
encode(x509_cert_oid);
784 write_attributes(cert_bags);
793 add_cert_bag(m_certificates[*end_entity_idx],
true);
794 for(
size_t i = 0; i < m_certificates.size(); ++i) {
795 if(i != *end_entity_idx) {
796 add_cert_bag(m_certificates[i],
false);
800 for(
const auto& c : m_certificates) {
801 add_cert_bag(c,
false);
809 std::vector<uint8_t> key_safe_contents;
810 if(!m_private_keys.empty()) {
814 for(
size_t i = 0; i < m_private_keys.size(); ++i) {
818 key_bags.
encode(shrouded_key_oid);
821 auto [enc_algo, enc_key] =
826 key_bags.
encode(enc_algo);
834 write_attributes(key_bags);
843 std::vector<uint8_t> auth_safe_content;
847 if(!cert_safe_contents.empty()) {
853 auth_safe.
encode(pkcs7_enc_data_oid);
856 auth_safe.
encode(
size_t(0));
858 auth_safe.
encode(pkcs7_data_oid);
859 auth_safe.
encode(enc_algo);
867 auth_safe.
encode(pkcs7_data_oid);
875 if(!key_safe_contents.empty()) {
877 auth_safe.
encode(pkcs7_data_oid);
887 std::vector<uint8_t> pfx_data;
893 pfx.
encode(pkcs7_data_oid);
900 const std::string& mac_hash = options.
mac_digest();
904 std::vector<uint8_t> mac_salt(hmac->output_length());
905 rng.
randomize(mac_salt.data(), mac_salt.size());
906 const size_t mac_key_len = hmac->output_length();
916 hmac->set_key(mac_key);
917 hmac->update(auth_safe_content);
922 const auto param_encoding =
std::vector< uint8_t > BER_encode() const
const std::string & value() const
void push_back(const BER_Object &obj)
BER_Decoder & decode(bool &out)
BER_Decoder & verify_end()
BER_Decoder & discard_remaining()
BER_Decoder start_sequence()
BER_Decoder start_context_specific(uint32_t tag)
DER_Encoder & add_object(ASN1_Type type_tag, ASN1_Class class_tag, const uint8_t rep[], size_t length)
DER_Encoder & start_context_specific(uint32_t tag)
DER_Encoder & start_sequence()
DER_Encoder & encode(bool b)
static std::unique_ptr< HashFunction > create_or_throw(std::string_view algo_spec, std::string_view provider="")
static std::unique_ptr< HashFunction > create(std::string_view algo_spec, std::string_view provider="")
static std::unique_ptr< MessageAuthenticationCode > create_or_throw(std::string_view algo_spec, std::string_view provider="")
static OID from_string(std::string_view str)
const std::optional< std::string > & friendly_name() const
PKCS12_Export_Options & without_mac()
Disable the integrity MAC. Generally not recommended.
PKCS12_Export_Options & with_mac_digest(std::string algo)
Set the digest used for the integrity MAC.
static PKCS12_Export_Options modern(std::string_view password, std::optional< std::string > friendly_name={})
const std::string & key_encryption_algo() const
PKCS12_Export_Options & with_friendly_name(std::string name)
Override the friendly-name attribute (otherwise taken from the bundle).
static PKCS12_Export_Options legacy_compat(std::string_view password, std::optional< std::string > friendly_name={})
size_t iterations() const
const std::string & password() const
const std::string & cert_encryption_algo() const
Empty means: store certificates unencrypted.
PKCS12_Export_Options & with_cert_encryption_algo(std::string algo)
PKCS12_Export_Options & with_iterations(size_t n)
Set number of KDF iterations.
const std::string & mac_digest() const
PKCS12_Export_Options(std::string_view password, std::optional< std::string > friendly_name={})
PKCS12_Export_Options & with_key_encryption_algo(std::string algo)
Set the private key encryption algorithm (PKCS#12 PBE or PBES2 name).
void derive_key(uint8_t out[], size_t out_len, const char *password, size_t password_len, const uint8_t salt[], size_t salt_len) const override
std::vector< uint8_t > export_to(const PKCS12_Export_Options &options, RandomNumberGenerator &rng) const
void clear_local_key_id()
Clear the localKeyId attribute.
const std::optional< std::vector< uint8_t > > & local_key_id() const
std::vector< X509_Certificate > ca_certificates() const
const std::optional< std::string > & friendly_name() const
void add_certificate(X509_Certificate cert)
void clear_friendly_name()
Clear the friendly-name attribute.
std::optional< X509_Certificate > end_entity_certificate() const
PKCS12()=default
Construct an empty bundle.
void set_friendly_name(std::string name)
Set (or replace) the friendly-name attribute.
void add_key(std::shared_ptr< Private_Key > key)
Add a private key. PKCS#12 supports multiple keys per file.
void set_local_key_id(std::vector< uint8_t > id)
Set (or replace) the localKeyId attribute.
void randomize(std::span< uint8_t > output)
std::vector< uint8_t > BER_encode(const Private_Key &key, RandomNumberGenerator &rng, std::string_view pass, std::chrono::milliseconds msec, std::string_view pbe_algo)
std::unique_ptr< Private_Key > load_key(DataSource &source, const std::function< std::string()> &get_pass)
std::string fmt(std::string_view format, const T &... args)
secure_vector< uint8_t > pkcs12_pbe_decrypt(std::span< const uint8_t > ciphertext, std::string_view password, const AlgorithmIdentifier &pbe_algo, bool openssl_empty_pwd_compat)
std::vector< T > unlock(const secure_vector< T > &in)
std::vector< T, secure_allocator< T > > secure_vector
std::pair< AlgorithmIdentifier, std::vector< uint8_t > > pkcs12_pbe_encrypt(std::span< const uint8_t > plaintext, std::string_view password, std::string_view algo, size_t iterations, RandomNumberGenerator &rng)
bool constant_time_compare(std::span< const uint8_t > x, std::span< const uint8_t > y)
void pkcs12_kdf(std::span< uint8_t > out, std::span< const uint8_t > pwd_bytes, std::span< const uint8_t > salt, size_t iterations, uint8_t id, HashFunction &hash)
std::vector< uint8_t > utf8_to_ucs2(std::string_view utf8)
constexpr size_t PKCS12_MAX_ITERATIONS