int _ssl_ctx_create(void **ctx) { _SSLO_CTX *so; if (ctx == NULL) { return ERR_TR50_PARMS; } *ctx = NULL; if ((so = _memory_malloc(sizeof(_SSLO_CTX))) == NULL) { return ERR_TR50_MALLOC; } _memory_memset(so, 0, sizeof(_SSLO_CTX)); so->ctx = SSL_CTX_new(TLSv1_method()); if (so->ctx == NULL) { _memory_free(so); return ERR_TR50_SSL_NOTINIT; } SSL_CTX_set_session_cache_mode(so->ctx, SSL_SESS_CACHE_OFF); SSL_CTX_set_mode(so->ctx, SSL_MODE_AUTO_RETRY); *ctx = so; return 0; }
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 tls_sc_create(lua_State *L) { tls_sc_t *ctx; const char *method_string = lua_tostring(L, 1); const SSL_METHOD *method = SSLv23_method(); if (method_string) { if (strcmp(method_string, "SSLv3_method") == 0) { method = SSLv3_method(); } else if (strcmp(method_string, "SSLv3_server_method") == 0) { method = SSLv3_server_method(); } else if (strcmp(method_string, "SSLv3_client_method") == 0) { method = SSLv3_client_method(); } else if (strcmp(method_string, "SSLv23_method") == 0) { method = SSLv23_method(); } else if (strcmp(method_string, "SSLv23_server_method") == 0) { method = SSLv23_server_method(); } else if (strcmp(method_string, "SSLv23_client_method") == 0) { method = SSLv23_client_method(); } else if (strcmp(method_string, "TLSv1_method") == 0) { method = TLSv1_method(); } else if (strcmp(method_string, "TLSv1_server_method") == 0) { method = TLSv1_server_method(); } else if (strcmp(method_string, "TLSv1_client_method") == 0) { method = TLSv1_client_method(); } else { return luaL_error(L, "method not supported: %s", method_string); } } ctx = newSC(L); ctx->ctx = SSL_CTX_new(method); /* TODO: customize Session cache */ SSL_CTX_set_session_cache_mode(ctx->ctx, SSL_SESS_CACHE_SERVER); return 1; }
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 SSL_CTX_set_session_id_context(sslCtx, (const uint8_t *)context.data(), std::min((int)context.length(), SSL_MAX_SSL_SESSION_ID_LENGTH)); } 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 tls_ctx_set_options (struct tls_root_ctx *ctx, unsigned int ssl_flags) { ASSERT(NULL != ctx); SSL_CTX_set_session_cache_mode (ctx->ctx, SSL_SESS_CACHE_OFF); SSL_CTX_set_options (ctx->ctx, SSL_OP_SINGLE_DH_USE); SSL_CTX_set_default_passwd_cb (ctx->ctx, pem_password_callback); /* Require peer certificate verification */ #if P2MP_SERVER if (ssl_flags & SSLF_CLIENT_CERT_NOT_REQUIRED) { msg (M_WARN, "WARNING: POTENTIALLY DANGEROUS OPTION " "--client-cert-not-required may accept clients which do not present " "a certificate"); } else #endif SSL_CTX_set_verify (ctx->ctx, SSL_VERIFY_PEER | SSL_VERIFY_FAIL_IF_NO_PEER_CERT, verify_callback); SSL_CTX_set_info_callback (ctx->ctx, info_callback); }
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); }
/** * Initializes a ssl connection for server use. * @param pemfilename Filename for the key/cert file * @return An ssl connection, or NULL if an error occured. */ ssl_server_connection *init_ssl_server(char *pemfile, char *clientpemfile) { SSL_METHOD *server_method = NULL; ssl_server_connection *ssl_server; ASSERT(pemfile); if (!ssl_initialized) start_ssl(); ssl_server = new_ssl_server_connection(pemfile, clientpemfile); #ifdef OPENSSL_FIPS if (FIPS_mode()) server_method = TLSv1_server_method(); else #endif server_method = SSLv23_server_method(); if (!(ssl_server->method = server_method)) { LogError("%s: Cannot initialize the SSL method -- %s\n", prog, SSLERROR); goto sslerror; } if (!(ssl_server->ctx = SSL_CTX_new(ssl_server->method))) { LogError("%s: Cannot initialize SSL server certificate handler -- %s\n", prog, SSLERROR); goto sslerror; } if (SSL_CTX_use_certificate_chain_file(ssl_server->ctx, pemfile) != 1) { LogError("%s: Cannot initialize SSL server certificate -- %s\n", prog, SSLERROR); goto sslerror; } if (SSL_CTX_use_PrivateKey_file(ssl_server->ctx, pemfile, SSL_FILETYPE_PEM) != 1) { LogError("%s: Cannot initialize SSL server private key -- %s\n", prog, SSLERROR); goto sslerror; } if (SSL_CTX_check_private_key(ssl_server->ctx) != 1) { LogError("%s: The private key doesn't match the certificate public key -- %s\n", prog, SSLERROR); goto sslerror; } /* Disable session cache */ SSL_CTX_set_session_cache_mode(ssl_server->ctx, SSL_SESS_CACHE_OFF); /* * We need this to force transmission of client certs */ if (!verify_init(ssl_server)) { LogError("%s: Verification engine was not properly initialized -- %s\n", prog, SSLERROR); goto sslerror; } if (ssl_server->clientpemfile) { STACK_OF(X509_NAME) *stack = SSL_CTX_get_client_CA_list(ssl_server->ctx); LogInfo("%s: Found %d client certificates\n", prog, sk_X509_NAME_num(stack)); } return ssl_server; sslerror: delete_ssl_server_socket(ssl_server); return NULL; }
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 */ }
void SSLContextManager::addSSLContextConfig( const SSLContextConfig& ctxConfig, const SSLCacheOptions& cacheOptions, const TLSTicketKeySeeds* ticketSeeds, const folly::SocketAddress& vipAddress, const std::shared_ptr<SSLCacheProvider>& externalCache) { unsigned numCerts = 0; std::string commonName; std::string lastCertPath; std::unique_ptr<std::list<std::string>> subjectAltName; auto sslCtx = std::make_shared<SSLContext>(ctxConfig.sslVersion); for (const auto& cert : ctxConfig.certificates) { try { sslCtx->loadCertificate(cert.certPath.c_str()); } catch (const std::exception& ex) { // The exception isn't very useful without the certificate path name, // so throw a new exception that includes the path to the certificate. string msg = folly::to<string>("error loading SSL certificate ", cert.certPath, ": ", folly::exceptionStr(ex)); LOG(ERROR) << msg; throw std::runtime_error(msg); } // Verify that the Common Name and (if present) Subject Alternative Names // are the same for all the certs specified for the SSL context. numCerts++; X509* x509 = getX509(sslCtx->getSSLCtx()); auto guard = folly::makeGuard([x509] { X509_free(x509); }); auto cn = SSLUtil::getCommonName(x509); if (!cn) { throw std::runtime_error(folly::to<string>("Cannot get CN for X509 ", cert.certPath)); } auto altName = SSLUtil::getSubjectAltName(x509); VLOG(2) << "cert " << cert.certPath << " CN: " << *cn; if (altName) { altName->sort(); VLOG(2) << "cert " << cert.certPath << " SAN: " << flattenList(*altName); } else { VLOG(2) << "cert " << cert.certPath << " SAN: " << "{none}"; } if (numCerts == 1) { commonName = *cn; subjectAltName = std::move(altName); } else { if (commonName != *cn) { throw std::runtime_error(folly::to<string>("X509 ", cert.certPath, " does not have same CN as ", lastCertPath)); } if (altName == nullptr) { if (subjectAltName != nullptr) { throw std::runtime_error(folly::to<string>("X509 ", cert.certPath, " does not have same SAN as ", lastCertPath)); } } else { if ((subjectAltName == nullptr) || (*altName != *subjectAltName)) { throw std::runtime_error(folly::to<string>("X509 ", cert.certPath, " does not have same SAN as ", lastCertPath)); } } } lastCertPath = cert.certPath; // TODO t4438250 - Add ECDSA support to the crypto_ssl offload server // so we can avoid storing the ECDSA private key in the // address space of the Internet-facing process. For // now, if cert name includes "-EC" to denote elliptic // curve, we load its private key even if the server as // a whole has been configured for async crypto. if (ctxConfig.isLocalPrivateKey || (cert.certPath.find("-EC") != std::string::npos)) { // The private key lives in the same process // This needs to be called before loadPrivateKey(). if (!cert.passwordPath.empty()) { auto sslPassword = std::make_shared<PasswordInFile>(cert.passwordPath); sslCtx->passwordCollector(sslPassword); } try { sslCtx->loadPrivateKey(cert.keyPath.c_str()); } catch (const std::exception& ex) { // Throw an error that includes the key path, so the user can tell // which key had a problem. string msg = folly::to<string>("error loading private SSL key ", cert.keyPath, ": ", folly::exceptionStr(ex)); LOG(ERROR) << msg; throw std::runtime_error(msg); } } } if (!ctxConfig.isLocalPrivateKey) { enableAsyncCrypto(sslCtx); } // Let the server pick the highest performing cipher from among the client's // choices. // // Let's use a unique private key for all DH key exchanges. // // Because some old implementations choke on empty fragments, most SSL // applications disable them (it's part of SSL_OP_ALL). This // will improve performance and decrease write buffer fragmentation. sslCtx->setOptions(SSL_OP_CIPHER_SERVER_PREFERENCE | SSL_OP_SINGLE_DH_USE | SSL_OP_DONT_INSERT_EMPTY_FRAGMENTS); // Configure SSL ciphers list if (!ctxConfig.tls11Ciphers.empty()) { // FIXME: create a dummy SSL_CTX for cipher testing purpose? It can // remove the ordering dependency // Test to see if the specified TLS1.1 ciphers are valid. Note that // these will be overwritten by the ciphers() call below. sslCtx->setCiphersOrThrow(ctxConfig.tls11Ciphers); } // Important that we do this *after* checking the TLS1.1 ciphers above, // since we test their validity by actually setting them. sslCtx->ciphers(ctxConfig.sslCiphers); // Use a fix DH param DH* dh = get_dh2048(); SSL_CTX_set_tmp_dh(sslCtx->getSSLCtx(), dh); DH_free(dh); const string& curve = ctxConfig.eccCurveName; if (!curve.empty()) { set_key_from_curve(sslCtx->getSSLCtx(), curve); } if (!ctxConfig.clientCAFile.empty()) { try { sslCtx->setVerificationOption(SSLContext::VERIFY_REQ_CLIENT_CERT); sslCtx->loadTrustedCertificates(ctxConfig.clientCAFile.c_str()); sslCtx->loadClientCAList(ctxConfig.clientCAFile.c_str()); } catch (const std::exception& ex) { string msg = folly::to<string>("error loading client CA", ctxConfig.clientCAFile, ": ", folly::exceptionStr(ex)); LOG(ERROR) << msg; throw std::runtime_error(msg); } } // - start - SSL session cache config // the internal cache never does what we want (per-thread-per-vip). // Disable it. SSLSessionCacheManager will set it appropriately. SSL_CTX_set_session_cache_mode(sslCtx->getSSLCtx(), SSL_SESS_CACHE_OFF); SSL_CTX_set_timeout(sslCtx->getSSLCtx(), cacheOptions.sslCacheTimeout.count()); std::unique_ptr<SSLSessionCacheManager> sessionCacheManager; if (ctxConfig.sessionCacheEnabled && cacheOptions.maxSSLCacheSize > 0 && cacheOptions.sslCacheFlushSize > 0) { sessionCacheManager = folly::make_unique<SSLSessionCacheManager>( cacheOptions.maxSSLCacheSize, cacheOptions.sslCacheFlushSize, sslCtx.get(), vipAddress, commonName, eventBase_, stats_, externalCache); } // - end - SSL session cache config std::unique_ptr<TLSTicketKeyManager> ticketManager = createTicketManagerHelper(sslCtx, ticketSeeds, ctxConfig, stats_); // finalize sslCtx setup by the individual features supported by openssl ctxSetupByOpensslFeature(sslCtx, ctxConfig); try { insert(sslCtx, std::move(sessionCacheManager), std::move(ticketManager), ctxConfig.isDefault); } catch (const std::exception& ex) { string msg = folly::to<string>("Error adding certificate : ", folly::exceptionStr(ex)); LOG(ERROR) << msg; throw std::runtime_error(msg); } }
/* * Setup default SSL_CTX (and SSL * ) behavior: * verification, cipherlist, acceptable versions, ... */ static int init_ssl_ctx_behavior( struct tls_domain *d ) { int verify_mode; #if (OPENSSL_VERSION_NUMBER > 0x10001000L) /* * set dh params */ if (!d->tmp_dh_file) { LM_DBG("no DH params file for tls[%s:%d] defined, " "using default '%s'\n", ip_addr2a(&d->addr), d->port, tls_tmp_dh_file); d->tmp_dh_file = tls_tmp_dh_file; } if (d->tmp_dh_file && set_dh_params(d->ctx, d->tmp_dh_file) < 0) return -1; if (d->tls_ec_curve) { if (set_ec_params(d->ctx, d->tls_ec_curve) < 0) { return -1; } } else { LM_NOTICE("No EC curve defined\n"); } #else if (d->tmp_dh_file || tls_tmp_dh_file) LM_WARN("DH params file discarded as not supported by your openSSL version\n"); if (d->tls_ec_curve) LM_WARN("EC params file discarded as not supported by your openSSL version\n"); #endif if( d->ciphers_list != 0 ) { if( SSL_CTX_set_cipher_list(d->ctx, d->ciphers_list) == 0 ) { LM_ERR("failure to set SSL context " "cipher list '%s'\n", d->ciphers_list); return -1; } else { LM_NOTICE("cipher list set to %s\n", d->ciphers_list); } } else { LM_DBG( "cipher list null ... setting default\n"); } /* Set a bunch of options: * do not accept SSLv2 * no session resumption * choose cipher according to server's preference's*/ #if OPENSSL_VERSION_NUMBER >= 0x000907000 SSL_CTX_set_options(d->ctx, SSL_OP_ALL | SSL_OP_NO_SSLv2 | SSL_OP_NO_SESSION_RESUMPTION_ON_RENEGOTIATION | SSL_OP_CIPHER_SERVER_PREFERENCE); #else SSL_CTX_set_options(d->ctx, SSL_OP_ALL | SSL_OP_NO_SSLv2 ); #endif /* Set verification procedure * The verification can be made null with SSL_VERIFY_NONE, or * at least easier with SSL_VERIFY_CLIENT_ONCE instead of * SSL_VERIFY_FAIL_IF_NO_PEER_CERT. * For extra control, instead of 0, we can specify a callback function: * int (*verify_callback)(int, X509_STORE_CTX *) * Also, depth 2 may be not enough in some scenarios ... though no need * to increase it much further */ if (d->type & TLS_DOMAIN_SRV) { /* Server mode: * SSL_VERIFY_NONE * the server will not send a client certificate request to the * client, so the client will not send a certificate. * SSL_VERIFY_PEER * the server sends a client certificate request to the client. * The certificate returned (if any) is checked. If the verification * process fails, the TLS/SSL handshake is immediately terminated * with an alert message containing the reason for the verification * failure. The behaviour can be controlled by the additional * SSL_VERIFY_FAIL_IF_NO_PEER_CERT and SSL_VERIFY_CLIENT_ONCE flags. * SSL_VERIFY_FAIL_IF_NO_PEER_CERT * if the client did not return a certificate, the TLS/SSL handshake * is immediately terminated with a ``handshake failure'' alert. * This flag must be used together with SSL_VERIFY_PEER. * SSL_VERIFY_CLIENT_ONCE * only request a client certificate on the initial TLS/SSL * handshake. Do not ask for a client certificate again in case of * a renegotiation. This flag must be used together with * SSL_VERIFY_PEER. */ if( d->verify_cert ) { verify_mode = SSL_VERIFY_PEER; if( d->require_client_cert ) { LM_WARN("client verification activated. Client " "certificates are mandatory.\n"); verify_mode |= SSL_VERIFY_FAIL_IF_NO_PEER_CERT; } else LM_WARN("client verification activated. Client " "certificates are NOT mandatory.\n"); } else { verify_mode = SSL_VERIFY_NONE; LM_WARN("client verification NOT activated. Weaker security.\n"); } } else { /* Client mode: * SSL_VERIFY_NONE * if not using an anonymous cipher (by default disabled), the * server will send a certificate which will be checked. The result * of the certificate verification process can be checked after the * TLS/SSL handshake using the SSL_get_verify_result(3) function. * The handshake will be continued regardless of the verification * result. * SSL_VERIFY_PEER * the server certificate is verified. If the verification process * fails, the TLS/SSL handshake is immediately terminated with an * alert message containing the reason for the verification failure. * If no server certificate is sent, because an anonymous cipher is * used, SSL_VERIFY_PEER is ignored. * SSL_VERIFY_FAIL_IF_NO_PEER_CERT * ignored * SSL_VERIFY_CLIENT_ONCE * ignored */ if( d->verify_cert ) { verify_mode = SSL_VERIFY_PEER; LM_WARN("server verification activated.\n"); } else { verify_mode = SSL_VERIFY_NONE; LM_WARN("server verification NOT activated. Weaker security.\n"); } } SSL_CTX_set_verify( d->ctx, verify_mode, verify_callback); SSL_CTX_set_verify_depth( d->ctx, VERIFY_DEPTH_S); SSL_CTX_set_session_cache_mode( d->ctx, SSL_SESS_CACHE_SERVER ); SSL_CTX_set_session_id_context( d->ctx, OS_SSL_SESS_ID, OS_SSL_SESS_ID_LEN ); return 0; }
void SSLHandler::init(const SecurityProperties& securityProperties) { if(isSSLEnabled) { this->securityProperties = securityProperties; if(securityProperties.alpnEnabled && securityProperties.alpnProtoList.size()>0) { for(int pn=0;pn<(int)securityProperties.alpnProtoList.size();pn++) { string protoname = securityProperties.alpnProtoList.at(pn); vector<unsigned char> res = vector<unsigned char>(1 + protoname.length()); unsigned char* p = res.data(); *p++ = protoname.length(); memcpy(p, protoname.c_str(), protoname.length()); advertisedProtos.push_back(res); } } string sslConfsettings = "Server setup with SSL enabled, CERTFILE = "; sslConfsettings.append(securityProperties.cert_file); sslConfsettings.append(", KEYFILE = "); sslConfsettings.append(securityProperties.key_file); sslConfsettings.append(", PASSWORD = "******", DHFILE = "); sslConfsettings.append(securityProperties.dh_file); sslConfsettings.append(", CA_LIST = "); sslConfsettings.append(securityProperties.ca_list); sslConfsettings.append(", ISDH_PARAMS = "); //sslConfsettings.append(CastUtil::lexical_cast<string>(securityProperties.isDHParams)); //sslConfsettings.append(", CLIENT_SEC_LEVEL = "); //sslConfsettings.append(CastUtil::lexical_cast<string>(securityProperties.client_auth)); logger << sslConfsettings << endl; /* Build our SSL context*/ ctx = SSLCommon::initialize_ctx(true); pass = (char*)securityProperties.sec_password.c_str(); SSL_CTX_set_default_passwd_cb(ctx, SSLHandler::password_cb); SSL_CTX_set_options(ctx, SSL_OP_ALL | SSL_OP_NO_SSLv2 | SSL_OP_NO_SSLv3 | SSL_OP_NO_COMPRESSION | SSL_OP_SINGLE_DH_USE | SSL_OP_NO_SESSION_RESUMPTION_ON_RENEGOTIATION | SSL_OP_SINGLE_ECDH_USE | SSL_OP_NO_TICKET | SSL_OP_CIPHER_SERVER_PREFERENCE); SSL_CTX_set_mode(ctx, SSL_MODE_AUTO_RETRY); SSL_CTX_set_mode(ctx, SSL_MODE_RELEASE_BUFFERS); if(securityProperties.isDHParams) { SSLCommon::load_dh_params(ctx,(char*)securityProperties.dh_file.c_str()); } else { SSLCommon::load_ecdh_params(ctx); } const unsigned char sid_ctx[] = "Ffead"; SSL_CTX_set_session_id_context(ctx, sid_ctx, sizeof(sid_ctx) - 1); SSL_CTX_set_session_cache_mode(ctx, SSL_SESS_CACHE_SERVER); /*SSL_CTX_set_session_id_context(ctx, (const unsigned char*)&s_server_session_id_context, sizeof s_server_session_id_context); */ /* Set our cipher list */ if(SSLCommon::ciphers!=""){ SSL_CTX_set_cipher_list(ctx, SSLCommon::ciphers.c_str()); } SSLCommon::loadCerts(ctx, (char*)securityProperties.cert_file.c_str(), (char*)securityProperties.key_file.c_str(), securityProperties.ca_list, true); if(securityProperties.client_auth==2) { /* Set to require peer (client) certificate verification */ SSL_CTX_set_verify(ctx, SSL_VERIFY_PEER|SSL_VERIFY_CLIENT_ONCE|SSL_VERIFY_FAIL_IF_NO_PEER_CERT, NULL); /* Set the verification depth to 1 */ #if (OPENSSL_VERSION_NUMBER < 0x00905100L) SSL_CTX_set_verify_depth(ctx,1); #endif } else if(securityProperties.client_auth==1) { /* Set to require peer (client) certificate verification */ SSL_CTX_set_verify(ctx, SSL_VERIFY_PEER, NULL); /* Set the verification depth to 1 */ #if (OPENSSL_VERSION_NUMBER < 0x00905100L) SSL_CTX_set_verify_depth(ctx,1); #endif } else { SSL_CTX_set_verify(ctx, SSL_VERIFY_NONE, NULL); } #if OPENSSL_VERSION_NUMBER >= 0x10002000L if(securityProperties.alpnEnabled) { for (int var = 0; var < (int)advertisedProtos.size(); ++var) { SSL_CTX_set_next_protos_advertised_cb(ctx, SSLHandler::next_proto_cb, &(advertisedProtos.at(var))); } // ALPN selection callback SSL_CTX_set_alpn_select_cb(ctx, SSLHandler::alpn_select_proto_cb, NULL); } #endif // OPENSSL_VERSION_NUMBER >= 0x10002000L } }
bud_error_t bud_config_new_ssl_ctx(bud_config_t* config, bud_context_t* context) { SSL_CTX* ctx; bud_error_t err; int options; /* Choose method, tlsv1_2 by default */ if (config->frontend.method == NULL) { if (strcmp(config->frontend.security, "tls1.1") == 0) config->frontend.method = TLSv1_1_server_method(); else if (strcmp(config->frontend.security, "tls1.0") == 0) config->frontend.method = TLSv1_server_method(); else if (strcmp(config->frontend.security, "tls1.2") == 0) config->frontend.method = TLSv1_2_server_method(); else if (strcmp(config->frontend.security, "ssl3") == 0) config->frontend.method = SSLv3_server_method(); else config->frontend.method = SSLv23_server_method(); } ctx = SSL_CTX_new(config->frontend.method); if (ctx == NULL) return bud_error_str(kBudErrNoMem, "SSL_CTX"); SSL_CTX_set_session_cache_mode(ctx, SSL_SESS_CACHE_SERVER | SSL_SESS_CACHE_NO_INTERNAL | SSL_SESS_CACHE_NO_AUTO_CLEAR); if (context->ciphers != NULL) SSL_CTX_set_cipher_list(ctx, context->ciphers); else if (config->frontend.ciphers != NULL) SSL_CTX_set_cipher_list(ctx, config->frontend.ciphers); /* Disable SSL2 */ options = SSL_OP_NO_SSLv2 | SSL_OP_ALL; if (!config->frontend.ssl3) options |= SSL_OP_NO_SSLv3; if (config->frontend.server_preference) options |= SSL_OP_CIPHER_SERVER_PREFERENCE; SSL_CTX_set_options(ctx, options); #ifdef SSL_CTRL_SET_TLSEXT_SERVERNAME_CB if (config->context_count != 0) { SSL_CTX_set_tlsext_servername_callback(ctx, bud_config_select_sni_context); SSL_CTX_set_tlsext_servername_arg(ctx, config); } #endif /* SSL_CTRL_SET_TLSEXT_SERVERNAME_CB */ #ifdef OPENSSL_NPN_NEGOTIATED context->npn_line = bud_config_encode_npn(config, context->npn, &context->npn_line_len, &err); if (!bud_is_ok(err)) goto fatal; if (context->npn_line != NULL) { SSL_CTX_set_next_protos_advertised_cb(ctx, bud_config_advertise_next_proto, context); } #else /* !OPENSSL_NPN_NEGOTIATED */ err = bud_error(kBudErrNPNNotSupported); goto fatal; #endif /* OPENSSL_NPN_NEGOTIATED */ SSL_CTX_set_tlsext_status_cb(ctx, bud_client_stapling_cb); context->ctx = ctx; return bud_ok(); fatal: SSL_CTX_free(ctx); return err; }
int ssl_server_init(char* ca_file, char *crt_file, char *key_file, char *dhp_file, char *ssl_cipher_list) { static const char *ssl_ctx_id = "httpd"; long ssl_options; if (!crt_file || !f_exists(crt_file)) { httpd_log("%s: Server certificate (%s) is not found!", SYSLOG_ID_SSL, crt_file); httpd_log("Please manual build the certificate via \"%s\" script.", "https-cert.sh"); return -1; } if (!key_file || !f_exists(key_file)) { httpd_log("%s: Server private key (%s) is not found!", SYSLOG_ID_SSL, key_file); httpd_log("Please manual build the certificate via \"%s\" script.", "https-cert.sh"); return -1; } SSL_load_error_strings(); SSL_library_init(); ssl_ctx = SSL_CTX_new(SSLv23_server_method()); if (!ssl_ctx) { httpd_log("%s: Unable to create SSL context!", SYSLOG_ID_SSL); return -1; } ssl_options = SSL_OP_ALL | SSL_OP_NO_COMPRESSION | SSL_OP_NO_SSLv2 | SSL_OP_NO_SESSION_RESUMPTION_ON_RENEGOTIATION; SSL_CTX_set_options(ssl_ctx, ssl_options); SSL_CTX_set_verify(ssl_ctx, SSL_VERIFY_NONE, NULL); if (ssl_cipher_list && strlen(ssl_cipher_list) > 2) { if (SSL_CTX_set_cipher_list(ssl_ctx, ssl_cipher_list) != 1) { httpd_log("%s: Cannot set SSL cipher list (%s)!", SYSLOG_ID_SSL, ssl_cipher_list); } else { SSL_CTX_set_options(ssl_ctx, SSL_OP_CIPHER_SERVER_PREFERENCE); } } if (ca_file && f_exists(ca_file)) { if (SSL_CTX_load_verify_locations(ssl_ctx, ca_file, NULL) != 1) { httpd_log("%s: Cannot load CA certificate (%s)!", SYSLOG_ID_SSL, ca_file); } } if (SSL_CTX_use_certificate_file(ssl_ctx, crt_file, SSL_FILETYPE_PEM) != 1) { httpd_log("%s: Cannot load server certificate (%s)!", SYSLOG_ID_SSL, crt_file); ssl_server_uninit(); return 1; } if (SSL_CTX_use_PrivateKey_file(ssl_ctx, key_file, SSL_FILETYPE_PEM) != 1) { httpd_log("%s: Cannot load server private key (%s)!", SYSLOG_ID_SSL, key_file); ssl_server_uninit(); return 1; } if (SSL_CTX_check_private_key(ssl_ctx) != 1) { httpd_log("%s: Private key does not match the certificate!", SYSLOG_ID_SSL); ssl_server_uninit(); return 1; } if (dhp_file && f_exists(dhp_file)) { /* DH parameters from file */ BIO *bio = BIO_new_file(dhp_file, "r"); if (bio) { DH *dh = PEM_read_bio_DHparams(bio, NULL, NULL, NULL); BIO_free(bio); if (dh) { SSL_CTX_set_tmp_dh(ssl_ctx, dh); SSL_CTX_set_options(ssl_ctx, SSL_OP_SINGLE_DH_USE); DH_free(dh); } else { httpd_log("%s: Cannot load DH parameters (%s)!", SYSLOG_ID_SSL, dhp_file); } } } else { /* Default DH parameters from RFC5114 */ DH *dh = DH_new(); if (dh) { dh->p = BN_bin2bn(dh1024_p, sizeof(dh1024_p), NULL); dh->g = BN_bin2bn(dh1024_g, sizeof(dh1024_g), NULL); dh->length = 160; if (dh->p && dh->g) { SSL_CTX_set_tmp_dh(ssl_ctx, dh); SSL_CTX_set_options(ssl_ctx, SSL_OP_SINGLE_DH_USE); } DH_free(dh); } } SSL_CTX_set_default_read_ahead(ssl_ctx, 1); SSL_CTX_set_session_cache_mode(ssl_ctx, SSL_SESS_CACHE_SERVER); SSL_CTX_set_session_id_context(ssl_ctx, (unsigned char *)ssl_ctx_id, strlen(ssl_ctx_id)); SSL_CTX_sess_set_cache_size(ssl_ctx, 10); SSL_CTX_set_info_callback(ssl_ctx, http_ssl_info_cb); return 0; }
void DtlsTransport::CreateSSL_CTX() { MS_TRACE(); std::string ssl_srtp_profiles; EC_KEY* ecdh = nullptr; int ret; /* Set the global DTLS context. */ // - Both DTLS 1.0 and 1.2 (requires OpenSSL >= 1.1.0). #if (OPENSSL_VERSION_NUMBER >= 0x10100000L) DtlsTransport::sslCtx = SSL_CTX_new(DTLS_method()); // - Just DTLS 1.0 (requires OpenSSL >= 1.0.1). #elif (OPENSSL_VERSION_NUMBER >= 0x10001000L) DtlsTransport::sslCtx = SSL_CTX_new(DTLSv1_method()); #else #error "too old OpenSSL version" #endif if (!DtlsTransport::sslCtx) { LOG_OPENSSL_ERROR("SSL_CTX_new() failed"); goto error; } ret = SSL_CTX_use_certificate(DtlsTransport::sslCtx, DtlsTransport::certificate); if (ret == 0) { LOG_OPENSSL_ERROR("SSL_CTX_use_certificate() failed"); goto error; } ret = SSL_CTX_use_PrivateKey(DtlsTransport::sslCtx, DtlsTransport::privateKey); if (ret == 0) { LOG_OPENSSL_ERROR("SSL_CTX_use_PrivateKey() failed"); goto error; } ret = SSL_CTX_check_private_key(DtlsTransport::sslCtx); if (ret == 0) { LOG_OPENSSL_ERROR("SSL_CTX_check_private_key() failed"); goto error; } // Set options. SSL_CTX_set_options(DtlsTransport::sslCtx, SSL_OP_CIPHER_SERVER_PREFERENCE | SSL_OP_NO_TICKET | SSL_OP_SINGLE_ECDH_USE); // Don't use sessions cache. SSL_CTX_set_session_cache_mode(DtlsTransport::sslCtx, SSL_SESS_CACHE_OFF); // Read always as much into the buffer as possible. // NOTE: This is the default for DTLS, but a bug in non latest OpenSSL // versions makes this call required. SSL_CTX_set_read_ahead(DtlsTransport::sslCtx, 1); SSL_CTX_set_verify_depth(DtlsTransport::sslCtx, 4); // Require certificate from peer. SSL_CTX_set_verify(DtlsTransport::sslCtx, SSL_VERIFY_PEER | SSL_VERIFY_FAIL_IF_NO_PEER_CERT, on_ssl_certificate_verify); // Set SSL info callback. SSL_CTX_set_info_callback(DtlsTransport::sslCtx, on_ssl_info); // Set ciphers. ret = SSL_CTX_set_cipher_list(DtlsTransport::sslCtx, "ALL:!ADH:!LOW:!EXP:!MD5:!aNULL:!eNULL:@STRENGTH"); if (ret == 0) { LOG_OPENSSL_ERROR("SSL_CTX_set_cipher_list() failed"); goto error; } // Enable ECDH ciphers. // DOC: http://en.wikibooks.org/wiki/OpenSSL/Diffie-Hellman_parameters // NOTE: https://code.google.com/p/chromium/issues/detail?id=406458 // For OpenSSL >= 1.0.2: #if (OPENSSL_VERSION_NUMBER >= 0x10002000L) SSL_CTX_set_ecdh_auto(DtlsTransport::sslCtx, 1); #else ecdh = EC_KEY_new_by_curve_name(NID_X9_62_prime256v1); if (!ecdh) { LOG_OPENSSL_ERROR("EC_KEY_new_by_curve_name() failed"); goto error; } if (SSL_CTX_set_tmp_ecdh(DtlsTransport::sslCtx, ecdh) != 1) { LOG_OPENSSL_ERROR("SSL_CTX_set_tmp_ecdh() failed"); goto error; } EC_KEY_free(ecdh); ecdh = nullptr; #endif // Set the "use_srtp" DTLS extension. for (auto it = DtlsTransport::srtpProfiles.begin(); it != DtlsTransport::srtpProfiles.end(); ++it) { if (it != DtlsTransport::srtpProfiles.begin()) ssl_srtp_profiles += ":"; SrtpProfileMapEntry* profile_entry = &(*it); ssl_srtp_profiles += profile_entry->name; } MS_DEBUG("setting SRTP profiles for DTLS: %s", ssl_srtp_profiles.c_str()); // NOTE: This function returns 0 on success. ret = SSL_CTX_set_tlsext_use_srtp(DtlsTransport::sslCtx, ssl_srtp_profiles.c_str()); if (ret != 0) { MS_ERROR("SSL_CTX_set_tlsext_use_srtp() failed when entering '%s'", ssl_srtp_profiles.c_str()); LOG_OPENSSL_ERROR("SSL_CTX_set_tlsext_use_srtp() failed"); goto error; } return; error: if (DtlsTransport::sslCtx) { SSL_CTX_free(DtlsTransport::sslCtx); DtlsTransport::sslCtx = nullptr; } if (ecdh) EC_KEY_free(ecdh); MS_THROW_ERROR("SSL context creation failed"); }
static int tls_drv_control(ErlDrvData handle, unsigned int command, char *buf, int len, char **rbuf, int rlen) { tls_data *d = (tls_data *)handle; int res; int size; ErlDrvBinary *b; X509 *cert; unsigned int flags = command; command &= 0xffff; ERR_clear_error(); switch (command) { case SET_CERTIFICATE_FILE_ACCEPT: case SET_CERTIFICATE_FILE_CONNECT: { time_t mtime = 0; SSL_CTX *ssl_ctx = hash_table_lookup(buf, &mtime); if (is_key_file_modified(buf, &mtime) || ssl_ctx == NULL) { SSL_CTX *ctx; hash_table_insert(buf, mtime, NULL); ctx = SSL_CTX_new(SSLv23_method()); die_unless(ctx, "SSL_CTX_new failed"); res = SSL_CTX_use_certificate_chain_file(ctx, buf); die_unless(res > 0, "SSL_CTX_use_certificate_file failed"); res = SSL_CTX_use_PrivateKey_file(ctx, buf, SSL_FILETYPE_PEM); die_unless(res > 0, "SSL_CTX_use_PrivateKey_file failed"); res = SSL_CTX_check_private_key(ctx); die_unless(res > 0, "SSL_CTX_check_private_key failed"); SSL_CTX_set_session_cache_mode(ctx, SSL_SESS_CACHE_OFF); SSL_CTX_set_default_verify_paths(ctx); #ifdef SSL_MODE_RELEASE_BUFFERS SSL_CTX_set_mode(ctx, SSL_MODE_RELEASE_BUFFERS); #endif if (command == SET_CERTIFICATE_FILE_ACCEPT) { SSL_CTX_set_verify(ctx, SSL_VERIFY_PEER|SSL_VERIFY_CLIENT_ONCE, verify_callback); } ssl_ctx = ctx; hash_table_insert(buf, mtime, ssl_ctx); } d->ssl = SSL_new(ssl_ctx); die_unless(d->ssl, "SSL_new failed"); if (flags & VERIFY_NONE) SSL_set_verify(d->ssl, SSL_VERIFY_NONE, verify_callback); d->bio_read = BIO_new(BIO_s_mem()); d->bio_write = BIO_new(BIO_s_mem()); SSL_set_bio(d->ssl, d->bio_read, d->bio_write); if (command == SET_CERTIFICATE_FILE_ACCEPT) { SSL_set_options(d->ssl, SSL_OP_NO_TICKET); SSL_set_accept_state(d->ssl); } else { SSL_set_options(d->ssl, SSL_OP_NO_SSLv2|SSL_OP_NO_TICKET); SSL_set_connect_state(d->ssl); } break; } case SET_ENCRYPTED_INPUT: die_unless(d->ssl, "SSL not initialized"); BIO_write(d->bio_read, buf, len); break; case SET_DECRYPTED_OUTPUT: die_unless(d->ssl, "SSL not initialized"); res = SSL_write(d->ssl, buf, len); if (res <= 0) { res = SSL_get_error(d->ssl, res); if (res == SSL_ERROR_WANT_READ || res == SSL_ERROR_WANT_WRITE) { b = driver_alloc_binary(1); b->orig_bytes[0] = 2; *rbuf = (char *)b; return 1; } else { die_unless(0, "SSL_write failed"); } } break; case GET_ENCRYPTED_OUTPUT: die_unless(d->ssl, "SSL not initialized"); size = BUF_SIZE + 1; rlen = 1; b = driver_alloc_binary(size); b->orig_bytes[0] = 0; while ((res = BIO_read(d->bio_write, b->orig_bytes + rlen, BUF_SIZE)) > 0) { //printf("%d bytes of encrypted data read from state machine\r\n", res); rlen += res; size += BUF_SIZE; b = driver_realloc_binary(b, size); } b = driver_realloc_binary(b, rlen); *rbuf = (char *)b; return rlen; case GET_DECRYPTED_INPUT: if (!SSL_is_init_finished(d->ssl)) { res = SSL_do_handshake(d->ssl); if (res <= 0) die_unless(SSL_get_error(d->ssl, res) == SSL_ERROR_WANT_READ, "SSL_do_handshake failed"); } else { size = BUF_SIZE + 1; rlen = 1; b = driver_alloc_binary(size); b->orig_bytes[0] = 0; while ((res = SSL_read(d->ssl, b->orig_bytes + rlen, BUF_SIZE)) > 0) { //printf("%d bytes of decrypted data read from state machine\r\n",res); rlen += res; size += BUF_SIZE; b = driver_realloc_binary(b, size); } if (res < 0) { int err = SSL_get_error(d->ssl, res); if (err == SSL_ERROR_WANT_READ) { //printf("SSL_read wants more data\r\n"); //return 0; } // TODO } b = driver_realloc_binary(b, rlen); *rbuf = (char *)b; return rlen; } break; case GET_PEER_CERTIFICATE: cert = SSL_get_peer_certificate(d->ssl); if (cert == NULL) { b = driver_alloc_binary(1); b->orig_bytes[0] = 1; *rbuf = (char *)b; return 1; } else { unsigned char *tmp_buf; rlen = i2d_X509(cert, NULL); if (rlen >= 0) { rlen++; b = driver_alloc_binary(rlen); b->orig_bytes[0] = 0; tmp_buf = (unsigned char *)&b->orig_bytes[1]; i2d_X509(cert, &tmp_buf); X509_free(cert); *rbuf = (char *)b; return rlen; } else X509_free(cert); } break; case GET_VERIFY_RESULT: b = driver_alloc_binary(1); b->orig_bytes[0] = SSL_get_verify_result(d->ssl); *rbuf = (char *)b; return 1; break; } b = driver_alloc_binary(1); b->orig_bytes[0] = 0; *rbuf = (char *)b; return 1; }
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 */ }
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; }
int be_tls_init(bool isServerStart) { STACK_OF(X509_NAME) *root_cert_list = NULL; SSL_CTX *context; /* This stuff need be done only once. */ if (!SSL_initialized) { #ifdef HAVE_OPENSSL_INIT_SSL OPENSSL_init_ssl(OPENSSL_INIT_LOAD_CONFIG, NULL); #else OPENSSL_config(NULL); SSL_library_init(); SSL_load_error_strings(); #endif SSL_initialized = true; } /* * 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). */ context = SSL_CTX_new(SSLv23_method()); if (!context) { ereport(isServerStart ? FATAL : LOG, (errmsg("could not create SSL context: %s", SSLerrmessage(ERR_get_error())))); goto error; } /* * Disable OpenSSL's moving-write-buffer sanity check, because it causes * unnecessary failures in nonblocking send cases. */ SSL_CTX_set_mode(context, SSL_MODE_ACCEPT_MOVING_WRITE_BUFFER); /* * Set password callback */ if (isServerStart) { if (ssl_passphrase_command[0]) SSL_CTX_set_default_passwd_cb(context, ssl_external_passwd_cb); } else { if (ssl_passphrase_command[0] && ssl_passphrase_command_supports_reload) SSL_CTX_set_default_passwd_cb(context, ssl_external_passwd_cb); else /* * If reloading and no external command is configured, override * OpenSSL's default handling of passphrase-protected files, * because we don't want to prompt for a passphrase in an * already-running server. */ SSL_CTX_set_default_passwd_cb(context, dummy_ssl_passwd_cb); } /* used by the callback */ ssl_is_server_start = isServerStart; /* * Load and verify server's certificate and private key */ if (SSL_CTX_use_certificate_chain_file(context, ssl_cert_file) != 1) { ereport(isServerStart ? FATAL : LOG, (errcode(ERRCODE_CONFIG_FILE_ERROR), errmsg("could not load server certificate file \"%s\": %s", ssl_cert_file, SSLerrmessage(ERR_get_error())))); goto error; } if (!check_ssl_key_file_permissions(ssl_key_file, isServerStart)) goto error; /* * OK, try to load the private key file. */ dummy_ssl_passwd_cb_called = false; if (SSL_CTX_use_PrivateKey_file(context, ssl_key_file, SSL_FILETYPE_PEM) != 1) { if (dummy_ssl_passwd_cb_called) ereport(isServerStart ? FATAL : LOG, (errcode(ERRCODE_CONFIG_FILE_ERROR), errmsg("private key file \"%s\" cannot be reloaded because it requires a passphrase", ssl_key_file))); else ereport(isServerStart ? FATAL : LOG, (errcode(ERRCODE_CONFIG_FILE_ERROR), errmsg("could not load private key file \"%s\": %s", ssl_key_file, SSLerrmessage(ERR_get_error())))); goto error; } if (SSL_CTX_check_private_key(context) != 1) { ereport(isServerStart ? FATAL : LOG, (errcode(ERRCODE_CONFIG_FILE_ERROR), errmsg("check of private key failed: %s", SSLerrmessage(ERR_get_error())))); goto error; } if (ssl_min_protocol_version) SSL_CTX_set_min_proto_version(context, ssl_protocol_version_to_openssl(ssl_min_protocol_version, "ssl_min_protocol_version")); if (ssl_max_protocol_version) SSL_CTX_set_max_proto_version(context, ssl_protocol_version_to_openssl(ssl_max_protocol_version, "ssl_max_protocol_version")); /* disallow SSL session tickets */ #ifdef SSL_OP_NO_TICKET /* added in OpenSSL 0.9.8f */ SSL_CTX_set_options(context, SSL_OP_NO_TICKET); #endif /* disallow SSL session caching, too */ SSL_CTX_set_session_cache_mode(context, SSL_SESS_CACHE_OFF); /* set up ephemeral DH and ECDH keys */ if (!initialize_dh(context, isServerStart)) goto error; if (!initialize_ecdh(context, isServerStart)) goto error; /* set up the allowed cipher list */ if (SSL_CTX_set_cipher_list(context, SSLCipherSuites) != 1) { ereport(isServerStart ? FATAL : LOG, (errcode(ERRCODE_CONFIG_FILE_ERROR), errmsg("could not set the cipher list (no valid ciphers available)"))); goto error; } /* Let server choose order */ if (SSLPreferServerCiphers) SSL_CTX_set_options(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(context, ssl_ca_file, NULL) != 1 || (root_cert_list = SSL_load_client_CA_file(ssl_ca_file)) == NULL) { ereport(isServerStart ? FATAL : LOG, (errcode(ERRCODE_CONFIG_FILE_ERROR), errmsg("could not load root certificate file \"%s\": %s", ssl_ca_file, SSLerrmessage(ERR_get_error())))); goto error; } } /*---------- * 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(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, (errcode(ERRCODE_CONFIG_FILE_ERROR), errmsg("SSL certificate revocation list file \"%s\" ignored", ssl_crl_file), errdetail("SSL library does not support certificate revocation lists."))); #endif } else { ereport(isServerStart ? FATAL : LOG, (errcode(ERRCODE_CONFIG_FILE_ERROR), errmsg("could not load SSL certificate revocation list file \"%s\": %s", ssl_crl_file, SSLerrmessage(ERR_get_error())))); goto error; } } } 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(context, (SSL_VERIFY_PEER | SSL_VERIFY_CLIENT_ONCE), verify_cb); /* * 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(context, root_cert_list); } /* * Success! Replace any existing SSL_context. */ if (SSL_context) SSL_CTX_free(SSL_context); SSL_context = context; /* * Set flag to remember whether CA store has been loaded into SSL_context. */ if (ssl_ca_file[0]) ssl_loaded_verify_locations = true; else ssl_loaded_verify_locations = false; return 0; error: if (context) SSL_CTX_free(context); return -1; }
/* * 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 context_init(void) { /* init SSL */ int i; #if SSLEAY_VERSION_NUMBER >= 0x00907000L /* Load all bundled ENGINEs into memory and make them visible */ ENGINE_load_builtin_engines(); /* Register all of them for every algorithm they collectively implement */ ENGINE_register_all_complete(); #endif if(!init_prng()) log(LOG_INFO, "PRNG seeded successfully"); SSLeay_add_ssl_algorithms(); SSL_load_error_strings(); if(options.option.client) { ctx=SSL_CTX_new(SSLv3_client_method()); } else { /* Server mode */ ctx=SSL_CTX_new(SSLv23_server_method()); #ifndef NO_RSA SSL_CTX_set_tmp_rsa_callback(ctx, tmp_rsa_cb); #endif /* NO_RSA */ if(init_dh()) log(LOG_WARNING, "Diffie-Hellman initialization failed"); } if(options.ssl_options) { log(LOG_DEBUG, "Configuration SSL options: 0x%08lX", options.ssl_options); log(LOG_DEBUG, "SSL options set: 0x%08lX", SSL_CTX_set_options(ctx, options.ssl_options)); } #if SSLEAY_VERSION_NUMBER >= 0x00906000L SSL_CTX_set_mode(ctx, SSL_MODE_ENABLE_PARTIAL_WRITE|SSL_MODE_ACCEPT_MOVING_WRITE_BUFFER); #endif /* OpenSSL-0.9.6 */ SSL_CTX_set_session_cache_mode(ctx, SSL_SESS_CACHE_BOTH); SSL_CTX_set_timeout(ctx, options.session_timeout); if(options.option.cert) { if(!SSL_CTX_use_certificate_chain_file(ctx, options.cert)) { log(LOG_ERR, "Error reading certificate file: %s", options.cert); sslerror("SSL_CTX_use_certificate_chain_file"); exit(1); } log(LOG_DEBUG, "Certificate: %s", options.cert); log(LOG_DEBUG, "Key file: %s", options.key); #ifdef USE_WIN32 SSL_CTX_set_default_passwd_cb(ctx, pem_passwd_cb); #endif for(i=0; i<3; i++) { #ifdef NO_RSA if(SSL_CTX_use_PrivateKey_file(ctx, options.key, SSL_FILETYPE_PEM)) #else /* NO_RSA */ if(SSL_CTX_use_RSAPrivateKey_file(ctx, options.key, SSL_FILETYPE_PEM)) #endif /* NO_RSA */ break; if(i<2 && ERR_GET_REASON(ERR_peek_error())==EVP_R_BAD_DECRYPT) { sslerror_stack(); /* dump the error stack */ log(LOG_ERR, "Wrong pass phrase: retrying"); continue; } #ifdef NO_RSA sslerror("SSL_CTX_use_PrivateKey_file"); #else /* NO_RSA */ sslerror("SSL_CTX_use_RSAPrivateKey_file"); #endif /* NO_RSA */ exit(1); } if(!SSL_CTX_check_private_key(ctx)) { sslerror("Private key does not match the certificate"); exit(1); } } verify_init(); /* Initialize certificate verification */ SSL_CTX_set_info_callback(ctx, info_callback); if(options.cipher_list) { if (!SSL_CTX_set_cipher_list(ctx, options.cipher_list)) { sslerror("SSL_CTX_set_cipher_list"); exit(1); } } }
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; }
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); }
BOOLEAN SSL_initialize(CONN *C) { #ifdef HAVE_SSL int i; int serr; C->ssl = NULL; C->ctx = NULL; C->method = NULL; C->cert = NULL; SSL_load_error_strings(); SSL_library_init(); if(!my.ssl_key && my.ssl_cert) { my.ssl_key = my.ssl_cert; } if(!my.ssl_ciphers) { my.ssl_ciphers = stralloc(SSL_DEFAULT_CIPHER_LIST); } C->method = SSLv23_client_method(); if(C->method==NULL){ SSL_error_stack(); return FALSE; } C->ctx = SSL_CTX_new(C->method); if(C->ctx==NULL){ SSL_error_stack(); return FALSE; } SSL_CTX_set_mode(C->ctx, SSL_MODE_ENABLE_PARTIAL_WRITE|SSL_MODE_ACCEPT_MOVING_WRITE_BUFFER); SSL_CTX_set_session_cache_mode(C->ctx, SSL_SESS_CACHE_BOTH); SSL_CTX_set_timeout(C->ctx, my.ssl_timeout); if(my.ssl_ciphers){ if(!SSL_CTX_set_cipher_list(C->ctx, my.ssl_ciphers)){ joe_error("SSL_CTX_set_cipher_list"); return FALSE; } } if(my.ssl_cert){ if(!SSL_CTX_use_certificate_chain_file(C->ctx, my.ssl_cert)){ SSL_error_stack(); /* dump the error stack */ joe_fatal("Error reading certificate file: %s", my.ssl_cert); } for(i=0; i<3; i++){ if(SSL_CTX_use_PrivateKey_file(C->ctx, my.ssl_key, SSL_FILETYPE_PEM)) break; if(i<2 && ERR_GET_REASON(ERR_peek_error())==EVP_R_BAD_DECRYPT){ SSL_error_stack(); /* dump the error stack */ log_warning("Wrong pass phrase: retrying"); continue; } } if(!SSL_CTX_check_private_key(C->ctx)){ joe_error("Private key does not match the certificate"); return FALSE; } } C->ssl = SSL_new(C->ctx); if(C->ssl==NULL){ SSL_error_stack(); return FALSE; } SSL_set_fd(C->ssl, C->sock); serr = SSL_connect(C->ssl); return TRUE; #else return FALSE; #endif/*HAVE_SSL*/ }
SSLContext::SSLContext( Usage usage, const std::string& privateKeyFile, const std::string& certificateFile, const std::string& caLocation, VerificationMode verificationMode, int verificationDepth, bool loadDefaultCAs, const std::string& cipherList): _usage(usage), _mode(verificationMode), _sslContext(0), _extendedVerificationErrorDetails(true) { crypto::initializeEngine(); createSSLContext(); int errCode = 0; if (!caLocation.empty()) { if (fs::isdir(caLocation)) errCode = SSL_CTX_load_verify_locations(_sslContext, 0, fs::transcode(caLocation).c_str()); else errCode = SSL_CTX_load_verify_locations(_sslContext, fs::transcode(caLocation).c_str(), 0); if (errCode != 1) { std::string msg = getLastError(); SSL_CTX_free(_sslContext); throw std::runtime_error(std::string("SSL Error: Cannot load CA file/directory at ") + caLocation + ": " + msg); } } if (loadDefaultCAs) { errCode = SSL_CTX_set_default_verify_paths(_sslContext); if (errCode != 1) { std::string msg = getLastError(); SSL_CTX_free(_sslContext); throw std::runtime_error("SSL Error: Cannot load default CA certificates: " + msg); } } if (!privateKeyFile.empty()) { errCode = SSL_CTX_use_PrivateKey_file(_sslContext, fs::transcode(privateKeyFile).c_str(), SSL_FILETYPE_PEM); if (errCode != 1) { std::string msg = getLastError(); SSL_CTX_free(_sslContext); throw std::runtime_error(std::string("SSL Error: Error loading private key from file ") + privateKeyFile + ": " + msg); } } if (!certificateFile.empty()) { errCode = SSL_CTX_use_certificate_chain_file(_sslContext, fs::transcode(certificateFile).c_str()); if (errCode != 1) { std::string errMsg = getLastError(); SSL_CTX_free(_sslContext); throw std::runtime_error(std::string("SSL Error: Error loading certificate from file ") + certificateFile + ": " + errMsg); //, errMsg); } } if (isForServerUse()) SSL_CTX_set_verify(_sslContext, verificationMode, &SSLManager::verifyServerCallback); else SSL_CTX_set_verify(_sslContext, verificationMode, &SSLManager::verifyClientCallback); SSL_CTX_set_cipher_list(_sslContext, cipherList.c_str()); SSL_CTX_set_verify_depth(_sslContext, verificationDepth); SSL_CTX_set_mode(_sslContext, SSL_MODE_AUTO_RETRY); SSL_CTX_set_session_cache_mode(_sslContext, SSL_SESS_CACHE_OFF); }
int main(int argc, char *argv[]) { char *CApath = NULL, *CAfile = NULL; int badop = 0; int ret = 1; int client_auth = 0; int server_auth = 0; SSL_CTX *s_ctx = NULL; SSL_CTX *c_ctx = NULL; char *scert = TEST_SERVER_CERT; char *ccert = TEST_CLIENT_CERT; SSL_METHOD *ssl_method = SSLv23_method(); RAND_seed(rnd_seed, sizeof rnd_seed); if (bio_err == NULL) bio_err = BIO_new_fp(stderr, BIO_NOCLOSE); if (bio_stdout == NULL) bio_stdout = BIO_new_fp(stdout, BIO_NOCLOSE); argc--; argv++; while (argc >= 1) { if (sgx_strcmp(*argv, "-server_auth") == 0) server_auth = 1; else if (sgx_strcmp(*argv, "-client_auth") == 0) client_auth = 1; else if (sgx_strcmp(*argv, "-reconnect") == 0) reconnect = 1; else if (sgx_strcmp(*argv, "-stats") == 0) cache_stats = 1; else if (sgx_strcmp(*argv, "-ssl3") == 0) ssl_method = SSLv3_method(); else if (sgx_strcmp(*argv, "-ssl2") == 0) ssl_method = SSLv2_method(); else if (sgx_strcmp(*argv, "-CApath") == 0) { if (--argc < 1) goto bad; CApath = *(++argv); } else if (sgx_strcmp(*argv, "-CAfile") == 0) { if (--argc < 1) goto bad; CAfile = *(++argv); } else if (sgx_strcmp(*argv, "-cert") == 0) { if (--argc < 1) goto bad; scert = *(++argv); } else if (sgx_strcmp(*argv, "-ccert") == 0) { if (--argc < 1) goto bad; ccert = *(++argv); } else if (sgx_strcmp(*argv, "-threads") == 0) { if (--argc < 1) goto bad; thread_number = atoi(*(++argv)); if (thread_number == 0) thread_number = 1; if (thread_number > MAX_THREAD_NUMBER) thread_number = MAX_THREAD_NUMBER; } else if (sgx_strcmp(*argv, "-loops") == 0) { if (--argc < 1) goto bad; number_of_loops = atoi(*(++argv)); if (number_of_loops == 0) number_of_loops = 1; } else { fprintf(stderr, "unknown option %s\n", *argv); badop = 1; break; } argc--; argv++; } if (badop) { bad: sv_usage(); goto end; } if (cipher == NULL && OPENSSL_issetugid() == 0) cipher = getenv("SSL_CIPHER"); SSL_load_error_strings(); OpenSSL_add_ssl_algorithms(); c_ctx = SSL_CTX_new(ssl_method); s_ctx = SSL_CTX_new(ssl_method); if ((c_ctx == NULL) || (s_ctx == NULL)) { ERR_print_errors(bio_err); goto end; } SSL_CTX_set_session_cache_mode(s_ctx, SSL_SESS_CACHE_NO_AUTO_CLEAR | SSL_SESS_CACHE_SERVER); SSL_CTX_set_session_cache_mode(c_ctx, SSL_SESS_CACHE_NO_AUTO_CLEAR | SSL_SESS_CACHE_SERVER); if (!SSL_CTX_use_certificate_file(s_ctx, scert, SSL_FILETYPE_PEM)) { ERR_print_errors(bio_err); } else if (!SSL_CTX_use_RSAPrivateKey_file(s_ctx, scert, SSL_FILETYPE_PEM)) { ERR_print_errors(bio_err); goto end; } if (client_auth) { SSL_CTX_use_certificate_file(c_ctx, ccert, SSL_FILETYPE_PEM); SSL_CTX_use_RSAPrivateKey_file(c_ctx, ccert, SSL_FILETYPE_PEM); } if ((!SSL_CTX_load_verify_locations(s_ctx, CAfile, CApath)) || (!SSL_CTX_set_default_verify_paths(s_ctx)) || (!SSL_CTX_load_verify_locations(c_ctx, CAfile, CApath)) || (!SSL_CTX_set_default_verify_paths(c_ctx))) { fprintf(stderr, "SSL_load_verify_locations\n"); ERR_print_errors(bio_err); goto end; } if (client_auth) { fprintf(stderr, "client authentication\n"); SSL_CTX_set_verify(s_ctx, SSL_VERIFY_PEER | SSL_VERIFY_FAIL_IF_NO_PEER_CERT, verify_callback); } if (server_auth) { fprintf(stderr, "server authentication\n"); SSL_CTX_set_verify(c_ctx, SSL_VERIFY_PEER, verify_callback); } thread_setup(); do_threads(s_ctx, c_ctx); thread_cleanup(); end: if (c_ctx != NULL) { fprintf(stderr, "Client SSL_CTX stats then free it\n"); print_stats(stderr, c_ctx); SSL_CTX_free(c_ctx); } if (s_ctx != NULL) { fprintf(stderr, "Server SSL_CTX stats then free it\n"); print_stats(stderr, s_ctx); if (cache_stats) { fprintf(stderr, "-----\n"); lh_stats(SSL_CTX_sessions(s_ctx), stderr); fprintf(stderr, "-----\n"); /*- lh_node_stats(SSL_CTX_sessions(s_ctx),stderr); fprintf(stderr,"-----\n"); */ lh_node_usage_stats(SSL_CTX_sessions(s_ctx), stderr); fprintf(stderr, "-----\n"); } SSL_CTX_free(s_ctx); fprintf(stderr, "done free\n"); } exit(ret); return (0); }
int rb_init_ssl(void) { int ret = 1; char libratbox_data[] = "libratbox data"; const char libratbox_ciphers[] = "kEECDH+HIGH:kEDH+HIGH:HIGH:!RC4:!aNULL"; SSL_load_error_strings(); SSL_library_init(); libratbox_index = SSL_get_ex_new_index(0, libratbox_data, NULL, NULL, NULL); #if defined(LIBRESSL_VERSION_NUMBER) || (OPENSSL_VERSION_NUMBER < 0x10100000L) ssl_server_ctx = SSL_CTX_new(SSLv23_server_method()); #else ssl_server_ctx = SSL_CTX_new(TLS_server_method()); #endif if(ssl_server_ctx == NULL) { rb_lib_log("rb_init_openssl: Unable to initialize OpenSSL server context: %s", get_ssl_error(ERR_get_error())); ret = 0; } long server_options = SSL_CTX_get_options(ssl_server_ctx); #if defined(LIBRESSL_VERSION_NUMBER) || (OPENSSL_VERSION_NUMBER < 0x10100000L) server_options |= SSL_OP_NO_SSLv2; server_options |= SSL_OP_NO_SSLv3; #endif #ifdef SSL_OP_SINGLE_DH_USE server_options |= SSL_OP_SINGLE_DH_USE; #endif #ifdef SSL_OP_SINGLE_ECDH_USE server_options |= SSL_OP_SINGLE_ECDH_USE; #endif #ifdef SSL_OP_NO_TICKET server_options |= SSL_OP_NO_TICKET; #endif server_options |= SSL_OP_CIPHER_SERVER_PREFERENCE; SSL_CTX_set_options(ssl_server_ctx, server_options); SSL_CTX_set_verify(ssl_server_ctx, SSL_VERIFY_PEER | SSL_VERIFY_CLIENT_ONCE, verify_accept_all_cb); SSL_CTX_set_session_cache_mode(ssl_server_ctx, SSL_SESS_CACHE_OFF); SSL_CTX_set_cipher_list(ssl_server_ctx, libratbox_ciphers); /* Set ECDHE on OpenSSL 1.00+, but make sure it's actually available because redhat are dicks and bastardise their OpenSSL for stupid reasons... */ #if (OPENSSL_VERSION_NUMBER >= 0x10000000L) && defined(NID_secp384r1) EC_KEY *key = EC_KEY_new_by_curve_name(NID_secp384r1); if (key) { SSL_CTX_set_tmp_ecdh(ssl_server_ctx, key); EC_KEY_free(key); } #endif #if defined(LIBRESSL_VERSION_NUMBER) || (OPENSSL_VERSION_NUMBER < 0x10100000L) ssl_client_ctx = SSL_CTX_new(TLSv1_client_method()); #else ssl_client_ctx = SSL_CTX_new(TLS_client_method()); #endif if(ssl_client_ctx == NULL) { rb_lib_log("rb_init_openssl: Unable to initialize OpenSSL client context: %s", get_ssl_error(ERR_get_error())); ret = 0; } #ifdef SSL_OP_NO_TICKET SSL_CTX_set_options(ssl_client_ctx, SSL_OP_NO_TICKET); #endif SSL_CTX_set_cipher_list(ssl_client_ctx, libratbox_ciphers); return ret; }
//SSL_CTX* init_ssl_server_ctx(const SSL_METHOD* method, const char* server_cert, const char* server_priv_key, const char* dh_params, const char* ecdh_curve, const char* ecdsa_cert, const char* ecdsa_privkey, int check_client) SSL_CTX* init_ssl_server_ctx(const SSL_METHOD* method, X509* server_cert, EVP_PKEY* server_priv_key, const char* dh_params, const char* ecdh_curve, X509* ecdsa_cert, EVP_PKEY* ecdsa_privkey, X509* root_cert) { SSL_CTX* ssl_ctx = 0; DH* dh = 0; EC_KEY* ecdh = 0; FILE* param_file = 0; X509_STORE* x509_store; int nid; //make ssl context if (!(ssl_ctx = SSL_CTX_new(method))) { write_out(PRINT_ERROR, "Unable to initialize OpenSSL."); write_raise_level(); print_ssl_error_stack(PRINT_ERROR); write_lower_level(); goto error_die; } //disable renegotiation to ensure a fresh start SSL_CTX_set_session_cache_mode(ssl_ctx, SSL_SESS_CACHE_OFF); SSL_CTX_set_options(ssl_ctx, SSL_OP_NO_SESSION_RESUMPTION_ON_RENEGOTIATION | SSL_OP_NO_TICKET); if (server_cert && server_priv_key) { //load rsa certs //if (SSL_CTX_use_certificate_file(ssl_ctx, server_cert, SSL_FILETYPE_PEM) != 1) if (SSL_CTX_use_certificate(ssl_ctx, server_cert) != 1) { write_out(PRINT_ERROR, "Unable to load RSA certificate."); write_raise_level(); print_ssl_error_stack(PRINT_ERROR); write_lower_level(); goto error_die; } if (SSL_CTX_use_PrivateKey(ssl_ctx, server_priv_key) != 1) { write_out(PRINT_ERROR, "Unable to load RSA private key."); write_raise_level(); print_ssl_error_stack(PRINT_ERROR); write_lower_level(); goto error_die; } if (!SSL_CTX_check_private_key(ssl_ctx)) { write_out(PRINT_ERROR, "RSA Certificate and private key do not match!"); goto error_die; } } if (dh_params) { //load dh params param_file = fopen(dh_params, "rb"); if (!param_file) { write_out(PRINT_ERROR, "DH Parameter file could not be read: %s", dh_params); } dh = PEM_read_DHparams(param_file, 0, 0, 0); if (!dh) { write_out(PRINT_ERROR, "DH Parameters could not be loaded!"); write_raise_level(); print_ssl_error_stack(PRINT_ERROR); write_lower_level(); goto error_die; } fclose(param_file); param_file = 0; if (SSL_CTX_set_tmp_dh(ssl_ctx, dh) != 1) { write_out(PRINT_ERROR, "DH Parameters could not be set!"); write_raise_level(); print_ssl_error_stack(PRINT_ERROR); write_lower_level(); goto error_die; } DH_free(dh); dh = 0; } if (ecdh_curve) { //load ecdh params if ((nid = OBJ_sn2nid(ecdh_curve)) == NID_undef) { write_out(PRINT_ERROR, "Unable to find elliptic curve %s.", ecdh_curve); goto error_die; } if ((ecdh = EC_KEY_new_by_curve_name(nid)) == 0) { write_out(PRINT_ERROR, "Unable to create elliptic curve %s.", ecdh_curve); goto error_die; } if (SSL_CTX_set_tmp_ecdh(ssl_ctx, ecdh) != 1) { write_out(PRINT_ERROR, "ECDH Parameters could not be set!"); write_raise_level(); print_ssl_error_stack(PRINT_ERROR); write_lower_level(); goto error_die; } EC_KEY_free(ecdh); ecdh = 0; } if (ecdsa_cert && ecdsa_privkey) { //load ecdsa certs //if (SSL_CTX_use_certificate_file(ssl_ctx, ecdsa_cert, SSL_FILETYPE_PEM) != 1) if (SSL_CTX_use_certificate(ssl_ctx, ecdsa_cert) != 1) { write_out(PRINT_ERROR, "Unable to load ECDSA certificate."); write_raise_level(); print_ssl_error_stack(PRINT_ERROR); write_lower_level(); goto error_die; } //if (SSL_CTX_use_PrivateKey_file(ssl_ctx, ecdsa_privkey, SSL_FILETYPE_PEM) != 1) if (SSL_CTX_use_PrivateKey(ssl_ctx, ecdsa_privkey) != 1) { write_out(PRINT_ERROR, "Unable to load ECDSA private key."); write_raise_level(); print_ssl_error_stack(PRINT_ERROR); write_lower_level(); goto error_die; } if (!SSL_CTX_check_private_key(ssl_ctx)) { write_out(PRINT_ERROR, "ECDSA Certificate and private key do not match!"); goto error_die; } } //setup the root_cert for verification if (root_cert) { x509_store = SSL_CTX_get_cert_store(ssl_ctx); X509_STORE_add_cert(x509_store, root_cert); } return ssl_ctx; error_die: if (ssl_ctx) SSL_CTX_free(ssl_ctx); if (param_file) fclose(param_file); if (dh) DH_free(dh); if (ecdh) EC_KEY_free(ecdh); return 0; }
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); }
OsSSL::OsSSL(const char* authorityPath, const char* publicCertificateFile, const char* privateKeyPath ) { if (!sInitialized) { // Initialize random number generator before using SSL // TODO: this is a bad way to do this - it may need to be fixed. // // We should be using better randomness if possible, but at the very // least we should be saving the current rand state in a file so that // is not reset each time. I think that on a modern Linux, this has // no effect because OpenSSL will use /dev/urandom internally anyway? // // This needs to be examined. /* make a random number and set the top and bottom bits */ int seed[32]; for (unsigned int i = 0; i < sizeof(seed)/sizeof(int);i++) { seed[i] = rand(); } RAND_seed(seed,sizeof(seed)); SSLeay_add_ssl_algorithms(); // It is suggested by the OpenSSL group that embedded systems // only enable loading of error strings when debugging. // Perhaps this should be conditional? SSL_load_error_strings(); OpenSSL_thread_setup(); sInitialized = true; } mCTX = SSL_CTX_new(SSLv23_method()); if (mCTX) { if (SSL_CTX_load_verify_locations(mCTX, NULL, // we do not support using a bundled CA file authorityPath ? authorityPath : defaultAuthorityPath) > 0) { if (SSL_CTX_use_certificate_file(mCTX, publicCertificateFile ? publicCertificateFile : defaultPublicCertificateFile, SSL_FILETYPE_PEM) > 0) { if (SSL_CTX_use_PrivateKey_file(mCTX, privateKeyPath ? privateKeyPath : defaultPrivateKeyFile, SSL_FILETYPE_PEM) > 0) { if (SSL_CTX_check_private_key(mCTX)) { OsSysLog::add(FAC_KERNEL, PRI_INFO ,"OsSSL::_ %p CTX %p loaded key pair:\n" " public '%s'\n" " private '%s'" ,this, mCTX, publicCertificateFile ? publicCertificateFile : defaultPublicCertificateFile, privateKeyPath ? privateKeyPath : defaultPrivateKeyFile ); // TODO: log our own certificate data // Establish verification rules SSL_CTX_set_verify(mCTX, SSL_VERIFY_PEER + SSL_VERIFY_CLIENT_ONCE, verifyCallback ); // disable server connection caching // TODO: Investigate turning this on... SSL_CTX_set_session_cache_mode(mCTX, SSL_SESS_CACHE_OFF); } else { OsSysLog::add(FAC_KERNEL, PRI_ERR, "OsSSL::_ Private key '%s' does not match certificate '%s'", privateKeyPath ? privateKeyPath : defaultPrivateKeyFile, publicCertificateFile ? publicCertificateFile : defaultPublicCertificateFile ); } } else { OsSysLog::add(FAC_KERNEL, PRI_ERR, "OsSSL::_ Private key '%s' could not be initialized.", privateKeyPath ? privateKeyPath : defaultPrivateKeyFile ); } } else { OsSysLog::add(FAC_KERNEL, PRI_ERR, "OsSSL::_ Public key '%s' could not be initialized.", publicCertificateFile ? publicCertificateFile : defaultPublicCertificateFile ); } } else { OsSysLog::add(FAC_KERNEL, PRI_ERR, "OsSSL::_ SSL_CTX_load_verify_locations failed\n" " authorityDir: '%s'", authorityPath ? authorityPath : defaultAuthorityPath); } } else { OsSysLog::add(FAC_KERNEL, PRI_ERR, "OsSSL::_ SSL_CTX_new failed"); } }
static int openssl_session_cache_mode(lua_State *L) { static const char* smode[] = { "off", "client", "server", "both", "no_auto_clear", NULL }; static const int imode[] = { SSL_SESS_CACHE_OFF, SSL_SESS_CACHE_CLIENT, SSL_SESS_CACHE_SERVER, SSL_SESS_CACHE_BOTH, SSL_SESS_CACHE_NO_AUTO_CLEAR, -1 }; SSL_CTX* ctx = CHECK_OBJECT(1, SSL_CTX, "openssl.ssl_ctx"); int n = lua_gettop(L); long mode = 0; int i; if (n > 1) { if (lua_isnumber(L, 2)) { mode = luaL_checkinteger(L, 2); mode = SSL_CTX_set_session_cache_mode(ctx, mode); } else { for (i = 2; i <= n; i++) { int j = auxiliar_checkoption(L, i, NULL, smode, imode); mode |= j; } mode = SSL_CTX_set_session_cache_mode(ctx, mode); } } else { mode = SSL_CTX_get_session_cache_mode(ctx); }; lua_newtable(L); i = 0; if (mode & SSL_SESS_CACHE_NO_AUTO_CLEAR) { lua_pushstring(L, smode[4]); lua_rawseti(L, -2, i++); } if (mode & SSL_SESS_CACHE_BOTH) { lua_pushstring(L, smode[3]); lua_rawseti(L, -2, i++); } else if (mode & SSL_SESS_CACHE_SERVER) { lua_pushstring(L, smode[2]); lua_rawseti(L, -2, i++); } else if (mode & SSL_SESS_CACHE_CLIENT) { lua_pushstring(L, smode[1]); lua_rawseti(L, -2, i++); } else if (mode & SSL_SESS_CACHE_OFF) { lua_pushstring(L, smode[0]); lua_rawseti(L, -2, i++); } return 1; }