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