Botan  1.11.15
src/lib/pubkey/pkcs8.cpp
Go to the documentation of this file.
00001 /*
00002 * PKCS #8
00003 * (C) 1999-2010,2014 Jack Lloyd
00004 *
00005 * Botan is released under the Simplified BSD License (see license.txt)
00006 */
00007 
00008 #include <botan/pkcs8.h>
00009 #include <botan/der_enc.h>
00010 #include <botan/ber_dec.h>
00011 #include <botan/alg_id.h>
00012 #include <botan/oids.h>
00013 #include <botan/pem.h>
00014 #include <botan/pbes2.h>
00015 #include <botan/scan_name.h>
00016 #include <botan/internal/pk_algs.h>
00017 
00018 namespace Botan {
00019 
00020 namespace PKCS8 {
00021 
00022 namespace {
00023 
00024 /*
00025 * Get info from an EncryptedPrivateKeyInfo
00026 */
00027 secure_vector<byte> PKCS8_extract(DataSource& source,
00028                                   AlgorithmIdentifier& pbe_alg_id)
00029    {
00030    secure_vector<byte> key_data;
00031 
00032    BER_Decoder(source)
00033       .start_cons(SEQUENCE)
00034          .decode(pbe_alg_id)
00035          .decode(key_data, OCTET_STRING)
00036       .verify_end();
00037 
00038    return key_data;
00039    }
00040 
00041 /*
00042 * PEM decode and/or decrypt a private key
00043 */
00044 secure_vector<byte> PKCS8_decode(
00045    DataSource& source,
00046    std::function<std::string ()> get_passphrase,
00047    AlgorithmIdentifier& pk_alg_id)
00048    {
00049    AlgorithmIdentifier pbe_alg_id;
00050    secure_vector<byte> key_data, key;
00051    bool is_encrypted = true;
00052 
00053    try {
00054       if(ASN1::maybe_BER(source) && !PEM_Code::matches(source))
00055          key_data = PKCS8_extract(source, pbe_alg_id);
00056       else
00057          {
00058          std::string label;
00059          key_data = PEM_Code::decode(source, label);
00060          if(label == "PRIVATE KEY")
00061             is_encrypted = false;
00062          else if(label == "ENCRYPTED PRIVATE KEY")
00063             {
00064             DataSource_Memory key_source(key_data);
00065             key_data = PKCS8_extract(key_source, pbe_alg_id);
00066             }
00067          else
00068             throw PKCS8_Exception("Unknown PEM label " + label);
00069          }
00070 
00071       if(key_data.empty())
00072          throw PKCS8_Exception("No key data found");
00073       }
00074    catch(Decoding_Error& e)
00075       {
00076       throw Decoding_Error("PKCS #8 private key decoding failed: " + std::string(e.what()));
00077       }
00078 
00079    try
00080       {
00081       if(is_encrypted)
00082          {
00083          if(OIDS::lookup(pbe_alg_id.oid) != "PBE-PKCS5v20")
00084             throw std::runtime_error("Unknown PBE type " + pbe_alg_id.oid.as_string());
00085          key = pbes2_decrypt(key_data, get_passphrase(), pbe_alg_id.parameters);
00086          }
00087       else
00088          key = key_data;
00089 
00090       BER_Decoder(key)
00091          .start_cons(SEQUENCE)
00092          .decode_and_check<size_t>(0, "Unknown PKCS #8 version number")
00093             .decode(pk_alg_id)
00094             .decode(key, OCTET_STRING)
00095             .discard_remaining()
00096          .end_cons();
00097       }
00098    catch(std::exception& e)
00099       {
00100       throw Decoding_Error("PKCS #8 private key decoding failed: " + std::string(e.what()));
00101       }
00102    return key;
00103    }
00104 
00105 }
00106 
00107 /*
00108 * BER encode a PKCS #8 private key, unencrypted
00109 */
00110 secure_vector<byte> BER_encode(const Private_Key& key)
00111    {
00112    const size_t PKCS8_VERSION = 0;
00113 
00114    return DER_Encoder()
00115          .start_cons(SEQUENCE)
00116             .encode(PKCS8_VERSION)
00117             .encode(key.pkcs8_algorithm_identifier())
00118             .encode(key.pkcs8_private_key(), OCTET_STRING)
00119          .end_cons()
00120       .get_contents();
00121    }
00122 
00123 /*
00124 * PEM encode a PKCS #8 private key, unencrypted
00125 */
00126 std::string PEM_encode(const Private_Key& key)
00127    {
00128    return PEM_Code::encode(PKCS8::BER_encode(key), "PRIVATE KEY");
00129    }
00130 
00131 namespace {
00132 
00133 std::pair<std::string, std::string>
00134 choose_pbe_params(const std::string& pbe_algo, const std::string& key_algo)
00135    {
00136    if(pbe_algo == "")
00137       {
00138       // Defaults:
00139       if(key_algo == "Curve25519" || key_algo == "McEliece")
00140          return std::make_pair("AES-256/GCM", "SHA-512");
00141       else // for everything else (RSA, DSA, ECDSA, GOST, ...)
00142          return std::make_pair("AES-256/CBC", "SHA-256");
00143       }
00144 
00145    SCAN_Name request(pbe_algo);
00146    if(request.algo_name() != "PBE-PKCS5v20" || request.arg_count() != 2)
00147       throw std::runtime_error("Unsupported PBE " + pbe_algo);
00148    return std::make_pair(request.arg(1), request.arg(0));
00149    }
00150 
00151 }
00152 
00153 /*
00154 * BER encode a PKCS #8 private key, encrypted
00155 */
00156 std::vector<byte> BER_encode(const Private_Key& key,
00157                              RandomNumberGenerator& rng,
00158                              const std::string& pass,
00159                              std::chrono::milliseconds msec,
00160                              const std::string& pbe_algo)
00161    {
00162    const auto pbe_params = choose_pbe_params(pbe_algo, key.algo_name());
00163 
00164    const std::pair<AlgorithmIdentifier, std::vector<byte>> pbe_info =
00165       pbes2_encrypt(PKCS8::BER_encode(key), pass, msec,
00166                     pbe_params.first, pbe_params.second, rng);
00167 
00168    return DER_Encoder()
00169          .start_cons(SEQUENCE)
00170             .encode(pbe_info.first)
00171             .encode(pbe_info.second, OCTET_STRING)
00172          .end_cons()
00173       .get_contents_unlocked();
00174    }
00175 
00176 /*
00177 * PEM encode a PKCS #8 private key, encrypted
00178 */
00179 std::string PEM_encode(const Private_Key& key,
00180                        RandomNumberGenerator& rng,
00181                        const std::string& pass,
00182                        std::chrono::milliseconds msec,
00183                        const std::string& pbe_algo)
00184    {
00185    if(pass == "")
00186       return PEM_encode(key);
00187 
00188    return PEM_Code::encode(PKCS8::BER_encode(key, rng, pass, msec, pbe_algo),
00189                            "ENCRYPTED PRIVATE KEY");
00190    }
00191 
00192 /*
00193 * Extract a private key and return it
00194 */
00195 Private_Key* load_key(DataSource& source,
00196                       RandomNumberGenerator& rng,
00197                       std::function<std::string ()> get_pass)
00198    {
00199    AlgorithmIdentifier alg_id;
00200    secure_vector<byte> pkcs8_key = PKCS8_decode(source, get_pass, alg_id);
00201 
00202    const std::string alg_name = OIDS::lookup(alg_id.oid);
00203    if(alg_name == "" || alg_name == alg_id.oid.as_string())
00204       throw PKCS8_Exception("Unknown algorithm OID: " +
00205                             alg_id.oid.as_string());
00206 
00207    return make_private_key(alg_id, pkcs8_key, rng);
00208    }
00209 
00210 /*
00211 * Extract a private key and return it
00212 */
00213 Private_Key* load_key(const std::string& fsname,
00214                       RandomNumberGenerator& rng,
00215                       std::function<std::string ()> get_pass)
00216    {
00217    DataSource_Stream source(fsname, true);
00218    return PKCS8::load_key(source, rng, get_pass);
00219    }
00220 
00221 /*
00222 * Extract a private key and return it
00223 */
00224 Private_Key* load_key(DataSource& source,
00225                       RandomNumberGenerator& rng,
00226                       const std::string& pass)
00227    {
00228    return PKCS8::load_key(source, rng, [pass]() { return pass; });
00229    }
00230 
00231 /*
00232 * Extract a private key and return it
00233 */
00234 Private_Key* load_key(const std::string& fsname,
00235                       RandomNumberGenerator& rng,
00236                       const std::string& pass)
00237    {
00238    return PKCS8::load_key(fsname, rng, [pass]() { return pass; });
00239    }
00240 
00241 /*
00242 * Make a copy of this private key
00243 */
00244 Private_Key* copy_key(const Private_Key& key,
00245                       RandomNumberGenerator& rng)
00246    {
00247    DataSource_Memory source(PEM_encode(key));
00248    return PKCS8::load_key(source, rng);
00249    }
00250 
00251 }
00252 
00253 }