parent
4f5f81b591
commit
9164f0e76b
2 changed files with 278 additions and 1 deletions
@ -0,0 +1,277 @@ |
||||
/*! @file
|
||||
|
||||
@id $Id$ |
||||
*/ |
||||
// 1 2 3 4 5 6 7 8
|
||||
// 45678901234567890123456789012345678901234567890123456789012345678901234567890
|
||||
|
||||
#ifndef __OPENSSL_HXX__ |
||||
#define __OPENSSL_HXX__ |
||||
|
||||
#include <openssl/pkcs12.h> |
||||
#include <openssl/x509.h> |
||||
|
||||
#include "openssl/bio.h" |
||||
#include "openssl/ssl.h" |
||||
#include <openssl/err.h> |
||||
#include <cstdio> |
||||
|
||||
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<X509*> 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 |
Loading…
Reference in new issue