From 9164f0e76b1477836d1547c2438a04317bf0a2f8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marc=20W=C3=A4ckerlin?= Date: Thu, 17 Sep 2009 14:57:22 +0000 Subject: [PATCH] now with openssl wrapper --- src/makefile.am | 2 +- src/openssl.hxx | 277 ++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 278 insertions(+), 1 deletion(-) create mode 100644 src/openssl.hxx diff --git a/src/makefile.am b/src/makefile.am index 3f44857..be082d2 100644 --- a/src/makefile.am +++ b/src/makefile.am @@ -5,7 +5,7 @@ ## 1 2 3 4 5 6 7 8 ## 45678901234567890123456789012345678901234567890123456789012345678901234567890 -include_HEADERS = pcsc.hxx cryptoki.hxx +include_HEADERS = pcsc.hxx cryptoki.hxx openssl.hxx pkcs11_HEADERS = pkcs11/pkcs11.h pkcs11/pkcs11types.h pkcs11/apiclient.h pkcs11dir = ${includedir}/pkcs11 diff --git a/src/openssl.hxx b/src/openssl.hxx new file mode 100644 index 0000000..15e706d --- /dev/null +++ b/src/openssl.hxx @@ -0,0 +1,277 @@ +/*! @file + + @id $Id$ +*/ +// 1 2 3 4 5 6 7 8 +// 45678901234567890123456789012345678901234567890123456789012345678901234567890 + +#ifndef __OPENSSL_HXX__ +#define __OPENSSL_HXX__ + +#include +#include + +#include "openssl/bio.h" +#include "openssl/ssl.h" +#include +#include + +namespace openssl { + + + //============================================================================ + class exception: public std::exception { + public: + exception(const std::string& reason) throw(): + _what("openssl: "+reason) { + } + ~exception() throw() {} + const char* what() const throw() { + return _what.c_str(); + } + private: + std::string _what; + }; + //---------------------------------------------------------------------------- + class openssl_error: public exception { + public: + openssl_error(const std::string& reason) throw(): + exception(reason+'\n'+ERR_error_string(ERR_get_error(), 0)) { + } + }; + //---------------------------------------------------------------------------- + class pkcs12_error: public openssl_error { + public: + pkcs12_error(const std::string& reason) throw(): + openssl_error("pkcs12: "+reason) { + } + }; + //---------------------------------------------------------------------------- + class x509_error: public openssl_error { + public: + x509_error(const std::string& reason) throw(): + openssl_error("x509: "+reason) { + } + }; + //---------------------------------------------------------------------------- + class bio_error: public openssl_error { + public: + bio_error(const std::string& reason) throw(): + openssl_error("bio: "+reason) { + } + }; + //---------------------------------------------------------------------------- + class allocation_failed: public x509_error { + public: + allocation_failed() throw(): + x509_error("memory allocation failed") { + } + }; + //---------------------------------------------------------------------------- + class undefined_certificate: public x509_error { + public: + undefined_certificate() throw(): + x509_error("certificate must not be 0") { + } + }; + //---------------------------------------------------------------------------- + class x509_parsing_failed: public x509_error { + public: + x509_parsing_failed() throw(): + x509_error("parsing DER encoded certificate failed") { + } + }; + //---------------------------------------------------------------------------- + class x509_copy_failed: public x509_error { + public: + x509_copy_failed() throw(): + x509_error("certificate object copy failed") { + } + }; + //---------------------------------------------------------------------------- + class pkcs12_reading_failed: public pkcs12_error { + public: + pkcs12_reading_failed(const std::string& file) throw(): + pkcs12_error("reading DER encoded p12 file failed: "+file) { + } + }; + //---------------------------------------------------------------------------- + class pkcs12_parsing_failed: public pkcs12_error { + public: + pkcs12_parsing_failed(const std::string& file) throw(): + pkcs12_error("parsing DER encoded p12 file failed: "+file) { + } + }; + //---------------------------------------------------------------------------- + class pkcs12_no_private_key: public pkcs12_error { + public: + pkcs12_no_private_key() throw(): pkcs12_error("no private key") {} + }; + //---------------------------------------------------------------------------- + class pkcs12_no_x509: public pkcs12_error { + public: + pkcs12_no_x509() throw(): pkcs12_error("no x509 certificate") {} + }; + //---------------------------------------------------------------------------- + class cannot_open_file: public exception { + public: + cannot_open_file(const std::string& file) throw(): + exception("cannot open file: "+file) { + } + }; + //---------------------------------------------------------------------------- + class bio_connection_failed: public bio_error { + public: + bio_connection_failed(const std::string& hostPort) throw(): + bio_error("connection failed to: "+hostPort) { + } + }; + + //============================================================================ + class Init { + public: + Init() { + SSL_load_error_strings(); + ERR_load_BIO_strings(); + OpenSSL_add_all_algorithms(); + } + }; + + //============================================================================ + class X509 { + public: + //! Construct empty certificate. + X509(): _x509(X509_new()) { + if (!_x509) throw allocation_failed(); + } + X509(const X509& o) _x509(0) { + char* d(0); + int len(i2d_X509(o._x509, &d)); + if (!len) throw x509_copy_failed(); + char* d1(d); + _x509 = d2i_X509(0, &d2, len); + if (d2!=d+len || !_x509) throw x509_copy_failed(); + } + //! Take over OpenSSL allocated certificate. + X509(::X509 *x509): _x509(x509) { + if (!_x509) throw undefined_certificate(); + } + ~X509() { + X509_free(_x509); + } + X509& operator=(const X509& o) { + X509_free(_x509); + _x509 = 0; + char* d(0); + int len(i2d_X509(o._x509, &d)); + if (!len) throw x509_copy_failed(); + char* d1(d); + _x509 = d2i_X509(0, &d2, len); + if (d2!=d+len || !_x509) throw x509_copy_failed(); + } + private: + ::X509* _x509; + }; + + //============================================================================ + class PrivateKey { + public: + PrivateKey(EVP_PKEY *) { + } + }; + + //============================================================================ + class PKCS12 { + + //...............................................................typedefs + public: + typedef std::vector X509List; + + //................................................................methods + public: + + //! Read from a PKCS#12 (.p12) file. + PKCS12(std::string filename, std::string password): + _key(0), _cert(0) { + FILE* file(fopen(filename.c_str(), "rb")); + if (!file) throw cannot_open_file(filename); + ::PKCS12 *p12(d2i_PKCS12_fp(file, 0)); + fclose(file); + if (!p12) throw pkcs12_reading_failed(filename); + try { + EVP_PKEY *pkey(0); + ::X509 *cert(0); + STACK_OF(X509) *ca(0); + if (!PKCS12_parse(p12, password.c_str(), &pkey, &cert, &ca)) + throw pkcs12_parsing_failed(filename); + if (pkey) _key = new PrivateKey(pkey); + if (cert) _cert = new X509(cert); + for (int i(sk_num(ca)); i>0; --i) + _ca.push_back(new X509((::X509*)sk_pop(ca))); + PKCS12_free(p12); + } catch (...) { + PKCS12_free(p12); + throw; + } + } + + ~PKCS12() { + delete _key; + delete _cert; + for (X509List::iterator it(_ca.begin()); it!=_ca.end(); ++it) + delete *it; + } + + bool hasPrivateKey() { + return _key; + } + + bool hasCert() { + return _cert; + } + + const PrivateKey& privateKey() { + if (!_key) throw pkcs12_no_private_key(); + return *_key; + }; + + const X509& x509() { + if (!_cert) throw pkcs12_no_x509(); + return *_cert; + }; + + const X509List& ca() const { + return _ca; + } + + private: + PrivateKey *_key; + X509 *_cert; + X509List _ca; + }; + + class BIO { + public: + BIO() {} + ~BIO() { + try { + close() + } catch (...) { + if (!std::uncaught_exception()) throw; + } + } + void connect(const std::string& hostPort) { + close(); + if (_bio = BIO_new_connect(hostPort.c_str())) + throw bio_connection_failed(hostPort); + } + void close() { + //! @todo tbd + } + private: + BIO* _bio; + }; + +} + +#endif