TCP- and SSL-Connection Examples
This commit is contained in:
		| @@ -3,7 +3,7 @@ | ||||
| ##       1         2         3         4         5         6         7         8 | ||||
| ## 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 | ||||
| if !MINGW32 | ||||
| @@ -27,4 +27,20 @@ else | ||||
| cryptoki_demo_LDADD += -ldl -lpthread -lssl | ||||
| 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 | ||||
|   | ||||
							
								
								
									
										28
									
								
								doc/examples/openssl-ssl-demo.cxx
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										28
									
								
								doc/examples/openssl-ssl-demo.cxx
									
									
									
									
									
										Normal file
									
								
							| @@ -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; | ||||
|  } | ||||
							
								
								
									
										25
									
								
								doc/examples/openssl-tcp-demo.cxx
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										25
									
								
								doc/examples/openssl-tcp-demo.cxx
									
									
									
									
									
										Normal file
									
								
							| @@ -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; | ||||
|  } | ||||
							
								
								
									
										547
									
								
								src/openssl.hxx
									
									
									
									
									
								
							
							
						
						
									
										547
									
								
								src/openssl.hxx
									
									
									
									
									
								
							| @@ -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 bio_connection_failed: public bio_error { | ||||
|   class tcp_connection_failed: public tcp_error { | ||||
|     public: | ||||
|       bio_connection_failed(const std::string& hostPort) throw(): | ||||
|           bio_error("connection failed to: "+hostPort) { | ||||
|       tcp_connection_failed(const std::string& hostPort) throw(): | ||||
|           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: | ||||
|       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: | ||||
|       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: | ||||
|       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 { | ||||
|     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; | ||||
|       } | ||||
|  | ||||
|       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; | ||||
|       } | ||||
|        | ||||
|       BIO& operator>>(std::string& s) { | ||||
|       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 | ||||
|   | ||||
		Reference in New Issue
	
	Block a user