aboutsummaryrefslogtreecommitdiffstats
path: root/src/pubkey/pk_codecs
diff options
context:
space:
mode:
Diffstat (limited to 'src/pubkey/pk_codecs')
-rw-r--r--src/pubkey/pk_codecs/pkcs8.cpp313
-rw-r--r--src/pubkey/pk_codecs/pkcs8.h182
-rw-r--r--src/pubkey/pk_codecs/x509_key.cpp176
-rw-r--r--src/pubkey/pk_codecs/x509_key.h110
4 files changed, 781 insertions, 0 deletions
diff --git a/src/pubkey/pk_codecs/pkcs8.cpp b/src/pubkey/pk_codecs/pkcs8.cpp
new file mode 100644
index 000000000..8a464ecfe
--- /dev/null
+++ b/src/pubkey/pk_codecs/pkcs8.cpp
@@ -0,0 +1,313 @@
+/*
+* PKCS #8
+* (C) 1999-2008 Jack Lloyd
+*
+* Distributed under the terms of the Botan license
+*/
+
+#include <botan/pkcs8.h>
+#include <botan/get_pbe.h>
+#include <botan/der_enc.h>
+#include <botan/ber_dec.h>
+#include <botan/asn1_obj.h>
+#include <botan/pk_algs.h>
+#include <botan/oids.h>
+#include <botan/pem.h>
+#include <memory>
+
+namespace Botan {
+
+namespace PKCS8 {
+
+namespace {
+
+/*
+* Get info from an EncryptedPrivateKeyInfo
+*/
+SecureVector<byte> PKCS8_extract(DataSource& source,
+ AlgorithmIdentifier& pbe_alg_id)
+ {
+ SecureVector<byte> 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
+*/
+SecureVector<byte> PKCS8_decode(DataSource& source, const User_Interface& ui,
+ AlgorithmIdentifier& pk_alg_id)
+ {
+ AlgorithmIdentifier pbe_alg_id;
+ SecureVector<byte> key_data, key;
+ bool is_encrypted = true;
+
+ try {
+ if(ASN1::maybe_BER(source) && !PEM_Code::matches(source))
+ key_data = PKCS8_extract(source, pbe_alg_id);
+ else
+ {
+ std::string label;
+ key_data = PEM_Code::decode(source, label);
+ 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.is_empty())
+ throw PKCS8_Exception("No key data found");
+ }
+ catch(Decoding_Error)
+ {
+ throw Decoding_Error("PKCS #8 private key decoding failed");
+ }
+
+ if(!is_encrypted)
+ key = key_data;
+
+ const u32bit MAX_TRIES = 3;
+
+ u32bit tries = 0;
+ while(true)
+ {
+ try {
+ if(MAX_TRIES && tries >= MAX_TRIES)
+ break;
+
+ if(is_encrypted)
+ {
+ DataSource_Memory params(pbe_alg_id.parameters);
+ std::auto_ptr<PBE> pbe(get_pbe(pbe_alg_id.oid, params));
+
+ User_Interface::UI_Result result = User_Interface::OK;
+ const std::string passphrase =
+ ui.get_passphrase("PKCS #8 private key", source.id(), result);
+
+ if(result == User_Interface::CANCEL_ACTION)
+ break;
+
+ pbe->set_key(passphrase);
+ Pipe decryptor(pbe.release());
+
+ decryptor.process_msg(key_data, key_data.size());
+ key = decryptor.read_all();
+ }
+
+ u32bit version;
+
+ BER_Decoder(key)
+ .start_cons(SEQUENCE)
+ .decode(version)
+ .decode(pk_alg_id)
+ .decode(key, OCTET_STRING)
+ .discard_remaining()
+ .end_cons();
+
+ if(version != 0)
+ throw Decoding_Error("PKCS #8: Unknown version number");
+
+ break;
+ }
+ catch(Decoding_Error)
+ {
+ ++tries;
+ }
+ }
+
+ if(key.is_empty())
+ throw Decoding_Error("PKCS #8 private key decoding failed");
+ return key;
+ }
+
+}
+
+/*
+* DER or PEM encode a PKCS #8 private key
+*/
+void encode(const Private_Key& key, Pipe& pipe, X509_Encoding encoding)
+ {
+ std::auto_ptr<PKCS8_Encoder> encoder(key.pkcs8_encoder());
+ if(!encoder.get())
+ throw Encoding_Error("PKCS8::encode: Key does not support encoding");
+
+ const u32bit PKCS8_VERSION = 0;
+
+ SecureVector<byte> contents =
+ DER_Encoder()
+ .start_cons(SEQUENCE)
+ .encode(PKCS8_VERSION)
+ .encode(encoder->alg_id())
+ .encode(encoder->key_bits(), OCTET_STRING)
+ .end_cons()
+ .get_contents();
+
+ if(encoding == PEM)
+ pipe.write(PEM_Code::encode(contents, "PRIVATE KEY"));
+ else
+ pipe.write(contents);
+ }
+
+/*
+* Encode and encrypt a PKCS #8 private key
+*/
+void encrypt_key(const Private_Key& key,
+ Pipe& pipe,
+ RandomNumberGenerator& rng,
+ const std::string& pass, const std::string& pbe_algo,
+ X509_Encoding encoding)
+ {
+ const std::string DEFAULT_PBE = "PBE-PKCS5v20(SHA-1,TripleDES/CBC)";
+
+ Pipe raw_key;
+ raw_key.start_msg();
+ encode(key, raw_key, RAW_BER);
+ raw_key.end_msg();
+
+ std::auto_ptr<PBE> pbe(get_pbe(((pbe_algo != "") ? pbe_algo : DEFAULT_PBE)));
+
+ pbe->new_params(rng);
+ pbe->set_key(pass);
+
+ AlgorithmIdentifier pbe_algid(pbe->get_oid(), pbe->encode_params());
+
+ Pipe key_encrytor(pbe.release());
+ key_encrytor.process_msg(raw_key);
+
+ SecureVector<byte> enc_key =
+ DER_Encoder()
+ .start_cons(SEQUENCE)
+ .encode(pbe_algid)
+ .encode(key_encrytor.read_all(), OCTET_STRING)
+ .end_cons()
+ .get_contents();
+
+ if(encoding == PEM)
+ pipe.write(PEM_Code::encode(enc_key, "ENCRYPTED PRIVATE KEY"));
+ else
+ pipe.write(enc_key);
+ }
+
+/*
+* PEM encode a PKCS #8 private key
+*/
+std::string PEM_encode(const Private_Key& key)
+ {
+ Pipe pem;
+ pem.start_msg();
+ encode(key, pem, PEM);
+ pem.end_msg();
+ return pem.read_all_as_string();
+ }
+
+/*
+* Encrypt and PEM encode a PKCS #8 private key
+*/
+std::string PEM_encode(const Private_Key& key,
+ RandomNumberGenerator& rng,
+ const std::string& pass,
+ const std::string& pbe_algo)
+ {
+ if(pass == "")
+ return PEM_encode(key);
+
+ Pipe pem;
+ pem.start_msg();
+ encrypt_key(key, pem, rng, pass, pbe_algo, PEM);
+ pem.end_msg();
+ return pem.read_all_as_string();
+ }
+
+/*
+* Extract a private key and return it
+*/
+Private_Key* load_key(DataSource& source,
+ RandomNumberGenerator& rng,
+ const User_Interface& ui)
+ {
+ AlgorithmIdentifier alg_id;
+ SecureVector<byte> pkcs8_key = PKCS8_decode(source, ui, alg_id);
+
+ const std::string alg_name = OIDS::lookup(alg_id.oid);
+ if(alg_name == "" || alg_name == alg_id.oid.as_string())
+ throw PKCS8_Exception("Unknown algorithm OID: " +
+ alg_id.oid.as_string());
+
+ std::auto_ptr<Private_Key> key(get_private_key(alg_name));
+
+ if(!key.get())
+ throw PKCS8_Exception("Unknown PK algorithm/OID: " + alg_name + ", " +
+ alg_id.oid.as_string());
+
+ std::auto_ptr<PKCS8_Decoder> decoder(key->pkcs8_decoder(rng));
+
+ if(!decoder.get())
+ throw Decoding_Error("Key does not support PKCS #8 decoding");
+
+ decoder->alg_id(alg_id);
+ decoder->key_bits(pkcs8_key);
+
+ return key.release();
+ }
+
+/*
+* Extract a private key and return it
+*/
+Private_Key* load_key(const std::string& fsname,
+ RandomNumberGenerator& rng,
+ const User_Interface& ui)
+ {
+ DataSource_Stream source(fsname, true);
+ return PKCS8::load_key(source, rng, ui);
+ }
+
+/*
+* Extract a private key and return it
+*/
+Private_Key* load_key(DataSource& source,
+ RandomNumberGenerator& rng,
+ const std::string& pass)
+ {
+ return PKCS8::load_key(source, rng, User_Interface(pass));
+ }
+
+/*
+* Extract a private key and return it
+*/
+Private_Key* load_key(const std::string& fsname,
+ RandomNumberGenerator& rng,
+ const std::string& pass)
+ {
+ return PKCS8::load_key(fsname, rng, User_Interface(pass));
+ }
+
+/*
+* Make a copy of this private key
+*/
+Private_Key* copy_key(const Private_Key& key,
+ RandomNumberGenerator& rng)
+ {
+ Pipe bits;
+
+ bits.start_msg();
+ PKCS8::encode(key, bits);
+ bits.end_msg();
+
+ DataSource_Memory source(bits.read_all());
+ return PKCS8::load_key(source, rng);
+ }
+
+}
+
+}
diff --git a/src/pubkey/pk_codecs/pkcs8.h b/src/pubkey/pk_codecs/pkcs8.h
new file mode 100644
index 000000000..87f8ba326
--- /dev/null
+++ b/src/pubkey/pk_codecs/pkcs8.h
@@ -0,0 +1,182 @@
+/*
+* PKCS #8
+* (C) 1999-2007 Jack Lloyd
+*
+* Distributed under the terms of the Botan license
+*/
+
+#ifndef BOTAN_PKCS8_H__
+#define BOTAN_PKCS8_H__
+
+#include <botan/x509_key.h>
+#include <botan/ui.h>
+
+namespace Botan {
+
+/**
+* PKCS #8 Private Key Encoder.
+*/
+class BOTAN_DLL PKCS8_Encoder
+ {
+ public:
+ /**
+ * Get the algorithm identifier associated with the scheme
+ * this encoders key is part of.
+ * @return the algorithm identifier
+ */
+ virtual AlgorithmIdentifier alg_id() const = 0;
+
+ /**
+ * Get the DER encoded key.
+ * @return the DER encoded key
+ */
+ // XXX: Why not SecureVector?
+ virtual MemoryVector<byte> key_bits() const = 0;
+ virtual ~PKCS8_Encoder() {}
+ };
+
+/*
+* PKCS #8 Private Key Decoder
+*/
+class BOTAN_DLL PKCS8_Decoder
+ {
+ public:
+ /**
+ * Set the algorithm identifier associated with the scheme
+ * this decoders key is part of.
+ * @param alg_id the algorithm identifier
+ */
+ virtual void alg_id(const AlgorithmIdentifier&) = 0;
+
+ /**
+ * Set the DER encoded key.
+ * @param key the DER encoded key
+ */
+ virtual void key_bits(const MemoryRegion<byte>&) = 0;
+ virtual ~PKCS8_Decoder() {}
+ };
+
+/**
+* PKCS #8 General Exception
+*/
+struct BOTAN_DLL PKCS8_Exception : public Decoding_Error
+ {
+ PKCS8_Exception(const std::string& error) :
+ Decoding_Error("PKCS #8: " + error) {}
+ };
+
+namespace PKCS8 {
+
+/**
+* Encode a private key into a pipe.
+* @param key the private key to encode
+* @param pipe the pipe to feed the encoded key into
+* @param enc the encoding type to use
+*/
+BOTAN_DLL void encode(const Private_Key& key, Pipe& pipe,
+ X509_Encoding enc = PEM);
+
+/**
+* Encode and encrypt a private key into a pipe.
+* @param key the private key to encode
+* @param pipe the pipe to feed the encoded key into
+* @param pass the password to use for encryption
+* @param rng the rng to use
+* @param pbe_algo the name of the desired password-based encryption algorithm.
+* Provide an empty string to use the default PBE defined in the configuration
+* under base/default_pbe.
+* @param enc the encoding type to use
+*/
+BOTAN_DLL void encrypt_key(const Private_Key& key,
+ Pipe& pipe,
+ RandomNumberGenerator& rng,
+ const std::string& pass,
+ const std::string& pbe_algo = "",
+ X509_Encoding enc = PEM);
+
+
+/**
+* Get a string containing a PEM encoded private key.
+* @param key the key to encode
+* @return the encoded key
+*/
+BOTAN_DLL std::string PEM_encode(const Private_Key& key);
+
+/**
+* Get a string containing a PEM encoded private key, encrypting it with a
+* password.
+* @param key the key to encode
+* @param rng the rng to use
+* @param pass the password to use for encryption
+* @param pbe_algo the name of the desired password-based encryption algorithm.
+* Provide an empty string to use the default PBE defined in the configuration
+* under base/default_pbe.
+*/
+BOTAN_DLL std::string PEM_encode(const Private_Key& key,
+ RandomNumberGenerator& rng,
+ const std::string& pass,
+ const std::string& pbe_algo = "");
+
+BOTAN_DLL std::string PEM_encode(const Private_Key&,
+ const std::string&,
+ const std::string& = "");
+
+
+/**
+* Load a key from a data source.
+* @param source the data source providing the encoded key
+* @param rng the rng to use
+* @param ui the user interface to be used for passphrase dialog
+* @return the loaded private key object
+*/
+BOTAN_DLL Private_Key* load_key(DataSource& source,
+ RandomNumberGenerator& rng,
+ const User_Interface& ui);
+
+/** Load a key from a data source.
+* @param source the data source providing the encoded key
+* @param rng the rng to use
+* @param pass the passphrase to decrypt the key. Provide an empty
+* string if the key is not encoded.
+* @return the loaded private key object
+*/
+BOTAN_DLL Private_Key* load_key(DataSource& source,
+ RandomNumberGenerator& rng,
+ const std::string& pass = "");
+
+/**
+* Load a key from a file.
+* @param filename the path to the file containing the encoded key
+* @param rng the rng to use
+* @param ui the user interface to be used for passphrase dialog
+* @return the loaded private key object
+*/
+BOTAN_DLL Private_Key* load_key(const std::string& filename,
+ RandomNumberGenerator& rng,
+ const User_Interface& ui);
+
+/** Load a key from a file.
+* @param filename the path to the file containing the encoded key
+* @param rng the rng to use
+* @param pass the passphrase to decrypt the key. Provide an empty
+* string if the key is not encoded.
+* @return the loaded private key object
+*/
+BOTAN_DLL Private_Key* load_key(const std::string& filename,
+ RandomNumberGenerator& rng,
+ const std::string& pass = "");
+
+/**
+* Copy an existing encoded key object.
+* @param key the key to copy
+* @param rng the rng to use
+* @return the new copy of the key
+*/
+BOTAN_DLL Private_Key* copy_key(const Private_Key& key,
+ RandomNumberGenerator& rng);
+
+}
+
+}
+
+#endif
diff --git a/src/pubkey/pk_codecs/x509_key.cpp b/src/pubkey/pk_codecs/x509_key.cpp
new file mode 100644
index 000000000..455e627f3
--- /dev/null
+++ b/src/pubkey/pk_codecs/x509_key.cpp
@@ -0,0 +1,176 @@
+/*
+* X.509 Public Key
+* (C) 1999-2007 Jack Lloyd
+*
+* Distributed under the terms of the Botan license
+*/
+
+#include <botan/x509_key.h>
+#include <botan/filters.h>
+#include <botan/asn1_obj.h>
+#include <botan/der_enc.h>
+#include <botan/ber_dec.h>
+#include <botan/pk_algs.h>
+#include <botan/oids.h>
+#include <botan/pem.h>
+#include <memory>
+
+namespace Botan {
+
+namespace X509 {
+
+/*
+* DER or PEM encode a X.509 public key
+*/
+void encode(const Public_Key& key, Pipe& pipe, X509_Encoding encoding)
+ {
+ std::auto_ptr<X509_Encoder> encoder(key.x509_encoder());
+ if(!encoder.get())
+ throw Encoding_Error("X509::encode: Key does not support encoding");
+
+ MemoryVector<byte> der =
+ DER_Encoder()
+ .start_cons(SEQUENCE)
+ .encode(encoder->alg_id())
+ .encode(encoder->key_bits(), BIT_STRING)
+ .end_cons()
+ .get_contents();
+
+ if(encoding == PEM)
+ pipe.write(PEM_Code::encode(der, "PUBLIC KEY"));
+ else
+ pipe.write(der);
+ }
+
+/*
+* PEM encode a X.509 public key
+*/
+std::string PEM_encode(const Public_Key& key)
+ {
+ Pipe pem;
+ pem.start_msg();
+ encode(key, pem, PEM);
+ pem.end_msg();
+ return pem.read_all_as_string();
+ }
+
+/*
+* Extract a public key and return it
+*/
+Public_Key* load_key(DataSource& source)
+ {
+ try {
+ AlgorithmIdentifier alg_id;
+ MemoryVector<byte> key_bits;
+
+ if(ASN1::maybe_BER(source) && !PEM_Code::matches(source))
+ {
+ BER_Decoder(source)
+ .start_cons(SEQUENCE)
+ .decode(alg_id)
+ .decode(key_bits, BIT_STRING)
+ .verify_end()
+ .end_cons();
+ }
+ else
+ {
+ DataSource_Memory ber(
+ PEM_Code::decode_check_label(source, "PUBLIC KEY")
+ );
+
+ BER_Decoder(ber)
+ .start_cons(SEQUENCE)
+ .decode(alg_id)
+ .decode(key_bits, BIT_STRING)
+ .verify_end()
+ .end_cons();
+ }
+
+ if(key_bits.is_empty())
+ throw Decoding_Error("X.509 public key decoding failed");
+
+ const std::string alg_name = OIDS::lookup(alg_id.oid);
+ if(alg_name == "")
+ throw Decoding_Error("Unknown algorithm OID: " +
+ alg_id.oid.as_string());
+
+ std::auto_ptr<Public_Key> key_obj(get_public_key(alg_name));
+ if(!key_obj.get())
+ throw Decoding_Error("Unknown PK algorithm/OID: " + alg_name + ", " +
+ alg_id.oid.as_string());
+
+ std::auto_ptr<X509_Decoder> decoder(key_obj->x509_decoder());
+
+ if(!decoder.get())
+ throw Decoding_Error("Key does not support X.509 decoding");
+
+ decoder->alg_id(alg_id);
+ decoder->key_bits(key_bits);
+
+ return key_obj.release();
+ }
+ catch(Decoding_Error)
+ {
+ throw Decoding_Error("X.509 public key decoding failed");
+ }
+ }
+
+/*
+* Extract a public key and return it
+*/
+Public_Key* load_key(const std::string& fsname)
+ {
+ DataSource_Stream source(fsname, true);
+ return X509::load_key(source);
+ }
+
+/*
+* Extract a public key and return it
+*/
+Public_Key* load_key(const MemoryRegion<byte>& mem)
+ {
+ DataSource_Memory source(mem);
+ return X509::load_key(source);
+ }
+
+/*
+* Make a copy of this public key
+*/
+Public_Key* copy_key(const Public_Key& key)
+ {
+ Pipe bits;
+ bits.start_msg();
+ X509::encode(key, bits, RAW_BER);
+ bits.end_msg();
+ DataSource_Memory source(bits.read_all());
+ return X509::load_key(source);
+ }
+
+/*
+* Find the allowable key constraints
+*/
+Key_Constraints find_constraints(const Public_Key& pub_key,
+ Key_Constraints limits)
+ {
+ const Public_Key* key = &pub_key;
+ u32bit constraints = 0;
+
+ if(dynamic_cast<const PK_Encrypting_Key*>(key))
+ constraints |= KEY_ENCIPHERMENT | DATA_ENCIPHERMENT;
+
+ if(dynamic_cast<const PK_Key_Agreement_Key*>(key))
+ constraints |= KEY_AGREEMENT;
+
+ if(dynamic_cast<const PK_Verifying_wo_MR_Key*>(key) ||
+ dynamic_cast<const PK_Verifying_with_MR_Key*>(key))
+ constraints |= DIGITAL_SIGNATURE | NON_REPUDIATION;
+
+ if(limits)
+ constraints &= limits;
+
+ return Key_Constraints(constraints);
+ }
+
+}
+
+}
diff --git a/src/pubkey/pk_codecs/x509_key.h b/src/pubkey/pk_codecs/x509_key.h
new file mode 100644
index 000000000..9404b7ecc
--- /dev/null
+++ b/src/pubkey/pk_codecs/x509_key.h
@@ -0,0 +1,110 @@
+/*
+* X.509 Public Key
+* (C) 1999-2007 Jack Lloyd
+*
+* Distributed under the terms of the Botan license
+*/
+
+#ifndef BOTAN_X509_PUBLIC_KEY_H__
+#define BOTAN_X509_PUBLIC_KEY_H__
+
+#include <botan/pipe.h>
+#include <botan/pk_keys.h>
+#include <botan/alg_id.h>
+#include <botan/pubkey_enums.h>
+
+namespace Botan {
+
+/**
+* This class represents abstract X.509 public key encoders.
+*/
+class BOTAN_DLL X509_Encoder
+ {
+ public:
+ virtual AlgorithmIdentifier alg_id() const = 0;
+ virtual MemoryVector<byte> key_bits() const = 0;
+ virtual ~X509_Encoder() {}
+ };
+
+/**
+* This class represents abstract X.509 public key decoders.
+*/
+class BOTAN_DLL X509_Decoder
+ {
+ public:
+ virtual void alg_id(const AlgorithmIdentifier&) = 0;
+ virtual void key_bits(const MemoryRegion<byte>&) = 0;
+ virtual ~X509_Decoder() {}
+ };
+
+/**
+* This namespace contains functions for handling X509 objects.
+*/
+namespace X509 {
+
+/*
+* X.509 Public Key Encoding/Decoding
+*/
+
+/**
+* Encode a key into a pipe.
+* @param key the public key to encode
+* @param pipe the pipe to feed the encoded key into
+* @param enc the encoding type to use
+*/
+BOTAN_DLL void encode(const Public_Key& key, Pipe& pipe,
+ X509_Encoding enc = PEM);
+
+/**
+* PEM encode a public key into a string.
+* @param key the key to encode
+* @return the PEM encoded key
+*/
+BOTAN_DLL std::string PEM_encode(const Public_Key& key);
+
+/**
+* Create a public key from a data source.
+* @param source the source providing the DER or PEM encoded key
+* @return the new public key object
+*/
+BOTAN_DLL Public_Key* load_key(DataSource& source);
+
+/**
+* Create a public key from a string.
+* @param enc the string containing the PEM encoded key
+* @return the new public key object
+*/
+BOTAN_DLL Public_Key* load_key(const std::string& enc);
+
+/**
+* Create a public key from a memory region.
+* @param enc the memory region containing the DER or PEM encoded key
+* @return the new public key object
+*/
+BOTAN_DLL Public_Key* load_key(const MemoryRegion<byte>& enc);
+
+/**
+* Copy a key.
+* @param key the public key to copy
+* @return the new public key object
+*/
+BOTAN_DLL Public_Key* copy_key(const Public_Key& key);
+
+/**
+* Create the key constraints for a specific public key.
+* @param pub_key the public key from which the basic set of
+* constraints to be placed in the return value is derived
+* @param limits additional limits that will be incorporated into the
+* return value
+* @return the combination of key type specific constraints and
+* additional limits
+*/
+
+BOTAN_DLL Key_Constraints find_constraints(const Public_Key& pub_key,
+ Key_Constraints limits);
+
+}
+
+}
+
+#endif