2009-09-17 14:57:22 +00:00
|
|
|
/*! @file
|
|
|
|
|
|
|
|
@id $Id$
|
|
|
|
*/
|
|
|
|
// 1 2 3 4 5 6 7 8
|
|
|
|
// 45678901234567890123456789012345678901234567890123456789012345678901234567890
|
|
|
|
|
|
|
|
#ifndef __OPENSSL_HXX__
|
|
|
|
#define __OPENSSL_HXX__
|
|
|
|
|
|
|
|
#include <openssl/pkcs12.h>
|
2009-10-26 12:40:28 +00:00
|
|
|
#include <openssl/pkcs7.h>
|
2009-09-17 14:57:22 +00:00
|
|
|
#include <openssl/x509.h>
|
|
|
|
#include "openssl/bio.h"
|
2009-10-14 13:31:27 +00:00
|
|
|
#include "openssl/des.h"
|
2011-09-08 08:56:56 +00:00
|
|
|
#ifdef DATADIR // DATADIR is defined in autoconf/automake
|
|
|
|
#undef DATADIR // but DATADIR is also a variablename in ssl.h
|
|
|
|
#endif
|
2009-09-17 14:57:22 +00:00
|
|
|
#include "openssl/ssl.h"
|
|
|
|
#include <openssl/err.h>
|
2009-09-21 07:43:32 +00:00
|
|
|
#include <vector>
|
|
|
|
|
2010-08-27 09:43:20 +00:00
|
|
|
#include <openssl/opensslv.h>
|
|
|
|
#ifndef OPENSSL_VERSION_NUMBER
|
|
|
|
# error OpenSSL Version Number not Found
|
2012-06-08 09:07:27 +00:00
|
|
|
#elif OPENSSL_VERSION_NUMBER < 0x00908000L
|
2012-06-11 06:25:05 +00:00
|
|
|
# ifdef ALLOW_SSL_OLDER_THAN_0_8
|
2013-10-10 12:23:30 +00:00
|
|
|
# warning OpenSSL older than 0.8 detected please upgrade to 1.0
|
2012-06-11 06:25:05 +00:00
|
|
|
# else
|
2013-10-10 12:23:30 +00:00
|
|
|
# error OpenSSL older than 0.8 detected please upgrade to 1.0
|
2012-06-11 06:25:05 +00:00
|
|
|
# endif
|
2012-06-08 09:38:14 +00:00
|
|
|
# define OPENSSL_0_7
|
2012-06-08 08:31:01 +00:00
|
|
|
# define V0_CONST
|
2010-08-27 12:51:15 +00:00
|
|
|
# define CV_STACK
|
|
|
|
# define CV_X509
|
2012-06-08 09:07:27 +00:00
|
|
|
#elif OPENSSL_VERSION_NUMBER < 0x10000000L
|
2012-06-11 06:25:05 +00:00
|
|
|
# ifdef ALLOW_SSL_0_8
|
2013-10-10 12:23:30 +00:00
|
|
|
# warning OpenSSL 0.8 detected please upgrade to 1.0
|
2012-06-11 06:25:05 +00:00
|
|
|
# else
|
2013-10-10 12:23:30 +00:00
|
|
|
# error OpenSSL 0.8 detected please upgrade to 1.0
|
2012-06-11 06:25:05 +00:00
|
|
|
# endif
|
2012-06-08 09:38:14 +00:00
|
|
|
# define OPENSSL_0_8
|
2012-06-08 09:07:27 +00:00
|
|
|
# define V0_CONST const
|
|
|
|
# define CV_STACK
|
|
|
|
# define CV_X509
|
2010-08-27 09:43:20 +00:00
|
|
|
#else
|
2012-06-08 09:38:14 +00:00
|
|
|
# define OPENSSL_1_0
|
2010-08-27 12:51:15 +00:00
|
|
|
# define V0_CONST const
|
|
|
|
# define CV_STACK (_STACK*)
|
|
|
|
# define CV_X509 (STACK_OF(X509)*)
|
2010-08-27 09:43:20 +00:00
|
|
|
#endif
|
|
|
|
|
2009-09-22 07:40:28 +00:00
|
|
|
#include <openssl/x509v3.h> // BASIC_CONSTRAINTS
|
2009-10-01 19:14:18 +00:00
|
|
|
#include <openssl/bn.h>
|
2009-09-21 07:43:32 +00:00
|
|
|
#include <cryptaux.hxx>
|
2009-09-17 14:57:22 +00:00
|
|
|
#include <cstdio>
|
2009-10-01 19:14:18 +00:00
|
|
|
#include <cassert>
|
2009-09-17 14:57:22 +00:00
|
|
|
|
2010-08-03 13:48:47 +00:00
|
|
|
namespace pcsc {
|
|
|
|
std::string version();
|
|
|
|
}
|
|
|
|
|
2014-01-31 13:32:31 +00:00
|
|
|
/*! @defgroup gopenssl C++ Wrapper around OpenSSL API
|
|
|
|
Support for SSL-connections, engines, keys and certificates. */
|
2009-09-18 11:41:30 +00:00
|
|
|
//@{
|
|
|
|
//! @defgroup openssllib OpenSSL C++ Library
|
|
|
|
//! @defgroup opensslexceptions OpenSSL Exceptions
|
|
|
|
|
2014-01-31 13:32:31 +00:00
|
|
|
//! @ref gopenssl @copydoc gpcsc
|
2009-09-17 14:57:22 +00:00
|
|
|
namespace openssl {
|
|
|
|
|
|
|
|
//============================================================================
|
2009-09-18 11:41:30 +00:00
|
|
|
//! @addtogroup opensslexceptions
|
|
|
|
//@{
|
|
|
|
|
|
|
|
//----------------------------------------------------------------------------
|
2009-09-17 14:57:22 +00:00
|
|
|
class exception: public std::exception {
|
|
|
|
public:
|
|
|
|
exception(const std::string& reason) throw():
|
|
|
|
_what("openssl: "+reason) {
|
2013-11-06 12:24:52 +00:00
|
|
|
CRYPTOLOG("**** exception ****");
|
2009-09-17 14:57:22 +00:00
|
|
|
}
|
|
|
|
~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():
|
2013-11-06 12:24:52 +00:00
|
|
|
exception(reason+' '+ERR_error_string(ERR_get_error(), 0)) {
|
|
|
|
CRYPTOLOG("**** exception ****");
|
2010-03-03 15:37:44 +00:00
|
|
|
}
|
|
|
|
};
|
|
|
|
//----------------------------------------------------------------------------
|
|
|
|
class cannot_init: public openssl_error {
|
|
|
|
public:
|
|
|
|
cannot_init(const std::string& reason) throw():
|
|
|
|
openssl_error("openssl initialization: "+reason) {
|
2013-11-06 12:24:52 +00:00
|
|
|
CRYPTOLOG("**** exception ****");
|
2009-09-17 14:57:22 +00:00
|
|
|
}
|
|
|
|
};
|
|
|
|
//----------------------------------------------------------------------------
|
2009-10-14 13:31:27 +00:00
|
|
|
class encryption_error: public openssl_error {
|
|
|
|
public:
|
|
|
|
encryption_error(const std::string& reason) throw():
|
|
|
|
openssl_error("encryption: "+reason) {
|
2013-11-06 12:24:52 +00:00
|
|
|
CRYPTOLOG("**** exception ****");
|
2009-10-14 13:31:27 +00:00
|
|
|
}
|
|
|
|
};
|
|
|
|
//----------------------------------------------------------------------------
|
2009-09-17 14:57:22 +00:00
|
|
|
class pkcs12_error: public openssl_error {
|
|
|
|
public:
|
|
|
|
pkcs12_error(const std::string& reason) throw():
|
|
|
|
openssl_error("pkcs12: "+reason) {
|
2013-11-06 12:24:52 +00:00
|
|
|
CRYPTOLOG("**** exception ****");
|
2009-09-17 14:57:22 +00:00
|
|
|
}
|
|
|
|
};
|
|
|
|
//----------------------------------------------------------------------------
|
2009-10-26 12:40:28 +00:00
|
|
|
class pkcs7_error: public openssl_error {
|
|
|
|
public:
|
|
|
|
pkcs7_error(const std::string& reason) throw():
|
|
|
|
openssl_error("pkcs7: "+reason) {
|
2013-11-06 12:24:52 +00:00
|
|
|
CRYPTOLOG("**** exception ****");
|
2009-10-26 12:40:28 +00:00
|
|
|
}
|
|
|
|
};
|
|
|
|
//----------------------------------------------------------------------------
|
2009-09-17 14:57:22 +00:00
|
|
|
class x509_error: public openssl_error {
|
|
|
|
public:
|
|
|
|
x509_error(const std::string& reason) throw():
|
|
|
|
openssl_error("x509: "+reason) {
|
2013-11-06 12:24:52 +00:00
|
|
|
CRYPTOLOG("**** exception ****");
|
2009-09-17 14:57:22 +00:00
|
|
|
}
|
|
|
|
};
|
|
|
|
//----------------------------------------------------------------------------
|
2009-10-01 19:14:18 +00:00
|
|
|
class key_error: public openssl_error {
|
|
|
|
public:
|
|
|
|
key_error(const std::string& reason) throw():
|
|
|
|
openssl_error("private key: "+reason) {
|
2013-11-06 12:24:52 +00:00
|
|
|
CRYPTOLOG("**** exception ****");
|
2009-10-01 19:14:18 +00:00
|
|
|
}
|
|
|
|
};
|
|
|
|
//----------------------------------------------------------------------------
|
2010-03-03 15:37:44 +00:00
|
|
|
class tcp_error: public openssl_error {
|
2009-09-17 14:57:22 +00:00
|
|
|
public:
|
2010-03-03 15:37:44 +00:00
|
|
|
tcp_error(const std::string& reason) throw():
|
|
|
|
openssl_error("tcp "+reason) {
|
2013-11-06 12:24:52 +00:00
|
|
|
CRYPTOLOG("**** exception ****");
|
2009-09-17 14:57:22 +00:00
|
|
|
}
|
|
|
|
};
|
|
|
|
//----------------------------------------------------------------------------
|
2009-09-18 13:31:00 +00:00
|
|
|
class ssl_error: public openssl_error {
|
|
|
|
public:
|
|
|
|
ssl_error(const std::string& reason) throw():
|
|
|
|
openssl_error("ssl: "+reason) {
|
2013-11-06 12:24:52 +00:00
|
|
|
CRYPTOLOG("**** exception ****");
|
2009-09-18 13:31:00 +00:00
|
|
|
}
|
|
|
|
};
|
|
|
|
//----------------------------------------------------------------------------
|
2009-10-14 13:31:27 +00:00
|
|
|
class cannot_encrypt: public encryption_error {
|
|
|
|
public:
|
|
|
|
cannot_encrypt(std::string reason) throw():
|
|
|
|
encryption_error("cannot encrypt text: "+reason) {
|
2013-11-06 12:24:52 +00:00
|
|
|
CRYPTOLOG("**** exception ****");
|
2009-10-14 13:31:27 +00:00
|
|
|
}
|
|
|
|
};
|
|
|
|
//----------------------------------------------------------------------------
|
2009-09-17 14:57:22 +00:00
|
|
|
class allocation_failed: public x509_error {
|
|
|
|
public:
|
|
|
|
allocation_failed() throw():
|
|
|
|
x509_error("memory allocation failed") {
|
2013-11-06 12:24:52 +00:00
|
|
|
CRYPTOLOG("**** exception ****");
|
2009-09-17 14:57:22 +00:00
|
|
|
}
|
|
|
|
};
|
|
|
|
//----------------------------------------------------------------------------
|
2009-09-21 07:43:32 +00:00
|
|
|
class x509_decoding_failed: public x509_error {
|
|
|
|
public:
|
|
|
|
x509_decoding_failed(const std::string& der) throw():
|
2013-11-06 12:24:52 +00:00
|
|
|
x509_error("certificate decoding failed: "+crypto::readable(der)) {
|
|
|
|
CRYPTOLOG("**** exception ****");
|
2009-09-21 07:43:32 +00:00
|
|
|
}
|
|
|
|
};
|
|
|
|
//----------------------------------------------------------------------------
|
2009-09-17 14:57:22 +00:00
|
|
|
class undefined_certificate: public x509_error {
|
|
|
|
public:
|
|
|
|
undefined_certificate() throw():
|
|
|
|
x509_error("certificate must not be 0") {
|
2013-11-06 12:24:52 +00:00
|
|
|
CRYPTOLOG("**** exception ****");
|
2009-09-17 14:57:22 +00:00
|
|
|
}
|
|
|
|
};
|
|
|
|
//----------------------------------------------------------------------------
|
|
|
|
class x509_parsing_failed: public x509_error {
|
|
|
|
public:
|
|
|
|
x509_parsing_failed() throw():
|
|
|
|
x509_error("parsing DER encoded certificate failed") {
|
2013-11-06 12:24:52 +00:00
|
|
|
CRYPTOLOG("**** exception ****");
|
2009-09-17 14:57:22 +00:00
|
|
|
}
|
|
|
|
};
|
|
|
|
//----------------------------------------------------------------------------
|
|
|
|
class x509_copy_failed: public x509_error {
|
|
|
|
public:
|
|
|
|
x509_copy_failed() throw():
|
|
|
|
x509_error("certificate object copy failed") {
|
2013-11-06 12:24:52 +00:00
|
|
|
CRYPTOLOG("**** exception ****");
|
2009-09-17 14:57:22 +00:00
|
|
|
}
|
|
|
|
};
|
|
|
|
//----------------------------------------------------------------------------
|
2009-10-01 19:14:18 +00:00
|
|
|
class key_copy_failed: public key_error {
|
|
|
|
public:
|
|
|
|
key_copy_failed() throw():
|
|
|
|
key_error("key object copy failed") {
|
2013-11-06 12:24:52 +00:00
|
|
|
CRYPTOLOG("**** exception ****");
|
2009-10-01 19:14:18 +00:00
|
|
|
}
|
|
|
|
};
|
|
|
|
//----------------------------------------------------------------------------
|
|
|
|
class undefined_key: public key_error {
|
|
|
|
public:
|
|
|
|
undefined_key() throw():
|
|
|
|
key_error("private key must not be 0") {
|
2013-11-06 12:24:52 +00:00
|
|
|
CRYPTOLOG("**** exception ****");
|
2009-10-01 19:14:18 +00:00
|
|
|
}
|
|
|
|
};
|
|
|
|
//----------------------------------------------------------------------------
|
2009-09-17 14:57:22 +00:00
|
|
|
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) {
|
2013-11-06 12:24:52 +00:00
|
|
|
CRYPTOLOG("**** exception ****");
|
2009-09-17 14:57:22 +00:00
|
|
|
}
|
|
|
|
};
|
|
|
|
//----------------------------------------------------------------------------
|
|
|
|
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) {
|
2013-11-06 12:24:52 +00:00
|
|
|
CRYPTOLOG("**** exception ****");
|
2009-09-17 14:57:22 +00:00
|
|
|
}
|
|
|
|
};
|
|
|
|
//----------------------------------------------------------------------------
|
|
|
|
class pkcs12_no_private_key: public pkcs12_error {
|
|
|
|
public:
|
2010-03-03 15:37:44 +00:00
|
|
|
pkcs12_no_private_key() throw(): pkcs12_error("no private key") {
|
2013-11-06 12:24:52 +00:00
|
|
|
CRYPTOLOG("**** exception ****");
|
2010-03-03 15:37:44 +00:00
|
|
|
}
|
2009-09-17 14:57:22 +00:00
|
|
|
};
|
|
|
|
//----------------------------------------------------------------------------
|
|
|
|
class pkcs12_no_x509: public pkcs12_error {
|
|
|
|
public:
|
2010-03-03 15:37:44 +00:00
|
|
|
pkcs12_no_x509() throw(): pkcs12_error("no x509 certificate") {
|
2013-11-06 12:24:52 +00:00
|
|
|
CRYPTOLOG("**** exception ****");
|
2010-03-03 15:37:44 +00:00
|
|
|
}
|
2009-09-17 14:57:22 +00:00
|
|
|
};
|
|
|
|
//----------------------------------------------------------------------------
|
2009-10-26 12:40:28 +00:00
|
|
|
class pkcs7_reading_failed: public pkcs7_error {
|
|
|
|
public:
|
|
|
|
pkcs7_reading_failed(const std::string& file) throw():
|
|
|
|
pkcs7_error("reading DER encoded p7 file failed: "+file) {
|
2013-11-06 12:24:52 +00:00
|
|
|
CRYPTOLOG("**** exception ****");
|
2009-10-26 12:40:28 +00:00
|
|
|
}
|
|
|
|
};
|
|
|
|
//----------------------------------------------------------------------------
|
|
|
|
class pkcs7_parsing_failed: public pkcs7_error {
|
|
|
|
public:
|
|
|
|
pkcs7_parsing_failed() throw():
|
|
|
|
pkcs7_error("parsing DER encoded p7 failed") {
|
2013-11-06 12:24:52 +00:00
|
|
|
CRYPTOLOG("**** exception ****");
|
2009-10-26 12:40:28 +00:00
|
|
|
}
|
|
|
|
pkcs7_parsing_failed(const std::string& file) throw():
|
|
|
|
pkcs7_error("parsing DER encoded p7 file failed: "+file) {
|
|
|
|
}
|
|
|
|
};
|
|
|
|
//----------------------------------------------------------------------------
|
|
|
|
class pkcs7_unsupported_format: public pkcs7_error {
|
|
|
|
public:
|
2010-03-03 15:37:44 +00:00
|
|
|
pkcs7_unsupported_format() throw(): pkcs7_error("format not supported") {
|
2013-11-06 12:24:52 +00:00
|
|
|
CRYPTOLOG("**** exception ****");
|
2010-03-03 15:37:44 +00:00
|
|
|
}
|
2009-10-26 12:40:28 +00:00
|
|
|
};
|
|
|
|
//----------------------------------------------------------------------------
|
|
|
|
class pkcs7_no_x509: public pkcs7_error {
|
|
|
|
public:
|
2010-03-03 15:37:44 +00:00
|
|
|
pkcs7_no_x509() throw(): pkcs7_error("no x509 certificate") {
|
2013-11-06 12:24:52 +00:00
|
|
|
CRYPTOLOG("**** exception ****");
|
2010-03-03 15:37:44 +00:00
|
|
|
}
|
2009-10-26 12:40:28 +00:00
|
|
|
};
|
|
|
|
//----------------------------------------------------------------------------
|
2009-09-17 14:57:22 +00:00
|
|
|
class cannot_open_file: public exception {
|
|
|
|
public:
|
|
|
|
cannot_open_file(const std::string& file) throw():
|
|
|
|
exception("cannot open file: "+file) {
|
2013-11-06 12:24:52 +00:00
|
|
|
CRYPTOLOG("**** exception ****");
|
2010-03-03 15:37:44 +00:00
|
|
|
}
|
|
|
|
};
|
|
|
|
//----------------------------------------------------------------------------
|
|
|
|
class tcp_connection_failed: public tcp_error {
|
|
|
|
public:
|
|
|
|
tcp_connection_failed(const std::string& hostPort) throw():
|
|
|
|
tcp_error("connection failed to: "+hostPort) {
|
2013-11-06 12:24:52 +00:00
|
|
|
CRYPTOLOG("**** exception ****");
|
2009-09-17 14:57:22 +00:00
|
|
|
}
|
|
|
|
};
|
|
|
|
//----------------------------------------------------------------------------
|
2010-03-03 15:37:44 +00:00
|
|
|
class tcp_server_not_specified: public tcp_error {
|
2009-09-17 14:57:22 +00:00
|
|
|
public:
|
2010-03-03 15:37:44 +00:00
|
|
|
tcp_server_not_specified() throw():
|
|
|
|
tcp_error("reconnect without prior connect") {
|
2013-11-06 12:24:52 +00:00
|
|
|
CRYPTOLOG("**** exception ****");
|
2009-09-17 14:57:22 +00:00
|
|
|
}
|
|
|
|
};
|
2009-09-18 13:31:00 +00:00
|
|
|
//----------------------------------------------------------------------------
|
2010-03-03 15:37:44 +00:00
|
|
|
class tcp_closed_connection: public tcp_error {
|
2009-09-18 13:31:00 +00:00
|
|
|
public:
|
2010-03-03 15:37:44 +00:00
|
|
|
tcp_closed_connection() throw(): tcp_error("closed connection") {
|
2013-11-06 12:24:52 +00:00
|
|
|
CRYPTOLOG("**** exception ****");
|
2010-03-03 15:37:44 +00:00
|
|
|
}
|
2009-09-18 13:31:00 +00:00
|
|
|
};
|
|
|
|
//----------------------------------------------------------------------------
|
2010-03-03 15:37:44 +00:00
|
|
|
class tcp_read_error: public tcp_error {
|
2009-09-18 13:31:00 +00:00
|
|
|
public:
|
2010-03-03 15:37:44 +00:00
|
|
|
tcp_read_error() throw(): tcp_error("read error") {
|
2013-11-06 12:24:52 +00:00
|
|
|
CRYPTOLOG("**** exception ****");
|
2010-03-03 15:37:44 +00:00
|
|
|
}
|
2009-09-18 13:31:00 +00:00
|
|
|
};
|
|
|
|
//----------------------------------------------------------------------------
|
2010-03-03 15:37:44 +00:00
|
|
|
class tcp_write_error: public tcp_error {
|
2009-09-18 13:31:00 +00:00
|
|
|
public:
|
2010-03-03 15:37:44 +00:00
|
|
|
tcp_write_error() throw(): tcp_error("write error") {
|
2013-11-06 12:24:52 +00:00
|
|
|
CRYPTOLOG("**** exception ****");
|
2010-03-03 15:37:44 +00:00
|
|
|
}
|
2009-09-18 13:31:00 +00:00
|
|
|
};
|
|
|
|
//----------------------------------------------------------------------------
|
|
|
|
class ssl_cannot_create_context: public ssl_error {
|
|
|
|
public:
|
2010-03-03 15:37:44 +00:00
|
|
|
ssl_cannot_create_context() throw(): ssl_error("cannot create context") {
|
2013-11-06 12:24:52 +00:00
|
|
|
CRYPTOLOG("**** exception ****");
|
2010-03-03 15:37:44 +00:00
|
|
|
}
|
2009-09-18 13:31:00 +00:00
|
|
|
};
|
|
|
|
//----------------------------------------------------------------------------
|
|
|
|
class ssl_certificate_file_not_loaded: public ssl_error {
|
|
|
|
public:
|
|
|
|
ssl_certificate_file_not_loaded(const std::string& file) throw():
|
|
|
|
ssl_error("certificate file not loaded: "+file) {
|
2013-11-06 12:24:52 +00:00
|
|
|
CRYPTOLOG("**** exception ****");
|
2009-09-18 13:31:00 +00:00
|
|
|
}
|
|
|
|
};
|
|
|
|
//----------------------------------------------------------------------------
|
|
|
|
class ssl_certificate_folder_not_loaded: public ssl_error {
|
|
|
|
public:
|
|
|
|
ssl_certificate_folder_not_loaded(const std::string& path) throw():
|
|
|
|
ssl_error("certificate folder not loaded: "+path) {
|
2013-11-06 12:24:52 +00:00
|
|
|
CRYPTOLOG("**** exception ****");
|
2010-03-03 15:37:44 +00:00
|
|
|
}
|
|
|
|
};
|
|
|
|
//----------------------------------------------------------------------------
|
|
|
|
class ssl_no_connection: public ssl_error {
|
|
|
|
public:
|
|
|
|
ssl_no_connection() throw():
|
|
|
|
ssl_error("no ssl connection") {
|
2013-11-06 12:24:52 +00:00
|
|
|
CRYPTOLOG("**** exception ****");
|
2010-03-03 15:37:44 +00:00
|
|
|
}
|
|
|
|
};
|
|
|
|
//----------------------------------------------------------------------------
|
|
|
|
class ssl_verification_failed: public ssl_error {
|
|
|
|
public:
|
|
|
|
ssl_verification_failed(int num) throw():
|
|
|
|
ssl_error("certificate verification failed: "+reason(num)) {
|
2013-11-06 12:24:52 +00:00
|
|
|
CRYPTOLOG("**** exception ****");
|
2010-03-03 15:37:44 +00:00
|
|
|
}
|
|
|
|
static std::string reason(int num) {
|
|
|
|
switch (num) {
|
|
|
|
case X509_V_OK:
|
|
|
|
return "X509_V_OK: Ok the operation was successful.";
|
|
|
|
case X509_V_ERR_UNABLE_TO_GET_ISSUER_CERT:
|
|
|
|
return "X509_V_ERR_UNABLE_TO_GET_ISSUER_CERT: Unable to get issuer"
|
|
|
|
" certificate the issuer certificate could not be found: this"
|
|
|
|
" occurs if the issuer certificate of an untrusted certificate"
|
|
|
|
" cannot be found.";
|
2011-09-05 08:35:05 +00:00
|
|
|
case X509_V_ERR_UNABLE_TO_GET_CRL:
|
|
|
|
return "X509_V_ERR_UNABLE_TO_GET_CRL:"
|
2010-03-03 15:37:44 +00:00
|
|
|
" unable to get certificate CRL the CRL of a certificate could"
|
|
|
|
" not be found. Unused.";
|
|
|
|
case X509_V_ERR_UNABLE_TO_DECRYPT_CERT_SIGNATURE:
|
|
|
|
return "4 X509_V_ERR_UNABLE_TO_DECRYPT_CERT_SIGNATURE: Unable to"
|
|
|
|
" decrypt certificate's signature the certificate signature"
|
|
|
|
" could not be decrypted. This means that the actual signature"
|
|
|
|
" value could not be determined rather than it not matching the"
|
|
|
|
" expected value, this is only meaningful for RSA keys.";
|
|
|
|
case X509_V_ERR_UNABLE_TO_DECODE_ISSUER_PUBLIC_KEY:
|
|
|
|
return "X509_V_ERR_UNABLE_TO_DECODE_ISSUER_PUBLIC_KEY: Unable to"
|
|
|
|
" decode issuer public key the public key in the certificate"
|
|
|
|
" SubjectPublicKeyInfo could not be read.";
|
|
|
|
case X509_V_ERR_CERT_SIGNATURE_FAILURE:
|
|
|
|
return "X509_V_ERR_CERT_SIGNATURE_FAILURE: Certificate signature"
|
|
|
|
" failure the signature of the certificate is invalid.";
|
|
|
|
case X509_V_ERR_CRL_SIGNATURE_FAILURE:
|
|
|
|
return "X509_V_ERR_CRL_SIGNATURE_FAILURE: Crl signature failure"
|
|
|
|
" the signature of the certificate is invalid. Unused.";
|
|
|
|
case X509_V_ERR_CERT_NOT_YET_VALID:
|
|
|
|
return "X509_V_ERR_CERT_NOT_YET_VALID: Certificate is not yet"
|
|
|
|
" valid the certificate is not yet valid: the notBefore date is"
|
|
|
|
" after the current time.";
|
|
|
|
case X509_V_ERR_CERT_HAS_EXPIRED:
|
|
|
|
return "X509_V_ERR_CERT_HAS_EXPIRED: Certificate has expired the"
|
|
|
|
" certificate has expired: that is the notAfter date is before"
|
|
|
|
" the current time.";
|
|
|
|
case X509_V_ERR_CRL_NOT_YET_VALID:
|
|
|
|
return "X509_V_ERR_CRL_NOT_YET_VALID: Crl is not yet valid the CRL"
|
|
|
|
" is not yet valid. Unused.";
|
|
|
|
case X509_V_ERR_CRL_HAS_EXPIRED:
|
|
|
|
return "X509_V_ERR_CRL_HAS_EXPIRED: Crl has expired the CRL has"
|
|
|
|
" expired. Unused.";
|
|
|
|
case X509_V_ERR_ERROR_IN_CERT_NOT_BEFORE_FIELD:
|
|
|
|
return "X509_V_ERR_ERROR_IN_CERT_NOT_BEFORE_FIELD: Format error in"
|
|
|
|
" certificate's notBefore field the certificate notBefore field"
|
|
|
|
" contains an invalid time.";
|
|
|
|
case X509_V_ERR_ERROR_IN_CERT_NOT_AFTER_FIELD:
|
|
|
|
return "X509_V_ERR_ERROR_IN_CERT_NOT_AFTER_FIELD: Format error in"
|
|
|
|
" certificate's notAfter field the certificate notAfter field"
|
|
|
|
" contains an invalid time.";
|
|
|
|
case X509_V_ERR_ERROR_IN_CRL_LAST_UPDATE_FIELD:
|
|
|
|
return "X509_V_ERR_ERROR_IN_CRL_LAST_UPDATE_FIELD: Format error in"
|
|
|
|
" CRL's lastUpdate field the CRL lastUpdate field contains an"
|
|
|
|
" invalid time. Unused.";
|
|
|
|
case X509_V_ERR_OUT_OF_MEM:
|
|
|
|
return "X509_V_ERR_OUT_OF_MEM: Out of memory an error occurred"
|
|
|
|
" trying to allocate memory. This should never happen.";
|
|
|
|
case X509_V_ERR_DEPTH_ZERO_SELF_SIGNED_CERT:
|
|
|
|
return "X509_V_ERR_DEPTH_ZERO_SELF_SIGNED_CERT: Self signed"
|
|
|
|
" certificate the passed certificate is self signed and the same"
|
|
|
|
" certificate cannot be found in the list of trusted"
|
|
|
|
" certificates.";
|
|
|
|
case X509_V_ERR_SELF_SIGNED_CERT_IN_CHAIN:
|
|
|
|
return "X509_V_ERR_SELF_SIGNED_CERT_IN_CHAIN: Self signed"
|
|
|
|
" certificate in certificate chain the certificate chain could"
|
|
|
|
" be built up using the untrusted certificates but the root"
|
|
|
|
" could not be found locally.";
|
|
|
|
case X509_V_ERR_UNABLE_TO_GET_ISSUER_CERT_LOCALLY:
|
|
|
|
return "X509_V_ERR_UNABLE_TO_GET_ISSUER_CERT_LOCALLY: Unable to"
|
|
|
|
" get local issuer certificate the issuer certificate of a"
|
|
|
|
" locally looked up certificate could not be found. This"
|
|
|
|
" normally means the list of trusted certificates is not"
|
|
|
|
" complete.";
|
|
|
|
case X509_V_ERR_UNABLE_TO_VERIFY_LEAF_SIGNATURE:
|
|
|
|
return "X509_V_ERR_UNABLE_TO_VERIFY_LEAF_SIGNATURE: Unable to"
|
|
|
|
" verify the first certificate no signatures could be verified"
|
|
|
|
" because the chain contains only one certificate and it is not"
|
|
|
|
" self signed.";
|
|
|
|
case X509_V_ERR_CERT_CHAIN_TOO_LONG:
|
|
|
|
return "X509_V_ERR_CERT_CHAIN_TOO_LONG: Certificate chain too long"
|
|
|
|
" the certificate chain length is greater than the supplied"
|
|
|
|
" maximum depth. Unused.";
|
|
|
|
case X509_V_ERR_CERT_REVOKED:
|
|
|
|
return "X509_V_ERR_CERT_REVOKED: Certificate revoked the"
|
|
|
|
" certificate has been revoked. Unused.";
|
|
|
|
case X509_V_ERR_INVALID_CA:
|
|
|
|
return "X509_V_ERR_INVALID_CA: Invalid CA certificate a CA"
|
|
|
|
" certificate is invalid. Either it is not a CA or its"
|
|
|
|
" extensions are not consistent with the supplied purpose.";
|
|
|
|
case X509_V_ERR_INVALID_PURPOSE:
|
|
|
|
return "X509_V_ERR_INVALID_PURPOSE: Unsupported certificate"
|
|
|
|
" purpose the supplied certificate cannot be used for the"
|
|
|
|
" specified purpose.";
|
|
|
|
case X509_V_ERR_CERT_UNTRUSTED:
|
|
|
|
return "X509_V_ERR_CERT_UNTRUSTED: Certificate not trusted the"
|
|
|
|
" root CA is not marked as trusted for the specified purpose.";
|
|
|
|
case X509_V_ERR_CERT_REJECTED:
|
|
|
|
return "X509_V_ERR_CERT_REJECTED: Certificate rejected the root CA"
|
|
|
|
" is marked to reject the specified purpose.";
|
|
|
|
case X509_V_ERR_SUBJECT_ISSUER_MISMATCH:
|
|
|
|
return "X509_V_ERR_SUBJECT_ISSUER_MISMATCH: Subject issuer"
|
|
|
|
" mismatch the current candidate issuer certificate was rejected"
|
|
|
|
" because its subject name did not match the issuer name of the"
|
|
|
|
" current certificate. Only displayed when the -issuer_checks"
|
|
|
|
" option is set.";
|
|
|
|
case X509_V_ERR_AKID_SKID_MISMATCH:
|
|
|
|
return "X509_V_ERR_AKID_SKID_MISMATCH: Authority and subject key"
|
|
|
|
" identifier mismatch the current candidate issuer certificate"
|
|
|
|
" was rejected because its subject key identifier was present"
|
|
|
|
" and did not match the authority key identifier current"
|
|
|
|
" certificate. Only displayed when the -issuer_checks option is"
|
|
|
|
" set.";
|
|
|
|
case X509_V_ERR_AKID_ISSUER_SERIAL_MISMATCH:
|
|
|
|
return "X509_V_ERR_AKID_ISSUER_SERIAL_MISMATCH: Authority and"
|
|
|
|
" issuer serial number mismatch the current candidate issuer"
|
|
|
|
" certificate was rejected because its issuer name and serial"
|
|
|
|
" number was present and did not match the authority key"
|
|
|
|
" identifier of the current certificate. Only displayed when the"
|
|
|
|
" -issuer_checks option is set.";
|
|
|
|
case X509_V_ERR_KEYUSAGE_NO_CERTSIGN:
|
|
|
|
return "X509_V_ERR_KEYUSAGE_NO_CERTSIGN: Ey usage does not include"
|
|
|
|
" certificate signing the current candidate issuer certificate"
|
|
|
|
" was rejected because its keyUsage extension does not permit"
|
|
|
|
" certificate signing.";
|
|
|
|
default: {
|
|
|
|
std::stringstream ss;
|
|
|
|
ss<<"Unknown certificate validation error code: "<<num;
|
|
|
|
return ss.str();
|
|
|
|
}
|
|
|
|
}
|
2009-09-18 13:31:00 +00:00
|
|
|
}
|
|
|
|
};
|
2009-09-18 11:41:30 +00:00
|
|
|
//@}
|
|
|
|
|
|
|
|
//! @addtogroup openssllib
|
|
|
|
//@{
|
2009-09-17 14:57:22 +00:00
|
|
|
|
|
|
|
//============================================================================
|
2010-03-03 15:37:44 +00:00
|
|
|
//! Initializes OpenSSL. Must be instanciated exactly once.
|
2009-09-17 14:57:22 +00:00
|
|
|
class Init {
|
|
|
|
public:
|
|
|
|
Init() {
|
2013-11-06 12:24:52 +00:00
|
|
|
CRYPTOLOG("log");
|
2009-09-17 14:57:22 +00:00
|
|
|
SSL_load_error_strings();
|
|
|
|
ERR_load_BIO_strings();
|
|
|
|
OpenSSL_add_all_algorithms();
|
2010-03-03 15:37:44 +00:00
|
|
|
if (!SSL_library_init()) throw cannot_init("cannot init SSL library");
|
2009-09-17 14:57:22 +00:00
|
|
|
}
|
|
|
|
};
|
|
|
|
|
2011-04-21 06:30:51 +00:00
|
|
|
//! Bignumber operations
|
|
|
|
class BigNum {
|
|
|
|
public:
|
|
|
|
BigNum():
|
|
|
|
_bn(BN_new()) {
|
2013-11-06 12:24:52 +00:00
|
|
|
CRYPTOLOG("log");
|
2011-04-21 06:30:51 +00:00
|
|
|
}
|
|
|
|
BigNum(const std::string& num):
|
|
|
|
_bn(BN_bin2bn((const unsigned char*)num.data(), num.size(), 0)) {
|
2013-11-06 12:24:52 +00:00
|
|
|
CRYPTOLOG("log");
|
2011-04-21 06:30:51 +00:00
|
|
|
}
|
|
|
|
~BigNum() {
|
2013-11-06 12:24:52 +00:00
|
|
|
CRYPTOLOG("log");
|
2011-04-21 06:30:51 +00:00
|
|
|
BN_free(_bn);
|
|
|
|
}
|
|
|
|
int size() const {
|
2013-11-06 12:24:52 +00:00
|
|
|
CRYPTOLOG("log");
|
2011-04-21 06:30:51 +00:00
|
|
|
return size(_bn);
|
|
|
|
}
|
|
|
|
static int size(BIGNUM* n) {
|
2013-11-06 12:24:52 +00:00
|
|
|
CRYPTOLOG("log");
|
2011-04-21 06:30:51 +00:00
|
|
|
return BN_num_bytes(n);
|
|
|
|
}
|
|
|
|
std::string string() const {
|
2013-11-06 12:24:52 +00:00
|
|
|
CRYPTOLOG("log");
|
2011-04-21 06:30:51 +00:00
|
|
|
return string(_bn);
|
|
|
|
}
|
|
|
|
static std::string string(BIGNUM* a) {
|
2013-11-06 12:24:52 +00:00
|
|
|
CRYPTOLOG("log");
|
2011-04-21 06:30:51 +00:00
|
|
|
std::string res(BN_num_bytes(a), '0');
|
|
|
|
BN_bn2bin(a, (unsigned char*)res.begin().operator->());
|
|
|
|
return res;
|
|
|
|
}
|
|
|
|
private:
|
|
|
|
BigNum(const BigNum& o);
|
|
|
|
BigNum& operator=(const BigNum& o);
|
|
|
|
private:
|
|
|
|
BIGNUM* _bn;
|
|
|
|
};
|
|
|
|
|
2009-10-14 13:31:27 +00:00
|
|
|
class CBlock8 {
|
|
|
|
public:
|
|
|
|
CBlock8() {
|
|
|
|
_cb[0] = _cb[1] = _cb[2] = _cb[3] =
|
|
|
|
_cb[4] = _cb[5] = _cb[6] = _cb[7] = 0;
|
|
|
|
}
|
|
|
|
CBlock8(unsigned char c1, unsigned char c2, unsigned char c3,
|
|
|
|
unsigned char c4, unsigned char c5, unsigned char c6,
|
|
|
|
unsigned char c7, unsigned char c8) {
|
|
|
|
_cb[0] = c1;
|
|
|
|
_cb[1] = c2;
|
|
|
|
_cb[2] = c3;
|
|
|
|
_cb[3] = c4;
|
|
|
|
_cb[4] = c5;
|
|
|
|
_cb[5] = c6;
|
|
|
|
_cb[6] = c7;
|
|
|
|
_cb[7] = c8;
|
|
|
|
}
|
|
|
|
//! String must contain exactly 8 char.
|
|
|
|
CBlock8(const std::string& s) {
|
|
|
|
assert(s.size()==8);
|
|
|
|
_cb[0] = s[0];
|
|
|
|
_cb[1] = s[1];
|
|
|
|
_cb[2] = s[3];
|
|
|
|
_cb[3] = s[4];
|
|
|
|
_cb[4] = s[5];
|
|
|
|
_cb[5] = s[6];
|
|
|
|
_cb[6] = s[7];
|
|
|
|
_cb[7] = s[8];
|
|
|
|
}
|
|
|
|
operator DES_cblock&() {
|
|
|
|
return _cb;
|
|
|
|
}
|
|
|
|
operator DES_cblock*() {
|
|
|
|
return &_cb;
|
|
|
|
}
|
|
|
|
operator std::string() const {
|
|
|
|
return std::string((char*)_cb, 8);
|
|
|
|
}
|
|
|
|
private:
|
|
|
|
DES_cblock _cb;
|
|
|
|
};
|
|
|
|
|
2010-03-03 15:37:44 +00:00
|
|
|
//! Encrypt a string using DES.
|
|
|
|
/*! @param txt text to encrypt - size must be a multiple of 8
|
|
|
|
@param key1 DES key for encryption */
|
|
|
|
inline std::string desEnc(const std::string& txt, CBlock8 key1) {
|
2013-11-06 12:24:52 +00:00
|
|
|
CRYPTOLOG("log");
|
2010-03-03 15:37:44 +00:00
|
|
|
std::string res(txt);
|
|
|
|
if (txt.size()%8!=0)
|
|
|
|
throw cannot_encrypt("text size must be a multiple of eight");
|
|
|
|
DES_key_schedule ks1;
|
|
|
|
DES_set_key_unchecked(key1, &ks1);
|
|
|
|
for (std::string::size_type pos(0); pos<txt.size(); pos+=8) {
|
|
|
|
union {
|
|
|
|
DES_cblock array;
|
|
|
|
const char* text;
|
|
|
|
} in, out;
|
|
|
|
in.text = txt.begin().operator->()+pos;
|
|
|
|
out.text = res.begin().operator->()+pos;
|
|
|
|
DES_ecb_encrypt(&in.array, &out.array, &ks1, DES_ENCRYPT);
|
|
|
|
}
|
|
|
|
return res;
|
|
|
|
}
|
|
|
|
|
|
|
|
//! Decrypt a DES encrypted string.
|
|
|
|
/*! @param txt text to decrypt - size must be a multiple of 8
|
|
|
|
@param key1 DES key for decryption */
|
|
|
|
inline std::string desDec(const std::string& txt, CBlock8 key1) {
|
2013-11-06 12:24:52 +00:00
|
|
|
CRYPTOLOG("log");
|
2010-03-03 15:37:44 +00:00
|
|
|
std::string res(txt);
|
|
|
|
if (txt.size()%8!=0)
|
|
|
|
throw cannot_encrypt("text size must be a multiple of eight");
|
|
|
|
DES_key_schedule ks1;
|
|
|
|
DES_set_key_unchecked(key1, &ks1);
|
|
|
|
for (std::string::size_type pos(0); pos<txt.size(); pos+=8) {
|
|
|
|
union {
|
|
|
|
DES_cblock array;
|
|
|
|
const char* text;
|
|
|
|
} in, out;
|
|
|
|
in.text = txt.begin().operator->()+pos;
|
|
|
|
out.text = res.begin().operator->()+pos;
|
|
|
|
DES_ecb_encrypt(&in.array, &out.array, &ks1, DES_DECRYPT);
|
|
|
|
}
|
|
|
|
return res;
|
|
|
|
}
|
|
|
|
|
|
|
|
//! DES CBC Encryption
|
2009-10-14 13:31:27 +00:00
|
|
|
/*! @param txt If the length is not an integral multiple of eight
|
|
|
|
bytes, it is zero filled. The output is always an
|
|
|
|
integral multiple of eight bytes. */
|
|
|
|
inline std::string desCbcEnc(std::string txt, CBlock8 key, CBlock8& ivec) {
|
2013-11-06 12:24:52 +00:00
|
|
|
CRYPTOLOG("log");
|
2009-10-14 13:31:27 +00:00
|
|
|
if (txt.size()%8!=0) txt.resize((txt.size()/8+1)*8, 0);
|
|
|
|
std::string res(txt.size(), 0);
|
|
|
|
DES_key_schedule ks;
|
|
|
|
DES_set_key_unchecked(key, &ks);
|
|
|
|
DES_ncbc_encrypt((unsigned char*)&txt[0], (unsigned char*)&res[0],
|
|
|
|
txt.size(), &ks, ivec, DES_ENCRYPT);
|
|
|
|
return res;
|
|
|
|
}
|
|
|
|
|
2010-03-03 15:37:44 +00:00
|
|
|
//! DES CBC Encryption with empty vector
|
2009-10-14 13:31:27 +00:00
|
|
|
/*! @param txt If the length is not an integral multiple of eight
|
|
|
|
bytes, it is zero filled. The output is always an
|
|
|
|
integral multiple of eight bytes. */
|
|
|
|
inline std::string desCbcEnc(const std::string& txt, const CBlock8& key) {
|
2013-11-06 12:24:52 +00:00
|
|
|
CRYPTOLOG("log");
|
2009-10-14 13:31:27 +00:00
|
|
|
CBlock8 ivec;
|
|
|
|
return desCbcEnc(txt, key, ivec);
|
|
|
|
}
|
|
|
|
|
2010-03-03 15:37:44 +00:00
|
|
|
//! DES CBC Decryption
|
2009-10-14 13:31:27 +00:00
|
|
|
/*! @param txt If the length is not an integral multiple of eight
|
|
|
|
bytes, it is zero filled. The output is always an
|
|
|
|
integral multiple of eight bytes. */
|
|
|
|
inline std::string desCbcDec(std::string txt, CBlock8 key, CBlock8& ivec) {
|
2013-11-06 12:24:52 +00:00
|
|
|
CRYPTOLOG("log");
|
2009-10-14 13:31:27 +00:00
|
|
|
if (txt.size()%8!=0) txt.resize((txt.size()/8+1)*8, 0);
|
|
|
|
std::string res(txt.size(), 0);
|
|
|
|
DES_key_schedule ks;
|
|
|
|
DES_set_key_unchecked(key, &ks);
|
|
|
|
DES_ncbc_encrypt((unsigned char*)&txt[0], (unsigned char*)&res[0],
|
|
|
|
txt.size(), &ks, ivec, DES_DECRYPT);
|
|
|
|
return res;
|
|
|
|
}
|
|
|
|
|
2010-03-03 15:37:44 +00:00
|
|
|
//! DES CBC Decryption with empty vector
|
2009-10-14 13:31:27 +00:00
|
|
|
/*! @param txt If the length is not an integral multiple of eight
|
|
|
|
bytes, it is zero filled. The output is always an
|
|
|
|
integral multiple of eight bytes. */
|
|
|
|
inline std::string desCbcDec(const std::string& txt, const CBlock8& key) {
|
2013-11-06 12:24:52 +00:00
|
|
|
CRYPTOLOG("log");
|
2009-10-14 13:31:27 +00:00
|
|
|
CBlock8 ivec;
|
|
|
|
return desCbcDec(txt, key, ivec);
|
|
|
|
}
|
|
|
|
|
|
|
|
/*! @param txt If the length is not an integral multiple of eight
|
|
|
|
bytes, it is zero filled. The output is always an
|
|
|
|
integral multiple of eight bytes. */
|
|
|
|
inline std::string des2edeCbcEnc(std::string txt,
|
|
|
|
CBlock8 key1, CBlock8 key2,
|
|
|
|
CBlock8 ivec = CBlock8()) {
|
2013-11-06 12:24:52 +00:00
|
|
|
CRYPTOLOG("log");
|
2009-10-14 13:31:27 +00:00
|
|
|
if (txt.size()%8!=0) txt.resize((txt.size()/8+1)*8, 0);
|
|
|
|
std::string res(txt.size(), 0);
|
|
|
|
DES_key_schedule ks1, ks2;
|
|
|
|
DES_set_key_unchecked(key1, &ks1);
|
|
|
|
DES_set_key_unchecked(key2, &ks2);
|
|
|
|
DES_ede2_cbc_encrypt((unsigned char*)&txt[0], (unsigned char*)&res[0],
|
|
|
|
txt.size(), &ks1, &ks2, ivec, DES_ENCRYPT);
|
|
|
|
return res;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*! @param txt If the length is not an integral multiple of eight
|
|
|
|
bytes, it is zero filled. The output is always an
|
|
|
|
integral multiple of eight bytes. */
|
|
|
|
inline std::string des2edeCbcDec(std::string txt,
|
|
|
|
CBlock8 key1, CBlock8 key2,
|
|
|
|
CBlock8 ivec = CBlock8()) {
|
2013-11-06 12:24:52 +00:00
|
|
|
CRYPTOLOG("log");
|
2009-10-14 13:31:27 +00:00
|
|
|
if (txt.size()%8!=0) txt.resize((txt.size()/8+1)*8, 0);
|
|
|
|
std::string res(txt.size(), 0);
|
|
|
|
DES_key_schedule ks1, ks2;
|
|
|
|
DES_set_key_unchecked(key1, &ks1);
|
|
|
|
DES_set_key_unchecked(key2, &ks2);
|
|
|
|
DES_ede2_cbc_encrypt((unsigned char*)&txt[0], (unsigned char*)&res[0],
|
|
|
|
txt.size(), &ks1, &ks2, ivec, DES_DECRYPT);
|
|
|
|
return res;
|
|
|
|
}
|
|
|
|
|
|
|
|
//! @todo untested
|
|
|
|
inline std::string des2ecbEnc(std::string txt,
|
|
|
|
CBlock8 key1, CBlock8 key2) {
|
2013-11-06 12:24:52 +00:00
|
|
|
CRYPTOLOG("log");
|
2009-10-14 13:31:27 +00:00
|
|
|
std::string res;
|
|
|
|
if (txt.size()%8!=0)
|
|
|
|
throw cannot_encrypt("text size must be a multiple of eight");
|
|
|
|
DES_key_schedule ks1, ks2;
|
|
|
|
DES_set_key_unchecked(key1, &ks1);
|
|
|
|
DES_set_key_unchecked(key2, &ks2);
|
|
|
|
for (std::string::size_type pos(0); pos<txt.size(); pos+=8) {
|
|
|
|
CBlock8 out, in(txt.substr(pos, 8));
|
|
|
|
DES_ecb2_encrypt(in, out, &ks1, &ks2, DES_ENCRYPT);
|
|
|
|
res+=out;
|
|
|
|
}
|
|
|
|
return res;
|
|
|
|
}
|
|
|
|
|
|
|
|
//! @todo untested
|
|
|
|
inline std::string des2ecbDec(std::string txt,
|
|
|
|
CBlock8 key1, CBlock8 key2) {
|
2013-11-06 12:24:52 +00:00
|
|
|
CRYPTOLOG("log");
|
2009-10-14 13:31:27 +00:00
|
|
|
std::string res;
|
|
|
|
if (txt.size()%8!=0)
|
|
|
|
throw cannot_encrypt("text size must be a multiple of eight");
|
|
|
|
DES_key_schedule ks1, ks2;
|
|
|
|
DES_set_key_unchecked(key1, &ks1);
|
|
|
|
DES_set_key_unchecked(key2, &ks2);
|
|
|
|
for (std::string::size_type pos(0); pos<txt.size(); pos+=8) {
|
|
|
|
CBlock8 out, in(txt.substr(pos, 8));
|
|
|
|
DES_ecb2_encrypt(in, out, &ks1, &ks2, DES_DECRYPT);
|
|
|
|
res+=out;
|
|
|
|
}
|
|
|
|
return res;
|
|
|
|
}
|
|
|
|
|
2009-09-17 14:57:22 +00:00
|
|
|
//============================================================================
|
2010-03-03 15:37:44 +00:00
|
|
|
//! X509 Certificate
|
2009-09-17 14:57:22 +00:00
|
|
|
class X509 {
|
|
|
|
public:
|
|
|
|
//! Construct empty certificate.
|
|
|
|
X509(): _x509(X509_new()) {
|
2013-11-06 12:24:52 +00:00
|
|
|
CRYPTOLOG("log");
|
2009-09-17 14:57:22 +00:00
|
|
|
if (!_x509) throw allocation_failed();
|
|
|
|
}
|
2009-09-21 07:43:32 +00:00
|
|
|
//! Initialize from DER encoded cerificate.
|
|
|
|
X509(const std::string& der): _x509(0) {
|
2013-11-06 12:24:52 +00:00
|
|
|
CRYPTOLOG("log");
|
2010-08-27 09:43:20 +00:00
|
|
|
V0_CONST unsigned char* c((unsigned char*)der.begin().operator->());
|
2009-09-21 07:43:32 +00:00
|
|
|
if (!(_x509=d2i_X509(0, &c, der.size())) ||
|
|
|
|
(const char*)c!=der.begin().operator->()+der.size())
|
|
|
|
throw x509_decoding_failed(der);
|
|
|
|
}
|
2009-09-18 08:24:22 +00:00
|
|
|
X509(const X509& o): _x509(0) {
|
2013-11-06 12:24:52 +00:00
|
|
|
CRYPTOLOG("log");
|
2011-04-21 06:30:51 +00:00
|
|
|
_x509 = X509_dup(o._x509);
|
|
|
|
// unsigned char* d(0);
|
|
|
|
// int len(i2d_X509(o._x509, &d));
|
|
|
|
// if (!len) throw x509_copy_failed();
|
|
|
|
// V0_CONST unsigned char* d2(d);
|
|
|
|
// _x509 = d2i_X509(0, &d2, len);
|
|
|
|
// OPENSSL_free(d);
|
2009-09-18 08:24:22 +00:00
|
|
|
if (!_x509) throw x509_copy_failed();
|
2009-09-17 14:57:22 +00:00
|
|
|
}
|
|
|
|
//! Take over OpenSSL allocated certificate.
|
|
|
|
X509(::X509 *x509): _x509(x509) {
|
2013-11-06 12:24:52 +00:00
|
|
|
CRYPTOLOG("log");
|
2009-09-17 14:57:22 +00:00
|
|
|
if (!_x509) throw undefined_certificate();
|
|
|
|
}
|
|
|
|
~X509() {
|
2013-11-06 12:24:52 +00:00
|
|
|
CRYPTOLOG("log");
|
2009-09-17 14:57:22 +00:00
|
|
|
X509_free(_x509);
|
|
|
|
}
|
|
|
|
X509& operator=(const X509& o) {
|
2013-11-06 12:24:52 +00:00
|
|
|
CRYPTOLOG("log");
|
2009-09-17 14:57:22 +00:00
|
|
|
X509_free(_x509);
|
|
|
|
_x509 = 0;
|
2011-04-21 06:30:51 +00:00
|
|
|
_x509 = X509_dup(o._x509);
|
|
|
|
// unsigned char* d(0);
|
|
|
|
// int len(i2d_X509(o._x509, &d));
|
|
|
|
// if (!len) throw x509_copy_failed();
|
|
|
|
// V0_CONST unsigned char* d2(d);
|
|
|
|
// _x509 = d2i_X509(0, &d2, len);
|
|
|
|
// OPENSSL_free(d);
|
2009-09-18 08:24:22 +00:00
|
|
|
if (!_x509) throw x509_copy_failed();
|
2009-09-17 14:57:22 +00:00
|
|
|
}
|
2011-04-21 06:30:51 +00:00
|
|
|
//! Get a copy of the OpenSSL low level certificate
|
|
|
|
/*! @note you are responsible to free the certificate */
|
|
|
|
::X509* lowLevelCopy() const {
|
|
|
|
return X509_dup(_x509);
|
|
|
|
}
|
2009-09-18 13:57:51 +00:00
|
|
|
//! Get DER encoded subject.
|
|
|
|
std::string subjectDER() const {
|
2013-11-06 12:24:52 +00:00
|
|
|
CRYPTOLOG("log");
|
2009-09-21 07:43:32 +00:00
|
|
|
unsigned char* c(0);
|
2009-09-18 13:57:51 +00:00
|
|
|
int len(i2d_X509_NAME(X509_get_subject_name(_x509), &c));
|
2009-09-21 07:43:32 +00:00
|
|
|
std::string res((char*)c, len);
|
2009-09-18 13:57:51 +00:00
|
|
|
OPENSSL_free(c);
|
|
|
|
return res;
|
|
|
|
}
|
2009-09-21 07:43:32 +00:00
|
|
|
//! Get DER encoded issuer.
|
|
|
|
std::string issuerDER() const {
|
2013-11-06 12:24:52 +00:00
|
|
|
CRYPTOLOG("log");
|
2009-09-21 07:43:32 +00:00
|
|
|
unsigned char* c(0);
|
|
|
|
int len(i2d_X509_NAME(X509_get_issuer_name(_x509), &c));
|
|
|
|
std::string res((char*)c, len);
|
|
|
|
OPENSSL_free(c);
|
|
|
|
return res;
|
|
|
|
}
|
|
|
|
//! Get DER encoded value.
|
|
|
|
std::string valueDER() const {
|
2013-11-06 12:24:52 +00:00
|
|
|
CRYPTOLOG("log");
|
2009-09-21 07:43:32 +00:00
|
|
|
unsigned char* c(0);
|
|
|
|
int len(i2d_X509(_x509, &c));
|
|
|
|
std::string res((char*)c, len);
|
|
|
|
OPENSSL_free(c);
|
|
|
|
return res;
|
|
|
|
}
|
|
|
|
//! Get serial number.
|
|
|
|
std::string serial() const {
|
2013-11-06 12:24:52 +00:00
|
|
|
CRYPTOLOG("log");
|
2010-03-03 15:37:44 +00:00
|
|
|
/* @bug tcp://albistechnologies.com reports: «could be a
|
2009-09-21 07:43:32 +00:00
|
|
|
failure in openSSL: len too short by 1 if serial number
|
|
|
|
starts with 00 ASN1_INTEGER* ser =
|
2009-09-22 13:25:55 +00:00
|
|
|
X509_get_serialNumber(_x509);»
|
|
|
|
@code
|
|
|
|
ASN1_INTEGER* ser(X509_get_serialNumber(_x509));
|
|
|
|
return std::string((char*)ser->data, ser->length);
|
|
|
|
@endcode
|
|
|
|
- requires memory free?
|
2010-03-03 15:37:44 +00:00
|
|
|
- ser->type?!? tcp://albistechnologies.com prepends
|
2009-09-22 13:25:55 +00:00
|
|
|
tag and length in the first two char-fields. */
|
|
|
|
unsigned char* c(0);
|
|
|
|
int len(i2d_X509(_x509, &c));
|
2011-09-05 08:35:05 +00:00
|
|
|
if (len<15 || len<15+c[14]) {
|
|
|
|
OPENSSL_free(c);
|
|
|
|
return std::string();
|
|
|
|
}
|
2009-09-22 13:25:55 +00:00
|
|
|
std::string res((char*)c+15, c[14]);
|
|
|
|
OPENSSL_free(c);
|
|
|
|
return res;
|
2009-09-21 07:43:32 +00:00
|
|
|
}
|
|
|
|
//! Get id.
|
|
|
|
std::string id() const {
|
2013-11-06 12:24:52 +00:00
|
|
|
CRYPTOLOG("log");
|
2009-09-21 07:43:32 +00:00
|
|
|
unsigned char c[SHA_DIGEST_LENGTH];
|
|
|
|
SHA1(_x509->cert_info->key->public_key->data,
|
|
|
|
_x509->cert_info->key->public_key->length,
|
|
|
|
c);
|
|
|
|
return std::string((char*)c, SHA_DIGEST_LENGTH);
|
|
|
|
}
|
2009-09-21 14:52:09 +00:00
|
|
|
//! Get common name.
|
|
|
|
std::string commonName() const {
|
2013-11-06 12:24:52 +00:00
|
|
|
CRYPTOLOG("log");
|
2009-09-21 14:52:09 +00:00
|
|
|
X509_NAME *name(X509_get_subject_name(_x509));
|
|
|
|
ASN1_STRING* cn
|
|
|
|
(X509_NAME_ENTRY_get_data
|
|
|
|
(X509_NAME_get_entry
|
|
|
|
(name, X509_NAME_get_index_by_NID(name, NID_commonName, -1))));
|
|
|
|
return std::string((char*)M_ASN1_STRING_data(cn),
|
|
|
|
M_ASN1_STRING_length(cn));
|
|
|
|
}
|
|
|
|
//! Get country name.
|
|
|
|
std::string countryName() const {
|
2013-11-06 12:24:52 +00:00
|
|
|
CRYPTOLOG("log");
|
2009-09-21 14:52:09 +00:00
|
|
|
X509_NAME *name(X509_get_subject_name(_x509));
|
|
|
|
ASN1_STRING* cn
|
|
|
|
(X509_NAME_ENTRY_get_data
|
|
|
|
(X509_NAME_get_entry
|
|
|
|
(name, X509_NAME_get_index_by_NID(name, NID_countryName, -1))));
|
|
|
|
return std::string((char*)M_ASN1_STRING_data(cn),
|
|
|
|
M_ASN1_STRING_length(cn));
|
|
|
|
}
|
|
|
|
//! Get locality name.
|
|
|
|
std::string localityName() const {
|
2013-11-06 12:24:52 +00:00
|
|
|
CRYPTOLOG("log");
|
2009-09-21 14:52:09 +00:00
|
|
|
X509_NAME *name(X509_get_subject_name(_x509));
|
|
|
|
ASN1_STRING* cn
|
|
|
|
(X509_NAME_ENTRY_get_data
|
|
|
|
(X509_NAME_get_entry
|
|
|
|
(name, X509_NAME_get_index_by_NID(name, NID_localityName, -1))));
|
|
|
|
return std::string((char*)M_ASN1_STRING_data(cn),
|
|
|
|
M_ASN1_STRING_length(cn));
|
|
|
|
}
|
|
|
|
//! Get state or province name.
|
|
|
|
std::string stateOrProvinceName() const {
|
2013-11-06 12:24:52 +00:00
|
|
|
CRYPTOLOG("log");
|
2009-09-21 14:52:09 +00:00
|
|
|
X509_NAME *name(X509_get_subject_name(_x509));
|
|
|
|
ASN1_STRING* cn
|
|
|
|
(X509_NAME_ENTRY_get_data
|
|
|
|
(X509_NAME_get_entry
|
|
|
|
(name, X509_NAME_get_index_by_NID
|
|
|
|
(name, NID_stateOrProvinceName, -1))));
|
|
|
|
return std::string((char*)M_ASN1_STRING_data(cn),
|
|
|
|
M_ASN1_STRING_length(cn));
|
|
|
|
}
|
|
|
|
//! Get organization name.
|
|
|
|
std::string organizationName() const {
|
2013-11-06 12:24:52 +00:00
|
|
|
CRYPTOLOG("log");
|
2009-09-21 14:52:09 +00:00
|
|
|
X509_NAME *name(X509_get_subject_name(_x509));
|
|
|
|
ASN1_STRING* cn
|
|
|
|
(X509_NAME_ENTRY_get_data
|
|
|
|
(X509_NAME_get_entry
|
|
|
|
(name, X509_NAME_get_index_by_NID
|
|
|
|
(name, NID_organizationName, -1))));
|
|
|
|
return std::string((char*)M_ASN1_STRING_data(cn),
|
|
|
|
M_ASN1_STRING_length(cn));
|
|
|
|
}
|
2009-09-22 07:40:28 +00:00
|
|
|
//! Check whether it's a CA certificate.
|
|
|
|
bool isCa() {
|
2013-11-06 12:24:52 +00:00
|
|
|
CRYPTOLOG("log");
|
2009-11-02 14:44:26 +00:00
|
|
|
BASIC_CONSTRAINTS* bc(0);
|
|
|
|
int pos(X509_get_ext_by_NID(_x509, NID_basic_constraints, -1));
|
|
|
|
if (pos>=0)
|
|
|
|
bc = (BASIC_CONSTRAINTS*)X509V3_EXT_d2i(X509_get_ext(_x509, pos));
|
2009-09-22 07:40:28 +00:00
|
|
|
return bc&&bc->ca;
|
2009-09-22 07:04:08 +00:00
|
|
|
}
|
2009-09-21 14:52:09 +00:00
|
|
|
//! Get organizational unit name.
|
|
|
|
std::string organizationalUnitName() const {
|
2013-11-06 12:24:52 +00:00
|
|
|
CRYPTOLOG("log");
|
2009-09-21 14:52:09 +00:00
|
|
|
X509_NAME *name(X509_get_subject_name(_x509));
|
|
|
|
ASN1_STRING* cn
|
|
|
|
(X509_NAME_ENTRY_get_data
|
|
|
|
(X509_NAME_get_entry
|
|
|
|
(name, X509_NAME_get_index_by_NID
|
|
|
|
(name, NID_organizationalUnitName, -1))));
|
|
|
|
return std::string((char*)M_ASN1_STRING_data(cn),
|
|
|
|
M_ASN1_STRING_length(cn));
|
2009-09-21 07:43:32 +00:00
|
|
|
}
|
2009-09-22 07:04:08 +00:00
|
|
|
//! Get key usage flags.
|
2009-10-01 19:14:18 +00:00
|
|
|
int keyUsageFlags() const {
|
2013-11-06 12:24:52 +00:00
|
|
|
CRYPTOLOG("log");
|
2009-10-01 19:14:18 +00:00
|
|
|
int res(X509v3_KU_UNDEF);
|
2009-09-22 07:04:08 +00:00
|
|
|
int pos(X509_get_ext_by_NID(_x509, NID_key_usage, -1));
|
|
|
|
if (pos>=0) {
|
2009-09-22 07:40:28 +00:00
|
|
|
ASN1_BIT_STRING* ku((ASN1_BIT_STRING*)X509V3_EXT_d2i
|
|
|
|
(X509_get_ext(_x509, pos)));
|
2009-10-01 19:14:18 +00:00
|
|
|
std::string val((char*)M_ASN1_STRING_data(ku),
|
|
|
|
M_ASN1_STRING_length(ku));
|
|
|
|
if (val.size()<=sizeof(int))
|
|
|
|
val = std::string(sizeof(int)-val.size(), '\0')+val;
|
|
|
|
assert(val.size()==sizeof(int));
|
|
|
|
res = *((int*)val.begin().operator->());
|
|
|
|
}
|
|
|
|
return res;
|
2009-09-22 07:04:08 +00:00
|
|
|
}
|
2009-09-17 14:57:22 +00:00
|
|
|
private:
|
|
|
|
::X509* _x509;
|
|
|
|
};
|
|
|
|
|
|
|
|
//============================================================================
|
2010-03-03 15:37:44 +00:00
|
|
|
//! Private certificate key
|
2009-09-17 14:57:22 +00:00
|
|
|
class PrivateKey {
|
|
|
|
public:
|
2009-10-01 19:14:18 +00:00
|
|
|
PrivateKey(): _key(EVP_PKEY_new()) {
|
2013-11-06 12:24:52 +00:00
|
|
|
CRYPTOLOG("log");
|
2009-10-01 19:14:18 +00:00
|
|
|
if (!_key) throw allocation_failed();
|
|
|
|
}
|
|
|
|
PrivateKey(const PrivateKey& o): _key(0) {
|
2013-11-06 12:24:52 +00:00
|
|
|
CRYPTOLOG("log");
|
2009-10-01 19:14:18 +00:00
|
|
|
copy(o);
|
|
|
|
}
|
|
|
|
PrivateKey(EVP_PKEY* k): _key(k) {
|
2013-11-06 12:24:52 +00:00
|
|
|
CRYPTOLOG("log");
|
2009-10-01 19:14:18 +00:00
|
|
|
if (!_key) throw undefined_key();
|
|
|
|
}
|
|
|
|
~PrivateKey() {
|
2013-11-06 12:24:52 +00:00
|
|
|
CRYPTOLOG("log");
|
2009-10-01 19:14:18 +00:00
|
|
|
EVP_PKEY_free(_key);
|
|
|
|
}
|
|
|
|
PrivateKey& operator=(const PrivateKey& o) {
|
2013-11-06 12:24:52 +00:00
|
|
|
CRYPTOLOG("log");
|
2009-10-01 19:14:18 +00:00
|
|
|
copy(o);
|
|
|
|
return *this;
|
|
|
|
}
|
|
|
|
std::string modulus() const {
|
2013-11-06 12:24:52 +00:00
|
|
|
CRYPTOLOG("log");
|
2011-04-21 06:30:51 +00:00
|
|
|
return BigNum::string(rsa()->n);
|
2009-10-01 19:14:18 +00:00
|
|
|
}
|
|
|
|
std::string publicExponent() const {
|
2013-11-06 12:24:52 +00:00
|
|
|
CRYPTOLOG("log");
|
2011-04-21 06:30:51 +00:00
|
|
|
return BigNum::string(rsa()->e);
|
2009-10-01 19:14:18 +00:00
|
|
|
}
|
|
|
|
std::string privateExponent() const {
|
2013-11-06 12:24:52 +00:00
|
|
|
CRYPTOLOG("log");
|
2011-04-21 06:30:51 +00:00
|
|
|
return BigNum::string(rsa()->d);
|
2009-10-01 19:14:18 +00:00
|
|
|
}
|
|
|
|
std::string prime1() const {
|
2013-11-06 12:24:52 +00:00
|
|
|
CRYPTOLOG("log");
|
2011-04-21 06:30:51 +00:00
|
|
|
return BigNum::string(rsa()->p);
|
2009-10-01 19:14:18 +00:00
|
|
|
}
|
|
|
|
std::string prime2() const {
|
2013-11-06 12:24:52 +00:00
|
|
|
CRYPTOLOG("log");
|
2011-04-21 06:30:51 +00:00
|
|
|
return BigNum::string(rsa()->q);
|
2009-10-01 19:14:18 +00:00
|
|
|
}
|
|
|
|
std::string exponent1() const {
|
2013-11-06 12:24:52 +00:00
|
|
|
CRYPTOLOG("log");
|
2011-04-21 06:30:51 +00:00
|
|
|
return BigNum::string(rsa()->dmp1);
|
2009-10-01 19:14:18 +00:00
|
|
|
}
|
|
|
|
std::string exponent2() const {
|
2013-11-06 12:24:52 +00:00
|
|
|
CRYPTOLOG("log");
|
2011-04-21 06:30:51 +00:00
|
|
|
return BigNum::string(rsa()->dmq1);
|
2009-10-01 19:14:18 +00:00
|
|
|
}
|
|
|
|
std::string coefficient() const {
|
2013-11-06 12:24:52 +00:00
|
|
|
CRYPTOLOG("log");
|
2011-04-21 06:30:51 +00:00
|
|
|
return BigNum::string(rsa()->iqmp);
|
2009-10-01 19:14:18 +00:00
|
|
|
}
|
|
|
|
private:
|
|
|
|
void copy(const PrivateKey& o) {
|
2013-11-06 12:24:52 +00:00
|
|
|
CRYPTOLOG("log");
|
2009-10-01 19:14:18 +00:00
|
|
|
EVP_PKEY_free(_key);
|
|
|
|
if (!(_key=EVP_PKEY_new())) throw allocation_failed();
|
|
|
|
rsa(o);
|
|
|
|
dsa(o);
|
|
|
|
dh(o);
|
2010-03-03 15:37:44 +00:00
|
|
|
/*ec(o);*/
|
2009-10-01 19:14:18 +00:00
|
|
|
}
|
|
|
|
void rsa(const PrivateKey& o) {
|
2013-11-06 12:24:52 +00:00
|
|
|
CRYPTOLOG("log");
|
2009-10-01 19:14:18 +00:00
|
|
|
//! @todo throw exception if 0?
|
|
|
|
RSA* tmp(o.rsa());
|
|
|
|
if (tmp&&!EVP_PKEY_set1_RSA(_key, tmp)) throw key_copy_failed();
|
|
|
|
}
|
|
|
|
void dsa(const PrivateKey& o) {
|
2013-11-06 12:24:52 +00:00
|
|
|
CRYPTOLOG("log");
|
2009-10-01 19:14:18 +00:00
|
|
|
DSA* tmp(o.dsa());
|
|
|
|
if (tmp&&!EVP_PKEY_set1_DSA(_key, tmp)) throw key_copy_failed();
|
|
|
|
}
|
|
|
|
void dh(const PrivateKey& o) {
|
2013-11-06 12:24:52 +00:00
|
|
|
CRYPTOLOG("log");
|
2009-10-01 19:14:18 +00:00
|
|
|
DH* tmp(o.dh());
|
|
|
|
if (tmp&&!EVP_PKEY_set1_DH(_key, tmp)) throw key_copy_failed();
|
|
|
|
}
|
2009-11-17 15:56:08 +00:00
|
|
|
/* Not available on mac osx
|
2009-10-01 19:14:18 +00:00
|
|
|
void ec(const PrivateKey& o) {
|
2013-11-06 12:24:52 +00:00
|
|
|
CRYPTOLOG("log");
|
2009-10-01 19:14:18 +00:00
|
|
|
EC_KEY* tmp(o.ec());
|
|
|
|
if (tmp&&!EVP_PKEY_set1_EC_KEY(_key, tmp)) throw key_copy_failed();
|
|
|
|
}
|
2009-11-17 15:56:08 +00:00
|
|
|
*/
|
2009-10-01 19:14:18 +00:00
|
|
|
RSA* rsa() const {
|
2013-11-06 12:24:52 +00:00
|
|
|
CRYPTOLOG("log");
|
2009-10-01 19:14:18 +00:00
|
|
|
//! @todo throw exception if 0?
|
|
|
|
return EVP_PKEY_get1_RSA(_key);
|
|
|
|
}
|
|
|
|
DSA* dsa() const {
|
2013-11-06 12:24:52 +00:00
|
|
|
CRYPTOLOG("log");
|
2009-10-01 19:14:18 +00:00
|
|
|
return EVP_PKEY_get1_DSA(_key);
|
|
|
|
}
|
|
|
|
DH* dh() const {
|
2013-11-06 12:24:52 +00:00
|
|
|
CRYPTOLOG("log");
|
2009-10-01 19:14:18 +00:00
|
|
|
return EVP_PKEY_get1_DH(_key);
|
|
|
|
}
|
2009-11-17 15:56:08 +00:00
|
|
|
/* Not available on mac osx
|
2009-10-01 19:14:18 +00:00
|
|
|
EC_KEY* ec() const {
|
2013-11-06 12:24:52 +00:00
|
|
|
CRYPTOLOG("log");
|
2009-10-01 19:14:18 +00:00
|
|
|
return EVP_PKEY_get1_EC_KEY(_key);
|
2010-03-03 15:37:44 +00:00
|
|
|
}*/
|
2009-10-01 19:14:18 +00:00
|
|
|
EVP_PKEY* _key;
|
2009-09-17 14:57:22 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
//============================================================================
|
2010-03-03 15:37:44 +00:00
|
|
|
//! PKCS#12 certificate file handler
|
2009-09-17 14:57:22 +00:00
|
|
|
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) {
|
2013-11-06 12:24:52 +00:00
|
|
|
CRYPTOLOG("log");
|
2009-09-17 14:57:22 +00:00
|
|
|
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);
|
2010-08-27 12:51:15 +00:00
|
|
|
for (int i(sk_num(CV_STACK ca)); i>0; --i)
|
|
|
|
_ca.push_back(new X509((::X509*)sk_pop(CV_STACK ca)));
|
2009-09-17 14:57:22 +00:00
|
|
|
PKCS12_free(p12);
|
|
|
|
} catch (...) {
|
|
|
|
PKCS12_free(p12);
|
|
|
|
throw;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
~PKCS12() {
|
2013-11-06 12:24:52 +00:00
|
|
|
CRYPTOLOG("log");
|
2009-09-17 14:57:22 +00:00
|
|
|
delete _key;
|
|
|
|
delete _cert;
|
|
|
|
for (X509List::iterator it(_ca.begin()); it!=_ca.end(); ++it)
|
|
|
|
delete *it;
|
|
|
|
}
|
|
|
|
|
2009-10-01 19:14:18 +00:00
|
|
|
bool hasPrivateKey() const {
|
2013-11-06 12:24:52 +00:00
|
|
|
CRYPTOLOG("log");
|
2009-09-17 14:57:22 +00:00
|
|
|
return _key;
|
|
|
|
}
|
|
|
|
|
2009-10-01 19:14:18 +00:00
|
|
|
bool hasCert() const {
|
2013-11-06 12:24:52 +00:00
|
|
|
CRYPTOLOG("log");
|
2009-09-17 14:57:22 +00:00
|
|
|
return _cert;
|
|
|
|
}
|
|
|
|
|
2009-10-01 19:14:18 +00:00
|
|
|
const PrivateKey& privateKey() const {
|
2013-11-06 12:24:52 +00:00
|
|
|
CRYPTOLOG("log");
|
2009-09-17 14:57:22 +00:00
|
|
|
if (!_key) throw pkcs12_no_private_key();
|
|
|
|
return *_key;
|
|
|
|
};
|
|
|
|
|
2009-10-01 19:14:18 +00:00
|
|
|
const X509& x509() const {
|
2013-11-06 12:24:52 +00:00
|
|
|
CRYPTOLOG("log");
|
2009-09-17 14:57:22 +00:00
|
|
|
if (!_cert) throw pkcs12_no_x509();
|
|
|
|
return *_cert;
|
|
|
|
};
|
|
|
|
|
|
|
|
const X509List& ca() const {
|
2013-11-06 12:24:52 +00:00
|
|
|
CRYPTOLOG("log");
|
2009-09-17 14:57:22 +00:00
|
|
|
return _ca;
|
|
|
|
}
|
|
|
|
|
|
|
|
private:
|
|
|
|
PrivateKey *_key;
|
|
|
|
X509 *_cert;
|
|
|
|
X509List _ca;
|
|
|
|
};
|
|
|
|
|
2009-10-26 12:40:28 +00:00
|
|
|
//============================================================================
|
2010-03-03 15:37:44 +00:00
|
|
|
//! PKCS#7 certificate file handler
|
2009-10-26 12:40:28 +00:00
|
|
|
class PKCS7 {
|
|
|
|
|
|
|
|
//...............................................................typedefs
|
|
|
|
public:
|
|
|
|
typedef std::vector<X509*> X509List;
|
|
|
|
|
|
|
|
//................................................................methods
|
|
|
|
public:
|
|
|
|
|
|
|
|
/*
|
|
|
|
//! Read from a PKCS#7 (.p7) file.
|
|
|
|
PKCS7(std::string filename) {
|
|
|
|
FILE* file(fopen(filename.c_str(), "rb"));
|
|
|
|
if (!file) throw cannot_open_file(filename);
|
|
|
|
::PKCS7 *p7(d2i_PKCS7_fp(file, 0));
|
|
|
|
fclose(file);
|
|
|
|
if (!p7) throw pkcs7_reading_failed(filename);
|
|
|
|
try {
|
|
|
|
if (PKCS7_type_is_signed(p7)) while (p7->d.sign->cert->num>0)
|
|
|
|
_certs.push_back(new X509((::X509*)sk_pop(p7->d.sign->cert)));
|
|
|
|
else //! @todo to be implemented: check for other types
|
|
|
|
throw pkcs7_unsupported_format();
|
|
|
|
PKCS7_free(p7);
|
|
|
|
} catch (...) {
|
|
|
|
PKCS7_free(p7);
|
|
|
|
throw;
|
|
|
|
}
|
|
|
|
}*/
|
|
|
|
|
|
|
|
//! Read PKCS#7 from memory.
|
|
|
|
PKCS7(const std::string& memory) {
|
2013-11-06 12:24:52 +00:00
|
|
|
CRYPTOLOG("log");
|
2009-10-26 12:40:28 +00:00
|
|
|
BIO* mem(BIO_new_mem_buf((void*)memory.data(), memory.size()));
|
|
|
|
::PKCS7 *p7(d2i_PKCS7_bio(mem, 0));
|
|
|
|
BIO_free(mem);
|
|
|
|
if (!p7) throw pkcs7_parsing_failed();
|
|
|
|
try {
|
2010-08-27 12:51:15 +00:00
|
|
|
if (PKCS7_type_is_signed(p7)) while ((CV_STACK p7->d.sign->cert)->num>0)
|
|
|
|
_certs.push_back(new X509((::X509*)sk_pop(CV_STACK p7->d.sign->cert)));
|
2009-10-26 12:40:28 +00:00
|
|
|
else //! @todo to be implemented: check for other types
|
|
|
|
throw pkcs7_unsupported_format();
|
|
|
|
PKCS7_free(p7);
|
|
|
|
} catch (...) {
|
|
|
|
PKCS7_free(p7);
|
|
|
|
throw;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
~PKCS7() {
|
2013-11-06 12:24:52 +00:00
|
|
|
CRYPTOLOG("log");
|
2009-10-26 12:40:28 +00:00
|
|
|
for (X509List::iterator it(_certs.begin()); it!=_certs.end(); ++it)
|
|
|
|
delete *it;
|
|
|
|
}
|
|
|
|
|
|
|
|
const X509List& certs() const {
|
2013-11-06 12:24:52 +00:00
|
|
|
CRYPTOLOG("log");
|
2009-10-26 12:40:28 +00:00
|
|
|
return _certs;
|
|
|
|
}
|
|
|
|
|
|
|
|
private:
|
|
|
|
X509List _certs;
|
|
|
|
};
|
|
|
|
|
2009-09-18 13:31:00 +00:00
|
|
|
//============================================================================
|
2010-03-03 15:37:44 +00:00
|
|
|
//! TCP Connection
|
|
|
|
class TCP {
|
2009-09-18 13:31:00 +00:00
|
|
|
|
|
|
|
private:
|
|
|
|
|
2010-03-03 15:37:44 +00:00
|
|
|
TCP(const TCP&);
|
|
|
|
TCP& operator=(const TCP&);
|
2009-09-18 13:31:00 +00:00
|
|
|
|
2009-09-17 14:57:22 +00:00
|
|
|
public:
|
2009-09-18 13:31:00 +00:00
|
|
|
|
2010-03-03 15:37:44 +00:00
|
|
|
TCP(): _bio(0) {
|
2013-11-06 12:24:52 +00:00
|
|
|
CRYPTOLOG("log");
|
2010-03-03 15:37:44 +00:00
|
|
|
}
|
2009-09-18 13:31:00 +00:00
|
|
|
|
2010-03-03 15:37:44 +00:00
|
|
|
TCP(const std::string& hostPort): _bio(0) {
|
2013-11-06 12:24:52 +00:00
|
|
|
CRYPTOLOG("log");
|
2010-03-03 15:37:44 +00:00
|
|
|
connect(hostPort);
|
|
|
|
}
|
|
|
|
|
|
|
|
virtual ~TCP() {
|
2013-11-06 12:24:52 +00:00
|
|
|
CRYPTOLOG("log");
|
2009-09-17 14:57:22 +00:00
|
|
|
try {
|
2009-09-18 08:24:22 +00:00
|
|
|
close();
|
2009-09-17 14:57:22 +00:00
|
|
|
} catch (...) {
|
|
|
|
if (!std::uncaught_exception()) throw;
|
|
|
|
}
|
|
|
|
}
|
2009-09-18 13:31:00 +00:00
|
|
|
|
2010-03-03 15:37:44 +00:00
|
|
|
virtual TCP& connect(const std::string& hostPort) {
|
2013-11-06 12:24:52 +00:00
|
|
|
CRYPTOLOG("log");
|
2009-09-17 14:57:22 +00:00
|
|
|
close();
|
2009-09-18 13:31:00 +00:00
|
|
|
if (!(_bio=BIO_new_connect(const_cast<char*>(hostPort.c_str()))) ||
|
|
|
|
BIO_do_connect(_bio)<=0)
|
2010-03-03 15:37:44 +00:00
|
|
|
throw tcp_connection_failed(hostPort);
|
|
|
|
_hostPort = hostPort;
|
2009-09-18 13:31:00 +00:00
|
|
|
return *this;
|
|
|
|
}
|
2010-03-03 15:37:44 +00:00
|
|
|
|
|
|
|
virtual TCP& connect() {
|
|
|
|
if (!_hostPort.size()) throw tcp_server_not_specified();
|
|
|
|
close();
|
|
|
|
connect(_hostPort);
|
|
|
|
return *this;
|
|
|
|
}
|
|
|
|
|
|
|
|
operator bool() const {
|
2013-11-06 12:24:52 +00:00
|
|
|
CRYPTOLOG("log");
|
2013-11-11 11:49:09 +00:00
|
|
|
return _bio;
|
2010-03-03 15:37:44 +00:00
|
|
|
}
|
2009-09-18 13:31:00 +00:00
|
|
|
|
2010-03-03 15:37:44 +00:00
|
|
|
TCP& operator>>(std::string& s) {
|
2013-11-06 12:24:52 +00:00
|
|
|
CRYPTOLOG("log");
|
2009-09-18 13:31:00 +00:00
|
|
|
s += read();
|
|
|
|
return *this;
|
|
|
|
}
|
|
|
|
|
2010-03-03 15:37:44 +00:00
|
|
|
TCP& operator<<(const std::string& s) {
|
2013-11-06 12:24:52 +00:00
|
|
|
CRYPTOLOG("log");
|
2009-09-18 13:31:00 +00:00
|
|
|
return write(s);
|
|
|
|
}
|
|
|
|
|
|
|
|
/*! @todo How can I find out, whether there's still data
|
|
|
|
available, or whether a response has been finished and
|
|
|
|
server is waiting for next request, but connection is still
|
|
|
|
open? */
|
|
|
|
std::string read() {
|
2013-11-06 12:24:52 +00:00
|
|
|
CRYPTOLOG("log");
|
2013-11-11 11:49:09 +00:00
|
|
|
if (!_bio) throw tcp_closed_connection();
|
2009-09-18 13:31:00 +00:00
|
|
|
const int BUFF_SZ(1024);
|
|
|
|
char buff[BUFF_SZ];
|
|
|
|
int x(BIO_read(_bio, buff, BUFF_SZ));
|
|
|
|
if (x<=0)
|
|
|
|
if (BIO_should_retry(_bio)) return read();
|
2010-03-03 15:37:44 +00:00
|
|
|
else {
|
|
|
|
close();
|
|
|
|
if (x==0) return std::string();
|
|
|
|
else throw tcp_read_error();
|
|
|
|
}
|
|
|
|
else if (x==1024) return std::string(buff, x)+read();
|
2009-09-18 13:31:00 +00:00
|
|
|
return std::string(buff, x);
|
|
|
|
}
|
|
|
|
|
2010-03-03 15:37:44 +00:00
|
|
|
TCP& write(const std::string& s) {
|
2013-11-06 12:24:52 +00:00
|
|
|
CRYPTOLOG("log");
|
2013-11-11 11:49:09 +00:00
|
|
|
if (!_bio) throw tcp_closed_connection();
|
2011-09-05 08:35:05 +00:00
|
|
|
unsigned int x(BIO_write(_bio, s.begin().operator->(), s.size()));
|
2009-09-18 13:31:00 +00:00
|
|
|
if (x<=0)
|
|
|
|
if (BIO_should_retry(_bio)) return write(s);
|
2010-03-03 15:37:44 +00:00
|
|
|
else {
|
|
|
|
close();
|
|
|
|
throw tcp_write_error();
|
|
|
|
}
|
|
|
|
else if (x<s.size()) return write(s.substr(x));
|
2009-09-18 13:31:00 +00:00
|
|
|
return *this;
|
2009-09-17 14:57:22 +00:00
|
|
|
}
|
2009-09-18 13:31:00 +00:00
|
|
|
|
2010-03-03 15:37:44 +00:00
|
|
|
virtual TCP& close() {
|
2013-11-06 12:24:52 +00:00
|
|
|
CRYPTOLOG("log");
|
2013-11-11 11:49:09 +00:00
|
|
|
if (_bio) BIO_free_all(_bio);
|
2010-03-03 15:37:44 +00:00
|
|
|
_bio = 0;
|
|
|
|
return *this;
|
2009-09-17 14:57:22 +00:00
|
|
|
}
|
2009-09-18 13:31:00 +00:00
|
|
|
|
2010-03-03 15:37:44 +00:00
|
|
|
protected:
|
2009-09-18 13:31:00 +00:00
|
|
|
|
2009-09-18 08:24:22 +00:00
|
|
|
::BIO* _bio;
|
2010-03-03 15:37:44 +00:00
|
|
|
std::string _hostPort;
|
2009-09-18 13:31:00 +00:00
|
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
//! Read authorized certificate from a single pem file.
|
|
|
|
class TrustStore {
|
|
|
|
public:
|
|
|
|
TrustStore(const std::string& pathToPemFile):
|
|
|
|
_file(pathToPemFile) {
|
2013-11-06 12:24:52 +00:00
|
|
|
CRYPTOLOG("log");
|
2009-09-18 13:31:00 +00:00
|
|
|
}
|
|
|
|
const std::string& file() const {
|
2013-11-06 12:24:52 +00:00
|
|
|
CRYPTOLOG("log");
|
2009-09-18 13:31:00 +00:00
|
|
|
return _file;
|
|
|
|
}
|
|
|
|
private:
|
|
|
|
std::string _file;
|
|
|
|
};
|
|
|
|
|
|
|
|
class CertificateFolder {
|
|
|
|
public:
|
|
|
|
CertificateFolder(const std::string& certificateFolder):
|
|
|
|
_path(certificateFolder) {
|
2013-11-06 12:24:52 +00:00
|
|
|
CRYPTOLOG("log");
|
2009-09-18 13:31:00 +00:00
|
|
|
}
|
|
|
|
const std::string& path() const {
|
2013-11-06 12:24:52 +00:00
|
|
|
CRYPTOLOG("log");
|
2009-09-18 13:31:00 +00:00
|
|
|
return _path;
|
|
|
|
}
|
|
|
|
private:
|
|
|
|
std::string _path;
|
|
|
|
};
|
|
|
|
|
2010-03-03 15:37:44 +00:00
|
|
|
class SSL: public TCP {
|
2009-09-18 13:31:00 +00:00
|
|
|
private:
|
|
|
|
SSL();
|
|
|
|
SSL(const SSL&);
|
|
|
|
SSL& operator=(const SSL&);
|
|
|
|
public:
|
|
|
|
SSL(const TrustStore& file):
|
|
|
|
_ctx(SSL_CTX_new(SSLv23_client_method())),
|
|
|
|
_ssl(0) {
|
2013-11-06 12:24:52 +00:00
|
|
|
CRYPTOLOG("log");
|
2009-09-18 13:31:00 +00:00
|
|
|
if (!_ctx) throw ssl_cannot_create_context();
|
|
|
|
if (!SSL_CTX_load_verify_locations(_ctx, file.file().c_str(), 0))
|
|
|
|
throw ssl_certificate_file_not_loaded(file.file());
|
|
|
|
}
|
|
|
|
SSL(const CertificateFolder& folder):
|
|
|
|
_ctx(SSL_CTX_new(SSLv23_client_method())),
|
|
|
|
_ssl(0) {
|
2013-11-06 12:24:52 +00:00
|
|
|
CRYPTOLOG("log");
|
2009-09-18 13:31:00 +00:00
|
|
|
if (!_ctx) throw ssl_cannot_create_context();
|
|
|
|
if (!SSL_CTX_load_verify_locations(_ctx, 0, folder.path().c_str()))
|
|
|
|
throw ssl_certificate_folder_not_loaded(folder.path());
|
|
|
|
}
|
|
|
|
~SSL() {
|
2013-11-06 12:24:52 +00:00
|
|
|
CRYPTOLOG("log");
|
2009-09-18 13:31:00 +00:00
|
|
|
close();
|
|
|
|
SSL_CTX_free(_ctx);
|
|
|
|
}
|
2010-03-03 15:37:44 +00:00
|
|
|
virtual SSL& connect(const std::string& hostPort) {
|
2013-11-06 12:24:52 +00:00
|
|
|
CRYPTOLOG("log");
|
2009-09-18 13:31:00 +00:00
|
|
|
close();
|
2010-03-03 15:37:44 +00:00
|
|
|
if (!(_bio=BIO_new_ssl_connect(_ctx)))
|
|
|
|
throw tcp_connection_failed(hostPort);
|
|
|
|
BIO_get_ssl(_bio, &_ssl);
|
|
|
|
if (!_ssl) throw ssl_no_connection();
|
2009-09-18 13:31:00 +00:00
|
|
|
SSL_set_mode(_ssl, SSL_MODE_AUTO_RETRY);
|
2010-03-03 15:37:44 +00:00
|
|
|
BIO_set_conn_hostname(_bio, const_cast<char*>(hostPort.c_str()));
|
|
|
|
if (BIO_do_connect(_bio)<=0)
|
|
|
|
throw tcp_connection_failed(hostPort);
|
|
|
|
verify();
|
|
|
|
return *this;
|
2009-09-18 13:31:00 +00:00
|
|
|
}
|
2010-03-03 15:37:44 +00:00
|
|
|
virtual SSL& close() {
|
2013-11-06 12:24:52 +00:00
|
|
|
CRYPTOLOG("log");
|
2010-03-03 15:37:44 +00:00
|
|
|
TCP::close();
|
2009-09-18 13:31:00 +00:00
|
|
|
_ssl = 0; //! @todo is this correct? <--
|
|
|
|
return *this;
|
|
|
|
}
|
2010-03-03 15:37:44 +00:00
|
|
|
protected:
|
|
|
|
void verify() {
|
2013-11-06 12:24:52 +00:00
|
|
|
CRYPTOLOG("log");
|
2010-03-03 15:37:44 +00:00
|
|
|
if (!_ssl) throw ssl_no_connection();
|
|
|
|
int res(SSL_get_verify_result(_ssl));
|
|
|
|
if (res!=X509_V_OK) throw ssl_verification_failed(res);
|
2009-09-18 13:31:00 +00:00
|
|
|
}
|
|
|
|
private:
|
|
|
|
SSL_CTX *_ctx;
|
|
|
|
::SSL *_ssl;
|
2009-09-17 14:57:22 +00:00
|
|
|
};
|
|
|
|
|
2009-09-18 11:41:30 +00:00
|
|
|
//@}
|
|
|
|
|
2009-09-17 14:57:22 +00:00
|
|
|
}
|
2010-03-03 15:37:44 +00:00
|
|
|
|
2010-04-15 14:27:42 +00:00
|
|
|
inline std::ostream& operator<<(std::ostream& os, openssl::TCP& is) {
|
2010-03-03 15:37:44 +00:00
|
|
|
return os<<is.read();
|
|
|
|
}
|
|
|
|
|
2010-04-15 14:27:42 +00:00
|
|
|
inline std::istream& operator>>(std::istream& is, openssl::TCP& os) {
|
2010-03-03 15:37:44 +00:00
|
|
|
std::string s;
|
|
|
|
is>>s;
|
|
|
|
os<<s;
|
|
|
|
return is;
|
|
|
|
}
|
|
|
|
|
2009-09-18 11:41:30 +00:00
|
|
|
//@}
|
2009-09-17 14:57:22 +00:00
|
|
|
|
|
|
|
#endif
|