TCP- and SSL-Connection Examples

master
Marc Wäckerlin 15 years ago
parent 234bb55b7b
commit 522fa3b4f1
  1. 18
      doc/examples/makefile.am
  2. 28
      doc/examples/openssl-ssl-demo.cxx
  3. 25
      doc/examples/openssl-tcp-demo.cxx
  4. 543
      src/openssl.hxx

@ -3,7 +3,7 @@
## 1 2 3 4 5 6 7 8 ## 1 2 3 4 5 6 7 8
## 45678901234567890123456789012345678901234567890123456789012345678901234567890 ## 45678901234567890123456789012345678901234567890123456789012345678901234567890
noinst_PROGRAMS = pcsc-demo cryptoki-demo noinst_PROGRAMS = pcsc-demo cryptoki-demo openssl-tcp-demo openssl-ssl-demo
AM_CPPFLAGS = -I${top_srcdir}/src AM_CPPFLAGS = -I${top_srcdir}/src
if !MINGW32 if !MINGW32
@ -27,4 +27,20 @@ else
cryptoki_demo_LDADD += -ldl -lpthread -lssl cryptoki_demo_LDADD += -ldl -lpthread -lssl
endif endif
openssl_tcp_demo_SOURCES = openssl-tcp-demo.cxx
openssl_tcp_demo_LDFLAGS = -L${top_builddir}/src
if MINGW32
openssl_tcp_demo_LDADD = -leay32
else
openssl_tcp_demo_LDADD = -ldl -lpthread -lssl
endif
openssl_ssl_demo_SOURCES = openssl-ssl-demo.cxx
openssl_ssl_demo_LDFLAGS = -L${top_builddir}/src
if MINGW32
openssl_ssl_demo_LDADD = -leay32
else
openssl_ssl_demo_LDADD = -ldl -lpthread -lssl
endif
MAINTAINERCLEANFILES = makefile.in MAINTAINERCLEANFILES = makefile.in

@ -0,0 +1,28 @@
/*! @file
@id $Id$
*/
// 1 2 3 4 5 6 7 8
// 45678901234567890123456789012345678901234567890123456789012345678901234567890
#define OPENSSL_LOG(X)
#include <openssl.hxx>
#include <iostream>
int main(int argc, char** argv) try {
openssl::Init init;
std::string host(argc>1?argv[1]:"dev.swisssign.com");
std::string port(argc>2?argv[2]:"443");
std::string path(argc>3?argv[3]:"/");
std::cout<<"Connect to: "<<host<<':'<<port<<std::endl;
openssl::SSL ssl
(openssl::TrustStore("/usr/lib/ssl/certs/SwissSign_Gold_CA_-_G2.pem"));
ssl.connect(host+':'+port)<<"GET "<<path<<" HTTP/1.1\n"
<<"Host: "<<host<<"\n"
<<"Connection: Close\n\n";
while (ssl) std::cout<<ssl;
return 0;
} catch (const std::exception& x) {
std::cerr<<"**** ERROR: "<<x.what()<<std::endl;
return 1;
}

@ -0,0 +1,25 @@
/*! @file
@id $Id$
*/
// 1 2 3 4 5 6 7 8
// 45678901234567890123456789012345678901234567890123456789012345678901234567890
//#define OPENSSL_LOG(X)
#include <openssl.hxx>
#include <iostream>
int main(int argc, char** argv) try {
openssl::Init init;
std::string host(argc>1?argv[1]:"swisssign.com");
std::string port(argc>2?argv[2]:"80");
std::cout<<"Connect to: "<<host<<':'<<port<<std::endl;
openssl::TCP ssl(host+':'+port);
ssl<<"GET / HTTP/1.1\x0D\x0AHost: "<<host
<<"\x0D\x0A\x43onnection: Close\x0D\x0A\x0D\x0A";
while (ssl) std::cout<<ssl;
return 0;
} catch (const std::exception& x) {
std::cerr<<"**** ERROR: "<<x.what()<<std::endl;
return 1;
}

@ -23,7 +23,25 @@
#include <cstdio> #include <cstdio>
#include <cassert> #include <cassert>
#include <iostream> //! @todo remove (debug only) #ifndef OPENSSL_LOG
#include <iostream>
#if __GNUC__ >= 2
//! Openssl Logging
/*! If you want to change openssl logging mechanism, just
redefine your own OPENSSL_LOG macro before <code>#include
&lt;openssl.hxx&gt;</code>. Define it empty for no logging at
all. By default logs to <code>std::clog</code>. */
#define OPENSSL_LOG(X) std::clog<<X<<" @ "<<__PRETTY_FUNCTION__<<std::endl
#else
//! Openssl Logging
/*! If you want to change openssl logging mechanism, just
redefine your own OPENSSL_LOG macro before <code>#include
&lt;openssl.hxx&gt;</code>. Define it empty for no logging at
all. By default logs to <code>std::clog</code>. */
#define OPENSSL_LOG(X) std::clog<<X<<" @ "<<__FILE__<<__LINE__<<std::endl
#endif
#endif
/*! @defgroup gopenssl C++ Wrapper around OpenSSL API */ /*! @defgroup gopenssl C++ Wrapper around OpenSSL API */
//@{ //@{
@ -43,6 +61,7 @@ namespace openssl {
public: public:
exception(const std::string& reason) throw(): exception(const std::string& reason) throw():
_what("openssl: "+reason) { _what("openssl: "+reason) {
OPENSSL_LOG("**** exception ****");
} }
~exception() throw() {} ~exception() throw() {}
const char* what() const throw() { const char* what() const throw() {
@ -56,6 +75,15 @@ namespace openssl {
public: public:
openssl_error(const std::string& reason) throw(): openssl_error(const std::string& reason) throw():
exception(reason+'\n'+ERR_error_string(ERR_get_error(), 0)) { exception(reason+'\n'+ERR_error_string(ERR_get_error(), 0)) {
OPENSSL_LOG("**** exception ****");
}
};
//----------------------------------------------------------------------------
class cannot_init: public openssl_error {
public:
cannot_init(const std::string& reason) throw():
openssl_error("openssl initialization: "+reason) {
OPENSSL_LOG("**** exception ****");
} }
}; };
//---------------------------------------------------------------------------- //----------------------------------------------------------------------------
@ -63,6 +91,7 @@ namespace openssl {
public: public:
encryption_error(const std::string& reason) throw(): encryption_error(const std::string& reason) throw():
openssl_error("encryption: "+reason) { openssl_error("encryption: "+reason) {
OPENSSL_LOG("**** exception ****");
} }
}; };
//---------------------------------------------------------------------------- //----------------------------------------------------------------------------
@ -70,6 +99,7 @@ namespace openssl {
public: public:
pkcs12_error(const std::string& reason) throw(): pkcs12_error(const std::string& reason) throw():
openssl_error("pkcs12: "+reason) { openssl_error("pkcs12: "+reason) {
OPENSSL_LOG("**** exception ****");
} }
}; };
//---------------------------------------------------------------------------- //----------------------------------------------------------------------------
@ -77,6 +107,7 @@ namespace openssl {
public: public:
pkcs7_error(const std::string& reason) throw(): pkcs7_error(const std::string& reason) throw():
openssl_error("pkcs7: "+reason) { openssl_error("pkcs7: "+reason) {
OPENSSL_LOG("**** exception ****");
} }
}; };
//---------------------------------------------------------------------------- //----------------------------------------------------------------------------
@ -84,6 +115,7 @@ namespace openssl {
public: public:
x509_error(const std::string& reason) throw(): x509_error(const std::string& reason) throw():
openssl_error("x509: "+reason) { openssl_error("x509: "+reason) {
OPENSSL_LOG("**** exception ****");
} }
}; };
//---------------------------------------------------------------------------- //----------------------------------------------------------------------------
@ -91,13 +123,15 @@ namespace openssl {
public: public:
key_error(const std::string& reason) throw(): key_error(const std::string& reason) throw():
openssl_error("private key: "+reason) { openssl_error("private key: "+reason) {
OPENSSL_LOG("**** exception ****");
} }
}; };
//---------------------------------------------------------------------------- //----------------------------------------------------------------------------
class bio_error: public openssl_error { class tcp_error: public openssl_error {
public: public:
bio_error(const std::string& reason) throw(): tcp_error(const std::string& reason) throw():
openssl_error("bio: "+reason) { openssl_error("tcp "+reason) {
OPENSSL_LOG("**** exception ****");
} }
}; };
//---------------------------------------------------------------------------- //----------------------------------------------------------------------------
@ -105,6 +139,7 @@ namespace openssl {
public: public:
ssl_error(const std::string& reason) throw(): ssl_error(const std::string& reason) throw():
openssl_error("ssl: "+reason) { openssl_error("ssl: "+reason) {
OPENSSL_LOG("**** exception ****");
} }
}; };
//---------------------------------------------------------------------------- //----------------------------------------------------------------------------
@ -112,6 +147,7 @@ namespace openssl {
public: public:
cannot_encrypt(std::string reason) throw(): cannot_encrypt(std::string reason) throw():
encryption_error("cannot encrypt text: "+reason) { encryption_error("cannot encrypt text: "+reason) {
OPENSSL_LOG("**** exception ****");
} }
}; };
//---------------------------------------------------------------------------- //----------------------------------------------------------------------------
@ -119,6 +155,7 @@ namespace openssl {
public: public:
allocation_failed() throw(): allocation_failed() throw():
x509_error("memory allocation failed") { x509_error("memory allocation failed") {
OPENSSL_LOG("**** exception ****");
} }
}; };
//---------------------------------------------------------------------------- //----------------------------------------------------------------------------
@ -126,6 +163,7 @@ namespace openssl {
public: public:
x509_decoding_failed(const std::string& der) throw(): x509_decoding_failed(const std::string& der) throw():
x509_error("certificate decoding failed:\n"+crypto::readable(der)) { x509_error("certificate decoding failed:\n"+crypto::readable(der)) {
OPENSSL_LOG("**** exception ****");
} }
}; };
//---------------------------------------------------------------------------- //----------------------------------------------------------------------------
@ -133,6 +171,7 @@ namespace openssl {
public: public:
undefined_certificate() throw(): undefined_certificate() throw():
x509_error("certificate must not be 0") { x509_error("certificate must not be 0") {
OPENSSL_LOG("**** exception ****");
} }
}; };
//---------------------------------------------------------------------------- //----------------------------------------------------------------------------
@ -140,6 +179,7 @@ namespace openssl {
public: public:
x509_parsing_failed() throw(): x509_parsing_failed() throw():
x509_error("parsing DER encoded certificate failed") { x509_error("parsing DER encoded certificate failed") {
OPENSSL_LOG("**** exception ****");
} }
}; };
//---------------------------------------------------------------------------- //----------------------------------------------------------------------------
@ -147,6 +187,7 @@ namespace openssl {
public: public:
x509_copy_failed() throw(): x509_copy_failed() throw():
x509_error("certificate object copy failed") { x509_error("certificate object copy failed") {
OPENSSL_LOG("**** exception ****");
} }
}; };
//---------------------------------------------------------------------------- //----------------------------------------------------------------------------
@ -154,6 +195,7 @@ namespace openssl {
public: public:
key_copy_failed() throw(): key_copy_failed() throw():
key_error("key object copy failed") { key_error("key object copy failed") {
OPENSSL_LOG("**** exception ****");
} }
}; };
//---------------------------------------------------------------------------- //----------------------------------------------------------------------------
@ -161,6 +203,7 @@ namespace openssl {
public: public:
undefined_key() throw(): undefined_key() throw():
key_error("private key must not be 0") { key_error("private key must not be 0") {
OPENSSL_LOG("**** exception ****");
} }
}; };
//---------------------------------------------------------------------------- //----------------------------------------------------------------------------
@ -168,6 +211,7 @@ namespace openssl {
public: public:
pkcs12_reading_failed(const std::string& file) throw(): pkcs12_reading_failed(const std::string& file) throw():
pkcs12_error("reading DER encoded p12 file failed: "+file) { pkcs12_error("reading DER encoded p12 file failed: "+file) {
OPENSSL_LOG("**** exception ****");
} }
}; };
//---------------------------------------------------------------------------- //----------------------------------------------------------------------------
@ -175,23 +219,29 @@ namespace openssl {
public: public:
pkcs12_parsing_failed(const std::string& file) throw(): pkcs12_parsing_failed(const std::string& file) throw():
pkcs12_error("parsing DER encoded p12 file failed: "+file) { pkcs12_error("parsing DER encoded p12 file failed: "+file) {
OPENSSL_LOG("**** exception ****");
} }
}; };
//---------------------------------------------------------------------------- //----------------------------------------------------------------------------
class pkcs12_no_private_key: public pkcs12_error { class pkcs12_no_private_key: public pkcs12_error {
public: public:
pkcs12_no_private_key() throw(): pkcs12_error("no private key") {} pkcs12_no_private_key() throw(): pkcs12_error("no private key") {
OPENSSL_LOG("**** exception ****");
}
}; };
//---------------------------------------------------------------------------- //----------------------------------------------------------------------------
class pkcs12_no_x509: public pkcs12_error { class pkcs12_no_x509: public pkcs12_error {
public: public:
pkcs12_no_x509() throw(): pkcs12_error("no x509 certificate") {} pkcs12_no_x509() throw(): pkcs12_error("no x509 certificate") {
OPENSSL_LOG("**** exception ****");
}
}; };
//---------------------------------------------------------------------------- //----------------------------------------------------------------------------
class pkcs7_reading_failed: public pkcs7_error { class pkcs7_reading_failed: public pkcs7_error {
public: public:
pkcs7_reading_failed(const std::string& file) throw(): pkcs7_reading_failed(const std::string& file) throw():
pkcs7_error("reading DER encoded p7 file failed: "+file) { pkcs7_error("reading DER encoded p7 file failed: "+file) {
OPENSSL_LOG("**** exception ****");
} }
}; };
//---------------------------------------------------------------------------- //----------------------------------------------------------------------------
@ -199,6 +249,7 @@ namespace openssl {
public: public:
pkcs7_parsing_failed() throw(): pkcs7_parsing_failed() throw():
pkcs7_error("parsing DER encoded p7 failed") { pkcs7_error("parsing DER encoded p7 failed") {
OPENSSL_LOG("**** exception ****");
} }
pkcs7_parsing_failed(const std::string& file) throw(): pkcs7_parsing_failed(const std::string& file) throw():
pkcs7_error("parsing DER encoded p7 file failed: "+file) { pkcs7_error("parsing DER encoded p7 file failed: "+file) {
@ -207,52 +258,75 @@ namespace openssl {
//---------------------------------------------------------------------------- //----------------------------------------------------------------------------
class pkcs7_unsupported_format: public pkcs7_error { class pkcs7_unsupported_format: public pkcs7_error {
public: public:
pkcs7_unsupported_format() throw(): pkcs7_error("format not supported") {} pkcs7_unsupported_format() throw(): pkcs7_error("format not supported") {
OPENSSL_LOG("**** exception ****");
}
}; };
//---------------------------------------------------------------------------- //----------------------------------------------------------------------------
class pkcs7_no_x509: public pkcs7_error { class pkcs7_no_x509: public pkcs7_error {
public: public:
pkcs7_no_x509() throw(): pkcs7_error("no x509 certificate") {} pkcs7_no_x509() throw(): pkcs7_error("no x509 certificate") {
OPENSSL_LOG("**** exception ****");
}
}; };
//---------------------------------------------------------------------------- //----------------------------------------------------------------------------
class cannot_open_file: public exception { class cannot_open_file: public exception {
public: public:
cannot_open_file(const std::string& file) throw(): cannot_open_file(const std::string& file) throw():
exception("cannot open file: "+file) { exception("cannot open file: "+file) {
OPENSSL_LOG("**** exception ****");
} }
}; };
//---------------------------------------------------------------------------- //----------------------------------------------------------------------------
class bio_connection_failed: public bio_error { class tcp_connection_failed: public tcp_error {
public: public:
bio_connection_failed(const std::string& hostPort) throw(): tcp_connection_failed(const std::string& hostPort) throw():
bio_error("connection failed to: "+hostPort) { tcp_error("connection failed to: "+hostPort) {
OPENSSL_LOG("**** exception ****");
} }
}; };
//---------------------------------------------------------------------------- //----------------------------------------------------------------------------
class bio_closed_connection: public bio_error { class tcp_server_not_specified: public tcp_error {
public: public:
bio_closed_connection() throw(): bio_error("closed connection") {} tcp_server_not_specified() throw():
tcp_error("reconnect without prior connect") {
OPENSSL_LOG("**** exception ****");
}
}; };
//---------------------------------------------------------------------------- //----------------------------------------------------------------------------
class bio_read_error: public bio_error { class tcp_closed_connection: public tcp_error {
public: public:
bio_read_error() throw(): bio_error("read error") {} tcp_closed_connection() throw(): tcp_error("closed connection") {
OPENSSL_LOG("**** exception ****");
}
}; };
//---------------------------------------------------------------------------- //----------------------------------------------------------------------------
class bio_write_error: public bio_error { class tcp_read_error: public tcp_error {
public: public:
bio_write_error() throw(): bio_error("write error") {} tcp_read_error() throw(): tcp_error("read error") {
OPENSSL_LOG("**** exception ****");
}
};
//----------------------------------------------------------------------------
class tcp_write_error: public tcp_error {
public:
tcp_write_error() throw(): tcp_error("write error") {
OPENSSL_LOG("**** exception ****");
}
}; };
//---------------------------------------------------------------------------- //----------------------------------------------------------------------------
class ssl_cannot_create_context: public ssl_error { class ssl_cannot_create_context: public ssl_error {
public: public:
ssl_cannot_create_context() throw(): ssl_error("cannot create context") {} ssl_cannot_create_context() throw(): ssl_error("cannot create context") {
OPENSSL_LOG("**** exception ****");
}
}; };
//---------------------------------------------------------------------------- //----------------------------------------------------------------------------
class ssl_certificate_file_not_loaded: public ssl_error { class ssl_certificate_file_not_loaded: public ssl_error {
public: public:
ssl_certificate_file_not_loaded(const std::string& file) throw(): ssl_certificate_file_not_loaded(const std::string& file) throw():
ssl_error("certificate file not loaded: "+file) { ssl_error("certificate file not loaded: "+file) {
OPENSSL_LOG("**** exception ****");
} }
}; };
//---------------------------------------------------------------------------- //----------------------------------------------------------------------------
@ -260,6 +334,154 @@ namespace openssl {
public: public:
ssl_certificate_folder_not_loaded(const std::string& path) throw(): ssl_certificate_folder_not_loaded(const std::string& path) throw():
ssl_error("certificate folder not loaded: "+path) { ssl_error("certificate folder not loaded: "+path) {
OPENSSL_LOG("**** exception ****");
}
};
//----------------------------------------------------------------------------
class ssl_no_connection: public ssl_error {
public:
ssl_no_connection() throw():
ssl_error("no ssl connection") {
OPENSSL_LOG("**** exception ****");
}
};
//----------------------------------------------------------------------------
class ssl_verification_failed: public ssl_error {
public:
ssl_verification_failed(int num) throw():
ssl_error("certificate verification failed: "+reason(num)) {
OPENSSL_LOG("**** exception ****");
}
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.";
case X509_V_ERR_UNABLE_TO_GET_CRL: "X509_V_ERR_UNABLE_TO_GET_CRL:"
" 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();
}
}
} }
}; };
//@} //@}
@ -268,51 +490,18 @@ namespace openssl {
//@{ //@{
//============================================================================ //============================================================================
//! Initializes OpenSSL. Must be instanciated exactly once.
class Init { class Init {
public: public:
Init() { Init() {
OPENSSL_LOG("log");
SSL_load_error_strings(); SSL_load_error_strings();
ERR_load_BIO_strings(); ERR_load_BIO_strings();
OpenSSL_add_all_algorithms(); OpenSSL_add_all_algorithms();
if (!SSL_library_init()) throw cannot_init("cannot init SSL library");
} }
}; };
inline std::string desEnc(const std::string& txt, DES_cblock key1) {
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(&(DES_cblock&)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;
}
inline std::string desDec(const std::string& txt, DES_cblock key1) {
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(&(DES_cblock&)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;
}
class CBlock8 { class CBlock8 {
public: public:
CBlock8() { CBlock8() {
@ -356,10 +545,56 @@ namespace openssl {
DES_cblock _cb; DES_cblock _cb;
}; };
//! 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) {
OPENSSL_LOG("log");
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) {
OPENSSL_LOG("log");
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
/*! @param txt If the length is not an integral multiple of eight /*! @param txt If the length is not an integral multiple of eight
bytes, it is zero filled. The output is always an bytes, it is zero filled. The output is always an
integral multiple of eight bytes. */ integral multiple of eight bytes. */
inline std::string desCbcEnc(std::string txt, CBlock8 key, CBlock8& ivec) { inline std::string desCbcEnc(std::string txt, CBlock8 key, CBlock8& ivec) {
OPENSSL_LOG("log");
if (txt.size()%8!=0) txt.resize((txt.size()/8+1)*8, 0); if (txt.size()%8!=0) txt.resize((txt.size()/8+1)*8, 0);
std::string res(txt.size(), 0); std::string res(txt.size(), 0);
DES_key_schedule ks; DES_key_schedule ks;
@ -369,18 +604,22 @@ namespace openssl {
return res; return res;
} }
//! DES CBC Encryption with empty vector
/*! @param txt If the length is not an integral multiple of eight /*! @param txt If the length is not an integral multiple of eight
bytes, it is zero filled. The output is always an bytes, it is zero filled. The output is always an
integral multiple of eight bytes. */ integral multiple of eight bytes. */
inline std::string desCbcEnc(const std::string& txt, const CBlock8& key) { inline std::string desCbcEnc(const std::string& txt, const CBlock8& key) {
OPENSSL_LOG("log");
CBlock8 ivec; CBlock8 ivec;
return desCbcEnc(txt, key, ivec); return desCbcEnc(txt, key, ivec);
} }
//! DES CBC Decryption
/*! @param txt If the length is not an integral multiple of eight /*! @param txt If the length is not an integral multiple of eight
bytes, it is zero filled. The output is always an bytes, it is zero filled. The output is always an
integral multiple of eight bytes. */ integral multiple of eight bytes. */
inline std::string desCbcDec(std::string txt, CBlock8 key, CBlock8& ivec) { inline std::string desCbcDec(std::string txt, CBlock8 key, CBlock8& ivec) {
OPENSSL_LOG("log");
if (txt.size()%8!=0) txt.resize((txt.size()/8+1)*8, 0); if (txt.size()%8!=0) txt.resize((txt.size()/8+1)*8, 0);
std::string res(txt.size(), 0); std::string res(txt.size(), 0);
DES_key_schedule ks; DES_key_schedule ks;
@ -390,10 +629,12 @@ namespace openssl {
return res; return res;
} }
//! DES CBC Decryption with empty vector
/*! @param txt If the length is not an integral multiple of eight /*! @param txt If the length is not an integral multiple of eight
bytes, it is zero filled. The output is always an bytes, it is zero filled. The output is always an
integral multiple of eight bytes. */ integral multiple of eight bytes. */
inline std::string desCbcDec(const std::string& txt, const CBlock8& key) { inline std::string desCbcDec(const std::string& txt, const CBlock8& key) {
OPENSSL_LOG("log");
CBlock8 ivec; CBlock8 ivec;
return desCbcDec(txt, key, ivec); return desCbcDec(txt, key, ivec);
} }
@ -404,6 +645,7 @@ namespace openssl {
inline std::string des2edeCbcEnc(std::string txt, inline std::string des2edeCbcEnc(std::string txt,
CBlock8 key1, CBlock8 key2, CBlock8 key1, CBlock8 key2,
CBlock8 ivec = CBlock8()) { CBlock8 ivec = CBlock8()) {
OPENSSL_LOG("log");
if (txt.size()%8!=0) txt.resize((txt.size()/8+1)*8, 0); if (txt.size()%8!=0) txt.resize((txt.size()/8+1)*8, 0);
std::string res(txt.size(), 0); std::string res(txt.size(), 0);
DES_key_schedule ks1, ks2; DES_key_schedule ks1, ks2;
@ -420,6 +662,7 @@ namespace openssl {
inline std::string des2edeCbcDec(std::string txt, inline std::string des2edeCbcDec(std::string txt,
CBlock8 key1, CBlock8 key2, CBlock8 key1, CBlock8 key2,
CBlock8 ivec = CBlock8()) { CBlock8 ivec = CBlock8()) {
OPENSSL_LOG("log");
if (txt.size()%8!=0) txt.resize((txt.size()/8+1)*8, 0); if (txt.size()%8!=0) txt.resize((txt.size()/8+1)*8, 0);
std::string res(txt.size(), 0); std::string res(txt.size(), 0);
DES_key_schedule ks1, ks2; DES_key_schedule ks1, ks2;
@ -433,6 +676,7 @@ namespace openssl {
//! @todo untested //! @todo untested
inline std::string des2ecbEnc(std::string txt, inline std::string des2ecbEnc(std::string txt,
CBlock8 key1, CBlock8 key2) { CBlock8 key1, CBlock8 key2) {
OPENSSL_LOG("log");
std::string res; std::string res;
if (txt.size()%8!=0) if (txt.size()%8!=0)
throw cannot_encrypt("text size must be a multiple of eight"); throw cannot_encrypt("text size must be a multiple of eight");
@ -450,6 +694,7 @@ namespace openssl {
//! @todo untested //! @todo untested
inline std::string des2ecbDec(std::string txt, inline std::string des2ecbDec(std::string txt,
CBlock8 key1, CBlock8 key2) { CBlock8 key1, CBlock8 key2) {
OPENSSL_LOG("log");
std::string res; std::string res;
if (txt.size()%8!=0) if (txt.size()%8!=0)
throw cannot_encrypt("text size must be a multiple of eight"); throw cannot_encrypt("text size must be a multiple of eight");
@ -465,20 +710,24 @@ namespace openssl {
} }
//============================================================================ //============================================================================
//! X509 Certificate
class X509 { class X509 {
public: public:
//! Construct empty certificate. //! Construct empty certificate.
X509(): _x509(X509_new()) { X509(): _x509(X509_new()) {
OPENSSL_LOG("log");
if (!_x509) throw allocation_failed(); if (!_x509) throw allocation_failed();
} }
//! Initialize from DER encoded cerificate. //! Initialize from DER encoded cerificate.
X509(const std::string& der): _x509(0) { X509(const std::string& der): _x509(0) {
OPENSSL_LOG("log");
const unsigned char* c((const unsigned char*)der.begin().operator->()); const unsigned char* c((const unsigned char*)der.begin().operator->());
if (!(_x509=d2i_X509(0, &c, der.size())) || if (!(_x509=d2i_X509(0, &c, der.size())) ||
(const char*)c!=der.begin().operator->()+der.size()) (const char*)c!=der.begin().operator->()+der.size())
throw x509_decoding_failed(der); throw x509_decoding_failed(der);
} }
X509(const X509& o): _x509(0) { X509(const X509& o): _x509(0) {
OPENSSL_LOG("log");
unsigned char* d(0); unsigned char* d(0);
int len(i2d_X509(o._x509, &d)); int len(i2d_X509(o._x509, &d));
if (!len) throw x509_copy_failed(); if (!len) throw x509_copy_failed();
@ -489,12 +738,15 @@ namespace openssl {
} }
//! Take over OpenSSL allocated certificate. //! Take over OpenSSL allocated certificate.
X509(::X509 *x509): _x509(x509) { X509(::X509 *x509): _x509(x509) {
OPENSSL_LOG("log");
if (!_x509) throw undefined_certificate(); if (!_x509) throw undefined_certificate();
} }
~X509() { ~X509() {
OPENSSL_LOG("log");
X509_free(_x509); X509_free(_x509);
} }
X509& operator=(const X509& o) { X509& operator=(const X509& o) {
OPENSSL_LOG("log");
X509_free(_x509); X509_free(_x509);
_x509 = 0; _x509 = 0;
unsigned char* d(0); unsigned char* d(0);
@ -507,6 +759,7 @@ namespace openssl {
} }
//! Get DER encoded subject. //! Get DER encoded subject.
std::string subjectDER() const { std::string subjectDER() const {
OPENSSL_LOG("log");
unsigned char* c(0); unsigned char* c(0);
int len(i2d_X509_NAME(X509_get_subject_name(_x509), &c)); int len(i2d_X509_NAME(X509_get_subject_name(_x509), &c));
std::string res((char*)c, len); std::string res((char*)c, len);
@ -515,6 +768,7 @@ namespace openssl {
} }
//! Get DER encoded issuer. //! Get DER encoded issuer.
std::string issuerDER() const { std::string issuerDER() const {
OPENSSL_LOG("log");
unsigned char* c(0); unsigned char* c(0);
int len(i2d_X509_NAME(X509_get_issuer_name(_x509), &c)); int len(i2d_X509_NAME(X509_get_issuer_name(_x509), &c));
std::string res((char*)c, len); std::string res((char*)c, len);
@ -523,6 +777,7 @@ namespace openssl {
} }
//! Get DER encoded value. //! Get DER encoded value.
std::string valueDER() const { std::string valueDER() const {
OPENSSL_LOG("log");
unsigned char* c(0); unsigned char* c(0);
int len(i2d_X509(_x509, &c)); int len(i2d_X509(_x509, &c));
std::string res((char*)c, len); std::string res((char*)c, len);
@ -531,7 +786,8 @@ namespace openssl {
} }
//! Get serial number. //! Get serial number.
std::string serial() const { std::string serial() const {
/* @bug http://albistechnologies.com reports: «could be a OPENSSL_LOG("log");
/* @bug tcp://albistechnologies.com reports: «could be a
failure in openSSL: len too short by 1 if serial number failure in openSSL: len too short by 1 if serial number
starts with 00 ASN1_INTEGER* ser = starts with 00 ASN1_INTEGER* ser =
X509_get_serialNumber(_x509);» X509_get_serialNumber(_x509);»
@ -540,7 +796,7 @@ namespace openssl {
return std::string((char*)ser->data, ser->length); return std::string((char*)ser->data, ser->length);
@endcode @endcode
- requires memory free? - requires memory free?
- ser->type?!? http://albistechnologies.com prepends - ser->type?!? tcp://albistechnologies.com prepends
tag and length in the first two char-fields. */ tag and length in the first two char-fields. */
unsigned char* c(0); unsigned char* c(0);
int len(i2d_X509(_x509, &c)); int len(i2d_X509(_x509, &c));
@ -550,6 +806,7 @@ namespace openssl {
} }
//! Get id. //! Get id.
std::string id() const { std::string id() const {
OPENSSL_LOG("log");
unsigned char c[SHA_DIGEST_LENGTH]; unsigned char c[SHA_DIGEST_LENGTH];
SHA1(_x509->cert_info->key->public_key->data, SHA1(_x509->cert_info->key->public_key->data,
_x509->cert_info->key->public_key->length, _x509->cert_info->key->public_key->length,
@ -558,6 +815,7 @@ namespace openssl {
} }
//! Get common name. //! Get common name.
std::string commonName() const { std::string commonName() const {
OPENSSL_LOG("log");
X509_NAME *name(X509_get_subject_name(_x509)); X509_NAME *name(X509_get_subject_name(_x509));
ASN1_STRING* cn ASN1_STRING* cn
(X509_NAME_ENTRY_get_data (X509_NAME_ENTRY_get_data
@ -568,6 +826,7 @@ namespace openssl {
} }
//! Get country name. //! Get country name.
std::string countryName() const { std::string countryName() const {
OPENSSL_LOG("log");
X509_NAME *name(X509_get_subject_name(_x509)); X509_NAME *name(X509_get_subject_name(_x509));
ASN1_STRING* cn ASN1_STRING* cn
(X509_NAME_ENTRY_get_data (X509_NAME_ENTRY_get_data
@ -578,6 +837,7 @@ namespace openssl {
} }
//! Get locality name. //! Get locality name.
std::string localityName() const { std::string localityName() const {
OPENSSL_LOG("log");
X509_NAME *name(X509_get_subject_name(_x509)); X509_NAME *name(X509_get_subject_name(_x509));
ASN1_STRING* cn ASN1_STRING* cn
(X509_NAME_ENTRY_get_data (X509_NAME_ENTRY_get_data
@ -588,6 +848,7 @@ namespace openssl {
} }
//! Get state or province name. //! Get state or province name.
std::string stateOrProvinceName() const { std::string stateOrProvinceName() const {
OPENSSL_LOG("log");
X509_NAME *name(X509_get_subject_name(_x509)); X509_NAME *name(X509_get_subject_name(_x509));
ASN1_STRING* cn ASN1_STRING* cn
(X509_NAME_ENTRY_get_data (X509_NAME_ENTRY_get_data
@ -599,6 +860,7 @@ namespace openssl {
} }
//! Get organization name. //! Get organization name.
std::string organizationName() const { std::string organizationName() const {
OPENSSL_LOG("log");
X509_NAME *name(X509_get_subject_name(_x509)); X509_NAME *name(X509_get_subject_name(_x509));
ASN1_STRING* cn ASN1_STRING* cn
(X509_NAME_ENTRY_get_data (X509_NAME_ENTRY_get_data
@ -610,6 +872,7 @@ namespace openssl {
} }
//! Check whether it's a CA certificate. //! Check whether it's a CA certificate.
bool isCa() { bool isCa() {
OPENSSL_LOG("log");
BASIC_CONSTRAINTS* bc(0); BASIC_CONSTRAINTS* bc(0);
int pos(X509_get_ext_by_NID(_x509, NID_basic_constraints, -1)); int pos(X509_get_ext_by_NID(_x509, NID_basic_constraints, -1));
if (pos>=0) if (pos>=0)
@ -618,6 +881,7 @@ namespace openssl {
} }
//! Get organizational unit name. //! Get organizational unit name.
std::string organizationalUnitName() const { std::string organizationalUnitName() const {
OPENSSL_LOG("log");
X509_NAME *name(X509_get_subject_name(_x509)); X509_NAME *name(X509_get_subject_name(_x509));
ASN1_STRING* cn ASN1_STRING* cn
(X509_NAME_ENTRY_get_data (X509_NAME_ENTRY_get_data
@ -629,6 +893,7 @@ namespace openssl {
} }
//! Get key usage flags. //! Get key usage flags.
int keyUsageFlags() const { int keyUsageFlags() const {
OPENSSL_LOG("log");
int res(X509v3_KU_UNDEF); int res(X509v3_KU_UNDEF);
int pos(X509_get_ext_by_NID(_x509, NID_key_usage, -1)); int pos(X509_get_ext_by_NID(_x509, NID_key_usage, -1));
if (pos>=0) { if (pos>=0) {
@ -648,50 +913,65 @@ namespace openssl {
}; };
//============================================================================ //============================================================================
//! Private certificate key
class PrivateKey { class PrivateKey {
public: public:
PrivateKey(): _key(EVP_PKEY_new()) { PrivateKey(): _key(EVP_PKEY_new()) {
OPENSSL_LOG("log");
if (!_key) throw allocation_failed(); if (!_key) throw allocation_failed();
} }
PrivateKey(const PrivateKey& o): _key(0) { PrivateKey(const PrivateKey& o): _key(0) {
OPENSSL_LOG("log");
copy(o); copy(o);
} }
PrivateKey(EVP_PKEY* k): _key(k) { PrivateKey(EVP_PKEY* k): _key(k) {
OPENSSL_LOG("log");
if (!_key) throw undefined_key(); if (!_key) throw undefined_key();
} }
~PrivateKey() { ~PrivateKey() {
OPENSSL_LOG("log");
EVP_PKEY_free(_key); EVP_PKEY_free(_key);
} }
PrivateKey& operator=(const PrivateKey& o) { PrivateKey& operator=(const PrivateKey& o) {
OPENSSL_LOG("log");
copy(o); copy(o);
return *this; return *this;
} }
std::string modulus() const { std::string modulus() const {
OPENSSL_LOG("log");
return string(rsa()->n); return string(rsa()->n);
} }
std::string publicExponent() const { std::string publicExponent() const {
OPENSSL_LOG("log");
return string(rsa()->e); return string(rsa()->e);
} }
std::string privateExponent() const { std::string privateExponent() const {
OPENSSL_LOG("log");
return string(rsa()->d); return string(rsa()->d);
} }
std::string prime1() const { std::string prime1() const {
OPENSSL_LOG("log");
return string(rsa()->p); return string(rsa()->p);
} }
std::string prime2() const { std::string prime2() const {
OPENSSL_LOG("log");
return string(rsa()->q); return string(rsa()->q);
} }
std::string exponent1() const { std::string exponent1() const {
OPENSSL_LOG("log");
return string(rsa()->dmp1); return string(rsa()->dmp1);
} }
std::string exponent2() const { std::string exponent2() const {
OPENSSL_LOG("log");
return string(rsa()->dmq1); return string(rsa()->dmq1);
} }
std::string coefficient() const { std::string coefficient() const {
OPENSSL_LOG("log");
return string(rsa()->iqmp); return string(rsa()->iqmp);
} }
private: private:
void copy(const PrivateKey& o) { void copy(const PrivateKey& o) {
OPENSSL_LOG("log");
EVP_PKEY_free(_key); EVP_PKEY_free(_key);
if (!(_key=EVP_PKEY_new())) throw allocation_failed(); if (!(_key=EVP_PKEY_new())) throw allocation_failed();
rsa(o); rsa(o);
@ -700,47 +980,57 @@ namespace openssl {
/*ec(o);*/ /*ec(o);*/
} }
std::string string(BIGNUM* a) const { std::string string(BIGNUM* a) const {
OPENSSL_LOG("log");
std::string res(BN_num_bytes(a), '0'); std::string res(BN_num_bytes(a), '0');
BN_bn2bin(a, (unsigned char*)res.begin().operator->()); BN_bn2bin(a, (unsigned char*)res.begin().operator->());
return res; return res;
} }
void rsa(const PrivateKey& o) { void rsa(const PrivateKey& o) {
OPENSSL_LOG("log");
//! @todo throw exception if 0? //! @todo throw exception if 0?
RSA* tmp(o.rsa()); RSA* tmp(o.rsa());
if (tmp&&!EVP_PKEY_set1_RSA(_key, tmp)) throw key_copy_failed(); if (tmp&&!EVP_PKEY_set1_RSA(_key, tmp)) throw key_copy_failed();
} }
void dsa(const PrivateKey& o) { void dsa(const PrivateKey& o) {
OPENSSL_LOG("log");
DSA* tmp(o.dsa()); DSA* tmp(o.dsa());
if (tmp&&!EVP_PKEY_set1_DSA(_key, tmp)) throw key_copy_failed(); if (tmp&&!EVP_PKEY_set1_DSA(_key, tmp)) throw key_copy_failed();
} }
void dh(const PrivateKey& o) { void dh(const PrivateKey& o) {
OPENSSL_LOG("log");
DH* tmp(o.dh()); DH* tmp(o.dh());
if (tmp&&!EVP_PKEY_set1_DH(_key, tmp)) throw key_copy_failed(); if (tmp&&!EVP_PKEY_set1_DH(_key, tmp)) throw key_copy_failed();
} }
/* Not available on mac osx /* Not available on mac osx
void ec(const PrivateKey& o) { void ec(const PrivateKey& o) {
OPENSSL_LOG("log");
EC_KEY* tmp(o.ec()); EC_KEY* tmp(o.ec());
if (tmp&&!EVP_PKEY_set1_EC_KEY(_key, tmp)) throw key_copy_failed(); if (tmp&&!EVP_PKEY_set1_EC_KEY(_key, tmp)) throw key_copy_failed();
} }
*/ */
RSA* rsa() const { RSA* rsa() const {
OPENSSL_LOG("log");
//! @todo throw exception if 0? //! @todo throw exception if 0?
return EVP_PKEY_get1_RSA(_key); return EVP_PKEY_get1_RSA(_key);
} }
DSA* dsa() const { DSA* dsa() const {
OPENSSL_LOG("log");
return EVP_PKEY_get1_DSA(_key); return EVP_PKEY_get1_DSA(_key);
} }
DH* dh() const { DH* dh() const {
OPENSSL_LOG("log");
return EVP_PKEY_get1_DH(_key); return EVP_PKEY_get1_DH(_key);
} }
/* Not available on mac osx /* Not available on mac osx
EC_KEY* ec() const { EC_KEY* ec() const {
OPENSSL_LOG("log");
return EVP_PKEY_get1_EC_KEY(_key); return EVP_PKEY_get1_EC_KEY(_key);
}*/ }*/
EVP_PKEY* _key; EVP_PKEY* _key;
}; };
//============================================================================ //============================================================================
//! PKCS#12 certificate file handler
class PKCS12 { class PKCS12 {
//...............................................................typedefs //...............................................................typedefs
@ -753,6 +1043,7 @@ namespace openssl {
//! Read from a PKCS#12 (.p12) file. //! Read from a PKCS#12 (.p12) file.
PKCS12(std::string filename, std::string password): PKCS12(std::string filename, std::string password):
_key(0), _cert(0) { _key(0), _cert(0) {
OPENSSL_LOG("log");
FILE* file(fopen(filename.c_str(), "rb")); FILE* file(fopen(filename.c_str(), "rb"));
if (!file) throw cannot_open_file(filename); if (!file) throw cannot_open_file(filename);
::PKCS12 *p12(d2i_PKCS12_fp(file, 0)); ::PKCS12 *p12(d2i_PKCS12_fp(file, 0));
@ -776,6 +1067,7 @@ namespace openssl {
} }
~PKCS12() { ~PKCS12() {
OPENSSL_LOG("log");
delete _key; delete _key;
delete _cert; delete _cert;
for (X509List::iterator it(_ca.begin()); it!=_ca.end(); ++it) for (X509List::iterator it(_ca.begin()); it!=_ca.end(); ++it)
@ -783,24 +1075,29 @@ namespace openssl {
} }
bool hasPrivateKey() const { bool hasPrivateKey() const {
OPENSSL_LOG("log");
return _key; return _key;
} }
bool hasCert() const { bool hasCert() const {
OPENSSL_LOG("log");
return _cert; return _cert;
} }
const PrivateKey& privateKey() const { const PrivateKey& privateKey() const {
OPENSSL_LOG("log");
if (!_key) throw pkcs12_no_private_key(); if (!_key) throw pkcs12_no_private_key();
return *_key; return *_key;
}; };
const X509& x509() const { const X509& x509() const {
OPENSSL_LOG("log");
if (!_cert) throw pkcs12_no_x509(); if (!_cert) throw pkcs12_no_x509();
return *_cert; return *_cert;
}; };
const X509List& ca() const { const X509List& ca() const {
OPENSSL_LOG("log");
return _ca; return _ca;
} }
@ -811,6 +1108,7 @@ namespace openssl {
}; };
//============================================================================ //============================================================================
//! PKCS#7 certificate file handler
class PKCS7 { class PKCS7 {
//...............................................................typedefs //...............................................................typedefs
@ -842,6 +1140,7 @@ namespace openssl {
//! Read PKCS#7 from memory. //! Read PKCS#7 from memory.
PKCS7(const std::string& memory) { PKCS7(const std::string& memory) {
OPENSSL_LOG("log");
BIO* mem(BIO_new_mem_buf((void*)memory.data(), memory.size())); BIO* mem(BIO_new_mem_buf((void*)memory.data(), memory.size()));
::PKCS7 *p7(d2i_PKCS7_bio(mem, 0)); ::PKCS7 *p7(d2i_PKCS7_bio(mem, 0));
BIO_free(mem); BIO_free(mem);
@ -859,11 +1158,13 @@ namespace openssl {
} }
~PKCS7() { ~PKCS7() {
OPENSSL_LOG("log");
for (X509List::iterator it(_certs.begin()); it!=_certs.end(); ++it) for (X509List::iterator it(_certs.begin()); it!=_certs.end(); ++it)
delete *it; delete *it;
} }
const X509List& certs() const { const X509List& certs() const {
OPENSSL_LOG("log");
return _certs; return _certs;
} }
@ -872,18 +1173,27 @@ namespace openssl {
}; };
//============================================================================ //============================================================================
class BIO { //! TCP Connection
class TCP {
private: private:
BIO(const BIO&); TCP(const TCP&);
BIO& operator=(const BIO&); TCP& operator=(const TCP&);
public: public:
BIO(): _bio(0) {} TCP(): _bio(0) {
OPENSSL_LOG("log");
}
TCP(const std::string& hostPort): _bio(0) {
OPENSSL_LOG("log");
connect(hostPort);
}
~BIO() { virtual ~TCP() {
OPENSSL_LOG("log");
try { try {
close(); close();
} catch (...) { } catch (...) {
@ -891,20 +1201,36 @@ namespace openssl {
} }
} }
BIO& connect(const std::string& hostPort) { virtual TCP& connect(const std::string& hostPort) {
OPENSSL_LOG("log");
close(); close();
if (!(_bio=BIO_new_connect(const_cast<char*>(hostPort.c_str()))) || if (!(_bio=BIO_new_connect(const_cast<char*>(hostPort.c_str()))) ||
BIO_do_connect(_bio)<=0) BIO_do_connect(_bio)<=0)
throw bio_connection_failed(hostPort); throw tcp_connection_failed(hostPort);
_hostPort = hostPort;
return *this;
}
virtual TCP& connect() {
if (!_hostPort.size()) throw tcp_server_not_specified();
close();
connect(_hostPort);
return *this; return *this;
} }
BIO& operator>>(std::string& s) { operator bool() const {
OPENSSL_LOG("log");
return _bio>0;
}
TCP& operator>>(std::string& s) {
OPENSSL_LOG("log");
s += read(); s += read();
return *this; return *this;
} }
BIO& operator<<(const std::string& s) { TCP& operator<<(const std::string& s) {
OPENSSL_LOG("log");
return write(s); return write(s);
} }
@ -913,34 +1239,47 @@ namespace openssl {
server is waiting for next request, but connection is still server is waiting for next request, but connection is still
open? */ open? */
std::string read() { std::string read() {
if (!_bio) throw bio_closed_connection(); OPENSSL_LOG("log");
if (_bio<=0) throw tcp_closed_connection();
const int BUFF_SZ(1024); const int BUFF_SZ(1024);
char buff[BUFF_SZ]; char buff[BUFF_SZ];
int x(BIO_read(_bio, buff, BUFF_SZ)); int x(BIO_read(_bio, buff, BUFF_SZ));
if (x<=0) if (x<=0)
if (BIO_should_retry(_bio)) return read(); if (BIO_should_retry(_bio)) return read();
else throw bio_read_error(); else {
close();
if (x==0) return std::string();
else throw tcp_read_error();
}
else if (x==1024) return std::string(buff, x)+read();
return std::string(buff, x); return std::string(buff, x);
} }
BIO& write(const std::string& s) { TCP& write(const std::string& s) {
OPENSSL_LOG("log");
if (_bio<=0) throw tcp_closed_connection();
int x(BIO_write(_bio, s.begin().operator->(), s.size())); int x(BIO_write(_bio, s.begin().operator->(), s.size()));
if (x<=0) if (x<=0)
if (BIO_should_retry(_bio)) return write(s); if (BIO_should_retry(_bio)) return write(s);
else throw bio_write_error(); else {
else close();
if (x<s.size()) return write(s.substr(x)); throw tcp_write_error();
}
else if (x<s.size()) return write(s.substr(x));
return *this; return *this;
} }
void close() { virtual TCP& close() {
BIO_free_all(_bio); OPENSSL_LOG("log");
if (_bio>0) BIO_free_all(_bio);
_bio = 0;
return *this;
} }
private: protected:
friend class SSL;
::BIO* _bio; ::BIO* _bio;
std::string _hostPort;
}; };
@ -949,8 +1288,10 @@ namespace openssl {
public: public:
TrustStore(const std::string& pathToPemFile): TrustStore(const std::string& pathToPemFile):
_file(pathToPemFile) { _file(pathToPemFile) {
OPENSSL_LOG("log");
} }
const std::string& file() const { const std::string& file() const {
OPENSSL_LOG("log");
return _file; return _file;
} }
private: private:
@ -961,15 +1302,17 @@ namespace openssl {
public: public:
CertificateFolder(const std::string& certificateFolder): CertificateFolder(const std::string& certificateFolder):
_path(certificateFolder) { _path(certificateFolder) {
OPENSSL_LOG("log");
} }
const std::string& path() const { const std::string& path() const {
OPENSSL_LOG("log");
return _path; return _path;
} }
private: private:
std::string _path; std::string _path;
}; };
class SSL { class SSL: public TCP {
private: private:
SSL(); SSL();
SSL(const SSL&); SSL(const SSL&);
@ -978,6 +1321,7 @@ namespace openssl {
SSL(const TrustStore& file): SSL(const TrustStore& file):
_ctx(SSL_CTX_new(SSLv23_client_method())), _ctx(SSL_CTX_new(SSLv23_client_method())),
_ssl(0) { _ssl(0) {
OPENSSL_LOG("log");
if (!_ctx) throw ssl_cannot_create_context(); if (!_ctx) throw ssl_cannot_create_context();
if (!SSL_CTX_load_verify_locations(_ctx, file.file().c_str(), 0)) if (!SSL_CTX_load_verify_locations(_ctx, file.file().c_str(), 0))
throw ssl_certificate_file_not_loaded(file.file()); throw ssl_certificate_file_not_loaded(file.file());
@ -985,42 +1329,63 @@ namespace openssl {
SSL(const CertificateFolder& folder): SSL(const CertificateFolder& folder):
_ctx(SSL_CTX_new(SSLv23_client_method())), _ctx(SSL_CTX_new(SSLv23_client_method())),
_ssl(0) { _ssl(0) {
OPENSSL_LOG("log");
if (!_ctx) throw ssl_cannot_create_context(); if (!_ctx) throw ssl_cannot_create_context();
if (!SSL_CTX_load_verify_locations(_ctx, 0, folder.path().c_str())) if (!SSL_CTX_load_verify_locations(_ctx, 0, folder.path().c_str()))
throw ssl_certificate_folder_not_loaded(folder.path()); throw ssl_certificate_folder_not_loaded(folder.path());
} }
~SSL() { ~SSL() {
OPENSSL_LOG("log");
close(); close();
SSL_CTX_free(_ctx); SSL_CTX_free(_ctx);
} }
BIO& connect(const std::string& hostPort) { virtual SSL& connect(const std::string& hostPort) {
OPENSSL_LOG("log");
close(); close();
if (!(_bio._bio=BIO_new_ssl_connect(_ctx))) if (!(_bio=BIO_new_ssl_connect(_ctx)))
throw bio_connection_failed(hostPort); throw tcp_connection_failed(hostPort);
BIO_get_ssl(_bio._bio, &_ssl); BIO_get_ssl(_bio, &_ssl);
if (!_ssl) if (!_ssl) throw ssl_no_connection();
SSL_set_mode(_ssl, SSL_MODE_AUTO_RETRY); SSL_set_mode(_ssl, SSL_MODE_AUTO_RETRY);
BIO_set_conn_hostname(_bio._bio, const_cast<char*>(hostPort.c_str())); BIO_set_conn_hostname(_bio, const_cast<char*>(hostPort.c_str()));
if (BIO_do_connect(_bio._bio)<=0) throw bio_connection_failed(hostPort); if (BIO_do_connect(_bio)<=0)
return _bio; throw tcp_connection_failed(hostPort);
verify();
return *this;
} }
SSL& close() { virtual SSL& close() {
_bio.close(); OPENSSL_LOG("log");
TCP::close();
_ssl = 0; //! @todo is this correct? <-- _ssl = 0; //! @todo is this correct? <--
return *this; return *this;
} }
bool verifyResult() { protected:
return _ssl && SSL_get_verify_result(_ssl)==X509_V_OK; void verify() {
OPENSSL_LOG("log");
if (!_ssl) throw ssl_no_connection();
int res(SSL_get_verify_result(_ssl));
if (res!=X509_V_OK) throw ssl_verification_failed(res);
} }
private: private:
SSL_CTX *_ctx; SSL_CTX *_ctx;
::SSL *_ssl; ::SSL *_ssl;
BIO _bio;
}; };
//@} //@}
} }
std::ostream& operator<<(std::ostream& os, openssl::TCP& is) {
return os<<is.read();
}
std::istream& operator>>(std::istream& is, openssl::TCP& os) {
std::string s;
is>>s;
os<<s;
return is;
}
//@} //@}
#endif #endif

Loading…
Cancel
Save