void Init_mini_ssl(VALUE puma) { VALUE mod, eng; SSL_library_init(); OpenSSL_add_ssl_algorithms(); SSL_load_error_strings(); ERR_load_crypto_strings(); mod = rb_define_module_under(puma, "MiniSSL"); eng = rb_define_class_under(mod, "Engine", rb_cObject); rb_define_singleton_method(mod, "check", noop, 0); eError = rb_define_class_under(mod, "SSLError", rb_eStandardError); rb_define_singleton_method(eng, "server", engine_init_server, 1); rb_define_singleton_method(eng, "client", engine_init_client, 0); rb_define_method(eng, "inject", engine_inject, 1); rb_define_method(eng, "read", engine_read, 0); rb_define_method(eng, "write", engine_write, 1); rb_define_method(eng, "extract", engine_extract, 0); rb_define_method(eng, "peercert", engine_peercert, 0); }
static std::unordered_map<uint16_t, std::string> getOpenSSLCipherNames() { std::unordered_map<uint16_t, std::string> ret; SSL_CTX* ctx = nullptr; SSL* ssl = nullptr; const SSL_METHOD* meth = SSLv23_server_method(); OpenSSL_add_ssl_algorithms(); if ((ctx = SSL_CTX_new(meth)) == nullptr) { return ret; } SCOPE_EXIT { SSL_CTX_free(ctx); }; if ((ssl = SSL_new(ctx)) == nullptr) { return ret; } SCOPE_EXIT { SSL_free(ssl); }; STACK_OF(SSL_CIPHER)* sk = SSL_get_ciphers(ssl); for (int i = 0; i < sk_SSL_CIPHER_num(sk); i++) { const SSL_CIPHER* c = sk_SSL_CIPHER_value(sk, i); unsigned long id = SSL_CIPHER_get_id(c); // OpenSSL 1.0.2 and prior does weird things such as stuff the SSL/TLS // version into the top 16 bits. Let's ignore those for now. This is // BoringSSL compatible (their id can be cast as uint16_t) uint16_t cipherCode = id & 0xffffL; ret[cipherCode] = SSL_CIPHER_get_name(c); } return ret; }
int git_openssl_stream_global_init(void) { #ifdef GIT_OPENSSL long ssl_opts = SSL_OP_NO_SSLv2 | SSL_OP_NO_SSLv3; /* Older OpenSSL and MacOS OpenSSL doesn't have this */ #ifdef SSL_OP_NO_COMPRESSION ssl_opts |= SSL_OP_NO_COMPRESSION; #endif SSL_load_error_strings(); OpenSSL_add_ssl_algorithms(); /* * Load SSLv{2,3} and TLSv1 so that we can talk with servers * which use the SSL hellos, which are often used for * compatibility. We then disable SSL so we only allow OpenSSL * to speak TLSv1 to perform the encryption itself. */ git__ssl_ctx = SSL_CTX_new(SSLv23_method()); SSL_CTX_set_options(git__ssl_ctx, ssl_opts); SSL_CTX_set_mode(git__ssl_ctx, SSL_MODE_AUTO_RETRY); SSL_CTX_set_verify(git__ssl_ctx, SSL_VERIFY_NONE, NULL); if (!SSL_CTX_set_default_verify_paths(git__ssl_ctx)) { SSL_CTX_free(git__ssl_ctx); git__ssl_ctx = NULL; return -1; } #endif git__on_shutdown(shutdown_ssl); return 0; }
BOOL CSSLTcpSocket::CreateSSLTcpSocketForClient() { SSL_load_error_strings(); /*为打印调试信息作准备*/ OpenSSL_add_ssl_algorithms(); /*初始化*/ m_meth = (SSL_METHOD *)TLSv1_client_method(); /*采用什么协议(SSLv2/SSLv3/TLSv1)在此指定,TLSv1_server_method,SSLv23_server_method()*/ m_ctx = SSL_CTX_new (m_meth); //设置为要求强制校验对方(客户端)证书SSL_VERIFY_PEER|SSL_VERIFY_FAIL_IF_NO_PEER_CERT SSL_CTX_set_verify(m_ctx,SSL_VERIFY_NONE,NULL); /*验证与否SSL_VERIFY_PEER*/ //SSL_CTX_load_verify_locations(ctx,CACERT,NULL); /*若验证,则放置CA证书*/ //RAND_seed // if (!SSL_CTX_check_private_key(m_ctx)) { // printf("密钥证书不匹配!\n"); // } // SSL_CTX_set_cipher_list(m_ctx,"DES-CBC3-SHA"); // SSL_CTX_set_mode(m_ctx, SSL_MODE_AUTO_RETRY); CreateTcpSocket(); m_ssl = SSL_new (m_ctx); SSL_set_fd (m_ssl, m_TcpSock); return FALSE; }
BOOL CSSLTcpSocket::CreateSSLTcpSocketForServer( LPCSTR pszCertFile , LPCSTR pszKeyFile ) { SSL_load_error_strings(); /*为打印调试信息作准备*/ OpenSSL_add_ssl_algorithms(); /*初始化*/ m_meth = (SSL_METHOD *)TLSv1_server_method(); /*采用什么协议(SSLv2/SSLv3/TLSv1)在此指定,TLSv1_server_method,SSLv23_server_method()*/ m_ctx = SSL_CTX_new (m_meth); //设置为要求强制校验对方(客户端)证书SSL_VERIFY_PEER|SSL_VERIFY_FAIL_IF_NO_PEER_CERT SSL_CTX_set_verify(m_ctx,SSL_VERIFY_NONE,NULL); /*验证与否SSL_VERIFY_PEER*/ //SSL_CTX_load_verify_locations(ctx,CACERT,NULL); /*若验证,则放置CA证书*/ if (SSL_CTX_use_certificate_file(m_ctx, pszCertFile, SSL_FILETYPE_PEM) <= 0) { printf("加载证书失败!\n"); } if (SSL_CTX_use_PrivateKey_file(m_ctx, pszKeyFile, SSL_FILETYPE_PEM) <= 0) { printf("加载私钥失败!\n"); } if (!SSL_CTX_check_private_key(m_ctx)) { printf("密钥证书不匹配!\n"); } SSL_CTX_set_cipher_list(m_ctx,"DES-CBC3-SHA"); SSL_CTX_set_mode(m_ctx, SSL_MODE_AUTO_RETRY); return CreateTcpSocket(); }
static int apps_startup() { #ifdef SIGPIPE signal(SIGPIPE, SIG_IGN); #endif CRYPTO_malloc_init(); ERR_load_crypto_strings(); ERR_load_SSL_strings(); OPENSSL_load_builtin_modules(); #ifndef OPENSSL_NO_ENGINE ENGINE_load_builtin_engines(); #endif if (!app_load_modules(NULL)) { ERR_print_errors(bio_err); BIO_printf(bio_err, "Error loading default configuration\n"); return 0; } OpenSSL_add_all_algorithms(); OpenSSL_add_ssl_algorithms(); setup_ui_method(); /*SSL_library_init();*/ return 1; }
static int OPENSSL_init_ssl(int opts, void *settings) { GIT_UNUSED(opts); GIT_UNUSED(settings); SSL_load_error_strings(); OpenSSL_add_ssl_algorithms(); return 0; }
static void ssl_ensure_initialized(){ static bool initialized = false; if(initialized) return; SSL_library_init(); OpenSSL_add_ssl_algorithms(); SSL_load_error_strings(); initialized = true; }
int git_openssl_stream_global_init(void) { #ifdef GIT_OPENSSL long ssl_opts = SSL_OP_NO_SSLv2 | SSL_OP_NO_SSLv3; const char *ciphers = git_libgit2__ssl_ciphers(); /* Older OpenSSL and MacOS OpenSSL doesn't have this */ #ifdef SSL_OP_NO_COMPRESSION ssl_opts |= SSL_OP_NO_COMPRESSION; #endif #if OPENSSL_VERSION_NUMBER < 0x10100000L || \ (defined(LIBRESSL_VERSION_NUMBER) && LIBRESSL_VERSION_NUMBER < 0x20700000L) SSL_load_error_strings(); OpenSSL_add_ssl_algorithms(); #else OPENSSL_init_ssl(0, NULL); #endif /* * Load SSLv{2,3} and TLSv1 so that we can talk with servers * which use the SSL hellos, which are often used for * compatibility. We then disable SSL so we only allow OpenSSL * to speak TLSv1 to perform the encryption itself. */ git__ssl_ctx = SSL_CTX_new(SSLv23_method()); SSL_CTX_set_options(git__ssl_ctx, ssl_opts); SSL_CTX_set_mode(git__ssl_ctx, SSL_MODE_AUTO_RETRY); SSL_CTX_set_verify(git__ssl_ctx, SSL_VERIFY_NONE, NULL); if (!SSL_CTX_set_default_verify_paths(git__ssl_ctx)) { SSL_CTX_free(git__ssl_ctx); git__ssl_ctx = NULL; return -1; } if (!ciphers) { ciphers = GIT_SSL_DEFAULT_CIPHERS; } if(!SSL_CTX_set_cipher_list(git__ssl_ctx, ciphers)) { SSL_CTX_free(git__ssl_ctx); git__ssl_ctx = NULL; return -1; } if (init_bio_method() < 0) { SSL_CTX_free(git__ssl_ctx); git__ssl_ctx = NULL; return -1; } #endif git__on_shutdown(shutdown_ssl); return 0; }
/* Initialize the SSL library internals for use by the messaging bus. */ bool BusSSL_Init(struct bus *b) { if (!SSL_library_init()) { return false; } SSL_load_error_strings(); ERR_load_BIO_strings(); OpenSSL_add_ssl_algorithms(); SSL_CTX *ctx = NULL; if (!init_client_SSL_CTX(&ctx)) { return false; } b->ssl_ctx = ctx; return true; }
extern void InitNET(void) { bindtextdomain(PACKAGE, LOCALEDIR); #ifdef USE_SSL ssl_error_message[0] = '\0'; ssl_warning_message[0] = '\0'; OpenSSL_add_ssl_algorithms(); OpenSSL_add_all_algorithms(); ERR_load_crypto_strings(); SSL_load_error_strings(); #endif }
static void init_ssl(void) { #ifdef GIT_SSL SSL_load_error_strings(); OpenSSL_add_ssl_algorithms(); /* * Load SSLv{2,3} and TLSv1 so that we can talk with servers * which use the SSL hellos, which are often used for * compatibility. We then disable SSL so we only allow OpenSSL * to speak TLSv1 to perform the encryption itself. */ git__ssl_ctx = SSL_CTX_new(SSLv23_method()); SSL_CTX_set_options(git__ssl_ctx, SSL_OP_NO_SSLv2 | SSL_OP_NO_SSLv3 /* Older OpenSSL and MacOS OpenSSL doesn't have this */ # ifdef SSL_OP_NO_COMPRESSION | SSL_OP_NO_COMPRESSION # endif ); SSL_CTX_set_mode(git__ssl_ctx, SSL_MODE_AUTO_RETRY); SSL_CTX_set_verify(git__ssl_ctx, SSL_VERIFY_NONE, NULL); if (!SSL_CTX_set_default_verify_paths(git__ssl_ctx)) { SSL_CTX_free(git__ssl_ctx); git__ssl_ctx = NULL; } # ifdef GIT_THREADS { int num_locks, i; num_locks = CRYPTO_num_locks(); openssl_locks = git__calloc(num_locks, sizeof(git_mutex)); if (openssl_locks == NULL) { SSL_CTX_free(git__ssl_ctx); git__ssl_ctx = NULL; } for (i = 0; i < num_locks; i++) { if (git_mutex_init(&openssl_locks[i]) != 0) { SSL_CTX_free(git__ssl_ctx); git__ssl_ctx = NULL; } } CRYPTO_set_locking_callback(openssl_locking_function); } git__on_shutdown(shutdown_ssl); # endif #endif }
void initSSL() { SSL_load_error_strings(); OpenSSL_add_ssl_algorithms(); srvctx=SSL_CTX_new(SSLv23_server_method()); /* setting up the server context */ if(srvctx==NULL) { p_log(LOG_ERROR,-1,lngtxt(970)); exit(0x1); } if (SSL_CTX_use_certificate_file(srvctx, SSLCERT, SSL_FILETYPE_PEM) <= 0) { p_log(LOG_ERROR,-1,lngtxt(971), SSLCERT); exit(0x1); } if (SSL_CTX_use_PrivateKey_file(srvctx, SSLKEY, SSL_FILETYPE_PEM) <= 0) { p_log(LOG_ERROR,-1,lngtxt(972), SSLKEY); exit(0x1); } if (!SSL_CTX_check_private_key(srvctx)) { p_log(LOG_ERROR,-1,lngtxt(973)); exit(0x1); } /* create client context */ clnctx=SSL_CTX_new(SSLv23_client_method()); if(clnctx==NULL) { p_log(LOG_ERROR,-1,lngtxt(974)); exit(0x1); } if (SSL_CTX_use_certificate_file(clnctx, SSLCERT, SSL_FILETYPE_PEM) <= 0) { p_log(LOG_ERROR,-1,lngtxt(975), SSLCERT); exit(3); } if (SSL_CTX_use_PrivateKey_file(clnctx, SSLKEY, SSL_FILETYPE_PEM) <= 0) { p_log(LOG_ERROR,-1,lngtxt(976), SSLKEY); exit(4); } if (!SSL_CTX_check_private_key(clnctx)) { p_log(LOG_ERROR,-1,lngtxt(977)); exit(5); } p_log(LOG_INFO,-1,lngtxt(978)); return; }
P_ST_TLS_STRUCT st_tls_create_ctx(P_ST_TLS_STRUCT p_st_tls) { P_SSL_CTX p_ctx = NULL; OpenSSL_add_ssl_algorithms(); SSL_load_error_strings(); SSL_library_init(); //SSL_library_init() always returns "1" tls_rand_seed(); if ( p_st_tls->work_status == WORK_SERVER ) { st_print("Initialize with TLSv1_server_method() \n"); RET_NULL_IF_TRUE_S(!(p_ctx = SSL_CTX_new(TLSv1_server_method()))); } else if ( p_st_tls->work_status == WORK_CLIENT ) { st_print("Initialize with TLSv1_client_method() \n"); RET_NULL_IF_TRUE_S(!(p_ctx = SSL_CTX_new(TLSv1_client_method()))); } else { st_print("Initialize with TLSv1_method() \n"); RET_NULL_IF_TRUE_S(!(p_ctx = SSL_CTX_new(TLSv1_method()))); } //SSL_CTX_set_default_passwd_cb(p_ctx, no_passphrase_callback); SSL_CTX_set_mode(p_ctx, SSL_MODE_ENABLE_PARTIAL_WRITE); if ( strlen(p_st_tls->ca_file) ) { RET_NULL_IF_TRUE_S( !SSL_CTX_load_verify_locations(p_ctx, p_st_tls->ca_file, NULL)); } else { st_print("No CAfile Verify!\n"); } RET_NULL_IF_TRUE_S( !SSL_CTX_use_PrivateKey_file(p_ctx, p_st_tls->key_file, SSL_FILETYPE_PEM)); RET_NULL_IF_TRUE_S( !SSL_CTX_use_certificate_chain_file(p_ctx, p_st_tls->cert_file)); // 判定私钥是否正确 RET_NULL_IF_TRUE_S( !SSL_CTX_check_private_key(p_ctx)); p_st_tls->p_ctx = p_ctx; return p_st_tls; }
void DDS_SP_init_library (void) { if (!dds_openssl_init_global) return; DDS_Security_set_library_lock (); OpenSSL_add_ssl_algorithms (); #ifdef DDS_DEBUG SSL_load_error_strings (); #endif dds_openssl_init_global = 0; }
/** * @desc Initialize OpenSSL lib * @throw Char * */ void IOSocketSSL::initSSL(const bool force_server_method = false) { TRACE_CALL(); SSL_load_error_strings(); ERR_load_BIO_strings(); OpenSSL_add_all_algorithms(); OpenSSL_add_ssl_algorithms(); switch (socket_t) { case IOSOCKET_LISTEN_T: ctx = SSL_CTX_new(SSLv3_server_method()); break; case IOSOCKET_CONNECT_T: if (force_server_method) ctx = SSL_CTX_new(SSLv3_server_method()); else ctx = SSL_CTX_new(SSLv3_client_method()); break; default: /* Shouln't happen, mother class constructor should have thrown * an exception earlier */ throw("Unknown socket type"); break; } /** * Should use a loop on ERR_get_error() * to retrieve the whole error process */ if (ctx == NULL) throw(new_SSL_error("initializing ssl context")); if (SSL_CTX_use_certificate_file(ctx, cert_file, SSL_FILETYPE_PEM) != 1) throw(new_SSL_error("loading cert file")); if (SSL_CTX_use_PrivateKey_file(ctx, key_file, SSL_FILETYPE_PEM) != 1) throw(new_SSL_error("loading private key file")); if (SSL_CTX_check_private_key(ctx) != 1) throw(new_SSL_error("verifying private key")); /* Don't bother with renego */ SSL_CTX_set_mode(ctx, SSL_MODE_AUTO_RETRY); init_ssl = true; }
static void apps_startup() { #ifdef SIGPIPE signal(SIGPIPE, SIG_IGN); #endif CRYPTO_malloc_init(); ERR_load_crypto_strings(); ERR_load_SSL_strings(); OpenSSL_add_all_algorithms(); OpenSSL_add_ssl_algorithms(); OPENSSL_load_builtin_modules(); setup_ui_method(); /*SSL_library_init();*/ #ifndef OPENSSL_NO_ENGINE ENGINE_load_builtin_engines(); #endif }
kul::https::Server& kul::https::Server::init(){ if(!crt) KEXCEPTION("HTTPS Server crt file does not exist: " + crt.full()); if(!key) KEXCEPTION("HTTPS Server key file does not exist: " + key.full()); SSL_library_init(); SSL_load_error_strings(); OpenSSL_add_ssl_algorithms(); ctx = SSL_CTX_new(TLSv1_2_server_method()); if (!ctx) KEXCEPTION("HTTPS Server SSL_CTX failed SSL_CTX_new"); if(SSL_CTX_use_certificate_file(ctx, crt.mini().c_str(), SSL_FILETYPE_PEM) <= 0) KEXCEPTION("HTTPS Server SSL_CTX_use_certificate_file failed"); if(SSL_CTX_use_PrivateKey_file(ctx, key.mini().c_str(), SSL_FILETYPE_PEM) <= 0) KEXCEPTION("HTTPS Server SSL_CTX_use_PrivateKey_file failed"); if (!SSL_CTX_check_private_key(ctx)) KEXCEPTION("HTTPS Server SSL_CTX_check_private_key failed"); if(!cs.empty() && !SSL_CTX_set_cipher_list(ctx, cs.c_str())) KEXCEPTION("HTTPS Server SSL_CTX_set_cipher_listctx failed"); return *this; }
int AC_CLD_Connector::open (ACE_Reactor *r, int flags) { if (PARENT::open (r, flags) != 0) return -1; OpenSSL_add_ssl_algorithms (); ssl_ctx_ = SSL_CTX_new (SSLv3_client_method ()); if (ssl_ctx_ == 0) return -1; if (SSL_CTX_use_certificate_file (ssl_ctx_, CLD_CERTIFICATE_FILENAME, SSL_FILETYPE_PEM) <= 0 || SSL_CTX_use_PrivateKey_file (ssl_ctx_, CLD_KEY_FILENAME, SSL_FILETYPE_PEM) <= 0 || !SSL_CTX_check_private_key (ssl_ctx_)) return -1; ssl_ = SSL_new (ssl_ctx_); if (ssl_ == 0) return -1; return 0; }
static void _hssl_library_init(void) { static int initialized = 0; if (!initialized) { log_verbose1("Initializing library"); SSL_library_init(); SSL_load_error_strings(); ERR_load_crypto_strings(); OpenSSL_add_ssl_algorithms(); initialized = 1; } return; }
int ssl_init(void) { if (!prng_init()) { Debug((DEBUG_NOTICE, "PRNG seeded")); } if ((bootopt & BOOT_TTY) && (bootopt & BOOT_DEBUG)) (void)fprintf(stderr, "ssl_init(): SSL_load_error_strings()\n" ); SSL_load_error_strings(); if ((bootopt & BOOT_TTY) && (bootopt & BOOT_DEBUG)) (void)fprintf(stderr, "ssl_init(): OpenSSL_add_ssl_algorythms()\n"); OpenSSL_add_ssl_algorithms(); if ((bootopt & BOOT_TTY) && (bootopt & BOOT_DEBUG)) (void)fprintf(stderr, "ssl_init(): SSL_CTX_new()\n"); ctx = SSL_CTX_new(SSLv23_server_method()); if (!ctx) { Debug((DEBUG_ERROR, "CTX_new: %s", ERR_error_string(ERR_get_error(), NULL))); return 0; } if ((bootopt & BOOT_TTY) && (bootopt & BOOT_DEBUG)) (void)fprintf(stderr, "ssl_init(): SSL_CTX_use_certificate_file()\n"); if (SSL_CTX_use_certificate_file(ctx, IRCD_CRT, SSL_FILETYPE_PEM) <= 0) { (void)disable_ssl(1); return 0; } if ((bootopt & BOOT_TTY) && (bootopt & BOOT_DEBUG)) (void)fprintf(stderr, "ssl_init(): SSL_CTX_use_PrivateKey_file()\n"); if (SSL_CTX_use_PrivateKey_file(ctx, IRCD_KEY, SSL_FILETYPE_PEM) <= 0) { (void)disable_ssl(1); return 0; } if ((bootopt & BOOT_TTY) && (bootopt & BOOT_DEBUG)) (void)fprintf(stderr, "ssl_init(): SSL_CTX_check_private_key()\n"); if (!SSL_CTX_check_private_key(ctx)) { (void)disable_ssl(1); return 0; } return 1; }
int TPC_Logging_Acceptor::open (const ACE_SOCK_Acceptor::PEER_ADDR &local_addr, ACE_Reactor *reactor, int flags, int use_select, int reuse_addr) { if (PARENT::open (local_addr, reactor, flags, use_select, reuse_addr) != 0) return -1; OpenSSL_add_ssl_algorithms (); ssl_ctx_ = SSL_CTX_new (SSLv3_server_method ()); if (ssl_ctx_ == 0) return -1; if (SSL_CTX_use_certificate_file (ssl_ctx_, TPC_CERTIFICATE_FILENAME, SSL_FILETYPE_PEM) <= 0 || SSL_CTX_use_PrivateKey_file (ssl_ctx_, TPC_KEY_FILENAME, SSL_FILETYPE_PEM) <= 0 || !SSL_CTX_check_private_key (ssl_ctx_)) return -1; ssl_ = SSL_new (ssl_ctx_); return ssl_ == 0 ? -1 : 0; }
static void init_ssl(void) { #ifdef GIT_SSL SSL_load_error_strings(); OpenSSL_add_ssl_algorithms(); git__ssl_ctx = SSL_CTX_new(SSLv23_method()); SSL_CTX_set_mode(git__ssl_ctx, SSL_MODE_AUTO_RETRY); SSL_CTX_set_verify(git__ssl_ctx, SSL_VERIFY_NONE, NULL); if (!SSL_CTX_set_default_verify_paths(git__ssl_ctx)) { SSL_CTX_free(git__ssl_ctx); git__ssl_ctx = NULL; } # ifdef GIT_THREADS { int num_locks, i; num_locks = CRYPTO_num_locks(); openssl_locks = git__calloc(num_locks, sizeof(git_mutex)); if (openssl_locks == NULL) { SSL_CTX_free(git__ssl_ctx); git__ssl_ctx = NULL; } for (i = 0; i < num_locks; i++) { if (git_mutex_init(&openssl_locks[i]) != 0) { SSL_CTX_free(git__ssl_ctx); git__ssl_ctx = NULL; } } CRYPTO_set_locking_callback(openssl_locking_function); } # endif #endif }
int MAIN(int argc, char **argv) { int off=0; SSL *con=NULL,*con2=NULL; X509_STORE *store = NULL; int s,k,width,state=0; char *cbuf=NULL,*sbuf=NULL,*mbuf=NULL; int cbuf_len,cbuf_off; int sbuf_len,sbuf_off; fd_set readfds,writefds; short port=PORT; int full_log=1; char *host=SSL_HOST_NAME; char *cert_file=NULL,*key_file=NULL; int cert_format = FORMAT_PEM, key_format = FORMAT_PEM; char *passarg = NULL, *pass = NULL; X509 *cert = NULL; EVP_PKEY *key = NULL; char *CApath=NULL,*CAfile=NULL,*cipher=NULL; int reconnect=0,badop=0,verify=SSL_VERIFY_NONE,bugs=0; int crlf=0; int write_tty,read_tty,write_ssl,read_ssl,tty_on,ssl_pending; SSL_CTX *ctx=NULL; int ret=1,in_init=1,i,nbio_test=0; int starttls_proto = PROTO_OFF; int prexit = 0, vflags = 0; SSL_METHOD *meth=NULL; #ifdef sock_type #undef sock_type #endif int sock_type=SOCK_STREAM; BIO *sbio; char *inrand=NULL; int mbuf_len=0; #ifndef OPENSSL_NO_ENGINE char *engine_id=NULL; ENGINE *e=NULL; #endif #if defined(OPENSSL_SYS_WINDOWS) || defined(OPENSSL_SYS_MSDOS) || defined(OPENSSL_SYS_NETWARE) struct timeval tv; #endif struct sockaddr peer; int peerlen = sizeof(peer); int enable_timeouts = 0 ; long mtu = 0; #if !defined(OPENSSL_NO_SSL2) && !defined(OPENSSL_NO_SSL3) meth=SSLv23_client_method(); #elif !defined(OPENSSL_NO_SSL3) meth=SSLv3_client_method(); #elif !defined(OPENSSL_NO_SSL2) meth=SSLv2_client_method(); #endif apps_startup(); c_Pause=0; c_quiet=0; c_ign_eof=0; c_debug=0; c_msg=0; c_showcerts=0; if (bio_err == NULL) bio_err=BIO_new_fp(stderr,BIO_NOCLOSE); if (!load_config(bio_err, NULL)) goto end; if ( ((cbuf=OPENSSL_malloc(BUFSIZZ)) == NULL) || ((sbuf=OPENSSL_malloc(BUFSIZZ)) == NULL) || ((mbuf=OPENSSL_malloc(BUFSIZZ)) == NULL)) { BIO_printf(bio_err,"out of memory\n"); goto end; } verify_depth=0; verify_error=X509_V_OK; #ifdef FIONBIO c_nbio=0; #endif argc--; argv++; while (argc >= 1) { if (strcmp(*argv,"-host") == 0) { if (--argc < 1) goto bad; host= *(++argv); } else if (strcmp(*argv,"-port") == 0) { if (--argc < 1) goto bad; port=atoi(*(++argv)); if (port == 0) goto bad; } else if (strcmp(*argv,"-connect") == 0) { if (--argc < 1) goto bad; if (!extract_host_port(*(++argv),&host,NULL,&port)) goto bad; } else if (strcmp(*argv,"-verify") == 0) { verify=SSL_VERIFY_PEER; if (--argc < 1) goto bad; verify_depth=atoi(*(++argv)); BIO_printf(bio_err,"verify depth is %d\n",verify_depth); } else if (strcmp(*argv,"-cert") == 0) { if (--argc < 1) goto bad; cert_file= *(++argv); } else if (strcmp(*argv,"-certform") == 0) { if (--argc < 1) goto bad; cert_format = str2fmt(*(++argv)); } else if (strcmp(*argv,"-crl_check") == 0) vflags |= X509_V_FLAG_CRL_CHECK; else if (strcmp(*argv,"-crl_check_all") == 0) vflags |= X509_V_FLAG_CRL_CHECK|X509_V_FLAG_CRL_CHECK_ALL; else if (strcmp(*argv,"-prexit") == 0) prexit=1; else if (strcmp(*argv,"-crlf") == 0) crlf=1; else if (strcmp(*argv,"-quiet") == 0) { c_quiet=1; c_ign_eof=1; } else if (strcmp(*argv,"-ign_eof") == 0) c_ign_eof=1; else if (strcmp(*argv,"-pause") == 0) c_Pause=1; else if (strcmp(*argv,"-debug") == 0) c_debug=1; #ifdef WATT32 else if (strcmp(*argv,"-wdebug") == 0) dbug_init(); #endif else if (strcmp(*argv,"-msg") == 0) c_msg=1; else if (strcmp(*argv,"-showcerts") == 0) c_showcerts=1; else if (strcmp(*argv,"-nbio_test") == 0) nbio_test=1; else if (strcmp(*argv,"-state") == 0) state=1; #ifndef OPENSSL_NO_SSL2 else if (strcmp(*argv,"-ssl2") == 0) meth=SSLv2_client_method(); #endif #ifndef OPENSSL_NO_SSL3 else if (strcmp(*argv,"-ssl3") == 0) meth=SSLv3_client_method(); #endif #ifndef OPENSSL_NO_TLS1 else if (strcmp(*argv,"-tls1") == 0) meth=TLSv1_client_method(); #endif #ifndef OPENSSL_NO_DTLS1 else if (strcmp(*argv,"-dtls1") == 0) { meth=DTLSv1_client_method(); sock_type=SOCK_DGRAM; } else if (strcmp(*argv,"-timeout") == 0) enable_timeouts=1; else if (strcmp(*argv,"-mtu") == 0) { if (--argc < 1) goto bad; mtu = atol(*(++argv)); } #endif else if (strcmp(*argv,"-bugs") == 0) bugs=1; else if (strcmp(*argv,"-keyform") == 0) { if (--argc < 1) goto bad; key_format = str2fmt(*(++argv)); } else if (strcmp(*argv,"-pass") == 0) { if (--argc < 1) goto bad; passarg = *(++argv); } else if (strcmp(*argv,"-key") == 0) { if (--argc < 1) goto bad; key_file= *(++argv); } else if (strcmp(*argv,"-reconnect") == 0) { reconnect=5; } else if (strcmp(*argv,"-CApath") == 0) { if (--argc < 1) goto bad; CApath= *(++argv); } else if (strcmp(*argv,"-CAfile") == 0) { if (--argc < 1) goto bad; CAfile= *(++argv); } else if (strcmp(*argv,"-no_tls1") == 0) off|=SSL_OP_NO_TLSv1; else if (strcmp(*argv,"-no_ssl3") == 0) off|=SSL_OP_NO_SSLv3; else if (strcmp(*argv,"-no_ssl2") == 0) off|=SSL_OP_NO_SSLv2; else if (strcmp(*argv,"-serverpref") == 0) off|=SSL_OP_CIPHER_SERVER_PREFERENCE; else if (strcmp(*argv,"-cipher") == 0) { if (--argc < 1) goto bad; cipher= *(++argv); } #ifdef FIONBIO else if (strcmp(*argv,"-nbio") == 0) { c_nbio=1; } #endif else if (strcmp(*argv,"-starttls") == 0) { if (--argc < 1) goto bad; ++argv; if (strcmp(*argv,"smtp") == 0) starttls_proto = PROTO_SMTP; else if (strcmp(*argv,"pop3") == 0) starttls_proto = PROTO_POP3; else if (strcmp(*argv,"imap") == 0) starttls_proto = PROTO_IMAP; else if (strcmp(*argv,"ftp") == 0) starttls_proto = PROTO_FTP; else goto bad; } #ifndef OPENSSL_NO_ENGINE else if (strcmp(*argv,"-engine") == 0) { if (--argc < 1) goto bad; engine_id = *(++argv); } #endif else if (strcmp(*argv,"-rand") == 0) { if (--argc < 1) goto bad; inrand= *(++argv); } else { BIO_printf(bio_err,"unknown option %s\n",*argv); badop=1; break; } argc--; argv++; } if (badop) { bad: sc_usage(); goto end; } OpenSSL_add_ssl_algorithms(); SSL_load_error_strings(); #ifndef OPENSSL_NO_ENGINE e = setup_engine(bio_err, engine_id, 1); #endif if (!app_passwd(bio_err, passarg, NULL, &pass, NULL)) { BIO_printf(bio_err, "Error getting password\n"); goto end; } if (key_file == NULL) key_file = cert_file; if (key_file) { key = load_key(bio_err, key_file, key_format, 0, pass, e, "client certificate private key file"); if (!key) { ERR_print_errors(bio_err); goto end; } } if (cert_file) { cert = load_cert(bio_err,cert_file,cert_format, NULL, e, "client certificate file"); if (!cert) { ERR_print_errors(bio_err); goto end; } } if (!app_RAND_load_file(NULL, bio_err, 1) && inrand == NULL && !RAND_status()) { BIO_printf(bio_err,"warning, not much extra random data, consider using the -rand option\n"); } if (inrand != NULL) BIO_printf(bio_err,"%ld semi-random bytes loaded\n", app_RAND_load_files(inrand)); if (bio_c_out == NULL) { if (c_quiet && !c_debug && !c_msg) { bio_c_out=BIO_new(BIO_s_null()); } else { if (bio_c_out == NULL) bio_c_out=BIO_new_fp(stdout,BIO_NOCLOSE); } } ctx=SSL_CTX_new(meth); if (ctx == NULL) { ERR_print_errors(bio_err); goto end; } if (bugs) SSL_CTX_set_options(ctx,SSL_OP_ALL|off); else SSL_CTX_set_options(ctx,off); /* DTLS: partial reads end up discarding unread UDP bytes :-( * Setting read ahead solves this problem. */ if (sock_type == SOCK_DGRAM) SSL_CTX_set_read_ahead(ctx, 1); if (state) SSL_CTX_set_info_callback(ctx,apps_ssl_info_callback); if (cipher != NULL) if(!SSL_CTX_set_cipher_list(ctx,cipher)) { BIO_printf(bio_err,"error setting cipher list\n"); ERR_print_errors(bio_err); goto end; } #if 0 else SSL_CTX_set_cipher_list(ctx,getenv("SSL_CIPHER")); #endif SSL_CTX_set_verify(ctx,verify,verify_callback); if (!set_cert_key_stuff(ctx,cert,key)) goto end; if ((!SSL_CTX_load_verify_locations(ctx,CAfile,CApath)) || (!SSL_CTX_set_default_verify_paths(ctx))) { /* BIO_printf(bio_err,"error setting default verify locations\n"); */ ERR_print_errors(bio_err); /* goto end; */ } store = SSL_CTX_get_cert_store(ctx); X509_STORE_set_flags(store, vflags); con=SSL_new(ctx); #ifndef OPENSSL_NO_KRB5 if (con && (con->kssl_ctx = kssl_ctx_new()) != NULL) { kssl_ctx_setstring(con->kssl_ctx, KSSL_SERVER, host); } #endif /* OPENSSL_NO_KRB5 */ /* SSL_set_cipher_list(con,"RC4-MD5"); */ re_start: if (init_client(&s,host,port,sock_type) == 0) { BIO_printf(bio_err,"connect:errno=%d\n",get_last_socket_error()); SHUTDOWN(s); goto end; } BIO_printf(bio_c_out,"CONNECTED(%08X)\n",s); #ifdef FIONBIO if (c_nbio) { unsigned long l=1; BIO_printf(bio_c_out,"turning on non blocking io\n"); if (BIO_socket_ioctl(s,FIONBIO,&l) < 0) { ERR_print_errors(bio_err); goto end; } } #endif if (c_Pause & 0x01) con->debug=1; if ( SSL_version(con) == DTLS1_VERSION) { struct timeval timeout; sbio=BIO_new_dgram(s,BIO_NOCLOSE); if (getsockname(s, &peer, (void *)&peerlen) < 0) { BIO_printf(bio_err, "getsockname:errno=%d\n", get_last_socket_error()); SHUTDOWN(s); goto end; } (void)BIO_ctrl_set_connected(sbio, 1, &peer); if ( enable_timeouts) { timeout.tv_sec = 0; timeout.tv_usec = DGRAM_RCV_TIMEOUT; BIO_ctrl(sbio, BIO_CTRL_DGRAM_SET_RECV_TIMEOUT, 0, &timeout); timeout.tv_sec = 0; timeout.tv_usec = DGRAM_SND_TIMEOUT; BIO_ctrl(sbio, BIO_CTRL_DGRAM_SET_SEND_TIMEOUT, 0, &timeout); } if ( mtu > 0) { SSL_set_options(con, SSL_OP_NO_QUERY_MTU); SSL_set_mtu(con, mtu); } else /* want to do MTU discovery */ BIO_ctrl(sbio, BIO_CTRL_DGRAM_MTU_DISCOVER, 0, NULL); } else sbio=BIO_new_socket(s,BIO_NOCLOSE); if (nbio_test) { BIO *test; test=BIO_new(BIO_f_nbio_test()); sbio=BIO_push(test,sbio); } if (c_debug) { con->debug=1; BIO_set_callback(sbio,bio_dump_callback); BIO_set_callback_arg(sbio,(char *)bio_c_out); } if (c_msg) { SSL_set_msg_callback(con, msg_cb); SSL_set_msg_callback_arg(con, bio_c_out); } SSL_set_bio(con,sbio,sbio); SSL_set_connect_state(con); /* ok, lets connect */ width=SSL_get_fd(con)+1; read_tty=1; write_tty=0; tty_on=0; read_ssl=1; write_ssl=1; cbuf_len=0; cbuf_off=0; sbuf_len=0; sbuf_off=0; /* This is an ugly hack that does a lot of assumptions */ /* We do have to handle multi-line responses which may come in a single packet or not. We therefore have to use BIO_gets() which does need a buffering BIO. So during the initial chitchat we do push a buffering BIO into the chain that is removed again later on to not disturb the rest of the s_client operation. */ if (starttls_proto == PROTO_SMTP) { int foundit=0; BIO *fbio = BIO_new(BIO_f_buffer()); BIO_push(fbio, sbio); /* wait for multi-line response to end from SMTP */ do { mbuf_len = BIO_gets(fbio,mbuf,BUFSIZZ); } while (mbuf_len>3 && mbuf[3]=='-'); /* STARTTLS command requires EHLO... */ BIO_printf(fbio,"EHLO openssl.client.net\r\n"); (void)BIO_flush(fbio); /* wait for multi-line response to end EHLO SMTP response */ do { mbuf_len = BIO_gets(fbio,mbuf,BUFSIZZ); if (strstr(mbuf,"STARTTLS")) foundit=1; } while (mbuf_len>3 && mbuf[3]=='-'); (void)BIO_flush(fbio); BIO_pop(fbio); BIO_free(fbio); if (!foundit) BIO_printf(bio_err, "didn't found starttls in server response," " try anyway...\n"); BIO_printf(sbio,"STARTTLS\r\n"); BIO_read(sbio,sbuf,BUFSIZZ); } else if (starttls_proto == PROTO_POP3) { BIO_read(sbio,mbuf,BUFSIZZ); BIO_printf(sbio,"STLS\r\n"); BIO_read(sbio,sbuf,BUFSIZZ); } else if (starttls_proto == PROTO_IMAP) { int foundit=0; BIO *fbio = BIO_new(BIO_f_buffer()); BIO_push(fbio, sbio); BIO_gets(fbio,mbuf,BUFSIZZ); /* STARTTLS command requires CAPABILITY... */ BIO_printf(fbio,". CAPABILITY\r\n"); (void)BIO_flush(fbio); /* wait for multi-line CAPABILITY response */ do { mbuf_len = BIO_gets(fbio,mbuf,BUFSIZZ); if (strstr(mbuf,"STARTTLS")) foundit=1; } while (mbuf_len>3 && mbuf[0]!='.'); (void)BIO_flush(fbio); BIO_pop(fbio); BIO_free(fbio); if (!foundit) BIO_printf(bio_err, "didn't found STARTTLS in server response," " try anyway...\n"); BIO_printf(sbio,". STARTTLS\r\n"); BIO_read(sbio,sbuf,BUFSIZZ); } else if (starttls_proto == PROTO_FTP) { BIO *fbio = BIO_new(BIO_f_buffer()); BIO_push(fbio, sbio); /* wait for multi-line response to end from FTP */ do { mbuf_len = BIO_gets(fbio,mbuf,BUFSIZZ); } while (mbuf_len>3 && mbuf[3]=='-'); (void)BIO_flush(fbio); BIO_pop(fbio); BIO_free(fbio); BIO_printf(sbio,"AUTH TLS\r\n"); BIO_read(sbio,sbuf,BUFSIZZ); } for (;;) { FD_ZERO(&readfds); FD_ZERO(&writefds); if (SSL_in_init(con) && !SSL_total_renegotiations(con)) { in_init=1; tty_on=0; } else { tty_on=1; if (in_init) { in_init=0; print_stuff(bio_c_out,con,full_log); if (full_log > 0) full_log--; if (starttls_proto) { BIO_printf(bio_err,"%s",mbuf); /* We don't need to know any more */ starttls_proto = PROTO_OFF; } if (reconnect) { reconnect--; BIO_printf(bio_c_out,"drop connection and then reconnect\n"); SSL_shutdown(con); SSL_set_connect_state(con); SHUTDOWN(SSL_get_fd(con)); goto re_start; } } } ssl_pending = read_ssl && SSL_pending(con); if (!ssl_pending) { #if !defined(OPENSSL_SYS_WINDOWS) && !defined(OPENSSL_SYS_MSDOS) && !defined(OPENSSL_SYS_NETWARE) if (tty_on) { if (read_tty) FD_SET(fileno(stdin),&readfds); if (write_tty) FD_SET(fileno(stdout),&writefds); } if (read_ssl) FD_SET(SSL_get_fd(con),&readfds); if (write_ssl) FD_SET(SSL_get_fd(con),&writefds); #else if(!tty_on || !write_tty) { if (read_ssl) FD_SET(SSL_get_fd(con),&readfds); if (write_ssl) FD_SET(SSL_get_fd(con),&writefds); } #endif /* printf("mode tty(%d %d%d) ssl(%d%d)\n", tty_on,read_tty,write_tty,read_ssl,write_ssl);*/ /* Note: under VMS with SOCKETSHR the second parameter * is currently of type (int *) whereas under other * systems it is (void *) if you don't have a cast it * will choke the compiler: if you do have a cast then * you can either go for (int *) or (void *). */ #if defined(OPENSSL_SYS_WINDOWS) || defined(OPENSSL_SYS_MSDOS) /* Under Windows/DOS we make the assumption that we can * always write to the tty: therefore if we need to * write to the tty we just fall through. Otherwise * we timeout the select every second and see if there * are any keypresses. Note: this is a hack, in a proper * Windows application we wouldn't do this. */ i=0; if(!write_tty) { if(read_tty) { tv.tv_sec = 1; tv.tv_usec = 0; i=select(width,(void *)&readfds,(void *)&writefds, NULL,&tv); #if defined(OPENSSL_SYS_WINCE) || defined(OPENSSL_SYS_MSDOS) if(!i && (!_kbhit() || !read_tty) ) continue; #else if(!i && (!((_kbhit()) || (WAIT_OBJECT_0 == WaitForSingleObject(GetStdHandle(STD_INPUT_HANDLE), 0))) || !read_tty) ) continue; #endif } else i=select(width,(void *)&readfds,(void *)&writefds, NULL,NULL); } #elif defined(OPENSSL_SYS_NETWARE) if(!write_tty) { if(read_tty) { tv.tv_sec = 1; tv.tv_usec = 0; i=select(width,(void *)&readfds,(void *)&writefds, NULL,&tv); } else i=select(width,(void *)&readfds,(void *)&writefds, NULL,NULL); } #else i=select(width,(void *)&readfds,(void *)&writefds, NULL,NULL); #endif if ( i < 0) { BIO_printf(bio_err,"bad select %d\n", get_last_socket_error()); goto shut; /* goto end; */ } } if (!ssl_pending && FD_ISSET(SSL_get_fd(con),&writefds)) { k=SSL_write(con,&(cbuf[cbuf_off]), (unsigned int)cbuf_len); switch (SSL_get_error(con,k)) { case SSL_ERROR_NONE: cbuf_off+=k; cbuf_len-=k; if (k <= 0) goto end; /* we have done a write(con,NULL,0); */ if (cbuf_len <= 0) { read_tty=1; write_ssl=0; } else /* if (cbuf_len > 0) */ { read_tty=0; write_ssl=1; } break; case SSL_ERROR_WANT_WRITE: BIO_printf(bio_c_out,"write W BLOCK\n"); write_ssl=1; read_tty=0; break; case SSL_ERROR_WANT_READ: BIO_printf(bio_c_out,"write R BLOCK\n"); write_tty=0; read_ssl=1; write_ssl=0; break; case SSL_ERROR_WANT_X509_LOOKUP: BIO_printf(bio_c_out,"write X BLOCK\n"); break; case SSL_ERROR_ZERO_RETURN: if (cbuf_len != 0) { BIO_printf(bio_c_out,"shutdown\n"); goto shut; } else { read_tty=1; write_ssl=0; break; } case SSL_ERROR_SYSCALL: if ((k != 0) || (cbuf_len != 0)) { BIO_printf(bio_err,"write:errno=%d\n", get_last_socket_error()); goto shut; } else { read_tty=1; write_ssl=0; } break; case SSL_ERROR_SSL: ERR_print_errors(bio_err); goto shut; } } #if defined(OPENSSL_SYS_WINDOWS) || defined(OPENSSL_SYS_MSDOS) || defined(OPENSSL_SYS_NETWARE) /* Assume Windows/DOS can always write */ else if (!ssl_pending && write_tty) #else else if (!ssl_pending && FD_ISSET(fileno(stdout),&writefds)) #endif { #ifdef CHARSET_EBCDIC ascii2ebcdic(&(sbuf[sbuf_off]),&(sbuf[sbuf_off]),sbuf_len); #endif i=write(fileno(stdout),&(sbuf[sbuf_off]),sbuf_len); if (i <= 0) { BIO_printf(bio_c_out,"DONE\n"); goto shut; /* goto end; */ } sbuf_len-=i;; sbuf_off+=i; if (sbuf_len <= 0) { read_ssl=1; write_tty=0; } } else if (ssl_pending || FD_ISSET(SSL_get_fd(con),&readfds)) { #ifdef RENEG { static int iiii; if (++iiii == 52) { SSL_renegotiate(con); iiii=0; } } #endif #if 1 k=SSL_read(con,sbuf,1024 /* BUFSIZZ */ ); #else /* Demo for pending and peek :-) */ k=SSL_read(con,sbuf,16); { char zbuf[10240]; printf("read=%d pending=%d peek=%d\n",k,SSL_pending(con),SSL_peek(con,zbuf,10240)); } #endif switch (SSL_get_error(con,k)) { case SSL_ERROR_NONE: if (k <= 0) goto end; sbuf_off=0; sbuf_len=k; read_ssl=0; write_tty=1; break; case SSL_ERROR_WANT_WRITE: BIO_printf(bio_c_out,"read W BLOCK\n"); write_ssl=1; read_tty=0; break; case SSL_ERROR_WANT_READ: BIO_printf(bio_c_out,"read R BLOCK\n"); write_tty=0; read_ssl=1; if ((read_tty == 0) && (write_ssl == 0)) write_ssl=1; break; case SSL_ERROR_WANT_X509_LOOKUP: BIO_printf(bio_c_out,"read X BLOCK\n"); break; case SSL_ERROR_SYSCALL: BIO_printf(bio_err,"read:errno=%d\n",get_last_socket_error()); goto shut; case SSL_ERROR_ZERO_RETURN: BIO_printf(bio_c_out,"closed\n"); goto shut; case SSL_ERROR_SSL: ERR_print_errors(bio_err); goto shut; /* break; */ } } #if defined(OPENSSL_SYS_WINDOWS) || defined(OPENSSL_SYS_MSDOS) #if defined(OPENSSL_SYS_WINCE) || defined(OPENSSL_SYS_MSDOS) else if (_kbhit()) #else else if ((_kbhit()) || (WAIT_OBJECT_0 == WaitForSingleObject(GetStdHandle(STD_INPUT_HANDLE), 0))) #endif #elif defined (OPENSSL_SYS_NETWARE) else if (_kbhit()) #else else if (FD_ISSET(fileno(stdin),&readfds)) #endif { if (crlf) { int j, lf_num; i=read(fileno(stdin),cbuf,BUFSIZZ/2); lf_num = 0; /* both loops are skipped when i <= 0 */ for (j = 0; j < i; j++) if (cbuf[j] == '\n') lf_num++; for (j = i-1; j >= 0; j--) { cbuf[j+lf_num] = cbuf[j]; if (cbuf[j] == '\n') { lf_num--; i++; cbuf[j+lf_num] = '\r'; } } assert(lf_num == 0); } else i=read(fileno(stdin),cbuf,BUFSIZZ); if ((!c_ign_eof) && ((i <= 0) || (cbuf[0] == 'Q'))) { BIO_printf(bio_err,"DONE\n"); goto shut; } if ((!c_ign_eof) && (cbuf[0] == 'R')) { BIO_printf(bio_err,"RENEGOTIATING\n"); SSL_renegotiate(con); cbuf_len=0; } else { cbuf_len=i; cbuf_off=0; #ifdef CHARSET_EBCDIC ebcdic2ascii(cbuf, cbuf, i); #endif } write_ssl=1; read_tty=0; } } shut: SSL_shutdown(con); SHUTDOWN(SSL_get_fd(con)); ret=0; end: if(prexit) print_stuff(bio_c_out,con,1); if (con != NULL) SSL_free(con); if (con2 != NULL) SSL_free(con2); if (ctx != NULL) SSL_CTX_free(ctx); if (cert) X509_free(cert); if (key) EVP_PKEY_free(key); if (pass) OPENSSL_free(pass); if (cbuf != NULL) { OPENSSL_cleanse(cbuf,BUFSIZZ); OPENSSL_free(cbuf); } if (sbuf != NULL) { OPENSSL_cleanse(sbuf,BUFSIZZ); OPENSSL_free(sbuf); } if (mbuf != NULL) { OPENSSL_cleanse(mbuf,BUFSIZZ); OPENSSL_free(mbuf); } if (bio_c_out != NULL) { BIO_free(bio_c_out); bio_c_out=NULL; } apps_shutdown(); OPENSSL_EXIT(ret); }
HTTPScode https_init(const char *useragent, const char *cafile, const char *proxy) { X509_STORE *store; X509 *cert; BIO *bio; char *p; if ((ctx = calloc(1, sizeof(*ctx))) == NULL || (ctx->useragent = strdup(useragent)) == NULL) { ctx->errstr = strerror(errno); return (HTTPS_ERR_SYSTEM); } /* Initialize SSL context */ SSL_library_init(); SSL_load_error_strings(); OpenSSL_add_ssl_algorithms(); /* XXX - ape openssl s_client -rand for testing on ancient systems */ if (!RAND_status()) { if ((p = getenv("RANDFILE")) != NULL) { RAND_load_file(p, 8192); } else { ctx->errstr = "No /dev/random, EGD, or $RANDFILE"; return (HTTPS_ERR_LIB); } } if ((ctx->ssl_ctx = SSL_CTX_new(TLSv1_client_method())) == NULL) { ctx->errstr = _SSL_strerror(); return (HTTPS_ERR_LIB); } /* Set up our CA cert */ if (cafile == NULL) { /* Load default CA cert from memory */ if ((bio = BIO_new_mem_buf((void *)CACERT_PEM, -1)) == NULL || (store = SSL_CTX_get_cert_store(ctx->ssl_ctx)) == NULL) { ctx->errstr = _SSL_strerror(); return (HTTPS_ERR_LIB); } while ((cert = PEM_read_bio_X509(bio, NULL, 0, NULL)) != NULL) { X509_STORE_add_cert(store, cert); X509_free(cert); } BIO_free_all(bio); SSL_CTX_set_verify(ctx->ssl_ctx, SSL_VERIFY_PEER, NULL); } else if (cafile[0] == '\0') { /* Skip verification */ SSL_CTX_set_verify(ctx->ssl_ctx, SSL_VERIFY_NONE, NULL); } else { /* Load CA cert from file */ if (!SSL_CTX_load_verify_locations(ctx->ssl_ctx, cafile, NULL)) { SSL_CTX_free(ctx->ssl_ctx); ctx->errstr = _SSL_strerror(); return (HTTPS_ERR_CLIENT); } SSL_CTX_set_verify(ctx->ssl_ctx, SSL_VERIFY_PEER, NULL); } /* Save our proxy config if any */ if ((p = getenv("http_proxy")) != NULL || (p = (char *)proxy) != NULL) { if (strstr(p, "://") != NULL) { if (strncmp(p, "http://", 7) != 0) { ctx->errstr = "http_proxy must be HTTP"; return (HTTPS_ERR_CLIENT); } p += 7; } p = strdup(p); if ((ctx->proxy = strchr(p, '@')) != NULL) { *ctx->proxy++ = '\0'; ctx->proxy_auth = p; } else { ctx->proxy = p; } strtok(ctx->proxy, "/"); if ((ctx->proxy_port = strchr(ctx->proxy, ':')) != NULL) { *ctx->proxy_port++ = '\0'; } else { ctx->proxy_port = "80"; } } /* Set HTTP parser callbacks */ ctx->parse_settings.on_body = __on_body; ctx->parse_settings.on_message_complete = __on_message_complete; signal(SIGPIPE, SIG_IGN); return (0); }
/* * OpenSSL provides SSL, TLS and general purpose cryptography. It wraps the * OpenSSL[http://www.openssl.org/] library. * * = Examples * * All examples assume you have loaded OpenSSL with: * * require 'openssl' * * These examples build atop each other. For example the key created in the * next is used in throughout these examples. * * == Keys * * === Creating a Key * * This example creates a 2048 bit RSA keypair and writes it to the current * directory. * * key = OpenSSL::PKey::RSA.new 2048 * * open 'private_key.pem', 'w' do |io| io.write key.to_pem end * open 'public_key.pem', 'w' do |io| io.write key.public_key.to_pem end * * === Exporting a Key * * Keys saved to disk without encryption are not secure as anyone who gets * ahold of the key may use it unless it is encrypted. In order to securely * export a key you may export it with a pass phrase. * * cipher = OpenSSL::Cipher.new 'AES-128-CBC' * pass_phrase = 'my secure pass phrase goes here' * * key_secure = key.export cipher, pass_phrase * * open 'private.secure.pem', 'w' do |io| * io.write key_secure * end * * OpenSSL::Cipher.ciphers returns a list of available ciphers. * * === Loading a Key * * A key can also be loaded from a file. * * key2 = OpenSSL::PKey::RSA.new File.read 'private_key.pem' * key2.public? # => true * * or * * key3 = OpenSSL::PKey::RSA.new File.read 'public_key.pem' * key3.private? # => false * * === Loading an Encrypted Key * * OpenSSL will prompt you for your pass phrase when loading an encrypted key. * If you will not be able to type in the pass phrase you may provide it when * loading the key: * * key4_pem = File.read 'private.secure.pem' * key4 = OpenSSL::PKey::RSA.new key4_pem, pass_phrase * * == RSA Encryption * * RSA provides encryption and decryption using the public and private keys. * You can use a variety of padding methods depending upon the intended use of * encrypted data. * * === Encryption & Decryption * * Asymmetric public/private key encryption is slow and victim to attack in * cases where it is used without padding or directly to encrypt larger chunks * of data. Typical use cases for RSA encryption involve "wrapping" a symmetric * key with the public key of the recipient who would "unwrap" that symmetric * key again using their private key. * The following illustrates a simplified example of such a key transport * scheme. It shouldn't be used in practice, though, standardized protocols * should always be preferred. * * wrapped_key = key.public_encrypt key * * A symmetric key encrypted with the public key can only be decrypted with * the corresponding private key of the recipient. * * original_key = key.private_decrypt wrapped_key * * By default PKCS#1 padding will be used, but it is also possible to use * other forms of padding, see PKey::RSA for further details. * * === Signatures * * Using "private_encrypt" to encrypt some data with the private key is * equivalent to applying a digital signature to the data. A verifying * party may validate the signature by comparing the result of decrypting * the signature with "public_decrypt" to the original data. However, * OpenSSL::PKey already has methods "sign" and "verify" that handle * digital signatures in a standardized way - "private_encrypt" and * "public_decrypt" shouldn't be used in practice. * * To sign a document, a cryptographically secure hash of the document is * computed first, which is then signed using the private key. * * digest = OpenSSL::Digest::SHA256.new * signature = key.sign digest, document * * To validate the signature, again a hash of the document is computed and * the signature is decrypted using the public key. The result is then * compared to the hash just computed, if they are equal the signature was * valid. * * digest = OpenSSL::Digest::SHA256.new * if key.verify digest, signature, document * puts 'Valid' * else * puts 'Invalid' * end * * == PBKDF2 Password-based Encryption * * If supported by the underlying OpenSSL version used, Password-based * Encryption should use the features of PKCS5. If not supported or if * required by legacy applications, the older, less secure methods specified * in RFC 2898 are also supported (see below). * * PKCS5 supports PBKDF2 as it was specified in PKCS#5 * v2.0[http://www.rsa.com/rsalabs/node.asp?id=2127]. It still uses a * password, a salt, and additionally a number of iterations that will * slow the key derivation process down. The slower this is, the more work * it requires being able to brute-force the resulting key. * * === Encryption * * The strategy is to first instantiate a Cipher for encryption, and * then to generate a random IV plus a key derived from the password * using PBKDF2. PKCS #5 v2.0 recommends at least 8 bytes for the salt, * the number of iterations largely depends on the hardware being used. * * cipher = OpenSSL::Cipher.new 'AES-128-CBC' * cipher.encrypt * iv = cipher.random_iv * * pwd = 'some hopefully not to easily guessable password' * salt = OpenSSL::Random.random_bytes 16 * iter = 20000 * key_len = cipher.key_len * digest = OpenSSL::Digest::SHA256.new * * key = OpenSSL::PKCS5.pbkdf2_hmac(pwd, salt, iter, key_len, digest) * cipher.key = key * * Now encrypt the data: * * encrypted = cipher.update document * encrypted << cipher.final * * === Decryption * * Use the same steps as before to derive the symmetric AES key, this time * setting the Cipher up for decryption. * * cipher = OpenSSL::Cipher.new 'AES-128-CBC' * cipher.decrypt * cipher.iv = iv # the one generated with #random_iv * * pwd = 'some hopefully not to easily guessable password' * salt = ... # the one generated above * iter = 20000 * key_len = cipher.key_len * digest = OpenSSL::Digest::SHA256.new * * key = OpenSSL::PKCS5.pbkdf2_hmac(pwd, salt, iter, key_len, digest) * cipher.key = key * * Now decrypt the data: * * decrypted = cipher.update encrypted * decrypted << cipher.final * * == PKCS #5 Password-based Encryption * * PKCS #5 is a password-based encryption standard documented at * RFC2898[http://www.ietf.org/rfc/rfc2898.txt]. It allows a short password or * passphrase to be used to create a secure encryption key. If possible, PBKDF2 * as described above should be used if the circumstances allow it. * * PKCS #5 uses a Cipher, a pass phrase and a salt to generate an encryption * key. * * pass_phrase = 'my secure pass phrase goes here' * salt = '8 octets' * * === Encryption * * First set up the cipher for encryption * * encrypter = OpenSSL::Cipher.new 'AES-128-CBC' * encrypter.encrypt * encrypter.pkcs5_keyivgen pass_phrase, salt * * Then pass the data you want to encrypt through * * encrypted = encrypter.update 'top secret document' * encrypted << encrypter.final * * === Decryption * * Use a new Cipher instance set up for decryption * * decrypter = OpenSSL::Cipher.new 'AES-128-CBC' * decrypter.decrypt * decrypter.pkcs5_keyivgen pass_phrase, salt * * Then pass the data you want to decrypt through * * plain = decrypter.update encrypted * plain << decrypter.final * * == X509 Certificates * * === Creating a Certificate * * This example creates a self-signed certificate using an RSA key and a SHA1 * signature. * * name = OpenSSL::X509::Name.parse 'CN=nobody/DC=example' * * cert = OpenSSL::X509::Certificate.new * cert.version = 2 * cert.serial = 0 * cert.not_before = Time.now * cert.not_after = Time.now + 3600 * * cert.public_key = key.public_key * cert.subject = name * * === Certificate Extensions * * You can add extensions to the certificate with * OpenSSL::SSL::ExtensionFactory to indicate the purpose of the certificate. * * extension_factory = OpenSSL::X509::ExtensionFactory.new nil, cert * * cert.add_extension \ * extension_factory.create_extension('basicConstraints', 'CA:FALSE', true) * * cert.add_extension \ * extension_factory.create_extension( * 'keyUsage', 'keyEncipherment,dataEncipherment,digitalSignature') * * cert.add_extension \ * extension_factory.create_extension('subjectKeyIdentifier', 'hash') * * The list of supported extensions (and in some cases their possible values) * can be derived from the "objects.h" file in the OpenSSL source code. * * === Signing a Certificate * * To sign a certificate set the issuer and use OpenSSL::X509::Certificate#sign * with a digest algorithm. This creates a self-signed cert because we're using * the same name and key to sign the certificate as was used to create the * certificate. * * cert.issuer = name * cert.sign key, OpenSSL::Digest::SHA1.new * * open 'certificate.pem', 'w' do |io| io.write cert.to_pem end * * === Loading a Certificate * * Like a key, a cert can also be loaded from a file. * * cert2 = OpenSSL::X509::Certificate.new File.read 'certificate.pem' * * === Verifying a Certificate * * Certificate#verify will return true when a certificate was signed with the * given public key. * * raise 'certificate can not be verified' unless cert2.verify key * * == Certificate Authority * * A certificate authority (CA) is a trusted third party that allows you to * verify the ownership of unknown certificates. The CA issues key signatures * that indicate it trusts the user of that key. A user encountering the key * can verify the signature by using the CA's public key. * * === CA Key * * CA keys are valuable, so we encrypt and save it to disk and make sure it is * not readable by other users. * * ca_key = OpenSSL::PKey::RSA.new 2048 * * cipher = OpenSSL::Cipher::Cipher.new 'AES-128-CBC' * * open 'ca_key.pem', 'w', 0400 do |io| * io.write ca_key.export(cipher, pass_phrase) * end * * === CA Certificate * * A CA certificate is created the same way we created a certificate above, but * with different extensions. * * ca_name = OpenSSL::X509::Name.parse 'CN=ca/DC=example' * * ca_cert = OpenSSL::X509::Certificate.new * ca_cert.serial = 0 * ca_cert.version = 2 * ca_cert.not_before = Time.now * ca_cert.not_after = Time.now + 86400 * * ca_cert.public_key = ca_key.public_key * ca_cert.subject = ca_name * ca_cert.issuer = ca_name * * extension_factory = OpenSSL::X509::ExtensionFactory.new * extension_factory.subject_certificate = ca_cert * extension_factory.issuer_certificate = ca_cert * * ca_cert.add_extension \ * extension_factory.create_extension('subjectKeyIdentifier', 'hash') * * This extension indicates the CA's key may be used as a CA. * * ca_cert.add_extension \ * extension_factory.create_extension('basicConstraints', 'CA:TRUE', true) * * This extension indicates the CA's key may be used to verify signatures on * both certificates and certificate revocations. * * ca_cert.add_extension \ * extension_factory.create_extension( * 'keyUsage', 'cRLSign,keyCertSign', true) * * Root CA certificates are self-signed. * * ca_cert.sign ca_key, OpenSSL::Digest::SHA1.new * * The CA certificate is saved to disk so it may be distributed to all the * users of the keys this CA will sign. * * open 'ca_cert.pem', 'w' do |io| * io.write ca_cert.to_pem * end * * === Certificate Signing Request * * The CA signs keys through a Certificate Signing Request (CSR). The CSR * contains the information necessary to identify the key. * * csr = OpenSSL::X509::Request.new * csr.version = 0 * csr.subject = name * csr.public_key = key.public_key * csr.sign key, OpenSSL::Digest::SHA1.new * * A CSR is saved to disk and sent to the CA for signing. * * open 'csr.pem', 'w' do |io| * io.write csr.to_pem * end * * === Creating a Certificate from a CSR * * Upon receiving a CSR the CA will verify it before signing it. A minimal * verification would be to check the CSR's signature. * * csr = OpenSSL::X509::Request.new File.read 'csr.pem' * * raise 'CSR can not be verified' unless csr.verify csr.public_key * * After verification a certificate is created, marked for various usages, * signed with the CA key and returned to the requester. * * csr_cert = OpenSSL::X509::Certificate.new * csr_cert.serial = 0 * csr_cert.version = 2 * csr_cert.not_before = Time.now * csr_cert.not_after = Time.now + 600 * * csr_cert.subject = csr.subject * csr_cert.public_key = csr.public_key * csr_cert.issuer = ca_cert.subject * * extension_factory = OpenSSL::X509::ExtensionFactory.new * extension_factory.subject_certificate = csr_cert * extension_factory.issuer_certificate = ca_cert * * csr_cert.add_extension \ * extension_factory.create_extension('basicConstraints', 'CA:FALSE') * * csr_cert.add_extension \ * extension_factory.create_extension( * 'keyUsage', 'keyEncipherment,dataEncipherment,digitalSignature') * * csr_cert.add_extension \ * extension_factory.create_extension('subjectKeyIdentifier', 'hash') * * csr_cert.sign ca_key, OpenSSL::Digest::SHA1.new * * open 'csr_cert.pem', 'w' do |io| * io.write csr_cert.to_pem * end * * == SSL and TLS Connections * * Using our created key and certificate we can create an SSL or TLS connection. * An SSLContext is used to set up an SSL session. * * context = OpenSSL::SSL::SSLContext.new * * === SSL Server * * An SSL server requires the certificate and private key to communicate * securely with its clients: * * context.cert = cert * context.key = key * * Then create an SSLServer with a TCP server socket and the context. Use the * SSLServer like an ordinary TCP server. * * require 'socket' * * tcp_server = TCPServer.new 5000 * ssl_server = OpenSSL::SSL::SSLServer.new tcp_server, context * * loop do * ssl_connection = ssl_server.accept * * data = connection.gets * * response = "I got #{data.dump}" * puts response * * connection.puts "I got #{data.dump}" * connection.close * end * * === SSL client * * An SSL client is created with a TCP socket and the context. * SSLSocket#connect must be called to initiate the SSL handshake and start * encryption. A key and certificate are not required for the client socket. * * require 'socket' * * tcp_client = TCPSocket.new 'localhost', 5000 * ssl_client = OpenSSL::SSL::SSLSocket.new client_socket, context * ssl_client.connect * * ssl_client.puts "hello server!" * puts ssl_client.gets * * === Peer Verification * * An unverified SSL connection does not provide much security. For enhanced * security the client or server can verify the certificate of its peer. * * The client can be modified to verify the server's certificate against the * certificate authority's certificate: * * context.ca_file = 'ca_cert.pem' * context.verify_mode = OpenSSL::SSL::VERIFY_PEER * * require 'socket' * * tcp_client = TCPSocket.new 'localhost', 5000 * ssl_client = OpenSSL::SSL::SSLSocket.new client_socket, context * ssl_client.connect * * ssl_client.puts "hello server!" * puts ssl_client.gets * * If the server certificate is invalid or <tt>context.ca_file</tt> is not set * when verifying peers an OpenSSL::SSL::SSLError will be raised. * */ void Init_openssl() { /* * Init timezone info */ #if 0 tzset(); #endif /* * Init all digests, ciphers */ /* CRYPTO_malloc_init(); */ /* ENGINE_load_builtin_engines(); */ OpenSSL_add_ssl_algorithms(); OpenSSL_add_all_algorithms(); ERR_load_crypto_strings(); SSL_load_error_strings(); /* * FIXME: * On unload do: */ #if 0 CONF_modules_unload(1); destroy_ui_method(); EVP_cleanup(); ENGINE_cleanup(); CRYPTO_cleanup_all_ex_data(); ERR_remove_state(0); ERR_free_strings(); #endif /* * Init main module */ mOSSL = rb_define_module("OpenSSL"); rb_global_variable(&mOSSL); /* * OpenSSL ruby extension version */ rb_define_const(mOSSL, "VERSION", rb_str_new2(OSSL_VERSION)); /* * Version of OpenSSL the ruby OpenSSL extension was built with */ rb_define_const(mOSSL, "OPENSSL_VERSION", rb_str_new2(OPENSSL_VERSION_TEXT)); /* * Version number of OpenSSL the ruby OpenSSL extension was built with * (base 16) */ rb_define_const(mOSSL, "OPENSSL_VERSION_NUMBER", INT2NUM(OPENSSL_VERSION_NUMBER)); /* * Boolean indicating whether OpenSSL is FIPS-enabled or not */ #ifdef HAVE_OPENSSL_FIPS rb_define_const(mOSSL, "OPENSSL_FIPS", Qtrue); #else rb_define_const(mOSSL, "OPENSSL_FIPS", Qfalse); #endif rb_define_module_function(mOSSL, "fips_mode=", ossl_fips_mode_set, 1); /* * Generic error, * common for all classes under OpenSSL module */ eOSSLError = rb_define_class_under(mOSSL,"OpenSSLError",rb_eStandardError); rb_global_variable(&eOSSLError); /* * Verify callback Proc index for ext-data */ if ((ossl_verify_cb_idx = X509_STORE_CTX_get_ex_new_index(0, (void *)"ossl_verify_cb_idx", 0, 0, 0)) < 0) ossl_raise(eOSSLError, "X509_STORE_CTX_get_ex_new_index"); /* * Init debug core */ dOSSL = Qfalse; rb_global_variable(&dOSSL); rb_define_module_function(mOSSL, "debug", ossl_debug_get, 0); rb_define_module_function(mOSSL, "debug=", ossl_debug_set, 1); rb_define_module_function(mOSSL, "errors", ossl_get_errors, 0); /* * Get ID of to_der */ ossl_s_to_der = rb_intern("to_der"); Init_ossl_locks(); /* * Init components */ Init_ossl_bn(); Init_ossl_cipher(); Init_ossl_config(); Init_ossl_digest(); Init_ossl_hmac(); Init_ossl_ns_spki(); Init_ossl_pkcs12(); Init_ossl_pkcs7(); Init_ossl_pkcs5(); Init_ossl_pkey(); Init_ossl_rand(); Init_ossl_ssl(); Init_ossl_x509(); Init_ossl_ocsp(); Init_ossl_engine(); Init_ossl_asn1(); }
TLS_APPL_STATE *tls_client_init(const TLS_CLIENT_INIT_PROPS *props) { long off = 0; int cachable; int scache_timeout; SSL_CTX *client_ctx; TLS_APPL_STATE *app_ctx; int log_mask; /* * Convert user loglevel to internal logmask. */ log_mask = tls_log_mask(props->log_param, props->log_level); if (log_mask & TLS_LOG_VERBOSE) msg_info("initializing the client-side TLS engine"); /* * Load (mostly cipher related) TLS-library internal main.cf parameters. */ tls_param_init(); /* * Detect mismatch between compile-time headers and run-time library. */ tls_check_version(); /* * Initialize the OpenSSL library by the book! To start with, we must * initialize the algorithms. We want cleartext error messages instead of * just error codes, so we load the error_strings. */ SSL_load_error_strings(); OpenSSL_add_ssl_algorithms(); /* * Create an application data index for SSL objects, so that we can * attach TLScontext information; this information is needed inside * tls_verify_certificate_callback(). */ if (TLScontext_index < 0) { if ((TLScontext_index = SSL_get_ex_new_index(0, 0, 0, 0, 0)) < 0) { msg_warn("Cannot allocate SSL application data index: " "disabling TLS support"); return (0); } } /* * If the administrator specifies an unsupported digest algorithm, fail * now, rather than in the middle of a TLS handshake. */ if (!tls_validate_digest(props->mdalg)) { msg_warn("disabling TLS support"); return (0); } /* * Initialize the PRNG (Pseudo Random Number Generator) with some seed * from external and internal sources. Don't enable TLS without some real * entropy. */ if (tls_ext_seed(var_tls_daemon_rand_bytes) < 0) { msg_warn("no entropy for TLS key generation: disabling TLS support"); return (0); } tls_int_seed(); /* * The SSL/TLS specifications require the client to send a message in the * oldest specification it understands with the highest level it * understands in the message. RFC2487 is only specified for TLSv1, but * we want to be as compatible as possible, so we will start off with a * SSLv2 greeting allowing the best we can offer: TLSv1. We can restrict * this with the options setting later, anyhow. */ ERR_clear_error(); if ((client_ctx = SSL_CTX_new(SSLv23_client_method())) == 0) { msg_warn("cannot allocate client SSL_CTX: disabling TLS support"); tls_print_errors(); return (0); } /* * See the verify callback in tls_verify.c */ SSL_CTX_set_verify_depth(client_ctx, props->verifydepth + 1); /* * Protocol selection is destination dependent, so we delay the protocol * selection options to the per-session SSL object. */ off |= tls_bug_bits(); SSL_CTX_set_options(client_ctx, off); /* * Set the call-back routine for verbose logging. */ if (log_mask & TLS_LOG_DEBUG) SSL_CTX_set_info_callback(client_ctx, tls_info_callback); /* * Load the CA public key certificates for both the client cert and for * the verification of server certificates. As provided by OpenSSL we * support two types of CA certificate handling: One possibility is to * add all CA certificates to one large CAfile, the other possibility is * a directory pointed to by CApath, containing separate files for each * CA with softlinks named after the hash values of the certificate. The * first alternative has the advantage that the file is opened and read * at startup time, so that you don't have the hassle to maintain another * copy of the CApath directory for chroot-jail. */ if (tls_set_ca_certificate_info(client_ctx, props->CAfile, props->CApath) < 0) { /* tls_set_ca_certificate_info() already logs a warning. */ SSL_CTX_free(client_ctx); /* 200411 */ return (0); } /* * We do not need a client certificate, so the certificates are only * loaded (and checked) if supplied. A clever client would handle * multiple client certificates and decide based on the list of * acceptable CAs, sent by the server, which certificate to submit. * OpenSSL does however not do this and also has no call-back hooks to * easily implement it. * * Load the client public key certificate and private key from file and * check whether the cert matches the key. We can use RSA certificates * ("cert") DSA certificates ("dcert") or ECDSA certificates ("eccert"). * All three can be made available at the same time. The CA certificates * for all three are handled in the same setup already finished. Which * one is used depends on the cipher negotiated (that is: the first * cipher listed by the client which does match the server). The client * certificate is presented after the server chooses the session cipher, * so we will just present the right cert for the chosen cipher (if it * uses certificates). */ if (tls_set_my_certificate_key_info(client_ctx, props->cert_file, props->key_file, props->dcert_file, props->dkey_file, props->eccert_file, props->eckey_file) < 0) { /* tls_set_my_certificate_key_info() already logs a warning. */ SSL_CTX_free(client_ctx); /* 200411 */ return (0); } /* * According to the OpenSSL documentation, temporary RSA key is needed * export ciphers are in use. We have to provide one, so well, we just do * it. */ SSL_CTX_set_tmp_rsa_callback(client_ctx, tls_tmp_rsa_cb); /* * Finally, the setup for the server certificate checking, done "by the * book". */ SSL_CTX_set_verify(client_ctx, SSL_VERIFY_NONE, tls_verify_certificate_callback); /* * Initialize the session cache. * * Since the client does not search an internal cache, we simply disable it. * It is only useful for expiring old sessions, but we do that in the * tlsmgr(8). * * This makes SSL_CTX_remove_session() not useful for flushing broken * sessions from the external cache, so we must delete them directly (not * via a callback). */ if (tls_mgr_policy(props->cache_type, &cachable, &scache_timeout) != TLS_MGR_STAT_OK) scache_timeout = 0; if (scache_timeout <= 0) cachable = 0; /* * Allocate an application context, and populate with mandatory protocol * and cipher data. */ app_ctx = tls_alloc_app_context(client_ctx, log_mask); /* * The external session cache is implemented by the tlsmgr(8) process. */ if (cachable) { app_ctx->cache_type = mystrdup(props->cache_type); /* * OpenSSL does not use callbacks to load sessions from a client * cache, so we must invoke that function directly. Apparently, * OpenSSL does not provide a way to pass session names from here to * call-back routines that do session lookup. * * OpenSSL can, however, automatically save newly created sessions for * us by callback (we create the session name in the call-back * function). * * XXX gcc 2.95 can't compile #ifdef .. #endif in the expansion of * SSL_SESS_CACHE_CLIENT | SSL_SESS_CACHE_NO_INTERNAL_STORE | * SSL_SESS_CACHE_NO_AUTO_CLEAR. */ #ifndef SSL_SESS_CACHE_NO_INTERNAL_STORE #define SSL_SESS_CACHE_NO_INTERNAL_STORE 0 #endif SSL_CTX_set_session_cache_mode(client_ctx, SSL_SESS_CACHE_CLIENT | SSL_SESS_CACHE_NO_INTERNAL_STORE | SSL_SESS_CACHE_NO_AUTO_CLEAR); SSL_CTX_sess_set_new_cb(client_ctx, new_client_session_cb); /* * OpenSSL ignores timed-out sessions. We need to set the internal * cache timeout at least as high as the external cache timeout. This * applies even if no internal cache is used. We set the session to * twice the cache lifetime. This way a session always lasts longer * than its lifetime in the cache. */ SSL_CTX_set_timeout(client_ctx, 2 * scache_timeout); } return (app_ctx); }
SslContext_t::SslContext_t (bool is_server, const string &privkeyfile, const string &certchainfile): pCtx (NULL), PrivateKey (NULL), Certificate (NULL) { /* TODO: the usage of the specified private-key and cert-chain filenames only applies to * client-side connections at this point. Server connections currently use the default materials. * That needs to be fixed asap. * Also, in this implementation, server-side connections use statically defined X-509 defaults. * One thing I'm really not clear on is whether or not you have to explicitly free X509 and EVP_PKEY * objects when we call our destructor, or whether just calling SSL_CTX_free is enough. */ if (!bLibraryInitialized) { bLibraryInitialized = true; SSL_library_init(); OpenSSL_add_ssl_algorithms(); OpenSSL_add_all_algorithms(); SSL_load_error_strings(); ERR_load_crypto_strings(); InitializeDefaultCredentials(); } bIsServer = is_server; pCtx = SSL_CTX_new (is_server ? SSLv23_server_method() : SSLv23_client_method()); if (!pCtx) throw std::runtime_error ("no SSL context"); SSL_CTX_set_options (pCtx, SSL_OP_ALL); //SSL_CTX_set_options (pCtx, (SSL_OP_NO_SSLv2 | SSL_OP_NO_SSLv3)); #ifdef SSL_MODE_RELEASE_BUFFERS SSL_CTX_set_mode (pCtx, SSL_MODE_RELEASE_BUFFERS); #endif if (is_server) { // The SSL_CTX calls here do NOT allocate memory. int e; if (privkeyfile.length() > 0) e = SSL_CTX_use_PrivateKey_file (pCtx, privkeyfile.c_str(), SSL_FILETYPE_PEM); else e = SSL_CTX_use_PrivateKey (pCtx, DefaultPrivateKey); if (e <= 0) ERR_print_errors_fp(stderr); assert (e > 0); if (certchainfile.length() > 0) e = SSL_CTX_use_certificate_chain_file (pCtx, certchainfile.c_str()); else e = SSL_CTX_use_certificate (pCtx, DefaultCertificate); if (e <= 0) ERR_print_errors_fp(stderr); assert (e > 0); } SSL_CTX_set_cipher_list (pCtx, "ALL:!ADH:!LOW:!EXP:!DES-CBC3-SHA:@STRENGTH"); if (is_server) { SSL_CTX_sess_set_cache_size (pCtx, 128); SSL_CTX_set_session_id_context (pCtx, (unsigned char*)"eventmachine", 12); } else { int e; if (privkeyfile.length() > 0) { e = SSL_CTX_use_PrivateKey_file (pCtx, privkeyfile.c_str(), SSL_FILETYPE_PEM); if (e <= 0) ERR_print_errors_fp(stderr); assert (e > 0); } if (certchainfile.length() > 0) { e = SSL_CTX_use_certificate_chain_file (pCtx, certchainfile.c_str()); if (e <= 0) ERR_print_errors_fp(stderr); assert (e > 0); } } }
/* * OpenSSL provides SSL, TLS and general purpose cryptography. It wraps the * OpenSSL[https://www.openssl.org/] library. * * = Examples * * All examples assume you have loaded OpenSSL with: * * require 'openssl' * * These examples build atop each other. For example the key created in the * next is used in throughout these examples. * * == Keys * * === Creating a Key * * This example creates a 2048 bit RSA keypair and writes it to the current * directory. * * key = OpenSSL::PKey::RSA.new 2048 * * open 'private_key.pem', 'w' do |io| io.write key.to_pem end * open 'public_key.pem', 'w' do |io| io.write key.public_key.to_pem end * * === Exporting a Key * * Keys saved to disk without encryption are not secure as anyone who gets * ahold of the key may use it unless it is encrypted. In order to securely * export a key you may export it with a pass phrase. * * cipher = OpenSSL::Cipher.new 'AES-128-CBC' * pass_phrase = 'my secure pass phrase goes here' * * key_secure = key.export cipher, pass_phrase * * open 'private.secure.pem', 'w' do |io| * io.write key_secure * end * * OpenSSL::Cipher.ciphers returns a list of available ciphers. * * === Loading a Key * * A key can also be loaded from a file. * * key2 = OpenSSL::PKey::RSA.new File.read 'private_key.pem' * key2.public? # => true * key2.private? # => true * * or * * key3 = OpenSSL::PKey::RSA.new File.read 'public_key.pem' * key3.public? # => true * key3.private? # => false * * === Loading an Encrypted Key * * OpenSSL will prompt you for your pass phrase when loading an encrypted key. * If you will not be able to type in the pass phrase you may provide it when * loading the key: * * key4_pem = File.read 'private.secure.pem' * pass_phrase = 'my secure pass phrase goes here' * key4 = OpenSSL::PKey::RSA.new key4_pem, pass_phrase * * == RSA Encryption * * RSA provides encryption and decryption using the public and private keys. * You can use a variety of padding methods depending upon the intended use of * encrypted data. * * === Encryption & Decryption * * Asymmetric public/private key encryption is slow and victim to attack in * cases where it is used without padding or directly to encrypt larger chunks * of data. Typical use cases for RSA encryption involve "wrapping" a symmetric * key with the public key of the recipient who would "unwrap" that symmetric * key again using their private key. * The following illustrates a simplified example of such a key transport * scheme. It shouldn't be used in practice, though, standardized protocols * should always be preferred. * * wrapped_key = key.public_encrypt key * * A symmetric key encrypted with the public key can only be decrypted with * the corresponding private key of the recipient. * * original_key = key.private_decrypt wrapped_key * * By default PKCS#1 padding will be used, but it is also possible to use * other forms of padding, see PKey::RSA for further details. * * === Signatures * * Using "private_encrypt" to encrypt some data with the private key is * equivalent to applying a digital signature to the data. A verifying * party may validate the signature by comparing the result of decrypting * the signature with "public_decrypt" to the original data. However, * OpenSSL::PKey already has methods "sign" and "verify" that handle * digital signatures in a standardized way - "private_encrypt" and * "public_decrypt" shouldn't be used in practice. * * To sign a document, a cryptographically secure hash of the document is * computed first, which is then signed using the private key. * * digest = OpenSSL::Digest::SHA256.new * signature = key.sign digest, document * * To validate the signature, again a hash of the document is computed and * the signature is decrypted using the public key. The result is then * compared to the hash just computed, if they are equal the signature was * valid. * * digest = OpenSSL::Digest::SHA256.new * if key.verify digest, signature, document * puts 'Valid' * else * puts 'Invalid' * end * * == PBKDF2 Password-based Encryption * * If supported by the underlying OpenSSL version used, Password-based * Encryption should use the features of PKCS5. If not supported or if * required by legacy applications, the older, less secure methods specified * in RFC 2898 are also supported (see below). * * PKCS5 supports PBKDF2 as it was specified in PKCS#5 * v2.0[http://www.rsa.com/rsalabs/node.asp?id=2127]. It still uses a * password, a salt, and additionally a number of iterations that will * slow the key derivation process down. The slower this is, the more work * it requires being able to brute-force the resulting key. * * === Encryption * * The strategy is to first instantiate a Cipher for encryption, and * then to generate a random IV plus a key derived from the password * using PBKDF2. PKCS #5 v2.0 recommends at least 8 bytes for the salt, * the number of iterations largely depends on the hardware being used. * * cipher = OpenSSL::Cipher.new 'AES-128-CBC' * cipher.encrypt * iv = cipher.random_iv * * pwd = 'some hopefully not to easily guessable password' * salt = OpenSSL::Random.random_bytes 16 * iter = 20000 * key_len = cipher.key_len * digest = OpenSSL::Digest::SHA256.new * * key = OpenSSL::PKCS5.pbkdf2_hmac(pwd, salt, iter, key_len, digest) * cipher.key = key * * Now encrypt the data: * * encrypted = cipher.update document * encrypted << cipher.final * * === Decryption * * Use the same steps as before to derive the symmetric AES key, this time * setting the Cipher up for decryption. * * cipher = OpenSSL::Cipher.new 'AES-128-CBC' * cipher.decrypt * cipher.iv = iv # the one generated with #random_iv * * pwd = 'some hopefully not to easily guessable password' * salt = ... # the one generated above * iter = 20000 * key_len = cipher.key_len * digest = OpenSSL::Digest::SHA256.new * * key = OpenSSL::PKCS5.pbkdf2_hmac(pwd, salt, iter, key_len, digest) * cipher.key = key * * Now decrypt the data: * * decrypted = cipher.update encrypted * decrypted << cipher.final * * == PKCS #5 Password-based Encryption * * PKCS #5 is a password-based encryption standard documented at * RFC2898[http://www.ietf.org/rfc/rfc2898.txt]. It allows a short password or * passphrase to be used to create a secure encryption key. If possible, PBKDF2 * as described above should be used if the circumstances allow it. * * PKCS #5 uses a Cipher, a pass phrase and a salt to generate an encryption * key. * * pass_phrase = 'my secure pass phrase goes here' * salt = '8 octets' * * === Encryption * * First set up the cipher for encryption * * encryptor = OpenSSL::Cipher.new 'AES-128-CBC' * encryptor.encrypt * encryptor.pkcs5_keyivgen pass_phrase, salt * * Then pass the data you want to encrypt through * * encrypted = encryptor.update 'top secret document' * encrypted << encryptor.final * * === Decryption * * Use a new Cipher instance set up for decryption * * decryptor = OpenSSL::Cipher.new 'AES-128-CBC' * decryptor.decrypt * decryptor.pkcs5_keyivgen pass_phrase, salt * * Then pass the data you want to decrypt through * * plain = decryptor.update encrypted * plain << decryptor.final * * == X509 Certificates * * === Creating a Certificate * * This example creates a self-signed certificate using an RSA key and a SHA1 * signature. * * key = OpenSSL::PKey::RSA.new 2048 * name = OpenSSL::X509::Name.parse 'CN=nobody/DC=example' * * cert = OpenSSL::X509::Certificate.new * cert.version = 2 * cert.serial = 0 * cert.not_before = Time.now * cert.not_after = Time.now + 3600 * * cert.public_key = key.public_key * cert.subject = name * * === Certificate Extensions * * You can add extensions to the certificate with * OpenSSL::SSL::ExtensionFactory to indicate the purpose of the certificate. * * extension_factory = OpenSSL::X509::ExtensionFactory.new nil, cert * * cert.add_extension \ * extension_factory.create_extension('basicConstraints', 'CA:FALSE', true) * * cert.add_extension \ * extension_factory.create_extension( * 'keyUsage', 'keyEncipherment,dataEncipherment,digitalSignature') * * cert.add_extension \ * extension_factory.create_extension('subjectKeyIdentifier', 'hash') * * The list of supported extensions (and in some cases their possible values) * can be derived from the "objects.h" file in the OpenSSL source code. * * === Signing a Certificate * * To sign a certificate set the issuer and use OpenSSL::X509::Certificate#sign * with a digest algorithm. This creates a self-signed cert because we're using * the same name and key to sign the certificate as was used to create the * certificate. * * cert.issuer = name * cert.sign key, OpenSSL::Digest::SHA1.new * * open 'certificate.pem', 'w' do |io| io.write cert.to_pem end * * === Loading a Certificate * * Like a key, a cert can also be loaded from a file. * * cert2 = OpenSSL::X509::Certificate.new File.read 'certificate.pem' * * === Verifying a Certificate * * Certificate#verify will return true when a certificate was signed with the * given public key. * * raise 'certificate can not be verified' unless cert2.verify key * * == Certificate Authority * * A certificate authority (CA) is a trusted third party that allows you to * verify the ownership of unknown certificates. The CA issues key signatures * that indicate it trusts the user of that key. A user encountering the key * can verify the signature by using the CA's public key. * * === CA Key * * CA keys are valuable, so we encrypt and save it to disk and make sure it is * not readable by other users. * * ca_key = OpenSSL::PKey::RSA.new 2048 * pass_phrase = 'my secure pass phrase goes here' * * cipher = OpenSSL::Cipher.new 'AES-128-CBC' * * open 'ca_key.pem', 'w', 0400 do |io| * io.write ca_key.export(cipher, pass_phrase) * end * * === CA Certificate * * A CA certificate is created the same way we created a certificate above, but * with different extensions. * * ca_name = OpenSSL::X509::Name.parse 'CN=ca/DC=example' * * ca_cert = OpenSSL::X509::Certificate.new * ca_cert.serial = 0 * ca_cert.version = 2 * ca_cert.not_before = Time.now * ca_cert.not_after = Time.now + 86400 * * ca_cert.public_key = ca_key.public_key * ca_cert.subject = ca_name * ca_cert.issuer = ca_name * * extension_factory = OpenSSL::X509::ExtensionFactory.new * extension_factory.subject_certificate = ca_cert * extension_factory.issuer_certificate = ca_cert * * ca_cert.add_extension \ * extension_factory.create_extension('subjectKeyIdentifier', 'hash') * * This extension indicates the CA's key may be used as a CA. * * ca_cert.add_extension \ * extension_factory.create_extension('basicConstraints', 'CA:TRUE', true) * * This extension indicates the CA's key may be used to verify signatures on * both certificates and certificate revocations. * * ca_cert.add_extension \ * extension_factory.create_extension( * 'keyUsage', 'cRLSign,keyCertSign', true) * * Root CA certificates are self-signed. * * ca_cert.sign ca_key, OpenSSL::Digest::SHA1.new * * The CA certificate is saved to disk so it may be distributed to all the * users of the keys this CA will sign. * * open 'ca_cert.pem', 'w' do |io| * io.write ca_cert.to_pem * end * * === Certificate Signing Request * * The CA signs keys through a Certificate Signing Request (CSR). The CSR * contains the information necessary to identify the key. * * csr = OpenSSL::X509::Request.new * csr.version = 0 * csr.subject = name * csr.public_key = key.public_key * csr.sign key, OpenSSL::Digest::SHA1.new * * A CSR is saved to disk and sent to the CA for signing. * * open 'csr.pem', 'w' do |io| * io.write csr.to_pem * end * * === Creating a Certificate from a CSR * * Upon receiving a CSR the CA will verify it before signing it. A minimal * verification would be to check the CSR's signature. * * csr = OpenSSL::X509::Request.new File.read 'csr.pem' * * raise 'CSR can not be verified' unless csr.verify csr.public_key * * After verification a certificate is created, marked for various usages, * signed with the CA key and returned to the requester. * * csr_cert = OpenSSL::X509::Certificate.new * csr_cert.serial = 0 * csr_cert.version = 2 * csr_cert.not_before = Time.now * csr_cert.not_after = Time.now + 600 * * csr_cert.subject = csr.subject * csr_cert.public_key = csr.public_key * csr_cert.issuer = ca_cert.subject * * extension_factory = OpenSSL::X509::ExtensionFactory.new * extension_factory.subject_certificate = csr_cert * extension_factory.issuer_certificate = ca_cert * * csr_cert.add_extension \ * extension_factory.create_extension('basicConstraints', 'CA:FALSE') * * csr_cert.add_extension \ * extension_factory.create_extension( * 'keyUsage', 'keyEncipherment,dataEncipherment,digitalSignature') * * csr_cert.add_extension \ * extension_factory.create_extension('subjectKeyIdentifier', 'hash') * * csr_cert.sign ca_key, OpenSSL::Digest::SHA1.new * * open 'csr_cert.pem', 'w' do |io| * io.write csr_cert.to_pem * end * * == SSL and TLS Connections * * Using our created key and certificate we can create an SSL or TLS connection. * An SSLContext is used to set up an SSL session. * * context = OpenSSL::SSL::SSLContext.new * * === SSL Server * * An SSL server requires the certificate and private key to communicate * securely with its clients: * * context.cert = cert * context.key = key * * Then create an SSLServer with a TCP server socket and the context. Use the * SSLServer like an ordinary TCP server. * * require 'socket' * * tcp_server = TCPServer.new 5000 * ssl_server = OpenSSL::SSL::SSLServer.new tcp_server, context * * loop do * ssl_connection = ssl_server.accept * * data = connection.gets * * response = "I got #{data.dump}" * puts response * * connection.puts "I got #{data.dump}" * connection.close * end * * === SSL client * * An SSL client is created with a TCP socket and the context. * SSLSocket#connect must be called to initiate the SSL handshake and start * encryption. A key and certificate are not required for the client socket. * * Note that SSLSocket#close doesn't close the underlying socket by default. Set * SSLSocket#sync_close to true if you want. * * require 'socket' * * tcp_socket = TCPSocket.new 'localhost', 5000 * ssl_client = OpenSSL::SSL::SSLSocket.new tcp_socket, context * ssl_client.sync_close = true * ssl_client.connect * * ssl_client.puts "hello server!" * puts ssl_client.gets * * ssl_client.close # shutdown the TLS connection and close tcp_socket * * === Peer Verification * * An unverified SSL connection does not provide much security. For enhanced * security the client or server can verify the certificate of its peer. * * The client can be modified to verify the server's certificate against the * certificate authority's certificate: * * context.ca_file = 'ca_cert.pem' * context.verify_mode = OpenSSL::SSL::VERIFY_PEER * * require 'socket' * * tcp_socket = TCPSocket.new 'localhost', 5000 * ssl_client = OpenSSL::SSL::SSLSocket.new tcp_socket, context * ssl_client.connect * * ssl_client.puts "hello server!" * puts ssl_client.gets * * If the server certificate is invalid or <tt>context.ca_file</tt> is not set * when verifying peers an OpenSSL::SSL::SSLError will be raised. * */ void Init_openssl(void) { /* * Init timezone info */ #if 0 tzset(); #endif /* * Init all digests, ciphers */ #if !defined(LIBRESSL_VERSION_NUMBER) && OPENSSL_VERSION_NUMBER >= 0x10100000 if (!OPENSSL_init_ssl(0, NULL)) rb_raise(rb_eRuntimeError, "OPENSSL_init_ssl"); #else OpenSSL_add_ssl_algorithms(); OpenSSL_add_all_algorithms(); ERR_load_crypto_strings(); SSL_load_error_strings(); #endif /* * Init main module */ mOSSL = rb_define_module("OpenSSL"); rb_global_variable(&mOSSL); /* * OpenSSL ruby extension version */ rb_define_const(mOSSL, "VERSION", rb_str_new2(OSSL_VERSION)); /* * Version of OpenSSL the ruby OpenSSL extension was built with */ rb_define_const(mOSSL, "OPENSSL_VERSION", rb_str_new2(OPENSSL_VERSION_TEXT)); /* * Version of OpenSSL the ruby OpenSSL extension is running with */ #if !defined(LIBRESSL_VERSION_NUMBER) && OPENSSL_VERSION_NUMBER >= 0x10100000 rb_define_const(mOSSL, "OPENSSL_LIBRARY_VERSION", rb_str_new2(OpenSSL_version(OPENSSL_VERSION))); #else rb_define_const(mOSSL, "OPENSSL_LIBRARY_VERSION", rb_str_new2(SSLeay_version(SSLEAY_VERSION))); #endif /* * Version number of OpenSSL the ruby OpenSSL extension was built with * (base 16) */ rb_define_const(mOSSL, "OPENSSL_VERSION_NUMBER", INT2NUM(OPENSSL_VERSION_NUMBER)); /* * Boolean indicating whether OpenSSL is FIPS-capable or not */ rb_define_const(mOSSL, "OPENSSL_FIPS", #ifdef OPENSSL_FIPS Qtrue #else Qfalse #endif ); rb_define_module_function(mOSSL, "fips_mode", ossl_fips_mode_get, 0); rb_define_module_function(mOSSL, "fips_mode=", ossl_fips_mode_set, 1); /* * Generic error, * common for all classes under OpenSSL module */ eOSSLError = rb_define_class_under(mOSSL,"OpenSSLError",rb_eStandardError); rb_global_variable(&eOSSLError); /* * Init debug core */ dOSSL = Qfalse; rb_global_variable(&dOSSL); rb_define_module_function(mOSSL, "debug", ossl_debug_get, 0); rb_define_module_function(mOSSL, "debug=", ossl_debug_set, 1); rb_define_module_function(mOSSL, "errors", ossl_get_errors, 0); /* * Get ID of to_der */ ossl_s_to_der = rb_intern("to_der"); #if !defined(HAVE_OPENSSL_110_THREADING_API) Init_ossl_locks(); #endif /* * Init components */ Init_ossl_bn(); Init_ossl_cipher(); Init_ossl_config(); Init_ossl_digest(); Init_ossl_hmac(); Init_ossl_ns_spki(); Init_ossl_pkcs12(); Init_ossl_pkcs7(); Init_ossl_pkey(); Init_ossl_rand(); Init_ossl_ssl(); Init_ossl_x509(); Init_ossl_ocsp(); Init_ossl_engine(); Init_ossl_asn1(); Init_ossl_kdf(); #if defined(OSSL_DEBUG) /* * For debugging Ruby/OpenSSL. Enable only when built with --enable-debug */ #if !defined(LIBRESSL_VERSION_NUMBER) && \ (OPENSSL_VERSION_NUMBER >= 0x10100000 && !defined(OPENSSL_NO_CRYPTO_MDEBUG) || \ defined(CRYPTO_malloc_debug_init)) rb_define_module_function(mOSSL, "mem_check_start", mem_check_start, 0); rb_define_module_function(mOSSL, "print_mem_leaks", print_mem_leaks, 0); #if defined(CRYPTO_malloc_debug_init) /* <= 1.0.2 */ CRYPTO_malloc_debug_init(); #endif #if defined(V_CRYPTO_MDEBUG_ALL) /* <= 1.0.2 */ CRYPTO_set_mem_debug_options(V_CRYPTO_MDEBUG_ALL); #endif #if OPENSSL_VERSION_NUMBER < 0x10100000 /* <= 1.0.2 */ { int i; /* * See crypto/ex_data.c; call def_get_class() immediately to avoid * allocations. 15 is the maximum number that is used as the class index * in OpenSSL 1.0.2. */ for (i = 0; i <= 15; i++) { if (CRYPTO_get_ex_new_index(i, 0, (void *)"ossl-mdebug-dummy", 0, 0, 0) < 0) rb_raise(rb_eRuntimeError, "CRYPTO_get_ex_new_index for " "class index %d failed", i); } } #endif #endif #endif }
int main(int argc, char *argv[]) { char *CApath = NULL, *CAfile = NULL; int badop = 0; int ret = 1; int client_auth = 0; int server_auth = 0; SSL_CTX *s_ctx = NULL; SSL_CTX *c_ctx = NULL; char *scert = TEST_SERVER_CERT; char *ccert = TEST_CLIENT_CERT; SSL_METHOD *ssl_method = SSLv23_method(); RAND_seed(rnd_seed, sizeof rnd_seed); if (bio_err == NULL) bio_err = BIO_new_fp(stderr, BIO_NOCLOSE); if (bio_stdout == NULL) bio_stdout = BIO_new_fp(stdout, BIO_NOCLOSE); argc--; argv++; while (argc >= 1) { if (sgx_strcmp(*argv, "-server_auth") == 0) server_auth = 1; else if (sgx_strcmp(*argv, "-client_auth") == 0) client_auth = 1; else if (sgx_strcmp(*argv, "-reconnect") == 0) reconnect = 1; else if (sgx_strcmp(*argv, "-stats") == 0) cache_stats = 1; else if (sgx_strcmp(*argv, "-ssl3") == 0) ssl_method = SSLv3_method(); else if (sgx_strcmp(*argv, "-ssl2") == 0) ssl_method = SSLv2_method(); else if (sgx_strcmp(*argv, "-CApath") == 0) { if (--argc < 1) goto bad; CApath = *(++argv); } else if (sgx_strcmp(*argv, "-CAfile") == 0) { if (--argc < 1) goto bad; CAfile = *(++argv); } else if (sgx_strcmp(*argv, "-cert") == 0) { if (--argc < 1) goto bad; scert = *(++argv); } else if (sgx_strcmp(*argv, "-ccert") == 0) { if (--argc < 1) goto bad; ccert = *(++argv); } else if (sgx_strcmp(*argv, "-threads") == 0) { if (--argc < 1) goto bad; thread_number = atoi(*(++argv)); if (thread_number == 0) thread_number = 1; if (thread_number > MAX_THREAD_NUMBER) thread_number = MAX_THREAD_NUMBER; } else if (sgx_strcmp(*argv, "-loops") == 0) { if (--argc < 1) goto bad; number_of_loops = atoi(*(++argv)); if (number_of_loops == 0) number_of_loops = 1; } else { fprintf(stderr, "unknown option %s\n", *argv); badop = 1; break; } argc--; argv++; } if (badop) { bad: sv_usage(); goto end; } if (cipher == NULL && OPENSSL_issetugid() == 0) cipher = getenv("SSL_CIPHER"); SSL_load_error_strings(); OpenSSL_add_ssl_algorithms(); c_ctx = SSL_CTX_new(ssl_method); s_ctx = SSL_CTX_new(ssl_method); if ((c_ctx == NULL) || (s_ctx == NULL)) { ERR_print_errors(bio_err); goto end; } SSL_CTX_set_session_cache_mode(s_ctx, SSL_SESS_CACHE_NO_AUTO_CLEAR | SSL_SESS_CACHE_SERVER); SSL_CTX_set_session_cache_mode(c_ctx, SSL_SESS_CACHE_NO_AUTO_CLEAR | SSL_SESS_CACHE_SERVER); if (!SSL_CTX_use_certificate_file(s_ctx, scert, SSL_FILETYPE_PEM)) { ERR_print_errors(bio_err); } else if (!SSL_CTX_use_RSAPrivateKey_file(s_ctx, scert, SSL_FILETYPE_PEM)) { ERR_print_errors(bio_err); goto end; } if (client_auth) { SSL_CTX_use_certificate_file(c_ctx, ccert, SSL_FILETYPE_PEM); SSL_CTX_use_RSAPrivateKey_file(c_ctx, ccert, SSL_FILETYPE_PEM); } if ((!SSL_CTX_load_verify_locations(s_ctx, CAfile, CApath)) || (!SSL_CTX_set_default_verify_paths(s_ctx)) || (!SSL_CTX_load_verify_locations(c_ctx, CAfile, CApath)) || (!SSL_CTX_set_default_verify_paths(c_ctx))) { fprintf(stderr, "SSL_load_verify_locations\n"); ERR_print_errors(bio_err); goto end; } if (client_auth) { fprintf(stderr, "client authentication\n"); SSL_CTX_set_verify(s_ctx, SSL_VERIFY_PEER | SSL_VERIFY_FAIL_IF_NO_PEER_CERT, verify_callback); } if (server_auth) { fprintf(stderr, "server authentication\n"); SSL_CTX_set_verify(c_ctx, SSL_VERIFY_PEER, verify_callback); } thread_setup(); do_threads(s_ctx, c_ctx); thread_cleanup(); end: if (c_ctx != NULL) { fprintf(stderr, "Client SSL_CTX stats then free it\n"); print_stats(stderr, c_ctx); SSL_CTX_free(c_ctx); } if (s_ctx != NULL) { fprintf(stderr, "Server SSL_CTX stats then free it\n"); print_stats(stderr, s_ctx); if (cache_stats) { fprintf(stderr, "-----\n"); lh_stats(SSL_CTX_sessions(s_ctx), stderr); fprintf(stderr, "-----\n"); /*- lh_node_stats(SSL_CTX_sessions(s_ctx),stderr); fprintf(stderr,"-----\n"); */ lh_node_usage_stats(SSL_CTX_sessions(s_ctx), stderr); fprintf(stderr, "-----\n"); } SSL_CTX_free(s_ctx); fprintf(stderr, "done free\n"); } exit(ret); return (0); }