TLSTicketKeyManager::TLSTicketKeyManager(folly::SSLContext* ctx, SSLStats* stats) : ctx_(ctx), randState_(0), stats_(stats) { SSLUtil::getSSLCtxExIndex(&sExDataIndex_); SSL_CTX_set_ex_data(ctx_->getSSLCtx(), sExDataIndex_, this); }
SSLSessionCacheManager::SSLSessionCacheManager( uint32_t maxCacheSize, uint32_t cacheCullSize, SSLContext* ctx, const folly::SocketAddress& sockaddr, const string& context, EventBase* eventBase, SSLStats* stats, const std::shared_ptr<SSLCacheProvider>& externalCache): ctx_(ctx), stats_(stats), externalCache_(externalCache) { SSL_CTX* sslCtx = ctx->getSSLCtx(); SSLUtil::getSSLCtxExIndex(&sExDataIndex_); SSL_CTX_set_ex_data(sslCtx, sExDataIndex_, this); SSL_CTX_sess_set_new_cb(sslCtx, SSLSessionCacheManager::newSessionCallback); SSL_CTX_sess_set_get_cb(sslCtx, SSLSessionCacheManager::getSessionCallback); SSL_CTX_sess_set_remove_cb(sslCtx, SSLSessionCacheManager::removeSessionCallback); if (!FLAGS_dcache_unit_test && !context.empty()) { // Use the passed in context ctx->setSessionCacheContext(context); } SSL_CTX_set_session_cache_mode(sslCtx, SSL_SESS_CACHE_NO_INTERNAL | SSL_SESS_CACHE_SERVER); localCache_ = SSLSessionCacheManager::getLocalCache(maxCacheSize, cacheCullSize); VLOG(2) << "On VipID=" << sockaddr.describe() << " context=" << context; }
CURLcode _qvd_sslctxfun(CURL *curl, SSL_CTX *sslctx, void *parm) { qvdclient *qvd = (qvdclient *) parm; if (qvd->ssl_no_cert_check) { qvd_printf("No strict certificate checking. Accepting any server certificate\n"); return CURLE_OK; } /* See SSL_set_ex_data and http://www.openssl.org/docs/ssl/SSL_get_ex_new_index.htm*/ /* parm is qvdclient *qvd, the qvd object, set with CURLOPT_SSL_CTX_DATA */ SSL_CTX_set_ex_data(sslctx, _qvd_ssl_index, parm); SSL_CTX_set_verify(sslctx, SSL_VERIFY_PEER, _qvd_verify_cert_callback); return CURLE_OK; }
int context_init(SERVICE_OPTIONS *section) { /* init SSL context */ /* create SSL context */ if(section->option.client) section->ctx=SSL_CTX_new(section->client_method); else /* server mode */ section->ctx=SSL_CTX_new(section->server_method); if(!section->ctx) { sslerror("SSL_CTX_new"); return 1; /* FAILED */ } SSL_CTX_set_ex_data(section->ctx, 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 */ }
ngx_int_t ngx_ssl_stapling(ngx_conf_t *cf, ngx_ssl_t *ssl, ngx_str_t *file, ngx_str_t *responder, ngx_uint_t verify) { ngx_int_t rc; ngx_pool_cleanup_t *cln; ngx_ssl_stapling_t *staple; staple = ngx_pcalloc(cf->pool, sizeof(ngx_ssl_stapling_t)); if (staple == NULL) { return NGX_ERROR; } cln = ngx_pool_cleanup_add(cf->pool, 0); if (cln == NULL) { return NGX_ERROR; } cln->handler = ngx_ssl_stapling_cleanup; cln->data = staple; if (SSL_CTX_set_ex_data(ssl->ctx, ngx_ssl_stapling_index, staple) == 0) { ngx_ssl_error(NGX_LOG_EMERG, ssl->log, 0, "SSL_CTX_set_ex_data() failed"); return NGX_ERROR; } staple->ssl_ctx = ssl->ctx; staple->timeout = 60000; staple->verify = verify; if (file->len) { /* use OCSP response from the file */ if (ngx_ssl_stapling_file(cf, ssl, file) != NGX_OK) { return NGX_ERROR; } goto done; } rc = ngx_ssl_stapling_issuer(cf, ssl); if (rc == NGX_DECLINED) { return NGX_OK; } if (rc != NGX_OK) { return NGX_ERROR; } rc = ngx_ssl_stapling_responder(cf, ssl, responder); if (rc == NGX_DECLINED) { return NGX_OK; } if (rc != NGX_OK) { return NGX_ERROR; } done: SSL_CTX_set_tlsext_status_cb(ssl->ctx, ngx_ssl_certificate_status_callback); SSL_CTX_set_tlsext_status_arg(ssl->ctx, staple); return NGX_OK; }
/* * call-seq: * ctx.setup => Qtrue # first time * ctx.setup => nil # thereafter * * This method is called automatically when a new SSLSocket is created. * Normally you do not need to call this method (unless you are writing an extension in C). */ static VALUE ossl_sslctx_setup(VALUE self) { SSL_CTX *ctx; X509 *cert = NULL, *client_ca = NULL; X509_STORE *store; EVP_PKEY *key = NULL; char *ca_path = NULL, *ca_file = NULL; int i, verify_mode; VALUE val; if(OBJ_FROZEN(self)) return Qnil; Data_Get_Struct(self, SSL_CTX, ctx); #if !defined(OPENSSL_NO_DH) if (RTEST(ossl_sslctx_get_tmp_dh_cb(self))){ SSL_CTX_set_tmp_dh_callback(ctx, ossl_tmp_dh_callback); } else{ SSL_CTX_set_tmp_dh_callback(ctx, ossl_default_tmp_dh_callback); } #endif SSL_CTX_set_ex_data(ctx, ossl_ssl_ex_ptr_idx, (void*)self); val = ossl_sslctx_get_cert_store(self); if(!NIL_P(val)){ /* * WORKAROUND: * X509_STORE can count references, but * X509_STORE_free() doesn't care it. * So we won't increment it but mark it by ex_data. */ store = GetX509StorePtr(val); /* NO NEED TO DUP */ SSL_CTX_set_cert_store(ctx, store); SSL_CTX_set_ex_data(ctx, ossl_ssl_ex_store_p, (void*)1); } val = ossl_sslctx_get_extra_cert(self); if(!NIL_P(val)){ rb_block_call(val, rb_intern("each"), 0, 0, ossl_sslctx_add_extra_chain_cert_i, self); } /* private key may be bundled in certificate file. */ val = ossl_sslctx_get_cert(self); cert = NIL_P(val) ? NULL : GetX509CertPtr(val); /* NO DUP NEEDED */ val = ossl_sslctx_get_key(self); key = NIL_P(val) ? NULL : GetPKeyPtr(val); /* NO DUP NEEDED */ if (cert && key) { if (!SSL_CTX_use_certificate(ctx, cert)) { /* Adds a ref => Safe to FREE */ ossl_raise(eSSLError, "SSL_CTX_use_certificate:"); } if (!SSL_CTX_use_PrivateKey(ctx, key)) { /* Adds a ref => Safe to FREE */ ossl_raise(eSSLError, "SSL_CTX_use_PrivateKey:"); } if (!SSL_CTX_check_private_key(ctx)) { ossl_raise(eSSLError, "SSL_CTX_check_private_key:"); } } val = ossl_sslctx_get_client_ca(self); if(!NIL_P(val)){ if(TYPE(val) == T_ARRAY){ for(i = 0; i < RARRAY_LEN(val); i++){ client_ca = GetX509CertPtr(RARRAY_PTR(val)[i]); if (!SSL_CTX_add_client_CA(ctx, client_ca)){ /* Copies X509_NAME => FREE it. */ ossl_raise(eSSLError, "SSL_CTX_add_client_CA"); } } } else{ client_ca = GetX509CertPtr(val); /* NO DUP NEEDED. */ if (!SSL_CTX_add_client_CA(ctx, client_ca)){ /* Copies X509_NAME => FREE it. */ ossl_raise(eSSLError, "SSL_CTX_add_client_CA"); } } } val = ossl_sslctx_get_ca_file(self); ca_file = NIL_P(val) ? NULL : StringValuePtr(val); val = ossl_sslctx_get_ca_path(self); ca_path = NIL_P(val) ? NULL : StringValuePtr(val); if(ca_file || ca_path){ if (!SSL_CTX_load_verify_locations(ctx, ca_file, ca_path)) rb_warning("can't set verify locations"); } val = ossl_sslctx_get_verify_mode(self); verify_mode = NIL_P(val) ? SSL_VERIFY_NONE : NUM2INT(val); SSL_CTX_set_verify(ctx, verify_mode, ossl_ssl_verify_callback); if (RTEST(ossl_sslctx_get_client_cert_cb(self))) SSL_CTX_set_client_cert_cb(ctx, ossl_client_cert_cb); val = ossl_sslctx_get_timeout(self); if(!NIL_P(val)) SSL_CTX_set_timeout(ctx, NUM2LONG(val)); val = ossl_sslctx_get_verify_dep(self); if(!NIL_P(val)) SSL_CTX_set_verify_depth(ctx, NUM2LONG(val)); val = ossl_sslctx_get_options(self); if(!NIL_P(val)) SSL_CTX_set_options(ctx, NUM2LONG(val)); rb_obj_freeze(self); val = ossl_sslctx_get_sess_id_ctx(self); if (!NIL_P(val)){ StringValue(val); if (!SSL_CTX_set_session_id_context(ctx, (unsigned char *)RSTRING_PTR(val), RSTRING_LEN(val))){ ossl_raise(eSSLError, "SSL_CTX_set_session_id_context:"); } } if (RTEST(rb_iv_get(self, "@session_get_cb"))) { SSL_CTX_sess_set_get_cb(ctx, ossl_sslctx_session_get_cb); OSSL_Debug("SSL SESSION get callback added"); } if (RTEST(rb_iv_get(self, "@session_new_cb"))) { SSL_CTX_sess_set_new_cb(ctx, ossl_sslctx_session_new_cb); OSSL_Debug("SSL SESSION new callback added"); } if (RTEST(rb_iv_get(self, "@session_remove_cb"))) { SSL_CTX_sess_set_remove_cb(ctx, ossl_sslctx_session_remove_cb); OSSL_Debug("SSL SESSION remove callback added"); } #ifdef HAVE_SSL_SET_TLSEXT_HOST_NAME val = rb_iv_get(self, "@servername_cb"); if (!NIL_P(val)) { SSL_CTX_set_tlsext_servername_callback(ctx, ssl_servername_cb); OSSL_Debug("SSL TLSEXT servername callback added"); } #endif return Qtrue; }
LWS_VISIBLE int lws_context_init_server_ssl(struct lws_context_creation_info *info, struct lws_vhost *vhost) { struct lws_context *context = vhost->context; struct lws wsi; unsigned long error; int n; if (!lws_check_opt(info->options, LWS_SERVER_OPTION_DO_SSL_GLOBAL_INIT)) { vhost->use_ssl = 0; return 0; } /* * If he is giving a cert filepath, take it as a sign he wants to use * it on this vhost. User code can leave the cert filepath NULL and * set the LWS_SERVER_OPTION_CREATE_VHOST_SSL_CTX option itself, in * which case he's expected to set up the cert himself at * LWS_CALLBACK_OPENSSL_LOAD_EXTRA_SERVER_VERIFY_CERTS, which * provides the vhost SSL_CTX * in the user parameter. */ if (info->ssl_cert_filepath) info->options |= LWS_SERVER_OPTION_CREATE_VHOST_SSL_CTX; if (info->port != CONTEXT_PORT_NO_LISTEN) { vhost->use_ssl = lws_check_opt(info->options, LWS_SERVER_OPTION_CREATE_VHOST_SSL_CTX); if (vhost->use_ssl && info->ssl_cipher_list) lwsl_notice(" SSL ciphers: '%s'\n", info->ssl_cipher_list); if (vhost->use_ssl) lwsl_notice(" Using SSL mode\n"); else lwsl_notice(" Using non-SSL mode\n"); } /* * give him a fake wsi with context + vhost set, so he can use * lws_get_context() in the callback */ memset(&wsi, 0, sizeof(wsi)); wsi.vhost = vhost; wsi.context = context; (void)n; (void)error; /* * Firefox insists on SSLv23 not SSLv3 * Konq disables SSLv2 by default now, SSLv23 works * * SSLv23_server_method() is the openssl method for "allow all TLS * versions", compared to e.g. TLSv1_2_server_method() which only allows * tlsv1.2. Unwanted versions must be disabled using SSL_CTX_set_options() */ #if !defined(LWS_WITH_MBEDTLS) { SSL_METHOD *method; method = (SSL_METHOD *)SSLv23_server_method(); if (!method) { error = ERR_get_error(); lwsl_err("problem creating ssl method %lu: %s\n", error, ERR_error_string(error, (char *)context->pt[0].serv_buf)); return 1; } vhost->ssl_ctx = SSL_CTX_new(method); /* create context */ if (!vhost->ssl_ctx) { error = ERR_get_error(); lwsl_err("problem creating ssl context %lu: %s\n", error, ERR_error_string(error, (char *)context->pt[0].serv_buf)); return 1; } } #else { const SSL_METHOD *method = TLSv1_2_server_method(); vhost->ssl_ctx = SSL_CTX_new(method); /* create context */ if (!vhost->ssl_ctx) { lwsl_err("problem creating ssl context\n"); return 1; } } #endif #if !defined(LWS_WITH_MBEDTLS) /* associate the lws context with the SSL_CTX */ SSL_CTX_set_ex_data(vhost->ssl_ctx, openssl_SSL_CTX_private_data_index, (char *)vhost->context); /* Disable SSLv2 and SSLv3 */ SSL_CTX_set_options(vhost->ssl_ctx, SSL_OP_NO_SSLv2 | SSL_OP_NO_SSLv3); #ifdef SSL_OP_NO_COMPRESSION SSL_CTX_set_options(vhost->ssl_ctx, SSL_OP_NO_COMPRESSION); #endif SSL_CTX_set_options(vhost->ssl_ctx, SSL_OP_SINGLE_DH_USE); SSL_CTX_set_options(vhost->ssl_ctx, SSL_OP_CIPHER_SERVER_PREFERENCE); if (info->ssl_cipher_list) SSL_CTX_set_cipher_list(vhost->ssl_ctx, info->ssl_cipher_list); #endif /* as a server, are we requiring clients to identify themselves? */ if (lws_check_opt(info->options, LWS_SERVER_OPTION_REQUIRE_VALID_OPENSSL_CLIENT_CERT)) { int verify_options = SSL_VERIFY_PEER; if (!lws_check_opt(info->options, LWS_SERVER_OPTION_PEER_CERT_NOT_REQUIRED)) verify_options |= SSL_VERIFY_FAIL_IF_NO_PEER_CERT; #if !defined(LWS_WITH_MBEDTLS) SSL_CTX_set_session_id_context(vhost->ssl_ctx, (unsigned char *)context, sizeof(void *)); /* absolutely require the client cert */ SSL_CTX_set_verify(vhost->ssl_ctx, verify_options, OpenSSL_verify_callback); #endif } #if !defined(LWS_WITH_MBEDTLS) && !defined(OPENSSL_NO_TLSEXT) SSL_CTX_set_tlsext_servername_callback(vhost->ssl_ctx, lws_ssl_server_name_cb); SSL_CTX_set_tlsext_servername_arg(vhost->ssl_ctx, context); #endif /* * give user code a chance to load certs into the server * allowing it to verify incoming client certs */ #if !defined(LWS_WITH_MBEDTLS) if (info->ssl_ca_filepath && !SSL_CTX_load_verify_locations(vhost->ssl_ctx, info->ssl_ca_filepath, NULL)) { lwsl_err("%s: SSL_CTX_load_verify_locations unhappy\n", __func__); } #endif if (vhost->use_ssl) { if (lws_context_ssl_init_ecdh_curve(info, vhost)) return -1; vhost->protocols[0].callback(&wsi, LWS_CALLBACK_OPENSSL_LOAD_EXTRA_SERVER_VERIFY_CERTS, vhost->ssl_ctx, NULL, 0); } if (lws_check_opt(info->options, LWS_SERVER_OPTION_ALLOW_NON_SSL_ON_SSL_PORT)) /* Normally SSL listener rejects non-ssl, optionally allow */ vhost->allow_non_ssl_on_ssl_port = 1; if (info->ssl_options_set) SSL_CTX_set_options(vhost->ssl_ctx, info->ssl_options_set); /* SSL_clear_options introduced in 0.9.8m */ #if !defined(LWS_WITH_MBEDTLS) #if (OPENSSL_VERSION_NUMBER >= 0x009080df) && !defined(USE_WOLFSSL) if (info->ssl_options_clear) SSL_CTX_clear_options(vhost->ssl_ctx, info->ssl_options_clear); #endif #endif lwsl_info(" SSL options 0x%lX\n", SSL_CTX_get_options(vhost->ssl_ctx)); if (vhost->use_ssl && info->ssl_cert_filepath) { /* * The user code can choose to either pass the cert and * key filepaths using the info members like this, or it can * leave them NULL; force the vhost SSL_CTX init using the info * options flag LWS_SERVER_OPTION_CREATE_VHOST_SSL_CTX; and * set up the cert himself using the user callback * LWS_CALLBACK_OPENSSL_LOAD_EXTRA_SERVER_VERIFY_CERTS, which * happened just above and has the vhost SSL_CTX * in the user * parameter. */ #if !defined(LWS_WITH_MBEDTLS) /* set the local certificate from CertFile */ n = SSL_CTX_use_certificate_chain_file(vhost->ssl_ctx, info->ssl_cert_filepath); if (n != 1) { error = ERR_get_error(); lwsl_err("problem getting cert '%s' %lu: %s\n", info->ssl_cert_filepath, error, ERR_error_string(error, (char *)context->pt[0].serv_buf)); return 1; } lws_ssl_bind_passphrase(vhost->ssl_ctx, info); #else uint8_t *p; lws_filepos_t flen; int err; if (alloc_pem_to_der_file(vhost->context, info->ssl_cert_filepath, &p, &flen)) { lwsl_err("couldn't find cert file %s\n", info->ssl_cert_filepath); return 1; } err = SSL_CTX_use_certificate_ASN1(vhost->ssl_ctx, flen, p); if (!err) { lwsl_err("Problem loading cert\n"); return 1; } #if !defined(LWS_WITH_ESP32) free(p); p = NULL; #endif if (info->ssl_private_key_filepath) { if (alloc_pem_to_der_file(vhost->context, info->ssl_private_key_filepath, &p, &flen)) { lwsl_err("couldn't find cert file %s\n", info->ssl_cert_filepath); return 1; } err = SSL_CTX_use_PrivateKey_ASN1(0, vhost->ssl_ctx, p, flen); if (!err) { lwsl_err("Problem loading key\n"); return 1; } } #if !defined(LWS_WITH_ESP32) free(p); p = NULL; #endif #endif if (info->ssl_private_key_filepath != NULL) { #if !defined(LWS_WITH_MBEDTLS) /* set the private key from KeyFile */ if (SSL_CTX_use_PrivateKey_file(vhost->ssl_ctx, info->ssl_private_key_filepath, SSL_FILETYPE_PEM) != 1) { error = ERR_get_error(); lwsl_err("ssl problem getting key '%s' %lu: %s\n", info->ssl_private_key_filepath, error, ERR_error_string(error, (char *)context->pt[0].serv_buf)); return 1; } #endif } else if (vhost->protocols[0].callback(&wsi, LWS_CALLBACK_OPENSSL_CONTEXT_REQUIRES_PRIVATE_KEY, vhost->ssl_ctx, NULL, 0)) { lwsl_err("ssl private key not set\n"); return 1; } #if !defined(LWS_WITH_MBEDTLS) /* verify private key */ if (!SSL_CTX_check_private_key(vhost->ssl_ctx)) { lwsl_err("Private SSL key doesn't match cert\n"); return 1; } #endif } if (vhost->use_ssl) { if (lws_context_ssl_init_ecdh(vhost)) return 1; /* * SSL is happy and has a cert it's content with * If we're supporting HTTP2, initialize that */ lws_context_init_http2_ssl(vhost); } return 0; }
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 */ }
void h2o_socket_ssl_set_session_cache(SSL_CTX *ctx, h2o_cache_t *cache) { SSL_CTX_set_ex_data(ctx, get_ssl_session_cache_index(), cache); }
/* * this may now get called after the vhost creation, when certs become * available. */ int lws_tls_server_certs_load(struct lws_vhost *vhost, struct lws *wsi, const char *cert, const char *private_key, const char *mem_cert, size_t mem_cert_len, const char *mem_privkey, size_t mem_privkey_len) { #if !defined(OPENSSL_NO_EC) const char *ecdh_curve = "prime256v1"; #if !defined(LWS_WITH_BORINGSSL) && defined(LWS_HAVE_SSL_EXTRA_CHAIN_CERTS) STACK_OF(X509) *extra_certs = NULL; #endif EC_KEY *ecdh, *EC_key = NULL; EVP_PKEY *pkey; X509 *x = NULL; int ecdh_nid; int KeyType; #endif unsigned long error; lws_filepos_t flen; uint8_t *p; int ret; int n = lws_tls_generic_cert_checks(vhost, cert, private_key), m; (void)ret; if (!cert && !private_key) n = LWS_TLS_EXTANT_ALTERNATIVE; if (n == LWS_TLS_EXTANT_NO && (!mem_cert || !mem_privkey)) return 0; if (n == LWS_TLS_EXTANT_NO) n = LWS_TLS_EXTANT_ALTERNATIVE; if (n == LWS_TLS_EXTANT_ALTERNATIVE && (!mem_cert || !mem_privkey)) return 1; /* no alternative */ if (n == LWS_TLS_EXTANT_ALTERNATIVE) { #if OPENSSL_VERSION_NUMBER >= 0x10100000L /* * Although we have prepared update certs, we no longer have * the rights to read our own cert + key we saved. * * If we were passed copies in memory buffers, use those * in favour of the filepaths we normally want. */ cert = NULL; private_key = NULL; } /* * use the multi-cert interface for backwards compatibility in the * both simple files case */ if (n != LWS_TLS_EXTANT_ALTERNATIVE && cert) { /* set the local certificate from CertFile */ m = SSL_CTX_use_certificate_chain_file(vhost->tls.ssl_ctx, cert); if (m != 1) { error = ERR_get_error(); lwsl_err("problem getting cert '%s' %lu: %s\n", cert, error, ERR_error_string(error, (char *)vhost->context->pt[0].serv_buf)); return 1; } if (private_key) { /* set the private key from KeyFile */ if (SSL_CTX_use_PrivateKey_file(vhost->tls.ssl_ctx, private_key, SSL_FILETYPE_PEM) != 1) { error = ERR_get_error(); lwsl_err("ssl problem getting key '%s' %lu: %s\n", private_key, error, ERR_error_string(error, (char *)vhost->context->pt[0].serv_buf)); return 1; } } else { if (vhost->protocols[0].callback(wsi, LWS_CALLBACK_OPENSSL_CONTEXT_REQUIRES_PRIVATE_KEY, vhost->tls.ssl_ctx, NULL, 0)) { lwsl_err("ssl private key not set\n"); return 1; } } return 0; } /* otherwise allow for DER or PEM, file or memory image */ if (lws_tls_alloc_pem_to_der_file(vhost->context, cert, mem_cert, mem_cert_len, &p, &flen)) { lwsl_err("%s: couldn't read cert file\n", __func__); return 1; } #if !defined(USE_WOLFSSL) ret = SSL_CTX_use_certificate_ASN1(vhost->tls.ssl_ctx, (int)flen, p); #else ret = wolfSSL_CTX_use_certificate_buffer(vhost->tls.ssl_ctx, (uint8_t *)p, (int)flen, WOLFSSL_FILETYPE_ASN1); #endif lws_free_set_NULL(p); if (ret != 1) { lwsl_err("%s: Problem loading cert\n", __func__); return 1; } if (lws_tls_alloc_pem_to_der_file(vhost->context, private_key, mem_privkey, mem_privkey_len, &p, &flen)) { lwsl_notice("unable to convert memory privkey\n"); return 1; } #if !defined(USE_WOLFSSL) ret = SSL_CTX_use_PrivateKey_ASN1(EVP_PKEY_RSA, vhost->tls.ssl_ctx, p, (long)(long long)flen); if (ret != 1) { ret = SSL_CTX_use_PrivateKey_ASN1(EVP_PKEY_EC, vhost->tls.ssl_ctx, p, (long)(long long)flen); } #else ret = wolfSSL_CTX_use_PrivateKey_buffer(vhost->tls.ssl_ctx, p, flen, WOLFSSL_FILETYPE_ASN1); #endif lws_free_set_NULL(p); if (ret != 1) { lwsl_notice("unable to use memory privkey\n"); return 1; } #else /* * Although we have prepared update certs, we no longer have * the rights to read our own cert + key we saved. * * If we were passed copies in memory buffers, use those * instead. * * The passed memory-buffer cert image is in DER, and the * memory-buffer private key image is PEM. */ #ifndef USE_WOLFSSL if (SSL_CTX_use_certificate_ASN1(vhost->tls.ssl_ctx, (int)mem_cert_len, (uint8_t *)mem_cert) != 1) { #else if (wolfSSL_CTX_use_certificate_buffer(vhost->tls.ssl_ctx, (uint8_t *)mem_cert, (int)mem_cert_len, WOLFSSL_FILETYPE_ASN1) != 1) { #endif lwsl_err("Problem loading update cert\n"); return 1; } if (lws_tls_alloc_pem_to_der_file(vhost->context, NULL, mem_privkey, mem_privkey_len, &p, &flen)) { lwsl_notice("unable to convert memory privkey\n"); return 1; } #ifndef USE_WOLFSSL if (SSL_CTX_use_PrivateKey_ASN1(EVP_PKEY_RSA, vhost->tls.ssl_ctx, p, (long)(long long)flen) != 1) { #else if (wolfSSL_CTX_use_PrivateKey_buffer(vhost->tls.ssl_ctx, p, flen, WOLFSSL_FILETYPE_ASN1) != 1) { #endif lwsl_notice("unable to use memory privkey\n"); return 1; } goto check_key; } /* set the local certificate from CertFile */ m = SSL_CTX_use_certificate_chain_file(vhost->tls.ssl_ctx, cert); if (m != 1) { error = ERR_get_error(); lwsl_err("problem getting cert '%s' %lu: %s\n", cert, error, ERR_error_string(error, (char *)vhost->context->pt[0].serv_buf)); return 1; } if (n != LWS_TLS_EXTANT_ALTERNATIVE && private_key) { /* set the private key from KeyFile */ if (SSL_CTX_use_PrivateKey_file(vhost->tls.ssl_ctx, private_key, SSL_FILETYPE_PEM) != 1) { error = ERR_get_error(); lwsl_err("ssl problem getting key '%s' %lu: %s\n", private_key, error, ERR_error_string(error, (char *)vhost->context->pt[0].serv_buf)); return 1; } } else { if (vhost->protocols[0].callback(wsi, LWS_CALLBACK_OPENSSL_CONTEXT_REQUIRES_PRIVATE_KEY, vhost->tls.ssl_ctx, NULL, 0)) { lwsl_err("ssl private key not set\n"); return 1; } } check_key: #endif /* verify private key */ if (!SSL_CTX_check_private_key(vhost->tls.ssl_ctx)) { lwsl_err("Private SSL key doesn't match cert\n"); return 1; } #if !defined(OPENSSL_NO_EC) if (vhost->tls.ecdh_curve[0]) ecdh_curve = vhost->tls.ecdh_curve; ecdh_nid = OBJ_sn2nid(ecdh_curve); if (NID_undef == ecdh_nid) { lwsl_err("SSL: Unknown curve name '%s'", ecdh_curve); return 1; } ecdh = EC_KEY_new_by_curve_name(ecdh_nid); if (NULL == ecdh) { lwsl_err("SSL: Unable to create curve '%s'", ecdh_curve); return 1; } SSL_CTX_set_tmp_ecdh(vhost->tls.ssl_ctx, ecdh); EC_KEY_free(ecdh); SSL_CTX_set_options(vhost->tls.ssl_ctx, SSL_OP_SINGLE_ECDH_USE); lwsl_notice(" SSL ECDH curve '%s'\n", ecdh_curve); if (lws_check_opt(vhost->context->options, LWS_SERVER_OPTION_SSL_ECDH)) lwsl_notice(" Using ECDH certificate support\n"); /* Get X509 certificate from ssl context */ #if !defined(LWS_WITH_BORINGSSL) #if !defined(LWS_HAVE_SSL_EXTRA_CHAIN_CERTS) x = sk_X509_value(vhost->tls.ssl_ctx->extra_certs, 0); #else SSL_CTX_get_extra_chain_certs_only(vhost->tls.ssl_ctx, &extra_certs); if (extra_certs) x = sk_X509_value(extra_certs, 0); else lwsl_info("%s: no extra certs\n", __func__); #endif if (!x) { //lwsl_err("%s: x is NULL\n", __func__); goto post_ecdh; } #else return 0; #endif /* Get the public key from certificate */ pkey = X509_get_pubkey(x); if (!pkey) { lwsl_err("%s: pkey is NULL\n", __func__); return 1; } /* Get the key type */ KeyType = EVP_PKEY_type(EVP_PKEY_id(pkey)); if (EVP_PKEY_EC != KeyType) { lwsl_notice("Key type is not EC\n"); return 0; } /* Get the key */ EC_key = EVP_PKEY_get1_EC_KEY(pkey); /* Set ECDH parameter */ if (!EC_key) { lwsl_err("%s: ECDH key is NULL \n", __func__); return 1; } SSL_CTX_set_tmp_ecdh(vhost->tls.ssl_ctx, EC_key); EC_KEY_free(EC_key); #else lwsl_notice(" OpenSSL doesn't support ECDH\n"); #endif #if !defined(OPENSSL_NO_EC) && !defined(LWS_WITH_BORINGSSL) post_ecdh: #endif vhost->tls.skipped_certs = 0; return 0; } int lws_tls_server_vhost_backend_init(const struct lws_context_creation_info *info, struct lws_vhost *vhost, struct lws *wsi) { unsigned long error; SSL_METHOD *method = (SSL_METHOD *)SSLv23_server_method(); if (!method) { error = ERR_get_error(); lwsl_err("problem creating ssl method %lu: %s\n", error, ERR_error_string(error, (char *)vhost->context->pt[0].serv_buf)); return 1; } vhost->tls.ssl_ctx = SSL_CTX_new(method); /* create context */ if (!vhost->tls.ssl_ctx) { error = ERR_get_error(); lwsl_err("problem creating ssl context %lu: %s\n", error, ERR_error_string(error, (char *)vhost->context->pt[0].serv_buf)); return 1; } SSL_CTX_set_ex_data(vhost->tls.ssl_ctx, openssl_SSL_CTX_private_data_index, (char *)vhost->context); /* Disable SSLv2 and SSLv3 */ SSL_CTX_set_options(vhost->tls.ssl_ctx, SSL_OP_NO_SSLv2 | SSL_OP_NO_SSLv3); #ifdef SSL_OP_NO_COMPRESSION SSL_CTX_set_options(vhost->tls.ssl_ctx, SSL_OP_NO_COMPRESSION); #endif SSL_CTX_set_options(vhost->tls.ssl_ctx, SSL_OP_SINGLE_DH_USE); SSL_CTX_set_options(vhost->tls.ssl_ctx, SSL_OP_CIPHER_SERVER_PREFERENCE); if (info->ssl_cipher_list) SSL_CTX_set_cipher_list(vhost->tls.ssl_ctx, info->ssl_cipher_list); #if defined(LWS_HAVE_SSL_CTX_set_ciphersuites) if (info->tls1_3_plus_cipher_list) SSL_CTX_set_ciphersuites(vhost->tls.ssl_ctx, info->tls1_3_plus_cipher_list); #endif #if !defined(OPENSSL_NO_TLSEXT) SSL_CTX_set_tlsext_servername_callback(vhost->tls.ssl_ctx, lws_ssl_server_name_cb); SSL_CTX_set_tlsext_servername_arg(vhost->tls.ssl_ctx, vhost->context); #endif if (info->ssl_ca_filepath && !SSL_CTX_load_verify_locations(vhost->tls.ssl_ctx, info->ssl_ca_filepath, NULL)) { lwsl_err("%s: SSL_CTX_load_verify_locations unhappy\n", __func__); } if (info->ssl_options_set) SSL_CTX_set_options(vhost->tls.ssl_ctx, info->ssl_options_set); /* SSL_clear_options introduced in 0.9.8m */ #if (OPENSSL_VERSION_NUMBER >= 0x009080df) && !defined(USE_WOLFSSL) if (info->ssl_options_clear) SSL_CTX_clear_options(vhost->tls.ssl_ctx, info->ssl_options_clear); #endif lwsl_info(" SSL options 0x%lX\n", (unsigned long)SSL_CTX_get_options(vhost->tls.ssl_ctx)); if (!vhost->tls.use_ssl || (!info->ssl_cert_filepath && !info->server_ssl_cert_mem)) return 0; lws_ssl_bind_passphrase(vhost->tls.ssl_ctx, info); return lws_tls_server_certs_load(vhost, wsi, info->ssl_cert_filepath, info->ssl_private_key_filepath, info->server_ssl_cert_mem, info->server_ssl_cert_mem_len, info->server_ssl_private_key_mem, info->server_ssl_private_key_mem_len); }
apn_return apn_ssl_connect(apn_ctx_t *const ctx) { assert(ctx); SSL_CTX *ssl_ctx = NULL; if (NULL == (ssl_ctx = SSL_CTX_new(TLSv1_client_method()))) { apn_log(ctx, APN_LOG_LEVEL_ERROR, "Could not initialize SSL context: %s", ERR_error_string(ERR_get_error(), NULL)); return APN_ERROR; } SSL_CTX_set_ex_data(ssl_ctx, 0, ctx); SSL_CTX_set_info_callback(ssl_ctx, __apn_ssl_info_callback); X509 *cert = NULL; if (ctx->pkcs12_file && ctx->pkcs12_pass) { FILE *pkcs12_file = NULL; #ifdef _WIN32 fopen_s(&pkcs12_file, ctx->pkcs12_file, "r"); #else pkcs12_file = fopen(ctx->pkcs12_file, "r"); #endif if (!pkcs12_file) { char *error = apn_error_string(errno); apn_log(ctx, APN_LOG_LEVEL_ERROR, "Unable to open file %s: %s (errno: %d)", ctx->pkcs12_file, error, errno); free(error); SSL_CTX_free(ssl_ctx); errno = APN_ERR_UNABLE_TO_USE_SPECIFIED_PKCS12; return APN_ERROR; } PKCS12 *pkcs12_cert = NULL; d2i_PKCS12_fp(pkcs12_file, &pkcs12_cert); fclose(pkcs12_file); EVP_PKEY *private_key = NULL; if (!PKCS12_parse(pkcs12_cert, ctx->pkcs12_pass, &private_key, &cert, NULL)) { apn_log(ctx, APN_LOG_LEVEL_ERROR, "Unable to use specified PKCS#12 file: %s", ERR_error_string(ERR_get_error(), NULL)); PKCS12_free(pkcs12_cert); SSL_CTX_free(ssl_ctx); errno = APN_ERR_UNABLE_TO_USE_SPECIFIED_PKCS12; return APN_ERROR; } PKCS12_free(pkcs12_cert); if (!SSL_CTX_use_certificate(ssl_ctx, cert)) { apn_log(ctx, APN_LOG_LEVEL_ERROR, "Unable to use specified PKCS#12 file: %s", ERR_error_string(ERR_get_error(), NULL)); X509_free(cert); EVP_PKEY_free(private_key); SSL_CTX_free(ssl_ctx); errno = APN_ERR_UNABLE_TO_USE_SPECIFIED_PKCS12; return APN_ERROR; } if (!SSL_CTX_use_PrivateKey(ssl_ctx, private_key)) { apn_log(ctx, APN_LOG_LEVEL_ERROR, "Unable to use specified PKCS#12 file: %s", ERR_error_string(ERR_get_error(), NULL)); X509_free(cert); EVP_PKEY_free(private_key); SSL_CTX_free(ssl_ctx); errno = APN_ERR_UNABLE_TO_USE_SPECIFIED_PKCS12; return APN_ERROR; } EVP_PKEY_free(private_key); } else { FILE *cert_file = NULL; #ifdef _WIN32 fopen_s(&cert_file, ctx->certificate_file, "r"); #else cert_file = fopen(ctx->certificate_file, "r"); #endif if (!cert_file) { char *error = apn_error_string(errno); apn_log(ctx, APN_LOG_LEVEL_ERROR, "Unable to open file %s: %s (errno: %d)", ctx->pkcs12_file, error, errno); free(error); X509_free(cert); SSL_CTX_free(ssl_ctx); errno = APN_ERR_UNABLE_TO_USE_SPECIFIED_CERTIFICATE; return APN_ERROR; } cert = PEM_read_X509(cert_file, NULL, NULL, NULL); if (!cert) { apn_log(ctx, APN_LOG_LEVEL_ERROR, "Unable to use specified certificate: %s", ERR_error_string(ERR_get_error(), NULL)); SSL_CTX_free(ssl_ctx); fclose(cert_file); errno = APN_ERR_UNABLE_TO_USE_SPECIFIED_CERTIFICATE; return EXIT_FAILURE; } fclose(cert_file); if (!SSL_CTX_use_certificate(ssl_ctx, cert)) { apn_log(ctx, APN_LOG_LEVEL_ERROR, "Unable to use specified certificate: %s", ERR_error_string(ERR_get_error(), NULL)); X509_free(cert); SSL_CTX_free(ssl_ctx); errno = APN_ERR_UNABLE_TO_USE_SPECIFIED_CERTIFICATE; return APN_ERROR; } SSL_CTX_set_default_passwd_cb(ssl_ctx, __apn_ssl_password_callback); char *password = NULL; if (ctx->private_key_pass) { password = apn_strndup(ctx->private_key_pass, strlen(ctx->private_key_pass)); if (!password) { X509_free(cert); SSL_CTX_free(ssl_ctx); return APN_ERROR; } SSL_CTX_set_default_passwd_cb_userdata(ssl_ctx, password); } else { SSL_CTX_set_default_passwd_cb_userdata(ssl_ctx, NULL); } if (!SSL_CTX_use_PrivateKey_file(ssl_ctx, ctx->private_key_file, SSL_FILETYPE_PEM)) { apn_log(ctx, APN_LOG_LEVEL_ERROR, "Unable to use specified private key: %s", ERR_error_string(ERR_get_error(), NULL)); apn_strfree(&password); X509_free(cert); SSL_CTX_free(ssl_ctx); errno = APN_ERR_UNABLE_TO_USE_SPECIFIED_PRIVATE_KEY; return APN_ERROR; } apn_strfree(&password); if (!SSL_CTX_check_private_key(ssl_ctx)) { apn_log(ctx, APN_LOG_LEVEL_ERROR, "Unable to use specified private key: %s", ERR_error_string(ERR_get_error(), NULL)); errno = APN_ERR_UNABLE_TO_USE_SPECIFIED_PRIVATE_KEY; X509_free(cert); SSL_CTX_free(ssl_ctx); return APN_ERROR; } } if(cert) { char *subject = __apn_cert_subject_string(cert); apn_log(ctx, APN_LOG_LEVEL_INFO, "Local certificate subject: %s", subject); char *issuer = __apn_cert_issuer_string(cert); apn_log(ctx, APN_LOG_LEVEL_INFO, "Local certificate issuer: %s", issuer); free(subject); free(issuer); char *cn = __apn_cert_subject_value_by_nib(cert, __APN_X509_ENTRY_CN); X509_free(cert); if(cn) { uint8_t invalid_cert = 0; if(apn_mode(ctx) == APN_MODE_PRODUCTION && 0 != strncmp("Apple Production", cn, 16)) { invalid_cert = 1; apn_log(ctx, APN_LOG_LEVEL_ERROR, "Invalid certificate. You are using a PRODUCTION mode, but certificate was created for usage in SANDBOX"); } else if (apn_mode(ctx) == APN_MODE_SANDBOX && 0 != strncmp("Apple Development", cn, 17)) { invalid_cert = 1; apn_log(ctx, APN_LOG_LEVEL_ERROR, "Invalid certificate. You are using a SANDBOX mode, but certificate was created for usage in PRODUCTION"); } free(cn); if(1 == invalid_cert) { SSL_CTX_free(ssl_ctx); errno = APN_ERR_UNABLE_TO_USE_SPECIFIED_CERTIFICATE; return APN_ERROR; } } } ctx->ssl = SSL_new(ssl_ctx); SSL_CTX_free(ssl_ctx); if (!ctx->ssl) { apn_log(ctx, APN_LOG_LEVEL_ERROR, "Could not initialize SSL"); errno = APN_ERR_UNABLE_TO_ESTABLISH_SSL_CONNECTION; return APN_ERROR; } int ret = 0; if (-1 == (ret = SSL_set_fd(ctx->ssl, ctx->sock))) { apn_log(ctx, APN_LOG_LEVEL_ERROR, "Unable to attach socket to SSL: SSL_set_fd() failed (%d)", SSL_get_error(ctx->ssl, ret)); errno = APN_ERR_UNABLE_TO_ESTABLISH_SSL_CONNECTION; return APN_ERROR; } if (1 > (ret = SSL_connect(ctx->ssl))) { char *error = apn_error_string(errno); apn_log(ctx, APN_LOG_LEVEL_ERROR, "Could not initialize SSL connection: SSL_connect() failed: %s, %s (errno: %d):", ERR_error_string((unsigned long) SSL_get_error(ctx->ssl, ret), NULL), error, errno); free(error); return APN_ERROR; } apn_log(ctx, APN_LOG_LEVEL_INFO, "SSL connection has been established"); X509 *remote_cert = SSL_get_peer_certificate(ctx->ssl); if (remote_cert) { char *subject = __apn_cert_subject_string(remote_cert); apn_log(ctx, APN_LOG_LEVEL_INFO, "Remote certificate subject: %s", subject); char *issuer = __apn_cert_issuer_string(remote_cert); apn_log(ctx, APN_LOG_LEVEL_INFO, "Remote certificate issuer: %s", issuer); free(subject); free(issuer); X509_free(remote_cert); } return APN_SUCCESS; }
LWS_VISIBLE int lws_context_init_server_ssl(struct lws_context_creation_info *info, struct lws_vhost *vhost) { SSL_METHOD *method; struct lws_context *context = vhost->context; struct lws wsi; int error; int n; if (!lws_check_opt(info->options, LWS_SERVER_OPTION_DO_SSL_GLOBAL_INIT)) { vhost->use_ssl = 0; return 0; } if (info->port != CONTEXT_PORT_NO_LISTEN) { vhost->use_ssl = info->ssl_cert_filepath != NULL; if (vhost->use_ssl && info->ssl_cipher_list) lwsl_notice(" SSL ciphers: '%s'\n", info->ssl_cipher_list); if (vhost->use_ssl) lwsl_notice(" Using SSL mode\n"); else lwsl_notice(" Using non-SSL mode\n"); } /* * give him a fake wsi with context + vhost set, so he can use * lws_get_context() in the callback */ memset(&wsi, 0, sizeof(wsi)); wsi.vhost = vhost; wsi.context = vhost->context; /* * Firefox insists on SSLv23 not SSLv3 * Konq disables SSLv2 by default now, SSLv23 works * * SSLv23_server_method() is the openssl method for "allow all TLS * versions", compared to e.g. TLSv1_2_server_method() which only allows * tlsv1.2. Unwanted versions must be disabled using SSL_CTX_set_options() */ method = (SSL_METHOD *)SSLv23_server_method(); if (!method) { error = ERR_get_error(); lwsl_err("problem creating ssl method %lu: %s\n", error, ERR_error_string(error, (char *)context->pt[0].serv_buf)); return 1; } vhost->ssl_ctx = SSL_CTX_new(method); /* create context */ if (!vhost->ssl_ctx) { error = ERR_get_error(); lwsl_err("problem creating ssl context %lu: %s\n", error, ERR_error_string(error, (char *)context->pt[0].serv_buf)); return 1; } /* associate the lws context with the SSL_CTX */ SSL_CTX_set_ex_data(vhost->ssl_ctx, openssl_SSL_CTX_private_data_index, vhost->context); /* Disable SSLv2 and SSLv3 */ SSL_CTX_set_options(vhost->ssl_ctx, SSL_OP_NO_SSLv2 | SSL_OP_NO_SSLv3); #ifdef SSL_OP_NO_COMPRESSION SSL_CTX_set_options(vhost->ssl_ctx, SSL_OP_NO_COMPRESSION); #endif SSL_CTX_set_options(vhost->ssl_ctx, SSL_OP_SINGLE_DH_USE); SSL_CTX_set_options(vhost->ssl_ctx, SSL_OP_CIPHER_SERVER_PREFERENCE); if (info->ssl_cipher_list) SSL_CTX_set_cipher_list(vhost->ssl_ctx, info->ssl_cipher_list); /* as a server, are we requiring clients to identify themselves? */ if (lws_check_opt(info->options, LWS_SERVER_OPTION_REQUIRE_VALID_OPENSSL_CLIENT_CERT)) { int verify_options = SSL_VERIFY_PEER; if (!lws_check_opt(info->options, LWS_SERVER_OPTION_PEER_CERT_NOT_REQUIRED)) verify_options |= SSL_VERIFY_FAIL_IF_NO_PEER_CERT; SSL_CTX_set_session_id_context(vhost->ssl_ctx, (unsigned char *)context, sizeof(void *)); /* absolutely require the client cert */ SSL_CTX_set_verify(vhost->ssl_ctx, verify_options, OpenSSL_verify_callback); } #ifndef OPENSSL_NO_TLSEXT SSL_CTX_set_tlsext_servername_callback(vhost->ssl_ctx, lws_ssl_server_name_cb); #endif /* * give user code a chance to load certs into the server * allowing it to verify incoming client certs */ if (info->ssl_ca_filepath && !SSL_CTX_load_verify_locations(vhost->ssl_ctx, info->ssl_ca_filepath, NULL)) { lwsl_err("%s: SSL_CTX_load_verify_locations unhappy\n", __func__); } if (vhost->use_ssl) { if (lws_context_ssl_init_ecdh_curve(info, vhost)) return -1; vhost->protocols[0].callback(&wsi, LWS_CALLBACK_OPENSSL_LOAD_EXTRA_SERVER_VERIFY_CERTS, vhost->ssl_ctx, NULL, 0); } if (lws_check_opt(info->options, LWS_SERVER_OPTION_ALLOW_NON_SSL_ON_SSL_PORT)) /* Normally SSL listener rejects non-ssl, optionally allow */ vhost->allow_non_ssl_on_ssl_port = 1; if (vhost->use_ssl) { /* openssl init for server sockets */ /* set the local certificate from CertFile */ n = SSL_CTX_use_certificate_chain_file(vhost->ssl_ctx, info->ssl_cert_filepath); if (n != 1) { error = ERR_get_error(); lwsl_err("problem getting cert '%s' %lu: %s\n", info->ssl_cert_filepath, error, ERR_error_string(error, (char *)context->pt[0].serv_buf)); return 1; } lws_ssl_bind_passphrase(vhost->ssl_ctx, info); if (info->ssl_private_key_filepath != NULL) { /* set the private key from KeyFile */ if (SSL_CTX_use_PrivateKey_file(vhost->ssl_ctx, info->ssl_private_key_filepath, SSL_FILETYPE_PEM) != 1) { error = ERR_get_error(); lwsl_err("ssl problem getting key '%s' %lu: %s\n", info->ssl_private_key_filepath, error, ERR_error_string(error, (char *)context->pt[0].serv_buf)); return 1; } } else if (vhost->protocols[0].callback(&wsi, LWS_CALLBACK_OPENSSL_CONTEXT_REQUIRES_PRIVATE_KEY, vhost->ssl_ctx, NULL, 0)) { lwsl_err("ssl private key not set\n"); return 1; } /* verify private key */ if (!SSL_CTX_check_private_key(vhost->ssl_ctx)) { lwsl_err("Private SSL key doesn't match cert\n"); return 1; } if (lws_context_ssl_init_ecdh(vhost)) return 1; /* * SSL is happy and has a cert it's content with * If we're supporting HTTP2, initialize that */ lws_context_init_http2_ssl(context); } return 0; }
int ssl_create(struct ssl_t *ssl, void *data) { ssl->ctx = SSL_CTX_new(SSLv23_method()); if (ssl->ctx == NULL) { ssl_error(LOG_ERR, "ssl_create SSL_CTX_new failed"); return -1; } if (SSL_CTX_set_ex_data(ssl->ctx, ssl_server_conf_index, data) == 0) { ssl_error(LOG_ERR, "ssl_create SSL_CTX_set_ex_data failed"); return -1; } /* client side options */ SSL_CTX_set_options(ssl->ctx, SSL_OP_MICROSOFT_SESS_ID_BUG); SSL_CTX_set_options(ssl->ctx, SSL_OP_NETSCAPE_CHALLENGE_BUG); /* server side options */ SSL_CTX_set_options(ssl->ctx, SSL_OP_SSLREF2_REUSE_CERT_TYPE_BUG); SSL_CTX_set_options(ssl->ctx, SSL_OP_MICROSOFT_BIG_SSLV3_BUFFER); /* this option allow a potential SSL 2.0 rollback (CAN-2005-2969) */ SSL_CTX_set_options(ssl->ctx, SSL_OP_MSIE_SSLV2_RSA_PADDING); SSL_CTX_set_options(ssl->ctx, SSL_OP_SSLEAY_080_CLIENT_DH_BUG); SSL_CTX_set_options(ssl->ctx, SSL_OP_TLS_D5_BUG); SSL_CTX_set_options(ssl->ctx, SSL_OP_TLS_BLOCK_PADDING_BUG); SSL_CTX_set_options(ssl->ctx, SSL_OP_DONT_INSERT_EMPTY_FRAGMENTS); SSL_CTX_set_options(ssl->ctx, SSL_OP_SINGLE_DH_USE); /* SSL protocols not configurable for now */ int protocols = SSL_PROTOCOLS; if (!(protocols & NGX_SSL_SSLv2)) { SSL_CTX_set_options(ssl->ctx, SSL_OP_NO_SSLv2); } if (!(protocols & NGX_SSL_SSLv3)) { SSL_CTX_set_options(ssl->ctx, SSL_OP_NO_SSLv3); } if (!(protocols & NGX_SSL_TLSv1)) { SSL_CTX_set_options(ssl->ctx, SSL_OP_NO_TLSv1); } #ifdef SSL_OP_NO_TLSv1_1 if (!(protocols & NGX_SSL_TLSv1_1)) { SSL_CTX_set_options(ssl->ctx, SSL_OP_NO_TLSv1_1); } #endif #ifdef SSL_OP_NO_TLSv1_2 if (!(protocols & NGX_SSL_TLSv1_2)) { SSL_CTX_set_options(ssl->ctx, SSL_OP_NO_TLSv1_2); } #endif #ifdef SSL_OP_NO_COMPRESSION SSL_CTX_set_options(ssl->ctx, SSL_OP_NO_COMPRESSION); #endif #ifdef SSL_MODE_RELEASE_BUFFERS SSL_CTX_set_mode(ssl->ctx, SSL_MODE_RELEASE_BUFFERS); #endif SSL_CTX_set_mode(ssl->ctx, SSL_MODE_ENABLE_PARTIAL_WRITE); SSL_CTX_set_read_ahead(ssl->ctx, 1); SSL_CTX_set_info_callback(ssl->ctx, (void *)ssl_info_callback); if (SSL_CTX_set_cipher_list(ssl->ctx, SSL_DEFAULT_CIPHERS) == 0) { ssl_error(LOG_ERR, "ssl_create SSL_CTX_set_cipher_list failed"); return -1; } /* prefer server-selected ciphers */ SSL_CTX_set_options(ssl->ctx, SSL_OP_CIPHER_SERVER_PREFERENCE); return 0; }