Botan
1.11.15
|
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 }