/*! @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 /*! @defgroup gopenssl C++ Wrapper around OpenSSL API */ //@{ //! @defgroup openssllib OpenSSL C++ Library //! @defgroup opensslexceptions OpenSSL Exceptions //! @see gopenssl namespace openssl { //============================================================================ //! @addtogroup opensslexceptions //@{ //---------------------------------------------------------------------------- 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) { } }; //@} //! @addtogroup openssllib //@{ //============================================================================ 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) { unsigned char* d(0); int len(i2d_X509(o._x509, &d)); if (!len) throw x509_copy_failed(); const unsigned char* d2(d); _x509 = d2i_X509(0, &d2, len); free(d); if (!_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; unsigned char* d(0); int len(i2d_X509(o._x509, &d)); if (!len) throw x509_copy_failed(); const unsigned char* d2(d); free(d); _x509 = d2i_X509(0, &d2, len); if (!_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(const_cast(hostPort.c_str()))) throw bio_connection_failed(hostPort); // ... } void close() { //! @todo tbd } private: ::BIO* _bio; }; //@} } //@} #endif