SSL_CTX *ssl_init() { SSL_CTX *ctx = NULL; SSL_load_error_strings(); SSL_library_init(); OpenSSL_add_all_algorithms(); ssl_data_index = SSL_get_ex_new_index(0,0,0,0,0); if ((locks = calloc(CRYPTO_num_locks(), sizeof(pthread_mutex_t)))) { for (int i = 0; i < CRYPTO_num_locks(); i++) { pthread_mutex_init(&locks[i], NULL); } CRYPTO_set_locking_callback(ssl_lock); CRYPTO_set_id_callback(ssl_id); if ((ctx = SSL_CTX_new(SSLv23_client_method()))) { SSL_CTX_set_verify(ctx, SSL_VERIFY_NONE, NULL); SSL_CTX_set_verify_depth(ctx, 0); SSL_CTX_set_mode(ctx, SSL_MODE_AUTO_RETRY); SSL_CTX_set_session_cache_mode(ctx, SSL_SESS_CACHE_CLIENT); SSL_CTX_sess_set_new_cb(ctx, new_session_callback); SSL_CTX_set_info_callback(ctx, ssl_info_callback); } } return ctx; }
SSLSessionCacheManager::SSLSessionCacheManager( uint32_t maxCacheSize, uint32_t cacheCullSize, SSLContext* ctx, const folly::SocketAddress& sockaddr, const string& context, EventBase* eventBase, SSLStats* stats, const std::shared_ptr<SSLCacheProvider>& externalCache): ctx_(ctx), stats_(stats), externalCache_(externalCache) { SSL_CTX* sslCtx = ctx->getSSLCtx(); SSLUtil::getSSLCtxExIndex(&sExDataIndex_); SSL_CTX_set_ex_data(sslCtx, sExDataIndex_, this); SSL_CTX_sess_set_new_cb(sslCtx, SSLSessionCacheManager::newSessionCallback); SSL_CTX_sess_set_get_cb(sslCtx, SSLSessionCacheManager::getSessionCallback); SSL_CTX_sess_set_remove_cb(sslCtx, SSLSessionCacheManager::removeSessionCallback); if (!FLAGS_dcache_unit_test && !context.empty()) { // Use the passed in context ctx->setSessionCacheContext(context); } SSL_CTX_set_session_cache_mode(sslCtx, SSL_SESS_CACHE_NO_INTERNAL | SSL_SESS_CACHE_SERVER); localCache_ = SSLSessionCacheManager::getLocalCache(maxCacheSize, cacheCullSize); VLOG(2) << "On VipID=" << sockaddr.describe() << " context=" << context; }
void h2o_socket_ssl_async_resumption_setup_ctx(SSL_CTX *ctx) { SSL_CTX_sess_set_get_cb(ctx, on_async_resumption_get); SSL_CTX_sess_set_new_cb(ctx, on_async_resumption_new); SSL_CTX_sess_set_remove_cb(ctx, on_async_resumption_remove); /* if necessary, it is the responsibility of the caller to disable the internal cache */ }
/* Initializes SSL and allocate global context SSL_context SYNOPSIS my_ssl_start mysql connection handle RETURN VALUES 0 success 1 error */ int ma_tls_start(char *errmsg, size_t errmsg_len) { int rc= 1; if (ma_tls_initialized) return 0; /* lock mutex to prevent multiple initialization */ pthread_mutex_init(&LOCK_openssl_config,MY_MUTEX_INIT_FAST); pthread_mutex_lock(&LOCK_openssl_config); #if OPENSSL_VERSION_NUMBER >= 0x10100000L OPENSSL_init_ssl(OPENSSL_INIT_LOAD_CONFIG, NULL); #else if (ssl_thread_init()) { strncpy(errmsg, "Not enough memory", errmsg_len); goto end; } SSL_library_init(); #if SSLEAY_VERSION_NUMBER >= 0x00907000L OPENSSL_config(NULL); #endif #endif /* load errors */ SSL_load_error_strings(); /* digests and ciphers */ OpenSSL_add_all_algorithms(); #if OPENSSL_VERSION_NUMBER >= 0x10100000L if (!(SSL_context= SSL_CTX_new(TLS_client_method()))) #else if (!(SSL_context= SSL_CTX_new(SSLv23_client_method()))) #endif { ma_tls_get_error(errmsg, errmsg_len); goto end; } #ifdef HAVE_TLS_SESSION_CACHE SSL_CTX_set_session_cache_mode(SSL_context, SSL_SESS_CACHE_CLIENT); ma_tls_sessions= (MA_SSL_SESSION *)calloc(1, sizeof(struct st_ma_tls_session) * ma_tls_session_cache_size); SSL_CTX_sess_set_new_cb(SSL_context, ma_tls_session_cb); SSL_CTX_sess_set_remove_cb(SSL_context, ma_tls_remove_session_cb); #endif disable_sigpipe(); #if OPENSSL_USE_BIOMETHOD memcpy(&ma_BIO_method, BIO_s_socket(), sizeof(BIO_METHOD)); ma_BIO_method.bread= ma_bio_read; ma_BIO_method.bwrite= ma_bio_write; #endif rc= 0; ma_tls_initialized= TRUE; end: pthread_mutex_unlock(&LOCK_openssl_config); return rc; }
static void ssl_init_ctx_session_cache(server_rec *s, apr_pool_t *p, apr_pool_t *ptemp, modssl_ctx_t *mctx) { SSL_CTX *ctx = mctx->ssl_ctx; SSLModConfigRec *mc = myModConfig(s); long cache_mode = SSL_SESS_CACHE_OFF; if (mc->nSessionCacheMode != SSL_SCMODE_NONE) { /* SSL_SESS_CACHE_NO_INTERNAL will force OpenSSL * to ignore process local-caching and * to always get/set/delete sessions using mod_ssl's callbacks. */ cache_mode = SSL_SESS_CACHE_SERVER|SSL_SESS_CACHE_NO_INTERNAL; } SSL_CTX_set_session_cache_mode(ctx, cache_mode); SSL_CTX_sess_set_new_cb(ctx, ssl_callback_NewSessionCacheEntry); SSL_CTX_sess_set_get_cb(ctx, ssl_callback_GetSessionCacheEntry); SSL_CTX_sess_set_remove_cb(ctx, ssl_callback_DelSessionCacheEntry); }
static int execute_test_session(SSL_SESSION_TEST_FIXTURE fix) { SSL_CTX *sctx = NULL, *cctx = NULL; SSL *serverssl1 = NULL, *clientssl1 = NULL; SSL *serverssl2 = NULL, *clientssl2 = NULL; #ifndef OPENSSL_NO_TLS1_1 SSL *serverssl3 = NULL, *clientssl3 = NULL; #endif SSL_SESSION *sess1 = NULL, *sess2 = NULL; int testresult = 0; if (!create_ssl_ctx_pair(TLS_server_method(), TLS_client_method(), &sctx, &cctx, cert, privkey)) { printf("Unable to create SSL_CTX pair\n"); return 0; } #ifndef OPENSSL_NO_TLS1_2 /* Only allow TLS1.2 so we can force a connection failure later */ SSL_CTX_set_min_proto_version(cctx, TLS1_2_VERSION); #endif /* Set up session cache */ if (fix.use_ext_cache) { SSL_CTX_sess_set_new_cb(cctx, new_session_cb); SSL_CTX_sess_set_remove_cb(cctx, remove_session_cb); } if (fix.use_int_cache) { /* Also covers instance where both are set */ SSL_CTX_set_session_cache_mode(cctx, SSL_SESS_CACHE_CLIENT); } else { SSL_CTX_set_session_cache_mode(cctx, SSL_SESS_CACHE_CLIENT | SSL_SESS_CACHE_NO_INTERNAL_STORE); } if (!create_ssl_objects(sctx, cctx, &serverssl1, &clientssl1, NULL, NULL)) { printf("Unable to create SSL objects\n"); goto end; } if (!create_ssl_connection(serverssl1, clientssl1)) { printf("Unable to create SSL connection\n"); goto end; } sess1 = SSL_get1_session(clientssl1); if (sess1 == NULL) { printf("Unexpected NULL session\n"); goto end; } if (fix.use_int_cache && SSL_CTX_add_session(cctx, sess1)) { /* Should have failed because it should already be in the cache */ printf("Unexpected success adding session to cache\n"); goto end; } if (fix.use_ext_cache && (new_called != 1 || remove_called != 0)) { printf("Session not added to cache\n"); goto end; } if (!create_ssl_objects(sctx, cctx, &serverssl2, &clientssl2, NULL, NULL)) { printf("Unable to create second SSL objects\n"); goto end; } if (!create_ssl_connection(serverssl2, clientssl2)) { printf("Unable to create second SSL connection\n"); goto end; } sess2 = SSL_get1_session(clientssl2); if (sess2 == NULL) { printf("Unexpected NULL session from clientssl2\n"); goto end; } if (fix.use_ext_cache && (new_called != 2 || remove_called != 0)) { printf("Remove session callback unexpectedly called\n"); goto end; } /* * This should clear sess2 from the cache because it is a "bad" session. See * SSL_set_session() documentation. */ if (!SSL_set_session(clientssl2, sess1)) { printf("Unexpected failure setting session\n"); goto end; } if (fix.use_ext_cache && (new_called != 2 || remove_called != 1)) { printf("Failed to call callback to remove session\n"); goto end; } if (SSL_get_session(clientssl2) != sess1) { printf("Unexpected session found\n"); goto end; } if (fix.use_int_cache) { if (!SSL_CTX_add_session(cctx, sess2)) { /* * Should have succeeded because it should not already be in the cache */ printf("Unexpected failure adding session to cache\n"); goto end; } if (!SSL_CTX_remove_session(cctx, sess2)) { printf("Unexpected failure removing session from cache\n"); goto end; } /* This is for the purposes of internal cache testing...ignore the * counter for external cache */ if (fix.use_ext_cache) remove_called--; } /* This shouldn't be in the cache so should fail */ if (SSL_CTX_remove_session(cctx, sess2)) { printf("Unexpected success removing session from cache\n"); goto end; } if (fix.use_ext_cache && (new_called != 2 || remove_called != 2)) { printf("Failed to call callback to remove session #2\n"); goto end; } #if !defined(OPENSSL_NO_TLS1_1) && !defined(OPENSSL_NO_TLS1_2) /* Force a connection failure */ SSL_CTX_set_max_proto_version(sctx, TLS1_1_VERSION); if (!create_ssl_objects(sctx, cctx, &serverssl3, &clientssl3, NULL, NULL)) { printf("Unable to create third SSL objects\n"); goto end; } if (!SSL_set_session(clientssl3, sess1)) { printf("Unable to set session for third connection\n"); goto end; } /* This should fail because of the mismatched protocol versions */ if (create_ssl_connection(serverssl3, clientssl3)) { printf("Unable to create third SSL connection\n"); goto end; } /* We should have automatically removed the session from the cache */ if (fix.use_ext_cache && (new_called != 2 || remove_called != 3)) { printf("Failed to call callback to remove session #2\n"); goto end; } if (fix.use_int_cache && !SSL_CTX_add_session(cctx, sess2)) { /* * Should have succeeded because it should not already be in the cache */ printf("Unexpected failure adding session to cache #2\n"); goto end; } #endif testresult = 1; end: SSL_free(serverssl1); SSL_free(clientssl1); SSL_free(serverssl2); SSL_free(clientssl2); #ifndef OPENSSL_NO_TLS1_1 SSL_free(serverssl3); SSL_free(clientssl3); #endif SSL_SESSION_free(sess1); SSL_SESSION_free(sess2); /* * Check if we need to remove any sessions up-refed for the external cache */ if (new_called >= 1) SSL_SESSION_free(sess1); if (new_called >= 2) SSL_SESSION_free(sess2); SSL_CTX_free(sctx); SSL_CTX_free(cctx); return testresult; }
/* * Create Global context SSL and use it in every new session * * - Load the trusted CAs * - Load the Private key & the certificate * - Set the Context options & Verify options */ static SSL_CTX *init_tls_ctx(EAP_TLS_CONF *conf) { SSL_METHOD *meth; SSL_CTX *ctx; X509_STORE *certstore; int verify_mode = SSL_VERIFY_NONE; int ctx_options = 0; int type; /* * Add all the default ciphers and message digests * Create our context. */ SSL_library_init(); SSL_load_error_strings(); /* * SHA256 is in all versions of OpenSSL, but isn't * initialized by default. It's needed for WiMAX * certificates. */ #ifdef HAVE_OPENSSL_EVP_SHA256 EVP_add_digest(EVP_sha256()); #endif meth = TLSv1_method(); ctx = SSL_CTX_new(meth); /* * Identify the type of certificates that needs to be loaded */ if (conf->file_type) { type = SSL_FILETYPE_PEM; } else { type = SSL_FILETYPE_ASN1; } /* * Set the password to load private key */ if (conf->private_key_password) { #ifdef __APPLE__ /* * We don't want to put the private key password in eap.conf, so check * for our special string which indicates we should get the password * programmatically. */ const char* special_string = "Apple:UseCertAdmin"; if (strncmp(conf->private_key_password, special_string, strlen(special_string)) == 0) { char cmd[256]; const long max_password_len = 128; snprintf(cmd, sizeof(cmd) - 1, "/usr/sbin/certadmin --get-private-key-passphrase \"%s\"", conf->private_key_file); DEBUG2("rlm_eap: Getting private key passphrase using command \"%s\"", cmd); FILE* cmd_pipe = popen(cmd, "r"); if (!cmd_pipe) { radlog(L_ERR, "rlm_eap: %s command failed. Unable to get private_key_password", cmd); radlog(L_ERR, "rlm_eap: Error reading private_key_file %s", conf->private_key_file); return NULL; } free(conf->private_key_password); conf->private_key_password = malloc(max_password_len * sizeof(char)); if (!conf->private_key_password) { radlog(L_ERR, "rlm_eap: Can't malloc space for private_key_password"); radlog(L_ERR, "rlm_eap: Error reading private_key_file %s", conf->private_key_file); pclose(cmd_pipe); return NULL; } fgets(conf->private_key_password, max_password_len, cmd_pipe); pclose(cmd_pipe); /* Get rid of newline at end of password. */ conf->private_key_password[strlen(conf->private_key_password) - 1] = '\0'; DEBUG2("rlm_eap: Password from command = \"%s\"", conf->private_key_password); } #endif SSL_CTX_set_default_passwd_cb_userdata(ctx, conf->private_key_password); SSL_CTX_set_default_passwd_cb(ctx, cbtls_password); } /* * Load our keys and certificates * * If certificates are of type PEM then we can make use * of cert chain authentication using openssl api call * SSL_CTX_use_certificate_chain_file. Please see how * the cert chain needs to be given in PEM from * openSSL.org */ if (type == SSL_FILETYPE_PEM) { if (!(SSL_CTX_use_certificate_chain_file(ctx, conf->certificate_file))) { radlog(L_ERR, "rlm_eap: SSL error %s", ERR_error_string(ERR_get_error(), NULL)); radlog(L_ERR, "rlm_eap_tls: Error reading certificate file %s", conf->certificate_file); return NULL; } } else if (!(SSL_CTX_use_certificate_file(ctx, conf->certificate_file, type))) { radlog(L_ERR, "rlm_eap: SSL error %s", ERR_error_string(ERR_get_error(), NULL)); radlog(L_ERR, "rlm_eap_tls: Error reading certificate file %s", conf->certificate_file); return NULL; } /* Load the CAs we trust */ if (conf->ca_file || conf->ca_path) { if (!SSL_CTX_load_verify_locations(ctx, conf->ca_file, conf->ca_path)) { radlog(L_ERR, "rlm_eap: SSL error %s", ERR_error_string(ERR_get_error(), NULL)); radlog(L_ERR, "rlm_eap_tls: Error reading Trusted root CA list %s",conf->ca_file ); return NULL; } } if (conf->ca_file && *conf->ca_file) SSL_CTX_set_client_CA_list(ctx, SSL_load_client_CA_file(conf->ca_file)); if (!(SSL_CTX_use_PrivateKey_file(ctx, conf->private_key_file, type))) { radlog(L_ERR, "rlm_eap: SSL error %s", ERR_error_string(ERR_get_error(), NULL)); radlog(L_ERR, "rlm_eap_tls: Error reading private key file %s", conf->private_key_file); return NULL; } /* * Check if the loaded private key is the right one */ if (!SSL_CTX_check_private_key(ctx)) { radlog(L_ERR, "rlm_eap_tls: Private key does not match the certificate public key"); return NULL; } /* * Set ctx_options */ ctx_options |= SSL_OP_NO_SSLv2; ctx_options |= SSL_OP_NO_SSLv3; #ifdef SSL_OP_NO_TICKET ctx_options |= SSL_OP_NO_TICKET ; #endif /* * SSL_OP_SINGLE_DH_USE must be used in order to prevent * small subgroup attacks and forward secrecy. Always * using * * SSL_OP_SINGLE_DH_USE has an impact on the computer * time needed during negotiation, but it is not very * large. */ ctx_options |= SSL_OP_SINGLE_DH_USE; /* * SSL_OP_DONT_INSERT_EMPTY_FRAGMENTS to work around issues * in Windows Vista client. * http://www.openssl.org/~bodo/tls-cbc.txt * http://www.nabble.com/(RADIATOR)-Radiator-Version-3.16-released-t2600070.html */ ctx_options |= SSL_OP_DONT_INSERT_EMPTY_FRAGMENTS; SSL_CTX_set_options(ctx, ctx_options); /* * TODO: Set the RSA & DH * SSL_CTX_set_tmp_rsa_callback(ctx, cbtls_rsa); * SSL_CTX_set_tmp_dh_callback(ctx, cbtls_dh); */ /* * set the message callback to identify the type of * message. For every new session, there can be a * different callback argument. * * SSL_CTX_set_msg_callback(ctx, cbtls_msg); */ /* Set Info callback */ SSL_CTX_set_info_callback(ctx, cbtls_info); /* * Callbacks, etc. for session resumption. */ if (conf->session_cache_enable) { SSL_CTX_sess_set_new_cb(ctx, cbtls_new_session); SSL_CTX_sess_set_get_cb(ctx, cbtls_get_session); SSL_CTX_sess_set_remove_cb(ctx, cbtls_remove_session); SSL_CTX_set_quiet_shutdown(ctx, 1); } /* * Check the certificates for revocation. */ #ifdef X509_V_FLAG_CRL_CHECK if (conf->check_crl) { certstore = SSL_CTX_get_cert_store(ctx); if (certstore == NULL) { radlog(L_ERR, "rlm_eap: SSL error %s", ERR_error_string(ERR_get_error(), NULL)); radlog(L_ERR, "rlm_eap_tls: Error reading Certificate Store"); return NULL; } X509_STORE_set_flags(certstore, X509_V_FLAG_CRL_CHECK); } #endif /* * Set verify modes * Always verify the peer certificate */ verify_mode |= SSL_VERIFY_PEER; verify_mode |= SSL_VERIFY_FAIL_IF_NO_PEER_CERT; verify_mode |= SSL_VERIFY_CLIENT_ONCE; SSL_CTX_set_verify(ctx, verify_mode, cbtls_verify); if (conf->verify_depth) { SSL_CTX_set_verify_depth(ctx, conf->verify_depth); } /* Load randomness */ if (!(RAND_load_file(conf->random_file, 1024*1024))) { radlog(L_ERR, "rlm_eap: SSL error %s", ERR_error_string(ERR_get_error(), NULL)); radlog(L_ERR, "rlm_eap_tls: Error loading randomness"); return NULL; } /* * Set the cipher list if we were told to */ if (conf->cipher_list) { if (!SSL_CTX_set_cipher_list(ctx, conf->cipher_list)) { radlog(L_ERR, "rlm_eap_tls: Error setting cipher list"); return NULL; } } /* * Setup session caching */ if (conf->session_cache_enable) { /* * Create a unique context Id per EAP-TLS configuration. */ if (conf->session_id_name) { snprintf(conf->session_context_id, sizeof(conf->session_context_id), "FreeRADIUS EAP-TLS %s", conf->session_id_name); } else { snprintf(conf->session_context_id, sizeof(conf->session_context_id), "FreeRADIUS EAP-TLS %p", conf); } /* * Cache it, and DON'T auto-clear it. */ SSL_CTX_set_session_cache_mode(ctx, SSL_SESS_CACHE_SERVER | SSL_SESS_CACHE_NO_AUTO_CLEAR); SSL_CTX_set_session_id_context(ctx, (unsigned char *) conf->session_context_id, (unsigned int) strlen(conf->session_context_id)); /* * Our timeout is in hours, this is in seconds. */ SSL_CTX_set_timeout(ctx, conf->session_timeout * 3600); /* * Set the maximum number of entries in the * session cache. */ SSL_CTX_sess_set_cache_size(ctx, conf->session_cache_size); } else { SSL_CTX_set_session_cache_mode(ctx, SSL_SESS_CACHE_OFF); } /* * Register the application indices. We can't use * hard-coded "0" and "1" as before, because we need to * set up a "free" handler for the cached session * information. */ if (eaptls_handle_idx < 0) { eaptls_handle_idx = SSL_get_ex_new_index(0, &eaptls_handle_idx, NULL, NULL, NULL); } if (eaptls_conf_idx < 0) { eaptls_conf_idx = SSL_get_ex_new_index(0, &eaptls_conf_idx, NULL, NULL, NULL); } if (eaptls_store_idx < 0) { eaptls_store_idx = SSL_get_ex_new_index(0, "eaptls_store_idx", NULL, NULL, NULL); } if (eaptls_session_idx < 0) { eaptls_session_idx = SSL_get_ex_new_index(0, &eaptls_session_idx, NULL, NULL, eaptls_session_free); } return ctx; }
void DnsTlsSessionCache::prepareSslContext(SSL_CTX* ssl_ctx) { SSL_CTX_set_session_cache_mode(ssl_ctx, SSL_SESS_CACHE_CLIENT); SSL_CTX_sess_set_new_cb(ssl_ctx, &DnsTlsSessionCache::newSessionCallback); }
/* * call-seq: * ctx.setup => Qtrue # first time * ctx.setup => nil # thereafter * * This method is called automatically when a new SSLSocket is created. * Normally you do not need to call this method (unless you are writing an extension in C). */ static VALUE ossl_sslctx_setup(VALUE self) { SSL_CTX *ctx; X509 *cert = NULL, *client_ca = NULL; X509_STORE *store; EVP_PKEY *key = NULL; char *ca_path = NULL, *ca_file = NULL; int i, verify_mode; VALUE val; if(OBJ_FROZEN(self)) return Qnil; Data_Get_Struct(self, SSL_CTX, ctx); #if !defined(OPENSSL_NO_DH) if (RTEST(ossl_sslctx_get_tmp_dh_cb(self))){ SSL_CTX_set_tmp_dh_callback(ctx, ossl_tmp_dh_callback); } else{ SSL_CTX_set_tmp_dh_callback(ctx, ossl_default_tmp_dh_callback); } #endif SSL_CTX_set_ex_data(ctx, ossl_ssl_ex_ptr_idx, (void*)self); val = ossl_sslctx_get_cert_store(self); if(!NIL_P(val)){ /* * WORKAROUND: * X509_STORE can count references, but * X509_STORE_free() doesn't care it. * So we won't increment it but mark it by ex_data. */ store = GetX509StorePtr(val); /* NO NEED TO DUP */ SSL_CTX_set_cert_store(ctx, store); SSL_CTX_set_ex_data(ctx, ossl_ssl_ex_store_p, (void*)1); } val = ossl_sslctx_get_extra_cert(self); if(!NIL_P(val)){ rb_block_call(val, rb_intern("each"), 0, 0, ossl_sslctx_add_extra_chain_cert_i, self); } /* private key may be bundled in certificate file. */ val = ossl_sslctx_get_cert(self); cert = NIL_P(val) ? NULL : GetX509CertPtr(val); /* NO DUP NEEDED */ val = ossl_sslctx_get_key(self); key = NIL_P(val) ? NULL : GetPKeyPtr(val); /* NO DUP NEEDED */ if (cert && key) { if (!SSL_CTX_use_certificate(ctx, cert)) { /* Adds a ref => Safe to FREE */ ossl_raise(eSSLError, "SSL_CTX_use_certificate:"); } if (!SSL_CTX_use_PrivateKey(ctx, key)) { /* Adds a ref => Safe to FREE */ ossl_raise(eSSLError, "SSL_CTX_use_PrivateKey:"); } if (!SSL_CTX_check_private_key(ctx)) { ossl_raise(eSSLError, "SSL_CTX_check_private_key:"); } } val = ossl_sslctx_get_client_ca(self); if(!NIL_P(val)){ if(TYPE(val) == T_ARRAY){ for(i = 0; i < RARRAY_LEN(val); i++){ client_ca = GetX509CertPtr(RARRAY_PTR(val)[i]); if (!SSL_CTX_add_client_CA(ctx, client_ca)){ /* Copies X509_NAME => FREE it. */ ossl_raise(eSSLError, "SSL_CTX_add_client_CA"); } } } else{ client_ca = GetX509CertPtr(val); /* NO DUP NEEDED. */ if (!SSL_CTX_add_client_CA(ctx, client_ca)){ /* Copies X509_NAME => FREE it. */ ossl_raise(eSSLError, "SSL_CTX_add_client_CA"); } } } val = ossl_sslctx_get_ca_file(self); ca_file = NIL_P(val) ? NULL : StringValuePtr(val); val = ossl_sslctx_get_ca_path(self); ca_path = NIL_P(val) ? NULL : StringValuePtr(val); if(ca_file || ca_path){ if (!SSL_CTX_load_verify_locations(ctx, ca_file, ca_path)) rb_warning("can't set verify locations"); } val = ossl_sslctx_get_verify_mode(self); verify_mode = NIL_P(val) ? SSL_VERIFY_NONE : NUM2INT(val); SSL_CTX_set_verify(ctx, verify_mode, ossl_ssl_verify_callback); if (RTEST(ossl_sslctx_get_client_cert_cb(self))) SSL_CTX_set_client_cert_cb(ctx, ossl_client_cert_cb); val = ossl_sslctx_get_timeout(self); if(!NIL_P(val)) SSL_CTX_set_timeout(ctx, NUM2LONG(val)); val = ossl_sslctx_get_verify_dep(self); if(!NIL_P(val)) SSL_CTX_set_verify_depth(ctx, NUM2LONG(val)); val = ossl_sslctx_get_options(self); if(!NIL_P(val)) SSL_CTX_set_options(ctx, NUM2LONG(val)); rb_obj_freeze(self); val = ossl_sslctx_get_sess_id_ctx(self); if (!NIL_P(val)){ StringValue(val); if (!SSL_CTX_set_session_id_context(ctx, (unsigned char *)RSTRING_PTR(val), RSTRING_LEN(val))){ ossl_raise(eSSLError, "SSL_CTX_set_session_id_context:"); } } if (RTEST(rb_iv_get(self, "@session_get_cb"))) { SSL_CTX_sess_set_get_cb(ctx, ossl_sslctx_session_get_cb); OSSL_Debug("SSL SESSION get callback added"); } if (RTEST(rb_iv_get(self, "@session_new_cb"))) { SSL_CTX_sess_set_new_cb(ctx, ossl_sslctx_session_new_cb); OSSL_Debug("SSL SESSION new callback added"); } if (RTEST(rb_iv_get(self, "@session_remove_cb"))) { SSL_CTX_sess_set_remove_cb(ctx, ossl_sslctx_session_remove_cb); OSSL_Debug("SSL SESSION remove callback added"); } #ifdef HAVE_SSL_SET_TLSEXT_HOST_NAME val = rb_iv_get(self, "@servername_cb"); if (!NIL_P(val)) { SSL_CTX_set_tlsext_servername_callback(ctx, ssl_servername_cb); OSSL_Debug("SSL TLSEXT servername callback added"); } #endif return Qtrue; }
static char * ngx_http_lua_merge_srv_conf(ngx_conf_t *cf, void *parent, void *child) { #if (NGX_HTTP_SSL) ngx_http_lua_srv_conf_t *prev = parent; ngx_http_lua_srv_conf_t *conf = child; ngx_http_ssl_srv_conf_t *sscf; dd("merge srv conf"); if (conf->srv.ssl_cert_src.len == 0) { conf->srv.ssl_cert_src = prev->srv.ssl_cert_src; conf->srv.ssl_cert_src_key = prev->srv.ssl_cert_src_key; conf->srv.ssl_cert_handler = prev->srv.ssl_cert_handler; } if (conf->srv.ssl_cert_src.len) { sscf = ngx_http_conf_get_module_srv_conf(cf, ngx_http_ssl_module); if (sscf == NULL || sscf->ssl.ctx == NULL) { ngx_log_error(NGX_LOG_EMERG, cf->log, 0, "no ssl configured for the server"); return NGX_CONF_ERROR; } #ifdef LIBRESSL_VERSION_NUMBER ngx_log_error(NGX_LOG_EMERG, cf->log, 0, "LibreSSL does not support ssl_ceritificate_by_lua*"); return NGX_CONF_ERROR; #else # if OPENSSL_VERSION_NUMBER >= 0x1000205fL SSL_CTX_set_cert_cb(sscf->ssl.ctx, ngx_http_lua_ssl_cert_handler, NULL); # else ngx_log_error(NGX_LOG_EMERG, cf->log, 0, "OpenSSL too old to support ssl_ceritificate_by_lua*"); return NGX_CONF_ERROR; # endif #endif } if (conf->srv.ssl_sess_store_src.len == 0) { conf->srv.ssl_sess_store_src = prev->srv.ssl_sess_store_src; conf->srv.ssl_sess_store_src_key = prev->srv.ssl_sess_store_src_key; conf->srv.ssl_sess_store_handler = prev->srv.ssl_sess_store_handler; } if (conf->srv.ssl_sess_store_src.len) { sscf = ngx_http_conf_get_module_srv_conf(cf, ngx_http_ssl_module); if (sscf && sscf->ssl.ctx) { #ifdef LIBRESSL_VERSION_NUMBER ngx_log_error(NGX_LOG_EMERG, cf->log, 0, "LibreSSL does not support " "ssl_session_store_by_lua*"); return NGX_CONF_ERROR; #else SSL_CTX_sess_set_new_cb(sscf->ssl.ctx, ngx_http_lua_ssl_sess_store_handler); #endif } } if (conf->srv.ssl_sess_fetch_src.len == 0) { conf->srv.ssl_sess_fetch_src = prev->srv.ssl_sess_fetch_src; conf->srv.ssl_sess_fetch_src_key = prev->srv.ssl_sess_fetch_src_key; conf->srv.ssl_sess_fetch_handler = prev->srv.ssl_sess_fetch_handler; } if (conf->srv.ssl_sess_fetch_src.len) { sscf = ngx_http_conf_get_module_srv_conf(cf, ngx_http_ssl_module); if (sscf && sscf->ssl.ctx) { #ifdef LIBRESSL_VERSION_NUMBER ngx_log_error(NGX_LOG_EMERG, cf->log, 0, "LibreSSL does not support " "ssl_session_fetch_by_lua*"); return NGX_CONF_ERROR; #else SSL_CTX_sess_set_get_cb(sscf->ssl.ctx, ngx_http_lua_ssl_sess_fetch_handler); #endif } } #endif /* NGX_HTTP_SSL */ return NGX_CONF_OK; }
SSL_CTX *uwsgi_ssl_new_server_context(char *name, char *crt, char *key, char *ciphers, char *client_ca) { SSL_CTX *ctx = SSL_CTX_new(SSLv23_server_method()); if (!ctx) { uwsgi_log("[uwsgi-ssl] unable to initialize context \"%s\"\n", name); return NULL; } // this part is taken from nginx and stud, removing unneeded functionality // stud (for me) has made the best choice on choosing DH approach long ssloptions = SSL_OP_NO_SSLv2 | SSL_OP_ALL | SSL_OP_NO_SESSION_RESUMPTION_ON_RENEGOTIATION; // disable compression (if possibile) #ifdef SSL_OP_NO_COMPRESSION ssloptions |= SSL_OP_NO_COMPRESSION; #endif // release/reuse buffers as soon as possibile #ifdef SSL_MODE_RELEASE_BUFFERS SSL_CTX_set_mode(ctx, SSL_MODE_RELEASE_BUFFERS); #endif if (SSL_CTX_use_certificate_chain_file(ctx, crt) <= 0) { uwsgi_log("[uwsgi-ssl] unable to assign certificate %s for context \"%s\"\n", crt, name); SSL_CTX_free(ctx); return NULL; } // this part is based from stud BIO *bio = BIO_new_file(crt, "r"); if (bio) { DH *dh = PEM_read_bio_DHparams(bio, NULL, NULL, NULL); BIO_free(bio); if (dh) { SSL_CTX_set_tmp_dh(ctx, dh); DH_free(dh); #if OPENSSL_VERSION_NUMBER >= 0x0090800fL #ifndef OPENSSL_NO_ECDH #ifdef NID_X9_62_prime256v1 EC_KEY *ecdh = EC_KEY_new_by_curve_name(NID_X9_62_prime256v1); SSL_CTX_set_tmp_ecdh(ctx, ecdh); EC_KEY_free(ecdh); #endif #endif #endif } } if (SSL_CTX_use_PrivateKey_file(ctx, key, SSL_FILETYPE_PEM) <= 0) { uwsgi_log("[uwsgi-ssl] unable to assign key %s for context \"%s\"\n", key, name); SSL_CTX_free(ctx); return NULL; } // if ciphers are specified, prefer server ciphers if (ciphers && strlen(ciphers) > 0) { if (SSL_CTX_set_cipher_list(ctx, ciphers) == 0) { uwsgi_log("[uwsgi-ssl] unable to set requested ciphers (%s) for context \"%s\"\n", ciphers, name); SSL_CTX_free(ctx); return NULL; } ssloptions |= SSL_OP_CIPHER_SERVER_PREFERENCE; } // set session context (if possibile), this is required for client certificate authentication if (name) { SSL_CTX_set_session_id_context(ctx, (unsigned char *) name, strlen(name)); } if (client_ca) { if (client_ca[0] == '!') { SSL_CTX_set_verify(ctx, SSL_VERIFY_PEER | SSL_VERIFY_FAIL_IF_NO_PEER_CERT, uwsgi_ssl_verify_callback); client_ca++; } else { SSL_CTX_set_verify(ctx, SSL_VERIFY_PEER, uwsgi_ssl_verify_callback); } // in the future we should allow to set the verify depth SSL_CTX_set_verify_depth(ctx, 1); if (SSL_CTX_load_verify_locations(ctx, client_ca, NULL) == 0) { uwsgi_log("[uwsgi-ssl] unable to set ssl verify locations (%s) for context \"%s\"\n", client_ca, name); SSL_CTX_free(ctx); return NULL; } STACK_OF(X509_NAME) * list = SSL_load_client_CA_file(client_ca); if (!list) { uwsgi_log("unable to load client CA certificate (%s) for context \"%s\"\n", client_ca, name); SSL_CTX_free(ctx); return NULL; } SSL_CTX_set_client_CA_list(ctx, list); } SSL_CTX_set_info_callback(ctx, uwsgi_ssl_info_cb); #ifdef SSL_CTRL_SET_TLSEXT_HOSTNAME SSL_CTX_set_tlsext_servername_callback(ctx, uwsgi_sni_cb); #endif // disable session caching by default SSL_CTX_set_session_cache_mode(ctx, SSL_SESS_CACHE_OFF); if (uwsgi.ssl_sessions_use_cache) { // we need to early initialize locking and caching uwsgi_setup_locking(); uwsgi_cache_create_all(); uwsgi.ssl_sessions_cache = uwsgi_cache_by_name(uwsgi.ssl_sessions_use_cache); if (!uwsgi.ssl_sessions_cache) { // check for default cache if (!strcmp(uwsgi.ssl_sessions_use_cache, "true") && uwsgi.caches) { uwsgi.ssl_sessions_cache = uwsgi.caches; } else { uwsgi_log("unable to find cache \"%s\"\n", uwsgi.ssl_sessions_use_cache ? uwsgi.ssl_sessions_use_cache : "default"); exit(1); } } if (!uwsgi.ssl_sessions_cache->max_items) { uwsgi_log("you have to enable uWSGI cache to use it as SSL session store !!!\n"); exit(1); } if (uwsgi.ssl_sessions_cache->blocksize < 4096) { uwsgi_log("cache blocksize for SSL session store must be at least 4096 bytes\n"); exit(1); } SSL_CTX_set_session_cache_mode(ctx, SSL_SESS_CACHE_SERVER| SSL_SESS_CACHE_NO_INTERNAL| SSL_SESS_CACHE_NO_AUTO_CLEAR); #ifdef SSL_OP_NO_TICKET ssloptions |= SSL_OP_NO_TICKET; #endif // just for fun SSL_CTX_sess_set_cache_size(ctx, 0); // set the callback for ssl sessions SSL_CTX_sess_set_new_cb(ctx, uwsgi_ssl_session_new_cb); SSL_CTX_sess_set_get_cb(ctx, uwsgi_ssl_session_get_cb); SSL_CTX_sess_set_remove_cb(ctx, uwsgi_ssl_session_remove_cb); } SSL_CTX_set_timeout(ctx, uwsgi.ssl_sessions_timeout); SSL_CTX_set_options(ctx, ssloptions); return ctx; }
TLS_APPL_STATE *tls_client_create(const TLS_CLIENT_INIT_PROPS *props) { const char *myname = "tls_client_create"; long off = 0; int cachable; SSL_CTX *client_ctx; TLS_APPL_STATE *app_ctx; /* * 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) { acl_msg_warn("%s: cannot allocate client SSL_CTX: disabling TLS support", myname); 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 (props->log_level >= 2) 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 (props->cache_type == 0 || tls_mgr_policy(props->cache_type, &cachable) != TLS_MGR_STAT_OK) cachable = 0; /* * Allocate an application context, and populate with mandatory protocol * and cipher data. */ app_ctx = tls_alloc_app_context(client_ctx); /* * The external session cache is implemented by the tlsmgr(8) process. */ if (cachable) { app_ctx->cache_type = acl_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_AUTO_CLEAR | SSL_SESS_CACHE_NO_INTERNAL_STORE); SSL_CTX_sess_set_new_cb(client_ctx, new_client_session_cb); } return (app_ctx); }
TLS_APPL_STATE *tls_server_init(const TLS_SERVER_INIT_PROPS *props) { SSL_CTX *server_ctx; long off = 0; int verify_flags = SSL_VERIFY_NONE; int cachable; int protomask; TLS_APPL_STATE *app_ctx; const EVP_MD *md_alg; unsigned int md_len; if (props->log_level >= 2) msg_info("initializing the server-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(); /* * First validate the protocols. If these are invalid, we can't continue. */ protomask = tls_protocol_mask(props->protocols); if (protomask == TLS_PROTOCOL_INVALID) { /* tls_protocol_mask() logs no warning. */ msg_warn("Invalid TLS protocol list \"%s\": disabling TLS support", props->protocols); return (0); } /* * 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); } } /* * Register SHA-2 digests, if implemented and not already registered. * Improves interoperability with clients and servers that prematurely * deploy SHA-2 certificates. */ #if defined(LN_sha256) && defined(NID_sha256) && !defined(OPENSSL_NO_SHA256) if (!EVP_get_digestbyname(LN_sha224)) EVP_add_digest(EVP_sha224()); if (!EVP_get_digestbyname(LN_sha256)) EVP_add_digest(EVP_sha256()); #endif #if defined(LN_sha512) && defined(NID_sha512) && !defined(OPENSSL_NO_SHA512) if (!EVP_get_digestbyname(LN_sha384)) EVP_add_digest(EVP_sha384()); if (!EVP_get_digestbyname(LN_sha512)) EVP_add_digest(EVP_sha512()); #endif /* * If the administrator specifies an unsupported digest algorithm, fail * now, rather than in the middle of a TLS handshake. */ if ((md_alg = EVP_get_digestbyname(props->fpt_dgst)) == 0) { msg_warn("Digest algorithm \"%s\" not found: disabling TLS support", props->fpt_dgst); return (0); } /* * Sanity check: Newer shared libraries may use larger digests. */ if ((md_len = EVP_MD_size(md_alg)) > EVP_MAX_MD_SIZE) { msg_warn("Digest algorithm \"%s\" output size %u too large:" " disabling TLS support", props->fpt_dgst, md_len); 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. Netscape communicator can still * communicate with SSLv2 servers, so it sends out a SSLv2 client hello. * To deal with it, our server must be SSLv2 aware (even if we don't like * SSLv2), so we need to have the SSLv23 server here. If we want to limit * the protocol level, we can add an option to not use SSLv2/v3/TLSv1 * later. */ ERR_clear_error(); if ((server_ctx = SSL_CTX_new(SSLv23_server_method())) == 0) { msg_warn("cannot allocate server SSL_CTX: disabling TLS support"); tls_print_errors(); return (0); } /* * See the verify callback in tls_verify.c */ SSL_CTX_set_verify_depth(server_ctx, props->verifydepth + 1); /* * Protocol work-arounds, OpenSSL version dependent. */ #ifdef SSL_OP_NO_TICKET off |= SSL_OP_NO_TICKET; #endif off |= tls_bug_bits(); SSL_CTX_set_options(server_ctx, off); /* * Global protocol selection. */ if (protomask != 0) SSL_CTX_set_options(server_ctx, ((protomask & TLS_PROTOCOL_TLSv1) ? SSL_OP_NO_TLSv1 : 0L) | ((protomask & TLS_PROTOCOL_TLSv1_1) ? SSL_OP_NO_TLSv1_1 : 0L) | ((protomask & TLS_PROTOCOL_TLSv1_2) ? SSL_OP_NO_TLSv1_2 : 0L) | ((protomask & TLS_PROTOCOL_SSLv3) ? SSL_OP_NO_SSLv3 : 0L) | ((protomask & TLS_PROTOCOL_SSLv2) ? SSL_OP_NO_SSLv2 : 0L)); #if OPENSSL_VERSION_NUMBER >= 0x0090700fL /* * Some sites may want to give the client less rope. On the other hand, * this could trigger inter-operability issues, the client should not * offer ciphers it implements poorly, but this hasn't stopped some * vendors from getting it wrong. * * XXX: Given OpenSSL's security history, nobody should still be using * 0.9.7, let alone 0.9.6 or earlier. Warning added to TLS_README.html. */ if (var_tls_preempt_clist) SSL_CTX_set_options(server_ctx, SSL_OP_CIPHER_SERVER_PREFERENCE); #endif /* * Set the call-back routine to debug handshake progress. */ if (props->log_level >= 2) SSL_CTX_set_info_callback(server_ctx, tls_info_callback); /* * Load the CA public key certificates for both the server cert and for * the verification of client 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(server_ctx, props->CAfile, props->CApath) < 0) { /* tls_set_ca_certificate_info() already logs a warning. */ SSL_CTX_free(server_ctx); /* 200411 */ return (0); } /* * Load the server 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). A client * with RSA only (e.g. Netscape) will use the RSA certificate only. A * client with openssl-library will use RSA first if not especially * changed in the cipher setup. */ if (tls_set_my_certificate_key_info(server_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(server_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(server_ctx, tls_tmp_rsa_cb); /* * Diffie-Hellman key generation parameters can either be loaded from * files (preferred) or taken from compiled in values. First, set the * callback that will select the values when requested, then load the * (possibly) available DH parameters from files. We are generous with * the error handling, since we do have default values compiled in, so we * will not abort but just log the error message. */ SSL_CTX_set_tmp_dh_callback(server_ctx, tls_tmp_dh_cb); if (*props->dh1024_param_file != 0) tls_set_dh_from_file(props->dh1024_param_file, 1024); if (*props->dh512_param_file != 0) tls_set_dh_from_file(props->dh512_param_file, 512); /* * Enable EECDH if available, errors are not fatal, we just keep going * with any remaining key-exchange algorithms. */ (void) tls_set_eecdh_curve(server_ctx, props->eecdh_grade); /* * If we want to check client certificates, we have to indicate it in * advance. By now we only allow to decide on a global basis. If we want * to allow certificate based relaying, we must ask the client to provide * one with SSL_VERIFY_PEER. The client now can decide, whether it * provides one or not. We can enforce a failure of the negotiation with * SSL_VERIFY_FAIL_IF_NO_PEER_CERT, if we do not allow a connection * without one. In the "server hello" following the initialization by the * "client hello" the server must provide a list of CAs it is willing to * accept. Some clever clients will then select one from the list of * available certificates matching these CAs. Netscape Communicator will * present the list of certificates for selecting the one to be sent, or * it will issue a warning, if there is no certificate matching the * available CAs. * * With regard to the purpose of the certificate for relaying, we might like * a later negotiation, maybe relaying would already be allowed for other * reasons, but this would involve severe changes in the internal postfix * logic, so we have to live with it the way it is. */ if (props->ask_ccert) verify_flags = SSL_VERIFY_PEER | SSL_VERIFY_CLIENT_ONCE; SSL_CTX_set_verify(server_ctx, verify_flags, tls_verify_certificate_callback); if (*props->CAfile) SSL_CTX_set_client_CA_list(server_ctx, SSL_load_client_CA_file(props->CAfile)); /* * Initialize our own TLS server handle, before diving into the details * of TLS session cache management. */ app_ctx = tls_alloc_app_context(server_ctx); /* * The session cache is implemented by the tlsmgr(8) server. * * XXX 200502 Surprise: when OpenSSL purges an entry from the in-memory * cache, it also attempts to purge the entry from the on-disk cache. * This is undesirable, especially when we set the in-memory cache size * to 1. For this reason we don't allow OpenSSL to purge on-disk cache * entries, and leave it up to the tlsmgr process instead. Found by * Victor Duchovni. */ if (tls_mgr_policy(props->cache_type, &cachable) != TLS_MGR_STAT_OK) cachable = 0; if (cachable || props->set_sessid) { /* * Initialize the session cache. * * With a large number of concurrent smtpd(8) processes, it is not a * good idea to cache multiple large session objects in each process. * We set the internal cache size to 1, and don't register a * "remove_cb" so as to avoid deleting good sessions from the * external cache prematurely (when the internal cache is full, * OpenSSL removes sessions from the external cache also)! * * 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). * * Set a session id context to identify to what type of server process * created a session. In our case, the context is simply the name of * the mail system: "Postfix/TLS". */ SSL_CTX_sess_set_cache_size(server_ctx, 1); SSL_CTX_set_session_id_context(server_ctx, (void *) &server_session_id_context, sizeof(server_session_id_context)); SSL_CTX_set_session_cache_mode(server_ctx, SSL_SESS_CACHE_SERVER | SSL_SESS_CACHE_NO_AUTO_CLEAR); if (cachable) { app_ctx->cache_type = mystrdup(props->cache_type); SSL_CTX_sess_set_get_cb(server_ctx, get_server_session_cb); SSL_CTX_sess_set_new_cb(server_ctx, new_server_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. */ SSL_CTX_set_timeout(server_ctx, props->scache_timeout); } else { /* * If we have no external cache, disable all caching. No use wasting * server memory resources with sessions they are unlikely to be able * to reuse. */ SSL_CTX_set_session_cache_mode(server_ctx, SSL_SESS_CACHE_OFF); } return (app_ctx); }
int context_init(SERVICE_OPTIONS *section) { /* init SSL context */ /* create SSL context */ if(section->option.client) section->ctx=SSL_CTX_new(section->client_method); else /* server mode */ section->ctx=SSL_CTX_new(section->server_method); if(!section->ctx) { sslerror("SSL_CTX_new"); return 1; /* FAILED */ } SSL_CTX_set_ex_data(section->ctx, index_opt, section); /* for callbacks */ /* load certificate and private key to be verified by the peer server */ #if !defined(OPENSSL_NO_ENGINE) && OPENSSL_VERSION_NUMBER>=0x0090809fL /* SSL_CTX_set_client_cert_engine() was introduced in OpenSSL 0.9.8i */ if(section->option.client && section->engine) { if(SSL_CTX_set_client_cert_engine(section->ctx, section->engine)) s_log(LOG_INFO, "Client certificate engine (%s) enabled", ENGINE_get_id(section->engine)); else /* no client certificate functionality in this engine */ sslerror("SSL_CTX_set_client_cert_engine"); /* ignore error */ } #endif if(auth_init(section)) return 1; /* FAILED */ /* initialize verification of the peer server certificate */ if(verify_init(section)) return 1; /* FAILED */ /* initialize DH/ECDH server mode */ if(!section->option.client) { #ifndef OPENSSL_NO_TLSEXT SSL_CTX_set_tlsext_servername_arg(section->ctx, section); SSL_CTX_set_tlsext_servername_callback(section->ctx, servername_cb); #endif /* OPENSSL_NO_TLSEXT */ #ifndef OPENSSL_NO_DH dh_init(section); /* ignore the result (errors are not critical) */ #endif /* OPENSSL_NO_DH */ #ifndef OPENSSL_NO_ECDH ecdh_init(section); /* ignore the result (errors are not critical) */ #endif /* OPENSSL_NO_ECDH */ } /* setup session cache */ if(!section->option.client) { unsigned servname_len=(unsigned)strlen(section->servname); if(servname_len>SSL_MAX_SSL_SESSION_ID_LENGTH) servname_len=SSL_MAX_SSL_SESSION_ID_LENGTH; if(!SSL_CTX_set_session_id_context(section->ctx, (unsigned char *)section->servname, servname_len)) { sslerror("SSL_CTX_set_session_id_context"); return 1; /* FAILED */ } } #ifdef SSL_SESS_CACHE_NO_INTERNAL_STORE /* the default cache mode is just SSL_SESS_CACHE_SERVER */ SSL_CTX_set_session_cache_mode(section->ctx, SSL_SESS_CACHE_SERVER|SSL_SESS_CACHE_NO_INTERNAL_STORE); #endif SSL_CTX_sess_set_cache_size(section->ctx, section->session_size); SSL_CTX_set_timeout(section->ctx, section->session_timeout); SSL_CTX_sess_set_new_cb(section->ctx, sess_new_cb); SSL_CTX_sess_set_get_cb(section->ctx, sess_get_cb); SSL_CTX_sess_set_remove_cb(section->ctx, sess_remove_cb); /* set info callback */ SSL_CTX_set_info_callback(section->ctx, info_callback); /* ciphers, options, mode */ if(section->cipher_list) if(!SSL_CTX_set_cipher_list(section->ctx, section->cipher_list)) { sslerror("SSL_CTX_set_cipher_list"); return 1; /* FAILED */ } SSL_CTX_set_options(section->ctx, (SSL_OPTIONS_TYPE)(section->ssl_options_set)); #if OPENSSL_VERSION_NUMBER>=0x009080dfL SSL_CTX_clear_options(section->ctx, (SSL_OPTIONS_TYPE)(section->ssl_options_clear)); s_log(LOG_DEBUG, "SSL options: 0x%08lX (+0x%08lX, -0x%08lX)", SSL_CTX_get_options(section->ctx), section->ssl_options_set, section->ssl_options_clear); #else /* OpenSSL older than 0.9.8m */ s_log(LOG_DEBUG, "SSL options: 0x%08lX (+0x%08lX)", SSL_CTX_get_options(section->ctx), section->ssl_options_set); #endif /* OpenSSL 0.9.8m or later */ /* initialize OpenSSL CONF options */ if(conf_init(section)) return 1; /* FAILED */ #ifdef SSL_MODE_RELEASE_BUFFERS SSL_CTX_set_mode(section->ctx, SSL_MODE_ENABLE_PARTIAL_WRITE | SSL_MODE_ACCEPT_MOVING_WRITE_BUFFER | SSL_MODE_RELEASE_BUFFERS); #else SSL_CTX_set_mode(section->ctx, SSL_MODE_ENABLE_PARTIAL_WRITE | SSL_MODE_ACCEPT_MOVING_WRITE_BUFFER); #endif return 0; /* OK */ }
int context_init(SERVICE_OPTIONS *section) { /* init SSL context */ /* create SSL context */ if(section->option.client) section->ctx=SSL_CTX_new(section->client_method); else /* server mode */ section->ctx=SSL_CTX_new(section->server_method); if(!section->ctx) { sslerror("SSL_CTX_new"); return 1; /* FAILED */ } SSL_CTX_set_ex_data(section->ctx, opt_index, section); /* for callbacks */ /* load certificate and private key to be verified by the peer server */ #ifdef HAVE_OSSL_ENGINE_H if(section->option.client && section->engine) { if(SSL_CTX_set_client_cert_engine(section->ctx, section->engine)) s_log(LOG_INFO, "Client certificate engine (%s) enabled", ENGINE_get_id(section->engine)); else /* no client certificate functionality in this engine */ sslerror("SSL_CTX_set_client_cert_engine"); /* ignore error */ } #endif if(load_cert(section)) return 1; /* FAILED */ /* initialize verification of the peer server certificate */ if(verify_init(section)) return 1; /* FAILED */ /* initialize DH/ECDH server mode */ if(!section->option.client) { #ifndef OPENSSL_NO_TLSEXT SSL_CTX_set_tlsext_servername_arg(section->ctx, section); SSL_CTX_set_tlsext_servername_callback(section->ctx, servername_cb); #endif /* OPENSSL_NO_TLSEXT */ #ifndef OPENSSL_NO_DH init_dh(section); /* ignore the result (errors are not critical) */ #endif /* OPENSSL_NO_DH */ #ifndef OPENSSL_NO_ECDH init_ecdh(section); /* ignore the result (errors are not critical) */ #endif /* OPENSSL_NO_ECDH */ } /* setup session cache */ if(!section->option.client) { unsigned int servname_len=strlen(section->servname); if(servname_len>SSL_MAX_SSL_SESSION_ID_LENGTH) servname_len=SSL_MAX_SSL_SESSION_ID_LENGTH; if(!SSL_CTX_set_session_id_context(section->ctx, (unsigned char *)section->servname, servname_len)) { sslerror("SSL_CTX_set_session_id_context"); return 1; /* FAILED */ } } SSL_CTX_set_session_cache_mode(section->ctx, SSL_SESS_CACHE_BOTH); SSL_CTX_sess_set_cache_size(section->ctx, section->session_size); SSL_CTX_set_timeout(section->ctx, section->session_timeout); if(section->option.sessiond) { SSL_CTX_sess_set_new_cb(section->ctx, sess_new_cb); SSL_CTX_sess_set_get_cb(section->ctx, sess_get_cb); SSL_CTX_sess_set_remove_cb(section->ctx, sess_remove_cb); } /* set info callback */ SSL_CTX_set_info_callback(section->ctx, info_callback); /* ciphers, options, mode */ if(section->cipher_list) if(!SSL_CTX_set_cipher_list(section->ctx, section->cipher_list)) { sslerror("SSL_CTX_set_cipher_list"); return 1; /* FAILED */ } s_log(LOG_DEBUG, "SSL options set: 0x%08lX", SSL_CTX_set_options(section->ctx, section->ssl_options)); #ifdef SSL_MODE_RELEASE_BUFFERS SSL_CTX_set_mode(section->ctx, SSL_MODE_ENABLE_PARTIAL_WRITE | SSL_MODE_ACCEPT_MOVING_WRITE_BUFFER | SSL_MODE_RELEASE_BUFFERS); #else SSL_CTX_set_mode(section->ctx, SSL_MODE_ENABLE_PARTIAL_WRITE | SSL_MODE_ACCEPT_MOVING_WRITE_BUFFER); #endif return 0; /* OK */ }
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); }
int evhtp_ssl_init(evhtp * htp, evhtp_ssl_cfg * cfg) { long cache_mode; evhtp_ssl_scache_init init_cb = NULL; evhtp_ssl_scache_add add_cb = NULL; evhtp_ssl_scache_get get_cb = NULL; evhtp_ssl_scache_del del_cb = NULL; if (cfg == NULL || htp == NULL || cfg->pemfile == NULL) { return -1; } SSL_library_init(); SSL_load_error_strings(); RAND_poll(); STACK_OF(SSL_COMP) * comp_methods = SSL_COMP_get_compression_methods(); sk_SSL_COMP_zero(comp_methods); htp->ssl_cfg = cfg; htp->ssl_ctx = SSL_CTX_new(SSLv23_server_method()); #if OPENSSL_VERSION_NUMBER >= 0x10000000L SSL_CTX_set_options(htp->ssl_ctx, SSL_MODE_RELEASE_BUFFERS); SSL_CTX_set_timeout(htp->ssl_ctx, 60 * 60 * 48); #endif SSL_CTX_set_options(htp->ssl_ctx, cfg->ssl_opts); if (cfg->ciphers != NULL) { SSL_CTX_set_cipher_list(htp->ssl_ctx, cfg->ciphers); } SSL_CTX_load_verify_locations(htp->ssl_ctx, cfg->cafile, cfg->capath); X509_STORE_set_flags(SSL_CTX_get_cert_store(htp->ssl_ctx), cfg->store_flags); SSL_CTX_set_verify(htp->ssl_ctx, cfg->verify_peer, cfg->x509_verify_cb); if (cfg->x509_chk_issued_cb != NULL) { htp->ssl_ctx->cert_store->check_issued = cfg->x509_chk_issued_cb; } if (cfg->verify_depth) { SSL_CTX_set_verify_depth(htp->ssl_ctx, cfg->verify_depth); } switch (cfg->scache_type) { case evhtp_ssl_scache_type_disabled: cache_mode = SSL_SESS_CACHE_OFF; break; case evhtp_ssl_scache_type_user: cache_mode = SSL_SESS_CACHE_SERVER | SSL_SESS_CACHE_NO_INTERNAL | SSL_SESS_CACHE_NO_INTERNAL_LOOKUP; init_cb = cfg->scache_init; add_cb = cfg->scache_add; get_cb = cfg->scache_get; del_cb = cfg->scache_del; break; case evhtp_ssl_scache_type_builtin: cache_mode = SSL_SESS_CACHE_SERVER | SSL_SESS_CACHE_NO_INTERNAL | SSL_SESS_CACHE_NO_INTERNAL_LOOKUP; #if 0 init_cb = _evhtp_ssl_builtin_init; add_cb = _evhtp_ssl_builtin_add; get_cb = _evhtp_ssl_builtin_get; del_cb = _evhtp_ssl_builtin_del; #endif break; case evhtp_ssl_scache_type_internal: default: cache_mode = SSL_SESS_CACHE_SERVER; break; } /* switch */ SSL_CTX_use_certificate_file(htp->ssl_ctx, cfg->pemfile, SSL_FILETYPE_PEM); SSL_CTX_use_PrivateKey_file(htp->ssl_ctx, cfg->privfile ? cfg->privfile: cfg->pemfile, SSL_FILETYPE_PEM); SSL_CTX_set_session_id_context(htp->ssl_ctx, (const unsigned char*)&session_id_context, sizeof(session_id_context)); SSL_CTX_set_app_data(htp->ssl_ctx, htp); SSL_CTX_set_session_cache_mode(htp->ssl_ctx, cache_mode); if (cache_mode != SSL_SESS_CACHE_OFF) { SSL_CTX_sess_set_cache_size(htp->ssl_ctx, cfg->scache_size ? cfg->scache_size : 1024); if (cfg->scache_type == evhtp_ssl_scache_type_builtin || cfg->scache_type == evhtp_ssl_scache_type_user) { SSL_CTX_sess_set_new_cb(htp->ssl_ctx, _evhtp_ssl_add_scache_ent); SSL_CTX_sess_set_get_cb(htp->ssl_ctx, _evhtp_ssl_get_scache_ent); SSL_CTX_sess_set_remove_cb(htp->ssl_ctx, _evhtp_ssl_delete_scache_ent); if (cfg->scache_init) { cfg->args = (cfg->scache_init)(htp); } } } return 0; } /* evhtp_use_ssl */