aboutsummaryrefslogtreecommitdiffstats
path: root/src/libs/3rdparty/botan/src/lib/pubkey/pkcs8.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/libs/3rdparty/botan/src/lib/pubkey/pkcs8.cpp')
-rw-r--r--src/libs/3rdparty/botan/src/lib/pubkey/pkcs8.cpp468
1 files changed, 468 insertions, 0 deletions
diff --git a/src/libs/3rdparty/botan/src/lib/pubkey/pkcs8.cpp b/src/libs/3rdparty/botan/src/lib/pubkey/pkcs8.cpp
new file mode 100644
index 0000000000..8d3eba6dc7
--- /dev/null
+++ b/src/libs/3rdparty/botan/src/lib/pubkey/pkcs8.cpp
@@ -0,0 +1,468 @@
+/*
+* PKCS #8
+* (C) 1999-2010,2014,2018 Jack Lloyd
+*
+* Botan is released under the Simplified BSD License (see license.txt)
+*/
+
+#include <botan/pkcs8.h>
+#include <botan/rng.h>
+#include <botan/der_enc.h>
+#include <botan/ber_dec.h>
+#include <botan/alg_id.h>
+#include <botan/oids.h>
+#include <botan/pem.h>
+#include <botan/scan_name.h>
+#include <botan/pk_algs.h>
+
+#if defined(BOTAN_HAS_PKCS5_PBES2)
+ #include <botan/pbes2.h>
+#endif
+
+namespace Botan {
+
+namespace PKCS8 {
+
+namespace {
+
+/*
+* Get info from an EncryptedPrivateKeyInfo
+*/
+secure_vector<uint8_t> PKCS8_extract(DataSource& source,
+ AlgorithmIdentifier& pbe_alg_id)
+ {
+ secure_vector<uint8_t> key_data;
+
+ BER_Decoder(source)
+ .start_cons(SEQUENCE)
+ .decode(pbe_alg_id)
+ .decode(key_data, OCTET_STRING)
+ .verify_end();
+
+ return key_data;
+ }
+
+/*
+* PEM decode and/or decrypt a private key
+*/
+secure_vector<uint8_t> PKCS8_decode(
+ DataSource& source,
+ std::function<std::string ()> get_passphrase,
+ AlgorithmIdentifier& pk_alg_id,
+ bool is_encrypted)
+ {
+ AlgorithmIdentifier pbe_alg_id;
+ secure_vector<uint8_t> key_data, key;
+
+ try {
+ if(ASN1::maybe_BER(source) && !PEM_Code::matches(source))
+ {
+ if(is_encrypted)
+ {
+ key_data = PKCS8_extract(source, pbe_alg_id);
+ }
+ else
+ {
+ // todo read more efficiently
+ while(!source.end_of_data())
+ {
+ uint8_t b;
+ size_t read = source.read_byte(b);
+ if(read)
+ {
+ key_data.push_back(b);
+ }
+ }
+ }
+ }
+ else
+ {
+ std::string label;
+ key_data = PEM_Code::decode(source, label);
+
+ // todo remove autodetect for pem as well?
+ if(label == "PRIVATE KEY")
+ is_encrypted = false;
+ else if(label == "ENCRYPTED PRIVATE KEY")
+ {
+ DataSource_Memory key_source(key_data);
+ key_data = PKCS8_extract(key_source, pbe_alg_id);
+ }
+ else
+ throw PKCS8_Exception("Unknown PEM label " + label);
+ }
+
+ if(key_data.empty())
+ throw PKCS8_Exception("No key data found");
+ }
+ catch(Decoding_Error& e)
+ {
+ throw Decoding_Error("PKCS #8 private key decoding failed: " + std::string(e.what()));
+ }
+
+ try
+ {
+ if(is_encrypted)
+ {
+ if(OIDS::lookup(pbe_alg_id.get_oid()) != "PBE-PKCS5v20")
+ throw Exception("Unknown PBE type " + pbe_alg_id.get_oid().as_string());
+#if defined(BOTAN_HAS_PKCS5_PBES2)
+ key = pbes2_decrypt(key_data, get_passphrase(), pbe_alg_id.get_parameters());
+#else
+ BOTAN_UNUSED(get_passphrase);
+ throw Decoding_Error("Private key is encrypted but PBES2 was disabled in build");
+#endif
+ }
+ else
+ key = key_data;
+
+ BER_Decoder(key)
+ .start_cons(SEQUENCE)
+ .decode_and_check<size_t>(0, "Unknown PKCS #8 version number")
+ .decode(pk_alg_id)
+ .decode(key, OCTET_STRING)
+ .discard_remaining()
+ .end_cons();
+ }
+ catch(std::exception& e)
+ {
+ throw Decoding_Error("PKCS #8 private key decoding failed: " + std::string(e.what()));
+ }
+ return key;
+ }
+
+}
+
+/*
+* BER encode a PKCS #8 private key, unencrypted
+*/
+secure_vector<uint8_t> BER_encode(const Private_Key& key)
+ {
+ // keeping around for compat
+ return key.private_key_info();
+ }
+
+/*
+* PEM encode a PKCS #8 private key, unencrypted
+*/
+std::string PEM_encode(const Private_Key& key)
+ {
+ return PEM_Code::encode(PKCS8::BER_encode(key), "PRIVATE KEY");
+ }
+
+#if defined(BOTAN_HAS_PKCS5_PBES2)
+
+namespace {
+
+std::pair<std::string, std::string>
+choose_pbe_params(const std::string& pbe_algo, const std::string& key_algo)
+ {
+ if(pbe_algo.empty())
+ {
+ // Defaults:
+ if(key_algo == "Curve25519" || key_algo == "McEliece")
+ return std::make_pair("AES-256/GCM", "SHA-512");
+ else // for everything else (RSA, DSA, ECDSA, GOST, ...)
+ return std::make_pair("AES-256/CBC", "SHA-256");
+ }
+
+ SCAN_Name request(pbe_algo);
+ if(request.algo_name() != "PBE-PKCS5v20" || request.arg_count() != 2)
+ throw Exception("Unsupported PBE " + pbe_algo);
+ return std::make_pair(request.arg(0), request.arg(1));
+ }
+
+}
+
+#endif
+
+/*
+* BER encode a PKCS #8 private key, encrypted
+*/
+std::vector<uint8_t> BER_encode(const Private_Key& key,
+ RandomNumberGenerator& rng,
+ const std::string& pass,
+ std::chrono::milliseconds msec,
+ const std::string& pbe_algo)
+ {
+#if defined(BOTAN_HAS_PKCS5_PBES2)
+ const auto pbe_params = choose_pbe_params(pbe_algo, key.algo_name());
+
+ const std::pair<AlgorithmIdentifier, std::vector<uint8_t>> pbe_info =
+ pbes2_encrypt_msec(PKCS8::BER_encode(key), pass, msec, nullptr,
+ pbe_params.first, pbe_params.second, rng);
+
+ std::vector<uint8_t> output;
+ DER_Encoder der(output);
+ der.start_cons(SEQUENCE)
+ .encode(pbe_info.first)
+ .encode(pbe_info.second, OCTET_STRING)
+ .end_cons();
+
+ return output;
+#else
+ BOTAN_UNUSED(key, rng, pass, msec, pbe_algo);
+ throw Encoding_Error("PKCS8::BER_encode cannot encrypt because PBES2 was disabled in build");
+#endif
+ }
+
+/*
+* PEM encode a PKCS #8 private key, encrypted
+*/
+std::string PEM_encode(const Private_Key& key,
+ RandomNumberGenerator& rng,
+ const std::string& pass,
+ std::chrono::milliseconds msec,
+ const std::string& pbe_algo)
+ {
+ if(pass.empty())
+ return PEM_encode(key);
+
+ return PEM_Code::encode(PKCS8::BER_encode(key, rng, pass, msec, pbe_algo),
+ "ENCRYPTED PRIVATE KEY");
+ }
+
+/*
+* BER encode a PKCS #8 private key, encrypted
+*/
+std::vector<uint8_t> BER_encode_encrypted_pbkdf_iter(const Private_Key& key,
+ RandomNumberGenerator& rng,
+ const std::string& pass,
+ size_t pbkdf_iterations,
+ const std::string& cipher,
+ const std::string& pbkdf_hash)
+ {
+#if defined(BOTAN_HAS_PKCS5_PBES2)
+ const std::pair<AlgorithmIdentifier, std::vector<uint8_t>> pbe_info =
+ pbes2_encrypt_iter(key.private_key_info(),
+ pass, pbkdf_iterations,
+ cipher.empty() ? "AES-256/CBC" : cipher,
+ pbkdf_hash.empty() ? "SHA-256" : pbkdf_hash,
+ rng);
+
+ std::vector<uint8_t> output;
+ DER_Encoder der(output);
+ der.start_cons(SEQUENCE)
+ .encode(pbe_info.first)
+ .encode(pbe_info.second, OCTET_STRING)
+ .end_cons();
+
+ return output;
+
+#else
+ BOTAN_UNUSED(key, rng, pass, pbkdf_iterations, cipher, pbkdf_hash);
+ throw Encoding_Error("PKCS8::BER_encode_encrypted_pbkdf_iter cannot encrypt because PBES2 disabled in build");
+#endif
+ }
+
+/*
+* PEM encode a PKCS #8 private key, encrypted
+*/
+std::string PEM_encode_encrypted_pbkdf_iter(const Private_Key& key,
+ RandomNumberGenerator& rng,
+ const std::string& pass,
+ size_t pbkdf_iterations,
+ const std::string& cipher,
+ const std::string& pbkdf_hash)
+ {
+ return PEM_Code::encode(
+ PKCS8::BER_encode_encrypted_pbkdf_iter(key, rng, pass, pbkdf_iterations, cipher, pbkdf_hash),
+ "ENCRYPTED PRIVATE KEY");
+ }
+
+/*
+* BER encode a PKCS #8 private key, encrypted
+*/
+std::vector<uint8_t> BER_encode_encrypted_pbkdf_msec(const Private_Key& key,
+ RandomNumberGenerator& rng,
+ const std::string& pass,
+ std::chrono::milliseconds pbkdf_msec,
+ size_t* pbkdf_iterations,
+ const std::string& cipher,
+ const std::string& pbkdf_hash)
+ {
+#if defined(BOTAN_HAS_PKCS5_PBES2)
+ const std::pair<AlgorithmIdentifier, std::vector<uint8_t>> pbe_info =
+ pbes2_encrypt_msec(key.private_key_info(), pass,
+ pbkdf_msec, pbkdf_iterations,
+ cipher.empty() ? "AES-256/CBC" : cipher,
+ pbkdf_hash.empty() ? "SHA-256" : pbkdf_hash,
+ rng);
+
+ std::vector<uint8_t> output;
+ DER_Encoder(output)
+ .start_cons(SEQUENCE)
+ .encode(pbe_info.first)
+ .encode(pbe_info.second, OCTET_STRING)
+ .end_cons();
+
+ return output;
+#else
+ BOTAN_UNUSED(key, rng, pass, pbkdf_msec, pbkdf_iterations, cipher, pbkdf_hash);
+ throw Encoding_Error("BER_encode_encrypted_pbkdf_msec cannot encrypt because PBES2 disabled in build");
+#endif
+ }
+
+/*
+* PEM encode a PKCS #8 private key, encrypted
+*/
+std::string PEM_encode_encrypted_pbkdf_msec(const Private_Key& key,
+ RandomNumberGenerator& rng,
+ const std::string& pass,
+ std::chrono::milliseconds pbkdf_msec,
+ size_t* pbkdf_iterations,
+ const std::string& cipher,
+ const std::string& pbkdf_hash)
+ {
+ return PEM_Code::encode(
+ PKCS8::BER_encode_encrypted_pbkdf_msec(key, rng, pass, pbkdf_msec, pbkdf_iterations, cipher, pbkdf_hash),
+ "ENCRYPTED PRIVATE KEY");
+ }
+
+namespace {
+
+/*
+* Extract a private key (encrypted/unencrypted) and return it
+*/
+std::unique_ptr<Private_Key>
+load_key(DataSource& source,
+ std::function<std::string ()> get_pass,
+ bool is_encrypted)
+ {
+ AlgorithmIdentifier alg_id;
+ secure_vector<uint8_t> pkcs8_key = PKCS8_decode(source, get_pass, alg_id, is_encrypted);
+
+ const std::string alg_name = OIDS::lookup(alg_id.get_oid());
+ if(alg_name.empty() || alg_name == alg_id.get_oid().as_string())
+ throw PKCS8_Exception("Unknown algorithm OID: " +
+ alg_id.get_oid().as_string());
+
+ return load_private_key(alg_id, pkcs8_key);
+ }
+
+}
+
+/*
+* Extract an encrypted private key and return it
+*/
+std::unique_ptr<Private_Key> load_key(DataSource& source,
+ std::function<std::string ()> get_pass)
+ {
+ return load_key(source, get_pass, true);
+ }
+
+/*
+* Extract an encrypted private key and return it
+*/
+std::unique_ptr<Private_Key> load_key(DataSource& source,
+ const std::string& pass)
+ {
+ return load_key(source, [pass]() { return pass; }, true);
+ }
+
+/*
+* Extract an unencrypted private key and return it
+*/
+std::unique_ptr<Private_Key> load_key(DataSource& source)
+ {
+ auto fail_fn = []() -> std::string {
+ throw PKCS8_Exception("Internal error: Attempt to read password for unencrypted key");
+ };
+
+ return load_key(source, fail_fn, false);
+ }
+
+/*
+* Make a copy of this private key
+*/
+std::unique_ptr<Private_Key> copy_key(const Private_Key& key)
+ {
+ DataSource_Memory source(PEM_encode(key));
+ return PKCS8::load_key(source);
+ }
+
+/*
+* Extract an encrypted private key and return it
+*/
+Private_Key* load_key(DataSource& source,
+ RandomNumberGenerator& rng,
+ std::function<std::string ()> get_pass)
+ {
+ BOTAN_UNUSED(rng);
+ return PKCS8::load_key(source, get_pass).release();
+ }
+
+/*
+* Extract an encrypted private key and return it
+*/
+Private_Key* load_key(DataSource& source,
+ RandomNumberGenerator& rng,
+ const std::string& pass)
+ {
+ BOTAN_UNUSED(rng);
+ return PKCS8::load_key(source, pass).release();
+ }
+
+/*
+* Extract an unencrypted private key and return it
+*/
+Private_Key* load_key(DataSource& source,
+ RandomNumberGenerator& rng)
+ {
+ BOTAN_UNUSED(rng);
+ return PKCS8::load_key(source).release();
+ }
+
+#if defined(BOTAN_TARGET_OS_HAS_FILESYSTEM)
+
+/*
+* Extract an encrypted private key and return it
+*/
+Private_Key* load_key(const std::string& fsname,
+ RandomNumberGenerator& rng,
+ std::function<std::string ()> get_pass)
+ {
+ BOTAN_UNUSED(rng);
+ DataSource_Stream in(fsname);
+ return PKCS8::load_key(in, get_pass).release();
+ }
+
+/*
+* Extract an encrypted private key and return it
+*/
+Private_Key* load_key(const std::string& fsname,
+ RandomNumberGenerator& rng,
+ const std::string& pass)
+ {
+ BOTAN_UNUSED(rng);
+ DataSource_Stream in(fsname);
+ return PKCS8::load_key(in, [pass]() { return pass; }).release();
+ }
+
+/*
+* Extract an unencrypted private key and return it
+*/
+Private_Key* load_key(const std::string& fsname,
+ RandomNumberGenerator& rng)
+ {
+ BOTAN_UNUSED(rng);
+ DataSource_Stream in(fsname);
+ return PKCS8::load_key(in).release();
+ }
+#endif
+
+/*
+* Make a copy of this private key
+*/
+Private_Key* copy_key(const Private_Key& key,
+ RandomNumberGenerator& rng)
+ {
+ BOTAN_UNUSED(rng);
+ return PKCS8::copy_key(key).release();
+ }
+
+
+
+}
+
+}