long SSL_CTX_set_dh_auto(SSL_CTX *ctx, int onoff) { if (onoff == 0) return 1; if (onoff == 2) { SSL_CTX_set_tmp_dh_callback(ctx, dh_legacy_cb); } else { SSL_CTX_set_tmp_dh_callback(ctx, dh_auto_cb); } SSL_CTX_set_options(ctx, SSL_OP_SINGLE_DH_USE); return 1; }
PeerDoorImp (std::string const& ip, int port, std::string const& sslCiphers, boost::asio::io_service& io_service) : mAcceptor ( io_service, boost::asio::ip::tcp::endpoint (boost::asio::ip::address ().from_string (ip.empty () ? "0.0.0.0" : ip), port)) , mCtx (boost::asio::ssl::context::sslv23) , mDelayTimer (io_service) { mCtx.set_options ( boost::asio::ssl::context::default_workarounds | boost::asio::ssl::context::no_sslv2 | boost::asio::ssl::context::single_dh_use); SSL_CTX_set_tmp_dh_callback (mCtx.native_handle (), handleTmpDh); if (SSL_CTX_set_cipher_list (mCtx.native_handle (), sslCiphers.c_str ()) != 1) std::runtime_error ("Error setting cipher list (no valid ciphers)."); if (! ip.empty () && port != 0) { Log (lsINFO) << "Peer port: " << ip << " " << port; startListening (); } }
/* The first line specifiy some settings in the ctx and ssl object: SSL_OP_ALL: enables all work around codes SSL_OP_NO_SSLv2: no SSLv2 connections are allowed (this should fail anyway because only TLSv1 connection are allowed) SSL_OP_SINGLE_DH_USE: the server generates a new private key for each new connection SSL_VERIFY_PEER: asks the client for a certificate SSL_VERIFY_FAIL_IF_NO_PEER_CERT: if the client doesn't present a cert the connection gets terminated CIPHER_LIST: is defined in ssl_server.h (look there for a detailed description) After setting up these things the bio object will be created and a ssl object assigned. Then the ssl engine mode is set to SSL_MODE_AUTO_RETRY. All available modes are: SSL_MODE_ENABLE_PARTIAL_WRITE: Allow SSL_write(..., n) to return r with 0 < r < n (i.e. report success when just a single record has been written). When not set (the default), SSL_write() will only report success once the complete chunk was written. Once SSL_write() returns with r, r bytes have been successfully written and the next call to SSL_write() must only send the n-r bytes left, imitating the behaviour of write(). SSL_MODE_ACCEPT_MOVING_WRITE_BUFFER: Make it possible to retry SSL_write() with changed buffer location (the buffer contents must stay the same). This is not the default to avoid the misconception that non-blocking SSL_write() behaves like non-blocking write(). SSL_MODE_AUTO_RETRY: Never bother the application with retries if the transport is blocking. If a renegotiation take place during normal operation, a ssl_read(3) or ssl_write(3) would return with -1 and indicate the need to retry with SSL_ERROR_WANT_READ . In a non-blocking environment applications must be prepared to handle incomplete read/write operations. In a blocking environment, applications are not always prepared to deal with read/write operations returning without success report. The flag SSL_MODE_AUTO_RETRY will cause read/write operations to only return after the handshake and successful completion. The server contains 3 bio objects: bio, abio and out. 'bio' contains the context, 'abio' binds to the socket and 'out' is the established connection. */ void SSL_Server::bind(){ SSL_CTX_set_verify(getCTX(), SSL_VERIFY_PEER | SSL_VERIFY_FAIL_IF_NO_PEER_CERT, NULL); SSL_CTX_set_options(getCTX(), SSL_OP_ALL | SSL_OP_NO_SSLv2 | SSL_OP_SINGLE_DH_USE); SSL_CTX_set_tmp_dh_callback(getCTX(), tmp_dh_callback); if(SSL_CTX_set_cipher_list(getCTX(), CIPHER_LIST) != 1) msgHandler->error("setting cipher list failed (no valid ciphers)", CRITICAL); msgHandler->debug("trying to set context to bio"); bio = BIO_new_ssl(getCTX(), 0); if(bio == NULL){ string error("Cannot set context to bio "); error.append(getSocket()); error.append("\nSSL_ERROR: "); error.append(ERR_reason_error_string(ERR_get_error())); msgHandler->error(error, CRITICAL); } else msgHandler->debug("set context to bio successful"); BIO_get_ssl(bio, &ssl); SSL_set_mode(ssl, SSL_MODE_AUTO_RETRY); msgHandler->debug("trying to bind to socket"); abio = BIO_new_accept((char*)getSocket().c_str()); BIO_set_accept_bios(abio, bio); if(BIO_do_accept(abio) <= 0){ string error("Bind to socket "); error.append(getSocket()); error.append(" failed.\nSSL_ERROR: "); error.append(ERR_reason_error_string(ERR_get_error())); msgHandler->error(error, CRITICAL); } else msgHandler->log("bind to socket successful"); }
bool OpenSSLServer::privateInit() { SSL_CTX_set_tmp_rsa_callback( m_ctx, tmp_rsa_callback ); SSL_CTX_set_tmp_dh_callback( m_ctx, tmp_dh_callback ); SSL_CTX_set_options( m_ctx, SSL_OP_CIPHER_SERVER_PREFERENCE ); return true; }
static SSL_CTX * setup_server_ctx (void) { SSL_CTX *ctx; ctx = SSL_CTX_new (SSLv23_method ()); /* Test de la passphrase */ SSL_CTX_set_default_passwd_cb (ctx, passwd_cb); if (SSL_CTX_load_verify_locations (ctx, CAFILE, CADIR) != 1) int_error ("ERREUR DE CHARGEMENT DU FICHIER"); if (SSL_CTX_set_default_verify_paths (ctx) != 1) int_error ("ERREUR DE CHARGEMENT DU FICHIER default CA file"); if (SSL_CTX_use_certificate_chain_file (ctx, CERTFILE) != 1) int_error ("ERREUR DE CHARGEMENT DU CERTIFICAT"); if (SSL_CTX_use_PrivateKey_file (ctx, CERTFILE, SSL_FILETYPE_PEM) != 1) int_error ("ERREUR DE CHARGEMENT DE LA CLEF PRIVE"); SSL_CTX_set_verify (ctx, SSL_VERIFY_PEER | SSL_VERIFY_FAIL_IF_NO_PEER_CERT, verify_callback); SSL_CTX_set_verify_depth (ctx, 4); SSL_CTX_set_options (ctx, SSL_OP_ALL | SSL_OP_NO_SSLv2 | SSL_OP_SINGLE_DH_USE); SSL_CTX_set_tmp_dh_callback (ctx, tmp_dh_callback); if (SSL_CTX_set_cipher_list (ctx, CIPHER_LIST) != 1) int_error ("ERREUR DE LECTURE DE LA LISTE DE CHIPTER"); return ctx; }
int ipfix_ssl_setup_server_ctx( SSL_CTX **ssl_ctx, SSL_METHOD *method, ipfix_ssl_opts_t *ssl_details ) { SSL_CTX *ctx; if ( ipfix_ssl_setup_ctx( &ctx, method?method:SSLv23_method(), ssl_details ) <0 ) { return -1; } SSL_CTX_set_verify( ctx, SSL_VERIFY_PEER|SSL_VERIFY_FAIL_IF_NO_PEER_CERT, ipfix_ssl_verify_callback ); SSL_CTX_set_verify_depth( ctx, 4 ); SSL_CTX_set_options( ctx, SSL_OP_ALL | SSL_OP_NO_SSLv2 | SSL_OP_SINGLE_DH_USE); if (!dh512 || !dh1024) { init_dhparams(); } SSL_CTX_set_tmp_dh_callback( ctx, ipfix_ssl_tmp_dh_callback ); if (SSL_CTX_set_cipher_list( ctx, CIPHER_LIST) != 1) { mlogf( 0, "[ipfix] error setting cipher list (no valid ciphers)"); goto err; } *ssl_ctx = ctx; return 0; err: SSL_CTX_free( ctx ); return -1; }
bool OpenSSLServer::privateInit() { SSL_CTX_set_tmp_rsa_callback( m_ctx, tmp_rsa_callback ); SSL_CTX_set_tmp_dh_callback( m_ctx, tmp_dh_callback ); SSL_CTX_set_tmp_ecdh( m_ctx, EC_KEY_new_by_curve_name( NID_sect163r2 ) ); SSL_CTX_set_options( m_ctx, SSL_OP_CIPHER_SERVER_PREFERENCE ); return true; }
// Does common initialization for all but the bare context type. void initCommon () { m_context.set_options ( boost::asio::ssl::context::default_workarounds | boost::asio::ssl::context::no_sslv2 | boost::asio::ssl::context::single_dh_use); SSL_CTX_set_tmp_dh_callback ( m_context.native_handle (), tmp_dh_handler); }
static void ssl_init_ctx_callbacks(server_rec *s, apr_pool_t *p, apr_pool_t *ptemp, modssl_ctx_t *mctx) { SSL_CTX *ctx = mctx->ssl_ctx; SSL_CTX_set_tmp_rsa_callback(ctx, ssl_callback_TmpRSA); SSL_CTX_set_tmp_dh_callback(ctx, ssl_callback_TmpDH); SSL_CTX_set_info_callback(ctx, ssl_callback_Info); }
static int krypt_set_adh(krypt_t *kconn) { SSL_CTX_set_cipher_list(kconn->ctx, "ADH"); DH *dh = get_dh_1024(); SSL_CTX_set_tmp_dh(kconn->ctx, dh); DH_free(dh); SSL_CTX_set_tmp_dh_callback(kconn->ctx, tmp_dh_callback); SSL_CTX_set_verify(kconn->ctx, SSL_VERIFY_NONE, NULL); return 0; }
/** * Configure DH parameters. */ static int set_dhparam(lua_State *L) { SSL_CTX *ctx = lsec_checkcontext(L, 1); SSL_CTX_set_tmp_dh_callback(ctx, dhparam_cb); /* Save callback */ luaL_getmetatable(L, "SSL:DH:Registry"); lua_pushlightuserdata(L, (void*)ctx); lua_pushvalue(L, 2); lua_settable(L, -3); return 0; }
static void ssl_init_ctx_callbacks(server_rec *s, apr_pool_t *p, apr_pool_t *ptemp, modssl_ctx_t *mctx) { SSL_CTX *ctx = mctx->ssl_ctx; SSL_CTX_set_tmp_rsa_callback(ctx, ssl_callback_TmpRSA); SSL_CTX_set_tmp_dh_callback(ctx, ssl_callback_TmpDH); if (s->loglevel >= APLOG_DEBUG) { /* this callback only logs if LogLevel >= info */ SSL_CTX_set_info_callback(ctx, ssl_callback_LogTracingState); } }
void WSDoor::startListening() { // Generate a single SSL context for use by all connections. boost::shared_ptr<boost::asio::ssl::context> mCtx; mCtx = boost::make_shared<boost::asio::ssl::context>(boost::asio::ssl::context::sslv23); mCtx->set_options( boost::asio::ssl::context::default_workarounds | boost::asio::ssl::context::no_sslv2 | boost::asio::ssl::context::single_dh_use); SSL_CTX_set_tmp_dh_callback(mCtx->native_handle(), handleTmpDh); // Construct a single handler for all requests. websocketpp::server_autotls::handler::ptr handler(new WSServerHandler<websocketpp::server_autotls>(mCtx, mPublic)); // Construct a websocket server. mSEndpoint = new websocketpp::server_autotls(handler); // mEndpoint->alog().unset_level(websocketpp::log::alevel::ALL); // mEndpoint->elog().unset_level(websocketpp::log::elevel::ALL); // Call the main-event-loop of the websocket server. try { mSEndpoint->listen( boost::asio::ip::tcp::endpoint( boost::asio::ip::address().from_string(mIp), mPort)); } catch (websocketpp::exception& e) { cLog(lsWARNING) << "websocketpp exception: " << e.what(); while (1) // temporary workaround for websocketpp throwing exceptions on access/close races { // https://github.com/zaphoyd/websocketpp/issues/98 try { mSEndpoint->get_io_service().run(); break; } catch (websocketpp::exception& e) { cLog(lsWARNING) << "websocketpp exception: " << e.what(); } } } delete mSEndpoint; }
bool init_ssl (void) { SSL_CTX_set_quiet_shutdown (ACE_SSL_Context::instance ()->context(), 1); SSL_CTX_set_options (ACE_SSL_Context::instance ()->context(), SSL_OP_SINGLE_DH_USE); SSL_CTX_set_tmp_dh_callback (ACE_SSL_Context::instance ()->context (), tmp_dh_callback); if (SSL_CTX_set_cipher_list (ACE_SSL_Context::instance ()->context (), "ADH")) { return true; } else { ACE_DEBUG ((LM_ERROR, ACE_TEXT ("SSL_CTX_set_cipher_list failed\n"))); return false; } }
/* * Initialize global SSL context. */ static int initialize_SSL(PGconn *conn) { struct stat buf; char homedir[MAXPGPATH]; char fnbuf[MAXPGPATH]; if (init_ssl_system(conn)) return -1; /* Set up to verify server cert, if root.crt is present */ if (pqGetHomeDirectory(homedir, sizeof(homedir))) { snprintf(fnbuf, sizeof(fnbuf), "%s/%s", homedir, ROOTCERTFILE); if (stat(fnbuf, &buf) == 0) { if (!SSL_CTX_load_verify_locations(SSL_context, fnbuf, NULL)) { char *err = SSLerrmessage(); printfPQExpBuffer(&conn->errorMessage, libpq_gettext("could not read root certificate file \"%s\": %s\n"), fnbuf, err); SSLerrfree(err); return -1; } SSL_CTX_set_verify(SSL_context, SSL_VERIFY_PEER, verify_cb); } } /* set up empheral DH keys */ SSL_CTX_set_tmp_dh_callback(SSL_context, tmp_dh_cb); SSL_CTX_set_options(SSL_context, SSL_OP_SINGLE_DH_USE); /* set up mechanism to provide client certificate, if available */ SSL_CTX_set_client_cert_cb(SSL_context, client_cert_cb); return 0; }
SSL_CTX *setup_server_ctx(void) { SSL_CTX *ctx; ctx = SSL_CTX_new(SSLv23_method( )); if (SSL_CTX_load_verify_locations(ctx, CAFILE, CADIR) != 1) int_error("Error loading CA file and/or directory"); if (SSL_CTX_set_default_verify_paths(ctx) != 1) int_error("Error loading default CA file and/or directory"); if (SSL_CTX_use_certificate_chain_file(ctx, CERTFILE) != 1) int_error("Error loading certificate from file"); if (SSL_CTX_use_PrivateKey_file(ctx, CERTFILE, SSL_FILETYPE_PEM) != 1) int_error("Error loading private key from file"); SSL_CTX_set_verify(ctx, SSL_VERIFY_PEER|SSL_VERIFY_FAIL_IF_NO_PEER_CERT, verify_callback); SSL_CTX_set_verify_depth(ctx, 4); SSL_CTX_set_options(ctx, SSL_OP_ALL | SSL_OP_NO_SSLv2 | SSL_OP_SINGLE_DH_USE); SSL_CTX_set_tmp_dh_callback(ctx, tmp_dh_callback); if (SSL_CTX_set_cipher_list(ctx, CIPHER_LIST) != 1) int_error("Error setting cipher list (no valid ciphers)"); return ctx; }
void TLSServerContext::InitialiseDHKeyExchange() { // if this fails, ciphers requiring DH key exchange // will not work bool failed = false; DH* dh = nullptr; BIO *bio = BIO_new_file(certificate.c_str(), "r"); if (!bio) { failed = true; goto finish; } #if OPENSSL_VERSION_NUMBER >= 0x00904000L dh = PEM_read_bio_DHparams(bio, nullptr, nullptr, nullptr); #else dh = PEM_read_bio_DHparams(bio, nullptr, nullptr); #endif if (!dh) { failed = true; goto finish; } if (SSL_CTX_set_tmp_dh(context, dh) != 1) { failed = true; goto finish; } finish: if (dh) DH_free(dh); if (bio) BIO_free(bio); if (failed) SSL_CTX_set_tmp_dh_callback(context, TempDHCallback); }
/* * Initialize global SSL context. */ static void initialize_SSL(void) { struct stat buf; STACK_OF(X509_NAME) *root_cert_list = NULL; if (!SSL_context) { #if SSLEAY_VERSION_NUMBER >= 0x0907000L OPENSSL_config(NULL); #endif SSL_library_init(); SSL_load_error_strings(); SSL_context = SSL_CTX_new(SSLv23_method()); if (!SSL_context) ereport(FATAL, (errmsg("could not create SSL context: %s", SSLerrmessage()))); /* * Disable OpenSSL's moving-write-buffer sanity check, because it * causes unnecessary failures in nonblocking send cases. */ SSL_CTX_set_mode(SSL_context, SSL_MODE_ACCEPT_MOVING_WRITE_BUFFER); /* * Load and verify server's certificate and private key */ if (SSL_CTX_use_certificate_chain_file(SSL_context, SERVER_CERT_FILE) != 1) ereport(FATAL, (errcode(ERRCODE_CONFIG_FILE_ERROR), errmsg("could not load server certificate file \"%s\": %s", SERVER_CERT_FILE, SSLerrmessage()))); if (stat(SERVER_PRIVATE_KEY_FILE, &buf) != 0) ereport(FATAL, (errcode_for_file_access(), errmsg("could not access private key file \"%s\": %m", SERVER_PRIVATE_KEY_FILE))); /* * Require no public access to key file. * * XXX temporarily suppress check when on Windows, because there may * not be proper support for Unix-y file permissions. Need to think * of a reasonable check to apply on Windows. (See also the data * directory permission check in postmaster.c) */ #if !defined(WIN32) && !defined(__CYGWIN__) if (!S_ISREG(buf.st_mode) || buf.st_mode & (S_IRWXG | S_IRWXO)) ereport(FATAL, (errcode(ERRCODE_CONFIG_FILE_ERROR), errmsg("private key file \"%s\" has group or world access", SERVER_PRIVATE_KEY_FILE), errdetail("Permissions should be u=rw (0600) or less."))); #endif if (SSL_CTX_use_PrivateKey_file(SSL_context, SERVER_PRIVATE_KEY_FILE, SSL_FILETYPE_PEM) != 1) ereport(FATAL, (errmsg("could not load private key file \"%s\": %s", SERVER_PRIVATE_KEY_FILE, SSLerrmessage()))); if (SSL_CTX_check_private_key(SSL_context) != 1) ereport(FATAL, (errmsg("check of private key failed: %s", SSLerrmessage()))); } /* set up ephemeral DH keys, and disallow SSL v2 while at it */ SSL_CTX_set_tmp_dh_callback(SSL_context, tmp_dh_cb); SSL_CTX_set_options(SSL_context, SSL_OP_SINGLE_DH_USE | SSL_OP_NO_SSLv2); /* set up the allowed cipher list */ if (SSL_CTX_set_cipher_list(SSL_context, SSLCipherSuites) != 1) elog(FATAL, "could not set the cipher list (no valid ciphers available)"); /* * Attempt to load CA store, so we can verify client certificates if * needed. */ ssl_loaded_verify_locations = false; if (access(ROOT_CERT_FILE, R_OK) != 0) { /* * If root certificate file simply not found, don't log an error here, * because it's quite likely the user isn't planning on using client * certificates. If we can't access it for other reasons, it is an * error. */ if (errno != ENOENT) ereport(FATAL, (errmsg("could not access root certificate file \"%s\": %m", ROOT_CERT_FILE))); } else if (SSL_CTX_load_verify_locations(SSL_context, ROOT_CERT_FILE, NULL) != 1 || (root_cert_list = SSL_load_client_CA_file(ROOT_CERT_FILE)) == NULL) { /* * File was there, but we could not load it. This means the file is * somehow broken, and we cannot do verification at all - so fail. */ ereport(FATAL, (errmsg("could not load root certificate file \"%s\": %s", ROOT_CERT_FILE, SSLerrmessage()))); } else { /*---------- * Load the Certificate Revocation List (CRL) if file exists. * http://searchsecurity.techtarget.com/sDefinition/0,,sid14_gci803160,00.html *---------- */ X509_STORE *cvstore = SSL_CTX_get_cert_store(SSL_context); if (cvstore) { /* Set the flags to check against the complete CRL chain */ if (X509_STORE_load_locations(cvstore, ROOT_CRL_FILE, NULL) == 1) { /* OpenSSL 0.96 does not support X509_V_FLAG_CRL_CHECK */ #ifdef X509_V_FLAG_CRL_CHECK X509_STORE_set_flags(cvstore, X509_V_FLAG_CRL_CHECK | X509_V_FLAG_CRL_CHECK_ALL); #else ereport(LOG, (errmsg("SSL certificate revocation list file \"%s\" ignored", ROOT_CRL_FILE), errdetail("SSL library does not support certificate revocation lists."))); #endif } else { /* Not fatal - we do not require CRL */ ereport(LOG, (errmsg("SSL certificate revocation list file \"%s\" not found, skipping: %s", ROOT_CRL_FILE, SSLerrmessage()), errdetail("Certificates will not be checked against revocation list."))); } /* * Always ask for SSL client cert, but don't fail if it's not * presented. We might fail such connections later, depending on * what we find in pg_hba.conf. */ SSL_CTX_set_verify(SSL_context, (SSL_VERIFY_PEER | SSL_VERIFY_CLIENT_ONCE), verify_cb); /* Set flag to remember CA store is successfully loaded */ ssl_loaded_verify_locations = true; } /* * Tell OpenSSL to send the list of root certs we trust to clients in * CertificateRequests. This lets a client with a keystore select the * appropriate client certificate to send to us. */ SSL_CTX_set_client_CA_list(SSL_context, root_cert_list); } }
bool TLS_SOCKET_CLASS::openSslInitialize() // DESCRIPTION : Called to initialize the OpenSSL library for this session. // PRECONDITIONS : // POSTCONDITIONS : // EXCEPTIONS : // NOTES : //<<=========================================================================== { int verify_mode; long ssl_options; openSslM_ptr = OPENSSL_CLASS::getInstance(); if (openSslM_ptr == NULL) { if (loggerM_ptr) { loggerM_ptr->text(LOG_ERROR, 1, "OpenSSL library not initialized when initializing Secure Socket"); } return false; } // setup the connection factory for this session if (tlsVersionM == TLS_VERSION_TLSv1) { ctxM_ptr = SSL_CTX_new(TLSv1_method()); } else if (tlsVersionM == TLS_VERSION_SSLv3) { ctxM_ptr = SSL_CTX_new(SSLv3_method()); } else { ctxM_ptr = SSL_CTX_new(SSLv23_method()); } if (ctxM_ptr == NULL) { openSslError("initializing connection factory"); return false; } SSL_CTX_set_default_passwd_cb(ctxM_ptr, OPENSSL_CLASS::openSslPasswordCallback); char *password = new char[certificateFilePasswordM.length() + 1]; // create a buffer to store the password // this is freed in the destructor strcpy(password, certificateFilePasswordM.c_str()); SSL_CTX_set_default_passwd_cb_userdata(ctxM_ptr, (void *)password); if (SSL_CTX_load_verify_locations(ctxM_ptr, certificateFilenameM.c_str(), NULL) != 1) { openSslError("loading trusted certificate file"); } SSL_CTX_set_client_CA_list(ctxM_ptr, SSL_load_client_CA_file(certificateFilenameM.c_str())); ERR_clear_error(); // the last call leaves an error in the stack if (!readCredentials(ctxM_ptr)) { openSslError("loading credentials"); } if (checkRemoteCertificateM) { verify_mode = SSL_VERIFY_PEER | SSL_VERIFY_FAIL_IF_NO_PEER_CERT; } else { verify_mode = SSL_VERIFY_NONE; } SSL_CTX_set_verify(ctxM_ptr, verify_mode, openSslVerifyCallback); if ((loggerM_ptr != NULL) && ((loggerM_ptr->getLogMask() & LOG_DEBUG) != 0)) { SSL_CTX_set_msg_callback(ctxM_ptr, openSslMsgCallback); // the 'this' pointer needed by openSslMsgCallback and openSslVerfyCallback must be set by // SSL_set_msg_callback_arg for each SSL created } ssl_options = SSL_OP_ALL | SSL_OP_SINGLE_DH_USE; if (tlsVersionM.find(TLS_VERSION_SSLv2) == string::npos) { ssl_options |= SSL_OP_NO_SSLv2; } if (tlsVersionM.find(TLS_VERSION_SSLv3) == string::npos) { ssl_options |= SSL_OP_NO_SSLv3; } if (tlsVersionM.find(TLS_VERSION_TLSv1) == string::npos) { ssl_options |= SSL_OP_NO_TLSv1; } SSL_CTX_set_options(ctxM_ptr, ssl_options); SSL_CTX_set_timeout(ctxM_ptr, tlsCacheTimeoutM); SSL_CTX_set_session_id_context(ctxM_ptr, (const unsigned char *)"DVT", 3); if (cacheTlsSessionsM) { SSL_CTX_set_session_cache_mode(ctxM_ptr, SSL_SESS_CACHE_BOTH); } else { SSL_CTX_set_session_cache_mode(ctxM_ptr, SSL_SESS_CACHE_OFF); } SSL_CTX_set_tmp_dh_callback(ctxM_ptr, OPENSSL_CLASS::tmpDhCallback); if (SSL_CTX_set_cipher_list(ctxM_ptr, cipherListM.c_str()) != 1) { openSslError("initializing cipher list (no valid ciphers)"); } return true; }
/* * 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; }
/* * initialize a new TLS context */ static int tlso_ctx_init( struct ldapoptions *lo, struct ldaptls *lt, int is_server ) { tlso_ctx *ctx = (tlso_ctx *)lo->ldo_tls_ctx; int i; if ( is_server ) { SSL_CTX_set_session_id_context( ctx, (const unsigned char *) "OpenLDAP", sizeof("OpenLDAP")-1 ); } #ifdef SSL_OP_NO_TLSv1 #ifdef SSL_OP_NO_TLSv1_1 #ifdef SSL_OP_NO_TLSv1_2 if ( lo->ldo_tls_protocol_min > LDAP_OPT_X_TLS_PROTOCOL_TLS1_2) SSL_CTX_set_options( ctx, SSL_OP_NO_SSLv2 | SSL_OP_NO_SSLv3 | SSL_OP_NO_TLSv1 | SSL_OP_NO_TLSv1_1 | SSL_OP_NO_TLSv1_2 ); else #endif if ( lo->ldo_tls_protocol_min > LDAP_OPT_X_TLS_PROTOCOL_TLS1_1) SSL_CTX_set_options( ctx, SSL_OP_NO_SSLv2 | SSL_OP_NO_SSLv3 | SSL_OP_NO_TLSv1 | SSL_OP_NO_TLSv1_1 ); else #endif if ( lo->ldo_tls_protocol_min > LDAP_OPT_X_TLS_PROTOCOL_TLS1_0) SSL_CTX_set_options( ctx, SSL_OP_NO_SSLv2 | SSL_OP_NO_SSLv3 | SSL_OP_NO_TLSv1); else #endif if ( lo->ldo_tls_protocol_min > LDAP_OPT_X_TLS_PROTOCOL_SSL3 ) SSL_CTX_set_options( ctx, SSL_OP_NO_SSLv2 | SSL_OP_NO_SSLv3 ); else if ( lo->ldo_tls_protocol_min > LDAP_OPT_X_TLS_PROTOCOL_SSL2 ) SSL_CTX_set_options( ctx, SSL_OP_NO_SSLv2 ); if ( lo->ldo_tls_ciphersuite && !SSL_CTX_set_cipher_list( ctx, lt->lt_ciphersuite ) ) { Debug( LDAP_DEBUG_ANY, "TLS: could not set cipher list %s.\n", lo->ldo_tls_ciphersuite, 0, 0 ); tlso_report_error(); return -1; } if (lo->ldo_tls_cacertfile != NULL || lo->ldo_tls_cacertdir != NULL) { if ( !SSL_CTX_load_verify_locations( ctx, lt->lt_cacertfile, lt->lt_cacertdir ) || !SSL_CTX_set_default_verify_paths( ctx ) ) { Debug( LDAP_DEBUG_ANY, "TLS: " "could not load verify locations (file:`%s',dir:`%s').\n", lo->ldo_tls_cacertfile ? lo->ldo_tls_cacertfile : "", lo->ldo_tls_cacertdir ? lo->ldo_tls_cacertdir : "", 0 ); tlso_report_error(); return -1; } if ( is_server ) { STACK_OF(X509_NAME) *calist; /* List of CA names to send to a client */ calist = tlso_ca_list( lt->lt_cacertfile, lt->lt_cacertdir ); if ( !calist ) { Debug( LDAP_DEBUG_ANY, "TLS: " "could not load client CA list (file:`%s',dir:`%s').\n", lo->ldo_tls_cacertfile ? lo->ldo_tls_cacertfile : "", lo->ldo_tls_cacertdir ? lo->ldo_tls_cacertdir : "", 0 ); tlso_report_error(); return -1; } SSL_CTX_set_client_CA_list( ctx, calist ); } } if ( lo->ldo_tls_certfile && !SSL_CTX_use_certificate_file( ctx, lt->lt_certfile, SSL_FILETYPE_PEM ) ) { Debug( LDAP_DEBUG_ANY, "TLS: could not use certificate `%s'.\n", lo->ldo_tls_certfile,0,0); tlso_report_error(); return -1; } /* Key validity is checked automatically if cert has already been set */ if ( lo->ldo_tls_keyfile && !SSL_CTX_use_PrivateKey_file( ctx, lt->lt_keyfile, SSL_FILETYPE_PEM ) ) { Debug( LDAP_DEBUG_ANY, "TLS: could not use key file `%s'.\n", lo->ldo_tls_keyfile,0,0); tlso_report_error(); return -1; } if ( lo->ldo_tls_dhfile ) { DH *dh = NULL; BIO *bio; dhplist *p; if (( bio=BIO_new_file( lt->lt_dhfile,"r" )) == NULL ) { Debug( LDAP_DEBUG_ANY, "TLS: could not use DH parameters file `%s'.\n", lo->ldo_tls_dhfile,0,0); tlso_report_error(); return -1; } while (( dh=PEM_read_bio_DHparams( bio, NULL, NULL, NULL ))) { p = LDAP_MALLOC( sizeof(dhplist) ); if ( p != NULL ) { p->keylength = DH_size( dh ) * 8; p->param = dh; p->next = tlso_dhparams; tlso_dhparams = p; } } BIO_free( bio ); } if ( tlso_opt_trace ) { SSL_CTX_set_info_callback( ctx, tlso_info_cb ); } i = SSL_VERIFY_NONE; if ( lo->ldo_tls_require_cert ) { i = SSL_VERIFY_PEER; if ( lo->ldo_tls_require_cert == LDAP_OPT_X_TLS_DEMAND || lo->ldo_tls_require_cert == LDAP_OPT_X_TLS_HARD ) { i |= SSL_VERIFY_FAIL_IF_NO_PEER_CERT; } } SSL_CTX_set_verify( ctx, i, lo->ldo_tls_require_cert == LDAP_OPT_X_TLS_ALLOW ? tlso_verify_ok : tlso_verify_cb ); SSL_CTX_set_tmp_rsa_callback( ctx, tlso_tmp_rsa_cb ); if ( lo->ldo_tls_dhfile ) { SSL_CTX_set_tmp_dh_callback( ctx, tlso_tmp_dh_cb ); } #ifdef HAVE_OPENSSL_CRL if ( lo->ldo_tls_crlcheck ) { X509_STORE *x509_s = SSL_CTX_get_cert_store( ctx ); if ( lo->ldo_tls_crlcheck == LDAP_OPT_X_TLS_CRL_PEER ) { X509_STORE_set_flags( x509_s, X509_V_FLAG_CRL_CHECK ); } else if ( lo->ldo_tls_crlcheck == LDAP_OPT_X_TLS_CRL_ALL ) { X509_STORE_set_flags( x509_s, X509_V_FLAG_CRL_CHECK | X509_V_FLAG_CRL_CHECK_ALL ); } } #endif return 0; }
/* Open the SSL module */ PUBLIC int sslOpen() { RandBuf randBuf; X509_STORE *store; uchar resume[16]; char *ciphers; trace(7, "Initializing SSL"); randBuf.now = time(0); randBuf.pid = getpid(); RAND_seed((void*) &randBuf, sizeof(randBuf)); #if ME_UNIX_LIKE trace(6, "OpenSsl: Before calling RAND_load_file"); RAND_load_file("/dev/urandom", 256); trace(6, "OpenSsl: After calling RAND_load_file"); #endif CRYPTO_malloc_init(); #if !ME_WIN_LIKE OpenSSL_add_all_algorithms(); #endif SSL_library_init(); SSL_load_error_strings(); SSLeay_add_ssl_algorithms(); if ((sslctx = SSL_CTX_new(SSLv23_server_method())) == 0) { error("Unable to create SSL context"); return -1; } /* Set the server certificate and key files */ if (*ME_GOAHEAD_SSL_KEY && sslSetKeyFile(ME_GOAHEAD_SSL_KEY) < 0) { sslClose(); return -1; } if (*ME_GOAHEAD_SSL_CERTIFICATE && sslSetCertFile(ME_GOAHEAD_SSL_CERTIFICATE) < 0) { sslClose(); return -1; } if (ME_GOAHEAD_SSL_VERIFY_PEER) { SSL_CTX_set_verify(sslctx, SSL_VERIFY_PEER | SSL_VERIFY_FAIL_IF_NO_PEER_CERT, verifyClientCertificate); SSL_CTX_set_verify_depth(sslctx, VERIFY_DEPTH); } else { SSL_CTX_set_verify(sslctx, SSL_VERIFY_NONE, verifyClientCertificate); } /* Set the client certificate verification locations */ if (ME_GOAHEAD_SSL_AUTHORITY && *ME_GOAHEAD_SSL_AUTHORITY) { if ((!SSL_CTX_load_verify_locations(sslctx, ME_GOAHEAD_SSL_AUTHORITY, NULL)) || (!SSL_CTX_set_default_verify_paths(sslctx))) { error("Unable to read cert verification locations"); sslClose(); return -1; } /* Define the list of CA certificates to send to the client before they send their client certificate for validation */ SSL_CTX_set_client_CA_list(sslctx, SSL_load_client_CA_file(ME_GOAHEAD_SSL_AUTHORITY)); } if (ME_GOAHEAD_SSL_REVOKE && *ME_GOAHEAD_SSL_REVOKE) { store = SSL_CTX_get_cert_store(sslctx); if (!X509_STORE_load_locations(store, ME_GOAHEAD_SSL_REVOKE, 0)) { error("Cannot load certificate revoke list: %s", ME_GOAHEAD_SSL_REVOKE); sslClose(); return -1; } } /* Configure DH parameters */ dhKey = getDhKey(); SSL_CTX_set_tmp_dh_callback(sslctx, dhcallback); /* Configure cipher suite */ if (ME_GOAHEAD_SSL_CIPHERS && *ME_GOAHEAD_SSL_CIPHERS) { ciphers = ME_GOAHEAD_SSL_CIPHERS; } else { ciphers = OPENSSL_DEFAULT_CIPHERS; } ciphers = mapCipherNames(ciphers); trace(5, "Using OpenSSL ciphers: %s", ciphers); if (SSL_CTX_set_cipher_list(sslctx, ciphers) != 1) { error("Unable to set cipher list \"%s\"", ciphers); sslClose(); wfree(ciphers); return -1; } wfree(ciphers); /* Define default OpenSSL options */ SSL_CTX_set_options(sslctx, SSL_OP_ALL); /* Ensure we generate a new private key for each connection */ SSL_CTX_set_options(sslctx, SSL_OP_SINGLE_DH_USE); /* Define a session reuse context */ RAND_bytes(resume, sizeof(resume)); SSL_CTX_set_session_id_context(sslctx, resume, sizeof(resume)); /* Elliptic Curve initialization */ #if SSL_OP_SINGLE_ECDH_USE #ifdef SSL_CTX_set_ecdh_auto SSL_CTX_set_ecdh_auto(sslctx, 1); #else { EC_KEY *ecdh; cchar *name; int nid; name = ME_GOAHEAD_SSL_CURVE; if ((nid = OBJ_sn2nid(name)) == 0) { error("Unknown curve name \"%s\"", name); sslClose(); return -1; } if ((ecdh = EC_KEY_new_by_curve_name(nid)) == 0) { error("Unable to create curve \"%s\"", name); sslClose(); return -1; } SSL_CTX_set_options(sslctx, SSL_OP_SINGLE_ECDH_USE); SSL_CTX_set_tmp_ecdh(sslctx, ecdh); EC_KEY_free(ecdh); } #endif #endif SSL_CTX_set_mode(sslctx, SSL_MODE_ENABLE_PARTIAL_WRITE | SSL_MODE_AUTO_RETRY | SSL_MODE_ACCEPT_MOVING_WRITE_BUFFER); #ifdef SSL_OP_MSIE_SSLV2_RSA_PADDING SSL_CTX_set_options(sslctx, SSL_OP_MSIE_SSLV2_RSA_PADDING); #endif #ifdef SSL_MODE_RELEASE_BUFFERS SSL_CTX_set_mode(sslctx, SSL_MODE_RELEASE_BUFFERS); #endif #ifdef SSL_OP_CIPHER_SERVER_PREFERENCE SSL_CTX_set_mode(sslctx, SSL_OP_CIPHER_SERVER_PREFERENCE); #endif /* Select the required protocols Disable both SSLv2 and SSLv3 by default - they are insecure */ SSL_CTX_set_options(sslctx, SSL_OP_NO_SSLv2); SSL_CTX_set_options(sslctx, SSL_OP_NO_SSLv3); #if defined(SSL_OP_NO_TLSv1) && ME_GOAHEAD_SSL_NO_V1 SSL_CTX_set_options(sslctx, SSL_OP_NO_TLSv1); #endif #if defined(SSL_OP_NO_TLSv1_1) && ME_GOAHEAD_SSL_NO_V1_1 SSL_CTX_set_options(sslctx, SSL_OP_NO_TLSv1_1); #endif #if defined(SSL_OP_NO_TLSv1_2) && ME_GOAHEAD_SSL_NO_V1_2 SSL_CTX_set_options(sslctx, SSL_OP_NO_TLSv1_2); #endif #if defined(SSL_OP_NO_TICKET) /* Ticket based session reuse is enabled by default */ #if defined(ME_GOAHEAD_SSL_TICKET) if (ME_GOAHEAD_SSL_TICKET) { SSL_CTX_clear_options(sslctx, SSL_OP_NO_TICKET); } else { SSL_CTX_set_options(sslctx, SSL_OP_NO_TICKET); } #else SSL_CTX_clear_options(sslctx, SSL_OP_NO_TICKET); #endif #endif #if defined(SSL_OP_NO_COMPRESSION) /* CRIME attack targets compression */ SSL_CTX_clear_options(sslctx, SSL_OP_NO_COMPRESSION); #endif #if defined(SSL_OP_DONT_INSERT_EMPTY_FRAGMENTS) /* Disables a countermeasure against a SSL 3.0/TLS 1.0 protocol vulnerability affecting CBC ciphers. Defaults to true. */ #if defined(ME_GOAHEAD_SSL_EMPTY_FRAGMENTS) if (ME_GOAHEAD_SSL_EMPTY_FRAGMENTS) { /* SSL_OP_ALL disables empty fragments. Only needed for ancient browsers like IE-6 on SSL-3.0/TLS-1.0 */ SSL_CTX_clear_options(sslctx, SSL_OP_DONT_INSERT_EMPTY_FRAGMENTS); } else { SSL_CTX_set_options(sslctx, SSL_OP_DONT_INSERT_EMPTY_FRAGMENTS); } #else SSL_CTX_set_options(sslctx, SSL_OP_DONT_INSERT_EMPTY_FRAGMENTS); #endif #endif #if defined(ME_GOAHEAD_SSL_CACHE) /* Set the number of sessions supported. Default in OpenSSL is 20K. */ SSL_CTX_sess_set_cache_size(sslctx, ME_GOAHEAD_SSL_CACHE); #else SSL_CTX_sess_set_cache_size(sslctx, 256); #endif return 0; }
/* * Initialize global SSL context. */ void be_tls_init(void) { struct stat buf; STACK_OF(X509_NAME) *root_cert_list = NULL; if (!SSL_context) { #if SSLEAY_VERSION_NUMBER >= 0x0907000L OPENSSL_config(NULL); #endif SSL_library_init(); SSL_load_error_strings(); /* * We use SSLv23_method() because it can negotiate use of the highest * mutually supported protocol version, while alternatives like * TLSv1_2_method() permit only one specific version. Note that we * don't actually allow SSL v2 or v3, only TLS protocols (see below). */ SSL_context = SSL_CTX_new(SSLv23_method()); if (!SSL_context) ereport(FATAL, (errmsg("could not create SSL context: %s", SSLerrmessage()))); /* * Disable OpenSSL's moving-write-buffer sanity check, because it * causes unnecessary failures in nonblocking send cases. */ SSL_CTX_set_mode(SSL_context, SSL_MODE_ACCEPT_MOVING_WRITE_BUFFER); /* * Load and verify server's certificate and private key */ if (SSL_CTX_use_certificate_chain_file(SSL_context, ssl_cert_file) != 1) ereport(FATAL, (errcode(ERRCODE_CONFIG_FILE_ERROR), errmsg("could not load server certificate file \"%s\": %s", ssl_cert_file, SSLerrmessage()))); if (stat(ssl_key_file, &buf) != 0) ereport(FATAL, (errcode_for_file_access(), errmsg("could not access private key file \"%s\": %m", ssl_key_file))); /* * Require no public access to key file. * * XXX temporarily suppress check when on Windows, because there may * not be proper support for Unix-y file permissions. Need to think * of a reasonable check to apply on Windows. (See also the data * directory permission check in postmaster.c) */ #if !defined(WIN32) && !defined(__CYGWIN__) if (!S_ISREG(buf.st_mode) || buf.st_mode & (S_IRWXG | S_IRWXO)) ereport(FATAL, (errcode(ERRCODE_CONFIG_FILE_ERROR), errmsg("private key file \"%s\" has group or world access", ssl_key_file), errdetail("Permissions should be u=rw (0600) or less."))); #endif if (SSL_CTX_use_PrivateKey_file(SSL_context, ssl_key_file, SSL_FILETYPE_PEM) != 1) ereport(FATAL, (errmsg("could not load private key file \"%s\": %s", ssl_key_file, SSLerrmessage()))); if (SSL_CTX_check_private_key(SSL_context) != 1) ereport(FATAL, (errmsg("check of private key failed: %s", SSLerrmessage()))); } /* set up ephemeral DH keys, and disallow SSL v2/v3 while at it */ SSL_CTX_set_tmp_dh_callback(SSL_context, tmp_dh_cb); SSL_CTX_set_options(SSL_context, SSL_OP_SINGLE_DH_USE | SSL_OP_NO_SSLv2 | SSL_OP_NO_SSLv3); /* set up ephemeral ECDH keys */ initialize_ecdh(); /* set up the allowed cipher list */ if (SSL_CTX_set_cipher_list(SSL_context, SSLCipherSuites) != 1) elog(FATAL, "could not set the cipher list (no valid ciphers available)"); /* Let server choose order */ if (SSLPreferServerCiphers) SSL_CTX_set_options(SSL_context, SSL_OP_CIPHER_SERVER_PREFERENCE); /* * Load CA store, so we can verify client certificates if needed. */ if (ssl_ca_file[0]) { if (SSL_CTX_load_verify_locations(SSL_context, ssl_ca_file, NULL) != 1 || (root_cert_list = SSL_load_client_CA_file(ssl_ca_file)) == NULL) ereport(FATAL, (errmsg("could not load root certificate file \"%s\": %s", ssl_ca_file, SSLerrmessage()))); } /*---------- * Load the Certificate Revocation List (CRL). * http://searchsecurity.techtarget.com/sDefinition/0,,sid14_gci803160,00.html *---------- */ if (ssl_crl_file[0]) { X509_STORE *cvstore = SSL_CTX_get_cert_store(SSL_context); if (cvstore) { /* Set the flags to check against the complete CRL chain */ if (X509_STORE_load_locations(cvstore, ssl_crl_file, NULL) == 1) { /* OpenSSL 0.96 does not support X509_V_FLAG_CRL_CHECK */ #ifdef X509_V_FLAG_CRL_CHECK X509_STORE_set_flags(cvstore, X509_V_FLAG_CRL_CHECK | X509_V_FLAG_CRL_CHECK_ALL); #else ereport(LOG, (errmsg("SSL certificate revocation list file \"%s\" ignored", ssl_crl_file), errdetail("SSL library does not support certificate revocation lists."))); #endif } else ereport(FATAL, (errmsg("could not load SSL certificate revocation list file \"%s\": %s", ssl_crl_file, SSLerrmessage()))); } } if (ssl_ca_file[0]) { /* * Always ask for SSL client cert, but don't fail if it's not * presented. We might fail such connections later, depending on what * we find in pg_hba.conf. */ SSL_CTX_set_verify(SSL_context, (SSL_VERIFY_PEER | SSL_VERIFY_CLIENT_ONCE), verify_cb); /* Set flag to remember CA store is successfully loaded */ ssl_loaded_verify_locations = true; /* * Tell OpenSSL to send the list of root certs we trust to clients in * CertificateRequests. This lets a client with a keystore select the * appropriate client certificate to send to us. */ SSL_CTX_set_client_CA_list(SSL_context, root_cert_list); } }
static int openssl_ssl_ctx_set_tmp(lua_State *L) { SSL_CTX* ctx = CHECK_OBJECT(1, SSL_CTX, "openssl.ssl_ctx"); static const char* which[] = { "dh", "rsa", "ecdh", NULL }; int nwhich = luaL_checkoption(L, 2, NULL, which); int ret = 0; if (lua_isfunction(L, 3)) { lua_pushvalue(L, 3); ret = 1; switch (nwhich) { case 0: openssl_setvalue(L, ctx, "tmp_dh_callback"); SSL_CTX_set_tmp_dh_callback(ctx, tmp_dh_callback); break; case 1: openssl_setvalue(L, ctx, "tmp_rsa_callback"); SSL_CTX_set_tmp_rsa_callback(ctx, tmp_rsa_callback); break; case 2: { luaL_argcheck(L, lua_isstring(L, 4), 4, "must supply curve name"); openssl_setvalue(L, ctx, "tmp_ecdh_callback"); SSL_CTX_set_tmp_ecdh_callback(ctx, tmp_ecdh_callback); lua_pushvalue(L, 4); openssl_setvalue(L, ctx, "curve"); } break; } } else if (lua_isstring(L, 3)) { BIO* bio = load_bio_object(L, 3); switch (nwhich) { case 0: { DH* dh = PEM_read_bio_DHparams(bio, NULL, NULL, NULL); if (dh) ret = SSL_CTX_set_tmp_dh(ctx, dh); else luaL_error(L, "generate new tmp dh fail"); } break; case 1: { RSA* rsa = PEM_read_bio_RSAPrivateKey(bio, NULL, NULL, NULL); if (rsa) ret = SSL_CTX_set_tmp_rsa(ctx, rsa); else luaL_error(L, "generate new tmp rsa fail"); } break; case 2: { int nid = NID_undef; EC_KEY* ec = PEM_read_bio_ECPrivateKey(bio, NULL, NULL, NULL); if (ec == NULL) { nid = OBJ_txt2nid(lua_tostring(L, 3)); if (nid != NID_undef) ec = EC_KEY_new_by_curve_name(nid); } if (ec) ret = SSL_CTX_set_tmp_ecdh(ctx, ec); else luaL_error(L, "generate new tmp ec_key fail"); } break; } BIO_free(bio); } else if (lua_isuserdata(L, 3)) { luaL_argerror(L, 3, "userdata arg NYI"); } else luaL_argerror(L, 3, "should be tmp key callback function or pem string or key object"); return openssl_pushresult(L, ret); }
/* * Initialize global SSL context. */ static int initialize_SSL(void) { char fnbuf[MAXPGPATH]; struct stat buf; if (!SSL_context) { SSL_library_init(); SSL_load_error_strings(); SSL_context = SSL_CTX_new(SSLv23_method()); if (!SSL_context) ereport(FATAL, (errmsg("could not create SSL context: %s", SSLerrmessage()))); /* * Load and verify certificate and private key */ snprintf(fnbuf, sizeof(fnbuf), "%s/server.crt", DataDir); if (!SSL_CTX_use_certificate_file(SSL_context, fnbuf, SSL_FILETYPE_PEM)) ereport(FATAL, (errcode(ERRCODE_CONFIG_FILE_ERROR), errmsg("could not load server certificate file \"%s\": %s", fnbuf, SSLerrmessage()))); snprintf(fnbuf, sizeof(fnbuf), "%s/server.key", DataDir); if (stat(fnbuf, &buf) == -1) ereport(FATAL, (errcode_for_file_access(), errmsg("could not access private key file \"%s\": %m", fnbuf))); if (!S_ISREG(buf.st_mode) || (buf.st_mode & (S_IRWXG | S_IRWXO)) || buf.st_uid != getuid()) ereport(FATAL, (errcode(ERRCODE_CONFIG_FILE_ERROR), errmsg("unsafe permissions on private key file \"%s\"", fnbuf), errdetail("File must be owned by the database user and must have no permissions for \"group\" or \"other\"."))); if (!SSL_CTX_use_PrivateKey_file(SSL_context, fnbuf, SSL_FILETYPE_PEM)) ereport(FATAL, (errmsg("could not load private key file \"%s\": %s", fnbuf, SSLerrmessage()))); if (!SSL_CTX_check_private_key(SSL_context)) ereport(FATAL, (errmsg("check of private key failed: %s", SSLerrmessage()))); } /* set up empheral DH keys */ SSL_CTX_set_tmp_dh_callback(SSL_context, tmp_dh_cb); SSL_CTX_set_options(SSL_context, SSL_OP_SINGLE_DH_USE | SSL_OP_NO_SSLv2); /* setup the allowed cipher list */ if (SSL_CTX_set_cipher_list(SSL_context, "ALL:!ADH:!LOW:!EXP:!MD5:@STRENGTH") != 1) elog(FATAL, "could not set the cipher list (no valid ciphers available)"); /* accept client certificates, but don't require them. */ snprintf(fnbuf, sizeof(fnbuf), "%s/root.crt", DataDir); if (!SSL_CTX_load_verify_locations(SSL_context, fnbuf, CA_PATH)) { /* Not fatal - we do not require client certificates */ ereport(LOG, (errmsg("could not load root certificate file \"%s\": %s", fnbuf, SSLerrmessage()), errdetail("Will not verify client certificates."))); return 0; } SSL_CTX_set_verify(SSL_context, SSL_VERIFY_PEER | SSL_VERIFY_CLIENT_ONCE, verify_cb); return 0; }
/* Create and initialize an SSL configuration for a route. This configuration is used by all requests for a given route. An application can have different SSL configurations for different routes. There is also a default SSL configuration that is used when a route does not define a configuration and one for clients. */ static int configOss(MprSsl *ssl, int flags, char **errorMsg) { OpenConfig *cfg; X509_STORE *store; SSL_CTX *ctx; cchar *key; uchar resume[16]; int verifyMode; assert(ssl); if (ssl->config && !ssl->changed) { return 0; } if ((ssl->config = mprAllocObj(OpenConfig, manageOpenConfig)) == 0) { return MPR_ERR_MEMORY; } cfg = ssl->config; if ((ctx = SSL_CTX_new(SSLv23_method())) == 0) { mprLog("error openssl", 0, "Unable to create SSL context"); return MPR_ERR_CANT_INITIALIZE; } SSL_CTX_set_app_data(ctx, (void*) ssl); if (ssl->verifyPeer && !(ssl->caFile || ssl->caPath)) { *errorMsg = sfmt("Cannot verify peer due to undefined CA certificates"); SSL_CTX_free(ctx); return MPR_ERR_CANT_INITIALIZE; } /* Configure the certificates */ if (ssl->certFile) { if (setCertFile(ctx, ssl->certFile) < 0) { SSL_CTX_free(ctx); return MPR_ERR_CANT_INITIALIZE; } key = (ssl->keyFile == 0) ? ssl->certFile : ssl->keyFile; if (key) { if (setKeyFile(ctx, key) < 0) { SSL_CTX_free(ctx); return MPR_ERR_CANT_INITIALIZE; } if (!SSL_CTX_check_private_key(ctx)) { mprLog("error openssl", 0, "Check of private key file failed: %s", key); SSL_CTX_free(ctx); return MPR_ERR_CANT_INITIALIZE; } } } if (ssl->ciphers) { ssl->ciphers = mapCipherNames(ssl->ciphers); } if (!ssl->ciphers && (flags & MPR_SOCKET_SERVER)) { ssl->ciphers = sclone(OPENSSL_DEFAULT_CIPHERS); } if (ssl->ciphers) { mprLog("info openssl", 5, "Using SSL ciphers: %s", ssl->ciphers); if (SSL_CTX_set_cipher_list(ctx, ssl->ciphers) != 1) { *errorMsg = sfmt("Unable to set cipher list \"%s\"", ssl->ciphers); SSL_CTX_free(ctx); return MPR_ERR_CANT_INITIALIZE; } } verifyMode = ssl->verifyPeer ? SSL_VERIFY_PEER | SSL_VERIFY_FAIL_IF_NO_PEER_CERT : SSL_VERIFY_NONE; if (verifyMode != SSL_VERIFY_NONE) { if (!(ssl->caFile || ssl->caPath)) { *errorMsg = sclone("No defined certificate authority file"); SSL_CTX_free(ctx); return MPR_ERR_CANT_INITIALIZE; } if ((!SSL_CTX_load_verify_locations(ctx, (char*) ssl->caFile, (char*) ssl->caPath)) || (!SSL_CTX_set_default_verify_paths(ctx))) { *errorMsg = sfmt("Unable to set certificate locations: %s: %s", ssl->caFile, ssl->caPath); SSL_CTX_free(ctx); return MPR_ERR_CANT_INITIALIZE; } if (ssl->caFile) { STACK_OF(X509_NAME) *certNames; certNames = SSL_load_client_CA_file(ssl->caFile); if (certNames) { /* Define the list of CA certificates to send to the client before they send their client certificate for validation */ SSL_CTX_set_client_CA_list(ctx, certNames); } } store = SSL_CTX_get_cert_store(ctx); if (ssl->revoke && !X509_STORE_load_locations(store, ssl->revoke, 0)) { mprLog("error openssl", 0, "Cannot load certificate revoke list: %s", ssl->revoke); SSL_CTX_free(ctx); return MPR_ERR_CANT_INITIALIZE; } if (flags & MPR_SOCKET_SERVER) { SSL_CTX_set_verify_depth(ctx, ssl->verifyDepth); } } /* Define callbacks */ SSL_CTX_set_verify(ctx, verifyMode, verifyPeerCertificate); if (flags & MPR_SOCKET_SERVER) { SSL_CTX_set_tlsext_servername_callback(ctx, sniHostname); } /* Configure DH parameters */ SSL_CTX_set_tmp_dh_callback(ctx, dhcallback); cfg->dhKey = getDhKey(); /* Define default OpenSSL options Ensure we generate a new private key for each connection Disable SSLv2 and SSLv3 by default -- they are insecure. */ cfg->setFlags = SSL_OP_ALL | SSL_OP_SINGLE_DH_USE | SSL_OP_SINGLE_ECDH_USE | SSL_OP_NO_SSLv2 | SSL_OP_NO_SSLv3; #ifdef SSL_OP_NO_TLSv1 if (!(ssl->protocols & MPR_PROTO_TLSV1)) { cfg->setFlags |= SSL_OP_NO_TLSv1; } #endif #ifdef SSL_OP_NO_TLSv1_1 if (!(ssl->protocols & MPR_PROTO_TLSV1_1)) { cfg->setFlags |= SSL_OP_NO_TLSv1_1; } #endif #ifdef SSL_OP_NO_TLSv1_2 if (!(ssl->protocols & MPR_PROTO_TLSV1_2)) { cfg->setFlags |= SSL_OP_NO_TLSv1_2; } #endif #ifdef SSL_OP_MSIE_SSLV2_RSA_PADDING cfg->setFlags |= SSL_OP_MSIE_SSLV2_RSA_PADDING; #endif #if defined(SSL_OP_NO_TICKET) /* Ticket based session reuse is enabled by default */ #if defined(ME_MPR_SSL_TICKET) if (ME_MPR_SSL_TICKET) { cfg->clearFlags |= SSL_OP_NO_TICKET; } else { cfg->setFlags |= SSL_OP_NO_TICKET; } #else cfg->clearFlags |= SSL_OP_NO_TICKET; #endif #endif #if defined(SSL_OP_NO_COMPRESSION) /* CRIME attack targets compression */ cfg->clearFlags |= SSL_OP_NO_COMPRESSION; #endif #if defined(SSL_OP_NO_SESSION_RESUMPTION_ON_RENEGOTIATION) /* Force a new session on renegotiation. Default to true. This is required when using SNI and changing context during the SSL hello */ #if defined(ME_MPR_SSL_RENEGOTIATE) if (ME_MPR_SSL_RENEGOTIATE) { cfg->clearFlags |= SSL_OP_NO_SESSION_RESUMPTION_ON_RENEGOTIATION; } else { cfg->setFlags |= SSL_OP_NO_SESSION_RESUMPTION_ON_RENEGOTIATION; } #else cfg->setFlags |= SSL_OP_NO_SESSION_RESUMPTION_ON_RENEGOTIATION; #endif #endif #if defined(SSL_OP_DONT_INSERT_EMPTY_FRAGMENTS) /* Disables a countermeasure against a SSL 3.0/TLS 1.0 protocol vulnerability affecting CBC ciphers. Defaults to true. */ #if defined(ME_MPR_SSL_EMPTY_FRAGMENTS) if (ME_MPR_SSL_EMPTY_FRAGMENTS) { /* SSL_OP_ALL disables empty fragments. Only needed for ancient browsers like IE-6 on SSL-3.0/TLS-1.0 */ cfg->clearFlags |= SSL_OP_DONT_INSERT_EMPTY_FRAGMENTS; } else { cfg->setFlags |= SSL_OP_DONT_INSERT_EMPTY_FRAGMENTS; } #else cfg->setFlags |= SSL_OP_DONT_INSERT_EMPTY_FRAGMENTS; #endif #endif /* Define a session reuse context */ RAND_bytes(resume, sizeof(resume)); SSL_CTX_set_session_id_context(ctx, resume, sizeof(resume)); /* Elliptic Curve initialization */ #if SSL_OP_SINGLE_ECDH_USE #ifdef SSL_CTX_set_ecdh_auto /* This is supported in OpenSSL 1.0.2 */ SSL_CTX_set_ecdh_auto(ctx, 1); #else { EC_KEY *ecdh; cchar *name; int nid; name = ME_MPR_SSL_CURVE; if ((nid = OBJ_sn2nid(name)) == 0) { *errorMsg = sfmt("Unknown curve name \"%s\"", name); SSL_CTX_free(ctx); return MPR_ERR_CANT_INITIALIZE; } if ((ecdh = EC_KEY_new_by_curve_name(nid)) == 0) { *errorMsg = sfmt("Unable to create curve \"%s\"", name); SSL_CTX_free(ctx); return MPR_ERR_CANT_INITIALIZE; } SSL_CTX_set_tmp_ecdh(ctx, ecdh); EC_KEY_free(ecdh); } #endif #endif SSL_CTX_set_mode(ctx, SSL_MODE_ENABLE_PARTIAL_WRITE | SSL_MODE_AUTO_RETRY | SSL_MODE_ACCEPT_MOVING_WRITE_BUFFER); #ifdef SSL_MODE_RELEASE_BUFFERS SSL_CTX_set_mode(ctx, SSL_MODE_RELEASE_BUFFERS); #endif #ifdef SSL_OP_CIPHER_SERVER_PREFERENCE SSL_CTX_set_mode(ctx, SSL_OP_CIPHER_SERVER_PREFERENCE); #endif #if defined(ME_MPR_SSL_CACHE) /* Set the number of sessions supported. Default in OpenSSL is 20K. */ SSL_CTX_sess_set_cache_size(ctx, ME_MPR_SSL_CACHE); #else SSL_CTX_sess_set_cache_size(ctx, 1024); #endif SSL_CTX_set_options(ctx, cfg->setFlags); SSL_CTX_clear_options(ctx, cfg->clearFlags); cfg->ctx = ctx; ssl->changed = 0; ssl->config = cfg; return 0; }
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 MaOpenSslConfig::start() { const SSL_METHOD *meth; char *hostName; if (keyFile == 0) { mprError(MPR_L, MPR_LOG, "OpenSSL: Cant start SSL: missing key file"); return MPR_ERR_CANT_INITIALIZE; } if (certFile == 0) { mprError(MPR_L, MPR_LOG, "OpenSSL: Cant start SSL: missing certificate file"); return MPR_ERR_CANT_INITIALIZE; } // // Depending on the order in the configuration file, we may get called // by sslModule::start() before OpenSslModule::start has run. So we // must initialize here. // openSslModule->start(); hostName = host->getName(); if (protocols == MPR_HTTP_PROTO_SSLV2) { meth = SSLv2_server_method(); } else { meth = SSLv23_server_method(); } context = SSL_CTX_new(meth); mprAssert(context); if (context == 0) { mprError(MPR_L, MPR_LOG, "OpenSSL: Unable to create SSL context"); return MPR_ERR_CANT_CREATE; } SSL_CTX_set_app_data(context, (void*) this); SSL_CTX_set_quiet_shutdown(context, 1); SSL_CTX_sess_set_cache_size(context, 512); // // Configure the certificate for this host // if (configureCertificates(context, keyFile, certFile) != 0) { SSL_CTX_free(context); context = 0; return MPR_ERR_CANT_INITIALIZE; } mprLog(4, "SSL: %s: Using ciphers %s\n", hostName, ciphers); SSL_CTX_set_cipher_list(context, ciphers); // // Configure the client verification certificate locations // if (verifyClient) { if (caFile == 0 && caPath == 0) { mprError(MPR_L, MPR_LOG, "OpenSSL: Must define CA certificates if using client verification"); SSL_CTX_free(context); context = 0; return MPR_ERR_BAD_STATE; } if (caFile || caPath) { if ((!SSL_CTX_load_verify_locations(context, caFile, caPath)) || (!SSL_CTX_set_default_verify_paths(context))) { mprError(MPR_L, MPR_LOG, "OpenSSL: Unable to set certificate locations"); SSL_CTX_free(context); context = 0; return MPR_ERR_CANT_ACCESS; } if (caFile) { STACK_OF(X509_NAME) *certNames; certNames = SSL_load_client_CA_file(caFile); if (certNames == 0) { } else { // // Define the list of CA certificates to send to the client // before they send their client certificate for validation // SSL_CTX_set_client_CA_list(context, certNames); } } } mprLog(4, "SSL: %s: is verifying client connections\n", hostName); if (caFile) { mprLog(4, "SSL: %s: Using certificates from %s\n", hostName, caFile); } else if (caPath) { mprLog(4, "SSL: %s: Using certificates from directory %s\n", hostName, caPath); } SSL_CTX_set_verify(context, SSL_VERIFY_PEER | SSL_VERIFY_FAIL_IF_NO_PEER_CERT, verifyX509Certificate); SSL_CTX_set_verify_depth(context, verifyDepth); } else { SSL_CTX_set_verify(context, SSL_VERIFY_NONE, verifyX509Certificate); } // // Define callbacks // SSL_CTX_set_tmp_rsa_callback(context, rsaCallback); SSL_CTX_set_tmp_dh_callback(context, dhCallback); // // Enable all buggy client work-arounds // SSL_CTX_set_options(context, SSL_OP_ALL); #ifdef SSL_OP_NO_TICKET SSL_CTX_set_options(context, SSL_OP_NO_TICKET); #endif #ifdef SSL_OP_NO_SESSION_RESUMPTION_ON_RENEGOTIATION SSL_CTX_set_options(context, SSL_OP_NO_SESSION_RESUMPTION_ON_RENEGOTIATION); #endif SSL_CTX_set_mode(context, SSL_MODE_ENABLE_PARTIAL_WRITE | SSL_MODE_AUTO_RETRY); // // Select the required protocols // SSL_CTX_set_options(context, SSL_OP_NO_SSLv2); if (!(protocols & MPR_HTTP_PROTO_SSLV3)) { SSL_CTX_set_options(context, SSL_OP_NO_SSLv3); mprLog(4, "SSL: %s: Disabling SSLv3\n", hostName); } if (!(protocols & MPR_HTTP_PROTO_TLSV1)) { SSL_CTX_set_options(context, SSL_OP_NO_TLSv1); mprLog(4, "SSL: %s: Disabling TLSv1\n", hostName); } // // Ensure we generate a new private key for each connection // SSL_CTX_set_options(context, SSL_OP_SINGLE_DH_USE); // // Pre-generate some keys that are slow to compute // rsaKey512 = RSA_generate_key(512, RSA_F4, 0, 0); rsaKey1024 = RSA_generate_key(1024, RSA_F4, 0, 0); dhKey512 = get_dh512(); dhKey1024 = get_dh1024(); return 0; }
/* Create and initialize an SSL configuration for a route. This configuration is used by all requests for a given route. An application can have different SSL configurations for different routes. There is also a default SSL configuration that is used when a route does not define a configuration and one for clients. */ static OpenConfig *createOpenSslConfig(MprSocket *sp) { MprSsl *ssl; OpenConfig *cfg; X509_STORE *store; SSL_CTX *context; cchar *key; uchar resume[16]; int verifyMode; ssl = sp->ssl; assert(ssl); if ((ssl->config = mprAllocObj(OpenConfig, manageOpenConfig)) == 0) { return 0; } cfg = ssl->config; if ((context = SSL_CTX_new(SSLv23_method())) == 0) { mprLog("error openssl", 0, "Unable to create SSL context"); return 0; } SSL_CTX_set_app_data(context, (void*) ssl); if (ssl->verifyPeer && !(ssl->caFile || ssl->caPath)) { sp->errorMsg = sfmt("Cannot verify peer due to undefined CA certificates"); SSL_CTX_free(context); return 0; } /* Configure the certificates */ if (ssl->certFile) { if (SSL_CTX_use_certificate_chain_file(context, ssl->certFile) <= 0) { if (SSL_CTX_use_certificate_file(context, ssl->certFile, SSL_FILETYPE_ASN1) <= 0) { mprLog("error openssl", 0, "Cannot open certificate file: %s", ssl->certFile); SSL_CTX_free(context); return 0; } } key = (ssl->keyFile == 0) ? ssl->certFile : ssl->keyFile; if (key) { if (SSL_CTX_use_PrivateKey_file(context, key, SSL_FILETYPE_PEM) <= 0) { /* attempt ASN1 for self-signed format */ if (SSL_CTX_use_PrivateKey_file(context, key, SSL_FILETYPE_ASN1) <= 0) { mprLog("error openssl", 0, "Cannot open private key file: %s", key); SSL_CTX_free(context); return 0; } } if (!SSL_CTX_check_private_key(context)) { mprLog("error openssl", 0, "Check of private key file failed: %s", key); SSL_CTX_free(context); return 0; } } } if (ssl->ciphers) { ssl->ciphers = mapCipherNames(ssl->ciphers); } if (!ssl->ciphers && (sp->flags & MPR_SOCKET_SERVER)) { ssl->ciphers = sclone(OPENSSL_DEFAULT_CIPHERS); } if (ssl->ciphers) { mprLog("info openssl", 5, "Using SSL ciphers: %s", ssl->ciphers); if (SSL_CTX_set_cipher_list(context, ssl->ciphers) != 1) { sp->errorMsg = sfmt("Unable to set cipher list \"%s\". %s", ssl->ciphers, getOssError(sp)); SSL_CTX_free(context); return 0; } } verifyMode = ssl->verifyPeer ? SSL_VERIFY_PEER | SSL_VERIFY_FAIL_IF_NO_PEER_CERT : SSL_VERIFY_NONE; if (verifyMode != SSL_VERIFY_NONE) { if (!(ssl->caFile || ssl->caPath)) { sp->errorMsg = sclone("No defined certificate authority file"); SSL_CTX_free(context); return 0; } if ((!SSL_CTX_load_verify_locations(context, (char*) ssl->caFile, (char*) ssl->caPath)) || (!SSL_CTX_set_default_verify_paths(context))) { sp->errorMsg = sfmt("Unable to set certificate locations: %s: %s", ssl->caFile, ssl->caPath); SSL_CTX_free(context); return 0; } if (ssl->caFile) { STACK_OF(X509_NAME) *certNames; certNames = SSL_load_client_CA_file(ssl->caFile); if (certNames) { /* Define the list of CA certificates to send to the client before they send their client certificate for validation */ SSL_CTX_set_client_CA_list(context, certNames); } } store = SSL_CTX_get_cert_store(context); if (ssl->revokeList && !X509_STORE_load_locations(store, ssl->revokeList, 0)) { mprLog("error openssl", 0, "Cannot load certificate revoke list: %s", ssl->revokeList); SSL_CTX_free(context); return 0; } if (sp->flags & MPR_SOCKET_SERVER) { SSL_CTX_set_verify_depth(context, ssl->verifyDepth); } } /* Define callbacks */ SSL_CTX_set_verify(context, verifyMode, verifyPeerCertificate); /* Configure DH parameters */ SSL_CTX_set_tmp_dh_callback(context, dhcallback); cfg->dhKey = getDhKey(); /* Define default OpenSSL options */ SSL_CTX_set_options(context, SSL_OP_ALL); /* Ensure we generate a new private key for each connection */ SSL_CTX_set_options(context, SSL_OP_SINGLE_DH_USE); /* Define a session reuse context */ RAND_bytes(resume, sizeof(resume)); SSL_CTX_set_session_id_context(context, resume, sizeof(resume)); /* Elliptic Curve initialization */ #if SSL_OP_SINGLE_ECDH_USE #ifdef SSL_CTX_set_ecdh_auto SSL_CTX_set_ecdh_auto(context, 1); #else { EC_KEY *ecdh; cchar *name; int nid; name = ME_MPR_SSL_CURVE; if ((nid = OBJ_sn2nid(name)) == 0) { sp->errorMsg = sfmt("Unknown curve name \"%s\"", name); SSL_CTX_free(context); return 0; } if ((ecdh = EC_KEY_new_by_curve_name(nid)) == 0) { sp->errorMsg = sfmt("Unable to create curve \"%s\"", name); SSL_CTX_free(context); return 0; } SSL_CTX_set_options(context, SSL_OP_SINGLE_ECDH_USE); SSL_CTX_set_tmp_ecdh(context, ecdh); EC_KEY_free(ecdh); } #endif #endif SSL_CTX_set_mode(context, SSL_MODE_ENABLE_PARTIAL_WRITE | SSL_MODE_AUTO_RETRY | SSL_MODE_ACCEPT_MOVING_WRITE_BUFFER); #ifdef SSL_OP_MSIE_SSLV2_RSA_PADDING SSL_CTX_set_options(context, SSL_OP_MSIE_SSLV2_RSA_PADDING); #endif #ifdef SSL_MODE_RELEASE_BUFFERS SSL_CTX_set_mode(context, SSL_MODE_RELEASE_BUFFERS); #endif #ifdef SSL_OP_CIPHER_SERVER_PREFERENCE SSL_CTX_set_mode(context, SSL_OP_CIPHER_SERVER_PREFERENCE); #endif /* Select the required protocols Disable SSLv2 and SSLv3 by default -- they are insecure. */ SSL_CTX_set_options(context, SSL_OP_NO_SSLv2); SSL_CTX_set_options(context, SSL_OP_NO_SSLv3); #ifdef SSL_OP_NO_TLSv1 if (!(ssl->protocols & MPR_PROTO_TLSV1)) { SSL_CTX_set_options(context, SSL_OP_NO_TLSv1); } #endif #ifdef SSL_OP_NO_TLSv1_1 if (!(ssl->protocols & MPR_PROTO_TLSV1_1)) { SSL_CTX_set_options(context, SSL_OP_NO_TLSv1_1); } #endif #ifdef SSL_OP_NO_TLSv1_2 if (!(ssl->protocols & MPR_PROTO_TLSV1_2)) { SSL_CTX_set_options(context, SSL_OP_NO_TLSv1_2); } #endif /* Options set via main.me mpr.ssl.* */ #if defined(SSL_OP_NO_TICKET) /* Ticket based session reuse is enabled by default */ #if defined(ME_MPR_SSL_TICKET) if (ME_MPR_SSL_TICKET) { SSL_CTX_clear_options(context, SSL_OP_NO_TICKET); } else { SSL_CTX_set_options(context, SSL_OP_NO_TICKET); } #else SSL_CTX_clear_options(context, SSL_OP_NO_TICKET); #endif #endif #if defined(SSL_OP_NO_COMPRESSION) /* Use of compression is not secure. Disabled by default. */ #if defined(ME_MPR_SSL_COMPRESSION) if (ME_MPR_SSL_COMPRESSION) { SSL_CTX_clear_options(context, SSL_OP_NO_COMPRESSION); } else { SSL_CTX_set_options(context, SSL_OP_NO_COMPRESSION); } #else /* CRIME attack targets compression */ SSL_CTX_clear_options(context, SSL_OP_NO_COMPRESSION); #endif #endif #if defined(SSL_OP_NO_SESSION_RESUMPTION_ON_RENEGOTIATION) /* Force a new session on renegotiation. Default to true. */ #if defined(ME_MPR_SSL_RENEGOTIATE) if (ME_MPR_SSL_RENEGOTIATE) { SSL_CTX_clear_options(context, SSL_OP_NO_SESSION_RESUMPTION_ON_RENEGOTIATION); } else { SSL_CTX_set_options(context, SSL_OP_NO_SESSION_RESUMPTION_ON_RENEGOTIATION); } #else SSL_CTX_set_options(context, SSL_OP_NO_SESSION_RESUMPTION_ON_RENEGOTIATION); #endif #endif #if defined(SSL_OP_DONT_INSERT_EMPTY_FRAGMENTS) /* Disables a countermeasure against a SSL 3.0/TLS 1.0 protocol vulnerability affecting CBC ciphers. Defaults to true. */ #if defined(ME_MPR_SSL_EMPTY_FRAGMENTS) if (ME_MPR_SSL_EMPTY_FRAGMENTS) { /* SSL_OP_ALL disables empty fragments. Only needed for ancient browsers like IE-6 on SSL-3.0/TLS-1.0 */ SSL_CTX_clear_options(context, SSL_OP_DONT_INSERT_EMPTY_FRAGMENTS); } else { SSL_CTX_set_options(context, SSL_OP_DONT_INSERT_EMPTY_FRAGMENTS); } #else SSL_CTX_set_options(context, SSL_OP_DONT_INSERT_EMPTY_FRAGMENTS); #endif #endif #if defined(ME_MPR_SSL_CACHE) /* Set the number of sessions supported. Default in OpenSSL is 20K. */ SSL_CTX_sess_set_cache_size(context, ME_MPR_SSL_CACHE); #else SSL_CTX_sess_set_cache_size(context, 1024); #endif cfg->context = context; return cfg; }