This library provides a simple and nice C++ wrapper around these libraries, so that programmers can concentrate on functionality. It offers general support for PCSC-lite, OpenSSL, PKCS#11, plus specific functionality for the SuisseID.
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

278 lines
8.0 KiB

/*! @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