aboutsummaryrefslogtreecommitdiffstats
path: root/src/python
diff options
context:
space:
mode:
Diffstat (limited to 'src/python')
-rw-r--r--src/python/__init__.py4
-rw-r--r--src/python/core.cpp232
-rw-r--r--src/python/filter.cpp177
-rw-r--r--src/python/python_botan.h86
-rw-r--r--src/python/rsa.cpp220
-rw-r--r--src/python/x509.cpp88
6 files changed, 807 insertions, 0 deletions
diff --git a/src/python/__init__.py b/src/python/__init__.py
new file mode 100644
index 000000000..2df9a456f
--- /dev/null
+++ b/src/python/__init__.py
@@ -0,0 +1,4 @@
+from _botan import *
+
+# Initialize the library when the module is imported
+init = LibraryInitializer()
diff --git a/src/python/core.cpp b/src/python/core.cpp
new file mode 100644
index 000000000..6dcceee74
--- /dev/null
+++ b/src/python/core.cpp
@@ -0,0 +1,232 @@
+/*
+* Boost.Python module definition
+* (C) 1999-2007 Jack Lloyd
+*/
+
+#include <botan/init.h>
+#include <botan/pipe.h>
+#include <botan/lookup.h>
+#include <botan/cryptobox.h>
+#include <botan/pbkdf2.h>
+#include <botan/hmac.h>
+using namespace Botan;
+
+#include "python_botan.h"
+
+class Py_Cipher
+ {
+ public:
+ Py_Cipher(std::string algo_name, std::string direction,
+ std::string key);
+
+ std::string cipher_noiv(const std::string& text);
+
+ std::string cipher(const std::string& text,
+ const std::string& iv);
+
+ std::string name() const { return algo_name; }
+ private:
+ std::string algo_name;
+ Keyed_Filter* filter;
+ Pipe pipe;
+ };
+
+std::string Py_Cipher::cipher(const std::string& input,
+ const std::string& iv_str)
+ {
+ if(iv_str.size())
+ {
+ const byte* iv_bytes = reinterpret_cast<const byte*>(iv_str.data());
+ u32bit iv_len = iv_str.size();
+ filter->set_iv(InitializationVector(iv_bytes, iv_len));
+ }
+
+ pipe.process_msg(input);
+ return pipe.read_all_as_string(Pipe::LAST_MESSAGE);
+ }
+
+// For IV-less algorithms
+std::string Py_Cipher::cipher_noiv(const std::string& input)
+ {
+ pipe.process_msg(input);
+ return pipe.read_all_as_string(Pipe::LAST_MESSAGE);
+ }
+
+Py_Cipher::Py_Cipher(std::string algo_name,
+ std::string direction,
+ std::string key_str)
+ {
+ const byte* key_bytes = reinterpret_cast<const byte*>(key_str.data());
+ u32bit key_len = key_str.size();
+
+ Cipher_Dir dir;
+
+ if(direction == "encrypt")
+ dir = ENCRYPTION;
+ else if(direction == "decrypt")
+ dir = DECRYPTION;
+ else
+ throw std::invalid_argument("Bad cipher direction " + direction);
+
+ filter = get_cipher(algo_name, dir);
+ filter->set_key(SymmetricKey(key_bytes, key_len));
+ pipe.append(filter);
+ }
+
+class Py_HashFunction
+ {
+ public:
+ Py_HashFunction(const std::string& algo_name)
+ {
+ hash = get_hash(algo_name);
+ }
+
+ ~Py_HashFunction() { delete hash; }
+
+ void update(const std::string& input)
+ {
+ hash->update(input);
+ }
+
+ std::string final()
+ {
+ std::string out(output_length(), 0);
+ hash->final(reinterpret_cast<byte*>(&out[0]));
+ return out;
+ }
+
+ std::string name() const
+ {
+ return hash->name();
+ }
+
+ u32bit output_length() const
+ {
+ return hash->output_length();
+ }
+
+ private:
+ HashFunction* hash;
+ };
+
+class Py_MAC
+ {
+ public:
+
+ Py_MAC(const std::string& name, const std::string& key_str)
+ {
+ mac = get_mac(name);
+
+ mac->set_key(reinterpret_cast<const byte*>(key_str.data()),
+ key_str.size());
+ }
+
+ ~Py_MAC() { delete mac; }
+
+ u32bit output_length() const { return mac->output_length(); }
+
+ std::string name() const { return mac->name(); }
+
+ void update(const std::string& in) { mac->update(in); }
+
+ std::string final()
+ {
+ std::string out(output_length(), 0);
+ mac->final(reinterpret_cast<byte*>(&out[0]));
+ return out;
+ }
+ private:
+ MessageAuthenticationCode* mac;
+ };
+
+std::string cryptobox_encrypt(const std::string& in,
+ const std::string& passphrase,
+ Python_RandomNumberGenerator& rng)
+ {
+ const byte* in_bytes = reinterpret_cast<const byte*>(in.data());
+
+ return CryptoBox::encrypt(in_bytes, in.size(),
+ passphrase, rng.get_underlying_rng());
+ }
+
+std::string cryptobox_decrypt(const std::string& in,
+ const std::string& passphrase)
+ {
+ const byte* in_bytes = reinterpret_cast<const byte*>(in.data());
+
+ return CryptoBox::decrypt(in_bytes, in.size(),
+ passphrase);
+ }
+
+std::string python_pbkdf2(const std::string& passphrase,
+ const std::string& salt,
+ u32bit iterations,
+ u32bit output_size,
+ const std::string& hash_fn)
+ {
+ PKCS5_PBKDF2 pbkdf2(new HMAC(get_hash(hash_fn)));
+
+ return make_string(
+ pbkdf2.derive_key(output_size,
+ passphrase,
+ reinterpret_cast<const byte*>(salt.data()),
+ salt.size(),
+ iterations).bits_of());
+ }
+
+std::string python_kdf2(const std::string& param,
+ const std::string& masterkey,
+ u32bit outputlength)
+ {
+ std::unique_ptr<KDF> kdf(get_kdf("KDF2(SHA-1)"));
+
+ return make_string(
+ kdf->derive_key(outputlength,
+ reinterpret_cast<const byte*>(masterkey.data()),
+ masterkey.length(),
+ param));
+ }
+
+BOOST_PYTHON_MODULE(_botan)
+ {
+ python::class_<LibraryInitializer>("LibraryInitializer")
+ .def(python::init< python::optional<std::string> >());
+
+ python::class_<Python_RandomNumberGenerator>("RandomNumberGenerator")
+ .def(python::init<>())
+ .def("__str__", &Python_RandomNumberGenerator::name)
+ .def("name", &Python_RandomNumberGenerator::name)
+ .def("reseed", &Python_RandomNumberGenerator::reseed)
+ .def("add_entropy", &Python_RandomNumberGenerator::add_entropy)
+ .def("gen_random_byte", &Python_RandomNumberGenerator::gen_random_byte)
+ .def("gen_random", &Python_RandomNumberGenerator::gen_random);
+
+ python::class_<Py_Cipher, boost::noncopyable>
+ ("Cipher", python::init<std::string, std::string, std::string>())
+ .def("name", &Py_Cipher::name)
+ .def("cipher", &Py_Cipher::cipher)
+ .def("cipher", &Py_Cipher::cipher_noiv);
+
+ python::class_<Py_HashFunction, boost::noncopyable>
+ ("HashFunction", python::init<std::string>())
+ .def("update", &Py_HashFunction::update)
+ .def("final", &Py_HashFunction::final)
+ .def("name", &Py_HashFunction::name)
+ .def("output_length", &Py_HashFunction::output_length);
+
+ python::class_<Py_MAC, boost::noncopyable>
+ ("MAC", python::init<std::string, std::string>())
+ .def("update", &Py_MAC::update)
+ .def("final", &Py_MAC::final)
+ .def("name", &Py_MAC::name)
+ .def("output_length", &Py_MAC::output_length);
+
+ python::def("cryptobox_encrypt", cryptobox_encrypt);
+ python::def("cryptobox_decrypt", cryptobox_decrypt);
+ python::def("pbkdf2", python_pbkdf2);
+ python::def("derive_key", python_kdf2);
+
+ export_filters();
+ export_rsa();
+ export_x509();
+ }
diff --git a/src/python/filter.cpp b/src/python/filter.cpp
new file mode 100644
index 000000000..e329ed708
--- /dev/null
+++ b/src/python/filter.cpp
@@ -0,0 +1,177 @@
+/*
+* Boost.Python module definition
+* (C) 1999-2007 Jack Lloyd
+*
+* Distributed under the terms of the Botan license
+*/
+
+#include <boost/python.hpp>
+using namespace boost::python;
+
+#include <botan/pipe.h>
+#include <botan/lookup.h>
+using namespace Botan;
+
+class Py_Filter : public Filter
+ {
+ public:
+ virtual void write_str(const std::string&) = 0;
+
+ std::string name() const { return "Py_Filter_FIXME"; }
+
+ void write(const byte data[], size_t length)
+ {
+ write_str(std::string((const char*)data, length));
+ }
+
+ void send_str(const std::string& str)
+ {
+ send((const byte*)str.data(), str.length());
+ }
+ };
+
+class FilterWrapper : public Py_Filter, public wrapper<Py_Filter>
+ {
+ public:
+ void start_msg()
+ {
+ if(override start_msg = this->get_override("start_msg"))
+ start_msg();
+ }
+
+ void end_msg()
+ {
+ if(override end_msg = this->get_override("end_msg"))
+ end_msg();
+ }
+
+ void default_start_msg() {}
+ void default_end_msg() {}
+
+ virtual void write_str(const std::string& str)
+ {
+ this->get_override("write")(str);
+ }
+ };
+
+Filter* return_or_raise(Filter* filter, const std::string& name)
+ {
+ if(filter)
+ return filter;
+ throw Invalid_Argument("Filter " + name + " could not be found");
+ }
+
+Filter* make_filter1(const std::string& name)
+ {
+ Filter* filter = 0;
+
+ if(have_hash(name)) filter = new Hash_Filter(name);
+ else if(name == "Hex_Encoder") filter = new Hex_Encoder;
+ else if(name == "Hex_Decoder") filter = new Hex_Decoder;
+ else if(name == "Base64_Encoder") filter = new Base64_Encoder;
+ else if(name == "Base64_Decoder") filter = new Base64_Decoder;
+
+ return return_or_raise(filter, name);
+ }
+
+Filter* make_filter2(const std::string& name,
+ const SymmetricKey& key)
+ {
+ Filter* filter = 0;
+
+ if(have_mac(name))
+ filter = new MAC_Filter(name, key);
+ else if(have_stream_cipher(name))
+ filter = new StreamCipher_Filter(name, key);
+
+ return return_or_raise(filter, name);
+ }
+
+// FIXME: add new wrapper for Keyed_Filter here
+Filter* make_filter3(const std::string& name,
+ const SymmetricKey& key,
+ Cipher_Dir direction)
+ {
+ return return_or_raise(
+ get_cipher(name, key, direction),
+ name);
+ }
+
+Filter* make_filter4(const std::string& name,
+ const SymmetricKey& key,
+ const InitializationVector& iv,
+ Cipher_Dir direction)
+ {
+ return return_or_raise(
+ get_cipher(name, key, iv, direction),
+ name);
+ }
+
+void append_filter(Pipe& pipe, std::auto_ptr<Filter> filter)
+ {
+ pipe.append(filter.get());
+ filter.release();
+ }
+
+void prepend_filter(Pipe& pipe, std::auto_ptr<Filter> filter)
+ {
+ pipe.prepend(filter.get());
+ filter.release();
+ }
+
+void do_send(std::auto_ptr<FilterWrapper> filter, const std::string& data)
+ {
+ filter->send_str(data);
+ }
+
+BOOST_PYTHON_MEMBER_FUNCTION_OVERLOADS(rallas_ovls, read_all_as_string, 0, 1)
+
+void export_filters()
+ {
+ class_<Filter, std::auto_ptr<Filter>, boost::noncopyable>
+ ("__Internal_FilterObj", no_init);
+
+ def("make_filter", make_filter1,
+ return_value_policy<manage_new_object>());
+ def("make_filter", make_filter2,
+ return_value_policy<manage_new_object>());
+ def("make_filter", make_filter3,
+ return_value_policy<manage_new_object>());
+ def("make_filter", make_filter4,
+ return_value_policy<manage_new_object>());
+
+ // This might not work - Pipe will delete the filter, but Python
+ // might have allocated the space with malloc() or who-knows-what -> bad
+ class_<FilterWrapper, std::auto_ptr<FilterWrapper>,
+ bases<Filter>, boost::noncopyable>
+ ("FilterObj")
+ .def("write", pure_virtual(&Py_Filter::write_str))
+ .def("send", &do_send)
+ .def("start_msg", &Filter::start_msg, &FilterWrapper::default_start_msg)
+ .def("end_msg", &Filter::end_msg, &FilterWrapper::default_end_msg);
+
+ implicitly_convertible<std::auto_ptr<FilterWrapper>,
+ std::auto_ptr<Filter> >();
+
+ void (Pipe::*pipe_write_str)(const std::string&) = &Pipe::write;
+ void (Pipe::*pipe_process_str)(const std::string&) = &Pipe::process_msg;
+
+ class_<Pipe, boost::noncopyable>("PipeObj")
+ .def(init<>())
+ /*
+ .def_readonly("LAST_MESSAGE", &Pipe::LAST_MESSAGE)
+ .def_readonly("DEFAULT_MESSAGE", &Pipe::DEFAULT_MESSAGE)
+ */
+ .add_property("default_msg", &Pipe::default_msg, &Pipe::set_default_msg)
+ .add_property("msg_count", &Pipe::message_count)
+ .def("append", append_filter)
+ .def("prepend", prepend_filter)
+ .def("reset", &Pipe::reset)
+ .def("pop", &Pipe::pop)
+ .def("end_of_data", &Pipe::end_of_data)
+ .def("start_msg", &Pipe::start_msg)
+ .def("end_msg", &Pipe::end_msg)
+ .def("write", pipe_write_str)
+ .def("process_msg", pipe_process_str)
+ .def("read_all", &Pipe::read_all_as_string, rallas_ovls());
+ }
diff --git a/src/python/python_botan.h b/src/python/python_botan.h
new file mode 100644
index 000000000..501f4b9eb
--- /dev/null
+++ b/src/python/python_botan.h
@@ -0,0 +1,86 @@
+/*
+* (C) 2009 Jack Lloyd
+*
+* Distributed under the terms of the Botan license
+*/
+
+#ifndef BOTAN_BOOST_PYTHON_COMMON_H__
+#define BOTAN_BOOST_PYTHON_COMMON_H__
+
+#include <botan/exceptn.h>
+#include <botan/parsing.h>
+#include <botan/secmem.h>
+using namespace Botan;
+
+#include <boost/python.hpp>
+namespace python = boost::python;
+
+extern void export_filters();
+extern void export_rsa();
+extern void export_x509();
+
+class Bad_Size : public Exception
+ {
+ public:
+ Bad_Size(u32bit got, u32bit expected) :
+ Exception("Bad size detected in Python/C++ conversion layer: got " +
+ std::to_string(got) + " bytes, expected " +
+ std::to_string(expected))
+ {}
+ };
+
+inline std::string make_string(const byte input[], u32bit length)
+ {
+ return std::string((const char*)input, length);
+ }
+
+template<typename Alloc>
+inline std::string make_string(const std::vector<byte, Alloc>& in)
+ {
+ return make_string(&in[0], in.size());
+ }
+
+inline void string2binary(const std::string& from, byte to[], u32bit expected)
+ {
+ if(from.size() != expected)
+ throw Bad_Size(from.size(), expected);
+ std::memcpy(to, from.data(), expected);
+ }
+
+template<typename T>
+inline python::object get_owner(T* me)
+ {
+ return python::object(
+ python::handle<>(
+ python::borrowed(python::detail::wrapper_base_::get_owner(*me))));
+ }
+
+class Python_RandomNumberGenerator
+ {
+ public:
+ Python_RandomNumberGenerator()
+ { rng = RandomNumberGenerator::make_rng(); }
+ ~Python_RandomNumberGenerator() { delete rng; }
+
+ std::string name() const { return rng->name(); }
+
+ void reseed() { rng->reseed(192); }
+
+ int gen_random_byte() { return rng->next_byte(); }
+
+ std::string gen_random(int n)
+ {
+ std::string s(n, 0);
+ rng->randomize(reinterpret_cast<byte*>(&s[0]), n);
+ return s;
+ }
+
+ void add_entropy(const std::string& in)
+ { rng->add_entropy(reinterpret_cast<const byte*>(in.c_str()), in.length()); }
+
+ RandomNumberGenerator& get_underlying_rng() { return *rng; }
+ private:
+ RandomNumberGenerator* rng;
+ };
+
+#endif
diff --git a/src/python/rsa.cpp b/src/python/rsa.cpp
new file mode 100644
index 000000000..770082945
--- /dev/null
+++ b/src/python/rsa.cpp
@@ -0,0 +1,220 @@
+/*
+* Boost.Python module definition
+* (C) 1999-2007 Jack Lloyd
+*
+* Distributed under the terms of the Botan license
+*/
+
+#include <botan/rsa.h>
+#include <botan/pubkey.h>
+#include <botan/x509_key.h>
+using namespace Botan;
+
+#include "python_botan.h"
+#include <sstream>
+
+std::string bigint2str(const BigInt& n)
+ {
+ std::ostringstream out;
+ out << n;
+ return out.str();
+ }
+
+class Py_RSA_PrivateKey
+ {
+ public:
+ Py_RSA_PrivateKey(std::string pem_str,
+ Python_RandomNumberGenerator& rng,
+ std::string pass);
+ Py_RSA_PrivateKey(std::string pem_str,
+ Python_RandomNumberGenerator& rng);
+
+ Py_RSA_PrivateKey(u32bit bits, Python_RandomNumberGenerator& rng);
+ ~Py_RSA_PrivateKey() { delete rsa_key; }
+
+ std::string to_string() const
+ {
+ return PKCS8::PEM_encode(*rsa_key);
+ }
+
+ std::string to_ber() const
+ {
+ secure_vector<byte> bits = PKCS8::BER_encode(*rsa_key);
+ return std::string(reinterpret_cast<const char*>(&bits[0]), bits.size());
+ }
+
+ std::string get_N() const { return bigint2str(get_bigint_N()); }
+ std::string get_E() const { return bigint2str(get_bigint_E()); }
+
+ const BigInt& get_bigint_N() const { return rsa_key->get_n(); }
+ const BigInt& get_bigint_E() const { return rsa_key->get_e(); }
+
+ std::string decrypt(const std::string& in,
+ const std::string& padding);
+
+ std::string sign(const std::string& in,
+ const std::string& padding,
+ Python_RandomNumberGenerator& rng);
+ private:
+ RSA_PrivateKey* rsa_key;
+ };
+
+std::string Py_RSA_PrivateKey::decrypt(const std::string& in,
+ const std::string& padding)
+ {
+ PK_Decryptor_EME dec(*rsa_key, padding);
+
+ const byte* in_bytes = reinterpret_cast<const byte*>(in.data());
+
+ return make_string(dec.decrypt(in_bytes, in.size()));
+ }
+
+std::string Py_RSA_PrivateKey::sign(const std::string& in,
+ const std::string& padding,
+ Python_RandomNumberGenerator& rng)
+ {
+ PK_Signer sign(*rsa_key, padding);
+ const byte* in_bytes = reinterpret_cast<const byte*>(in.data());
+ sign.update(in_bytes, in.size());
+ return make_string(sign.signature(rng.get_underlying_rng()));
+ }
+
+Py_RSA_PrivateKey::Py_RSA_PrivateKey(u32bit bits,
+ Python_RandomNumberGenerator& rng)
+ {
+ rsa_key = new RSA_PrivateKey(rng.get_underlying_rng(), bits);
+ }
+
+Py_RSA_PrivateKey::Py_RSA_PrivateKey(std::string pem_str,
+ Python_RandomNumberGenerator& rng)
+ {
+ DataSource_Memory in(pem_str);
+
+ Private_Key* pkcs8_key =
+ PKCS8::load_key(in,
+ rng.get_underlying_rng());
+
+ rsa_key = dynamic_cast<RSA_PrivateKey*>(pkcs8_key);
+
+ if(!rsa_key)
+ throw std::invalid_argument("Key is not an RSA key");
+ }
+
+Py_RSA_PrivateKey::Py_RSA_PrivateKey(std::string pem_str,
+ Python_RandomNumberGenerator& rng,
+ std::string passphrase)
+ {
+ DataSource_Memory in(pem_str);
+
+ Private_Key* pkcs8_key =
+ PKCS8::load_key(in,
+ rng.get_underlying_rng(),
+ passphrase);
+
+ rsa_key = dynamic_cast<RSA_PrivateKey*>(pkcs8_key);
+
+ if(!rsa_key)
+ throw std::invalid_argument("Key is not an RSA key");
+ }
+
+class Py_RSA_PublicKey
+ {
+ public:
+ Py_RSA_PublicKey(std::string pem_str);
+ Py_RSA_PublicKey(const Py_RSA_PrivateKey&);
+ ~Py_RSA_PublicKey() { delete rsa_key; }
+
+ std::string get_N() const { return bigint2str(get_bigint_N()); }
+ std::string get_E() const { return bigint2str(get_bigint_E()); }
+
+ const BigInt& get_bigint_N() const { return rsa_key->get_n(); }
+ const BigInt& get_bigint_E() const { return rsa_key->get_e(); }
+
+ std::string to_string() const
+ {
+ return X509::PEM_encode(*rsa_key);
+ }
+
+ std::string to_ber() const
+ {
+ std::vector<byte> bits = X509::BER_encode(*rsa_key);
+
+ return std::string(reinterpret_cast<const char*>(&bits[0]),
+ bits.size());
+ }
+
+ std::string encrypt(const std::string& in,
+ const std::string& padding,
+ Python_RandomNumberGenerator& rng);
+
+ bool verify(const std::string& in,
+ const std::string& padding,
+ const std::string& signature);
+ private:
+ RSA_PublicKey* rsa_key;
+ };
+
+Py_RSA_PublicKey::Py_RSA_PublicKey(const Py_RSA_PrivateKey& priv)
+ {
+ rsa_key = new RSA_PublicKey(priv.get_bigint_N(), priv.get_bigint_E());
+ }
+
+Py_RSA_PublicKey::Py_RSA_PublicKey(std::string pem_str)
+ {
+ DataSource_Memory in(pem_str);
+ Public_Key* x509_key = X509::load_key(in);
+
+ rsa_key = dynamic_cast<RSA_PublicKey*>(x509_key);
+
+ if(!rsa_key)
+ throw std::invalid_argument("Key is not an RSA key");
+ }
+
+std::string Py_RSA_PublicKey::encrypt(const std::string& in,
+ const std::string& padding,
+ Python_RandomNumberGenerator& rng)
+ {
+ PK_Encryptor_EME enc(*rsa_key, padding);
+
+ const byte* in_bytes = reinterpret_cast<const byte*>(in.data());
+
+ return make_string(enc.encrypt(in_bytes, in.size(),
+ rng.get_underlying_rng()));
+ }
+
+bool Py_RSA_PublicKey::verify(const std::string& in,
+ const std::string& signature,
+ const std::string& padding)
+ {
+ PK_Verifier ver(*rsa_key, padding);
+
+ const byte* in_bytes = reinterpret_cast<const byte*>(in.data());
+ const byte* sig_bytes = reinterpret_cast<const byte*>(signature.data());
+
+ ver.update(in_bytes, in.size());
+ return ver.check_signature(sig_bytes, signature.size());
+ }
+
+void export_rsa()
+ {
+ python::class_<Py_RSA_PublicKey>
+ ("RSA_PublicKey", python::init<std::string>())
+ .def(python::init<const Py_RSA_PrivateKey&>())
+ .def("to_string", &Py_RSA_PublicKey::to_string)
+ .def("to_ber", &Py_RSA_PublicKey::to_ber)
+ .def("encrypt", &Py_RSA_PublicKey::encrypt)
+ .def("verify", &Py_RSA_PublicKey::verify)
+ .def("get_N", &Py_RSA_PublicKey::get_N)
+ .def("get_E", &Py_RSA_PublicKey::get_E);
+
+ python::class_<Py_RSA_PrivateKey>
+ ("RSA_PrivateKey", python::init<std::string, Python_RandomNumberGenerator&, std::string>())
+ .def(python::init<std::string, Python_RandomNumberGenerator&>())
+ .def(python::init<u32bit, Python_RandomNumberGenerator&>())
+ .def("to_string", &Py_RSA_PrivateKey::to_string)
+ .def("to_ber", &Py_RSA_PrivateKey::to_ber)
+ .def("decrypt", &Py_RSA_PrivateKey::decrypt)
+ .def("sign", &Py_RSA_PrivateKey::sign)
+ .def("get_N", &Py_RSA_PrivateKey::get_N)
+ .def("get_E", &Py_RSA_PrivateKey::get_E);
+ }
diff --git a/src/python/x509.cpp b/src/python/x509.cpp
new file mode 100644
index 000000000..57beb7e4a
--- /dev/null
+++ b/src/python/x509.cpp
@@ -0,0 +1,88 @@
+/*
+* Boost.Python module definition
+* (C) 2009 Jack Lloyd
+*
+* Distributed under the terms of the Botan license
+*/
+
+#include <botan/oids.h>
+#include <botan/pipe.h>
+#include <botan/filters.h>
+#include <botan/x509cert.h>
+#include <botan/x509_crl.h>
+using namespace Botan;
+
+#include <boost/python.hpp>
+namespace python = boost::python;
+
+template<typename T>
+class vector_to_list
+ {
+ public:
+ static PyObject* convert(const std::vector<T>& in)
+ {
+ python::list out;
+ typename std::vector<T>::const_iterator i = in.begin();
+ while(i != in.end())
+ {
+ out.append(*i);
+ ++i;
+ }
+ return python::incref(out.ptr());
+ }
+
+ vector_to_list()
+ {
+ python::to_python_converter<std::vector<T>, vector_to_list<T> >();
+ }
+ };
+
+template<typename T>
+class memvec_to_hexstr
+ {
+ public:
+ static PyObject* convert(const T& in)
+ {
+ Pipe pipe(new Hex_Encoder);
+ pipe.process_msg(in);
+ std::string result = pipe.read_all_as_string();
+ return python::incref(python::str(result).ptr());
+ }
+
+ memvec_to_hexstr()
+ {
+ python::to_python_converter<T, memvec_to_hexstr<T> >();
+ }
+ };
+
+BOOST_PYTHON_MEMBER_FUNCTION_OVERLOADS(add_cert_ols, add_cert, 1, 2)
+BOOST_PYTHON_MEMBER_FUNCTION_OVERLOADS(validate_cert_ols, validate_cert, 1, 2)
+
+void export_x509()
+ {
+ vector_to_list<std::string>();
+ vector_to_list<X509_Certificate>();
+ memvec_to_hexstr<std::vector<byte> >();
+
+ python::class_<X509_Certificate>
+ ("X509_Certificate", python::init<std::string>())
+ .def(python::self == python::self)
+ .def(python::self != python::self)
+ .add_property("version", &X509_Certificate::x509_version)
+ .add_property("is_CA", &X509_Certificate::is_CA_cert)
+ .add_property("self_signed", &X509_Certificate::is_self_signed)
+ .add_property("pathlimit", &X509_Certificate::path_limit)
+ .add_property("as_pem", &X509_Object::PEM_encode)
+ .def("start_time", &X509_Certificate::start_time)
+ .def("end_time", &X509_Certificate::end_time)
+ .def("subject_info", &X509_Certificate::subject_info)
+ .def("issuer_info", &X509_Certificate::issuer_info)
+ .def("ex_constraints", &X509_Certificate::ex_constraints)
+ .def("policies", &X509_Certificate::policies)
+ .def("subject_key_id", &X509_Certificate::subject_key_id)
+ .def("authority_key_id", &X509_Certificate::authority_key_id);
+
+ python::class_<X509_CRL>
+ ("X509_CRL", python::init<std::string>())
+ .add_property("as_pem", &X509_Object::PEM_encode);
+ }