static int uwsgi_sni_cb(SSL *ssl, int *ad, void *arg) { const char *servername = SSL_get_servername(ssl, TLSEXT_NAMETYPE_host_name); if (!servername) return SSL_TLSEXT_ERR_NOACK; size_t servername_len = strlen(servername); struct uwsgi_string_list *usl = uwsgi.sni; while(usl) { if (!uwsgi_strncmp(usl->value, usl->len, (char *)servername, servername_len)) { SSL_set_SSL_CTX(ssl, usl->custom_ptr); return SSL_TLSEXT_ERR_OK; } usl = usl->next; } #ifdef UWSGI_PCRE struct uwsgi_regexp_list *url = uwsgi.sni_regexp; while(url) { if (uwsgi_regexp_match(url->pattern, url->pattern_extra, (char *)servername, servername_len) >= 0) { SSL_set_SSL_CTX(ssl, url->custom_ptr); return SSL_TLSEXT_ERR_OK; } url = url->next; } #endif if (uwsgi.sni_dir) { size_t sni_dir_len = strlen(uwsgi.sni_dir); char *sni_dir_cert = uwsgi_concat4n(uwsgi.sni_dir, sni_dir_len, "/", 1, (char *) servername, servername_len, ".crt", 4); char *sni_dir_key = uwsgi_concat4n(uwsgi.sni_dir, sni_dir_len, "/", 1, (char *) servername, servername_len, ".key", 4); char *sni_dir_client_ca = uwsgi_concat4n(uwsgi.sni_dir, sni_dir_len, "/", 1, (char *) servername, servername_len, ".ca", 3); if (uwsgi_file_exists(sni_dir_cert) && uwsgi_file_exists(sni_dir_key)) { char *client_ca = NULL; if (uwsgi_file_exists(sni_dir_client_ca)) { client_ca = sni_dir_client_ca; } usl = uwsgi_ssl_add_sni_item(uwsgi_str((char *)servername), sni_dir_cert, sni_dir_key, uwsgi.sni_dir_ciphers, client_ca); if (!usl) goto done; free(sni_dir_cert); free(sni_dir_key); free(sni_dir_client_ca); SSL_set_SSL_CTX(ssl, usl->custom_ptr); uwsgi_log("[uwsgi-sni for pid %d] added context for %s\n", (int) getpid(), servername); return SSL_TLSEXT_ERR_OK; } done: free(sni_dir_cert); free(sni_dir_key); free(sni_dir_client_ca); } return SSL_TLSEXT_ERR_NOACK; }
int CALLBACK CSSLContext::InternalServerNameCallback(SSL* ssl, int* ad, void* arg) { USES_CONVERSION; CSSLContext* pThis = (CSSLContext*)arg; ASSERT(pThis->m_fnServerNameCallback != nullptr); const char* lpszServerName = SSL_get_servername(ssl, TLSEXT_NAMETYPE_host_name); if(lpszServerName == nullptr) return SSL_TLSEXT_ERR_NOACK; int iIndex = pThis->m_fnServerNameCallback(A2CT(lpszServerName)); if(iIndex == 0) return SSL_TLSEXT_ERR_OK; if(iIndex < 0) { ::SetLastError(ERROR_INVALID_NAME); return SSL_TLSEXT_ERR_ALERT_FATAL; } SSL_CTX* sslCtx = pThis->GetContext(iIndex); if(sslCtx == nullptr) { ::SetLastError(ERROR_INVALID_INDEX); return SSL_TLSEXT_ERR_ALERT_FATAL; } SSL_set_SSL_CTX(ssl, sslCtx); return SSL_TLSEXT_ERR_OK; }
int bud_config_select_sni_context(SSL* s, int* ad, void* arg) { bud_config_t* config; bud_context_t* ctx; const char* servername; config = arg; servername = SSL_get_servername(s, TLSEXT_NAMETYPE_host_name); /* No servername - no context selection */ if (servername == NULL) return SSL_TLSEXT_ERR_OK; /* Async SNI */ ctx = SSL_get_ex_data(s, kBudSSLSNIIndex); /* Normal SNI */ if (ctx == NULL) ctx = bud_config_select_context(config, servername, strlen(servername)); if (ctx != NULL) { SSL_set_SSL_CTX(s, ctx->ctx); if (!SSL_set_ex_data(s, kBudSSLSNIIndex, ctx)) return SSL_TLSEXT_ERR_ALERT_FATAL; } return SSL_TLSEXT_ERR_OK; }
static VALUE ossl_call_servername_cb(VALUE ary) { VALUE ssl_obj, sslctx_obj, cb, ret_obj; Check_Type(ary, T_ARRAY); ssl_obj = rb_ary_entry(ary, 0); sslctx_obj = rb_iv_get(ssl_obj, "@context"); if (NIL_P(sslctx_obj)) return Qnil; cb = rb_iv_get(sslctx_obj, "@servername_cb"); if (NIL_P(cb)) return Qnil; ret_obj = rb_funcall(cb, rb_intern("call"), 1, ary); if (rb_obj_is_kind_of(ret_obj, cSSLContext)) { SSL *ssl; SSL_CTX *ctx2; ossl_sslctx_setup(ret_obj); Data_Get_Struct(ssl_obj, SSL, ssl); Data_Get_Struct(ret_obj, SSL_CTX, ctx2); SSL_set_SSL_CTX(ssl, ctx2); } else if (!NIL_P(ret_obj)) { rb_raise(rb_eArgError, "servername_cb must return an OpenSSL::SSL::SSLContext object or nil"); } return ret_obj; }
static int tlsext_servername_callback(SSL *ssl, int *ad, void *arg) { SSL_CTX *newctx = NULL; SSL_CTX *ctx = SSL_get_SSL_CTX(ssl); lua_State *L = SSL_CTX_get_app_data(ctx); const char *name = SSL_get_servername(ssl, TLSEXT_NAMETYPE_host_name); /* No name, use default context */ if (!name) return SSL_TLSEXT_ERR_NOACK; /* Search for the name in the map */ openssl_getvalue(L, ctx, "tlsext_servername"); if (lua_istable(L, -1)) { lua_getfield(L, -1, name); if (auxiliar_isclass(L, "openssl.ssl_ctx", -1)) { newctx = CHECK_OBJECT(-1, SSL_CTX, "openssl.ssl_ctx"); SSL_set_SSL_CTX(ssl, newctx); lua_pop(L, 2); return SSL_TLSEXT_ERR_OK; } } else if (lua_isfunction(L, -1)) { } else { } lua_pop(L, 1); return SSL_TLSEXT_ERR_ALERT_FATAL; }
/* Select the appropriate server CTX. * Returns SSL_TLSEXT_ERR_OK if a match was found. * If |ignore| is 1, returns SSL_TLSEXT_ERR_NOACK on mismatch. * Otherwise, returns SSL_TLSEXT_ERR_ALERT_FATAL on mismatch. * An empty SNI extension also returns SSL_TSLEXT_ERR_NOACK. */ static int select_server_ctx(SSL *s, void *arg, int ignore) { const char *servername = SSL_get_servername(s, TLSEXT_NAMETYPE_host_name); HANDSHAKE_EX_DATA *ex_data = (HANDSHAKE_EX_DATA*)(SSL_get_ex_data(s, ex_data_idx)); if (servername == NULL) { ex_data->servername = SSL_TEST_SERVERNAME_SERVER1; return SSL_TLSEXT_ERR_NOACK; } if (strcmp(servername, "server2") == 0) { SSL_CTX *new_ctx = (SSL_CTX*)arg; SSL_set_SSL_CTX(s, new_ctx); /* * Copy over all the SSL_CTX options - reasonable behavior * allows testing of cases where the options between two * contexts differ/conflict */ SSL_clear_options(s, 0xFFFFFFFFL); SSL_set_options(s, SSL_CTX_get_options(new_ctx)); ex_data->servername = SSL_TEST_SERVERNAME_SERVER2; return SSL_TLSEXT_ERR_OK; } else if (strcmp(servername, "server1") == 0) { ex_data->servername = SSL_TEST_SERVERNAME_SERVER1; return SSL_TLSEXT_ERR_OK; } else if (ignore) { ex_data->servername = SSL_TEST_SERVERNAME_SERVER1; return SSL_TLSEXT_ERR_NOACK; } else { /* Don't set an explicit alert, to test library defaults. */ return SSL_TLSEXT_ERR_ALERT_FATAL; } }
static int sni_cb(SSL *s, int *al, void *arg) { SSL_CTX *ctx = (SSL_CTX *)arg; if (SSL_set_SSL_CTX(s, ctx) == NULL) { *al = SSL_AD_INTERNAL_ERROR; return SSL_TLSEXT_ERR_ALERT_FATAL; } snicb++; return SSL_TLSEXT_ERR_OK; }
ret_t cherokee_cryptor_libssl_find_vserver (SSL *ssl, cherokee_server_t *srv, cherokee_buffer_t *servername, cherokee_connection_t *conn) { ret_t ret; cherokee_virtual_server_t *vsrv = NULL; SSL_CTX *ctx; /* Try to match the connection to a server */ ret = cherokee_server_get_vserver(srv, servername, conn, &vsrv); if ((ret != ret_ok) || (vsrv == NULL)) { LOG_ERROR (CHEROKEE_ERROR_SSL_SRV_MATCH, servername->buf); return ret_error; } TRACE (ENTRIES, "Setting new TLS context. Virtual host='%s'\n", vsrv->name.buf); /* Check whether the Virtual Server supports TLS */ if ((vsrv->cryptor == NULL) || (CRYPTOR_VSRV_SSL(vsrv->cryptor)->context == NULL)) { TRACE (ENTRIES, "Virtual server '%s' does not support SSL\n", servername->buf); return ret_error; } /* Set the new SSL context */ ctx = SSL_set_SSL_CTX (ssl, CRYPTOR_VSRV_SSL(vsrv->cryptor)->context); if (ctx != CRYPTOR_VSRV_SSL(vsrv->cryptor)->context) { LOG_ERROR (CHEROKEE_ERROR_SSL_CHANGE_CTX, servername->buf); } /* SSL_set_SSL_CTX() only change certificates. We need to * changes more options by hand. */ SSL_set_options(ssl, SSL_CTX_get_options(ssl->ctx)); if ((SSL_get_verify_mode(ssl) == SSL_VERIFY_NONE) || (SSL_num_renegotiations(ssl) == 0)) { SSL_set_verify(ssl, SSL_CTX_get_verify_mode(ssl->ctx), SSL_CTX_get_verify_callback(ssl->ctx)); } return ret_ok; }
static int bb_ssl_servername(SSL *ssl,int *ad, void *arg) { const char *servername = SSL_get_servername(ssl, TLSEXT_NAMETYPE_host_name); if (!servername) return SSL_TLSEXT_ERR_NOACK; struct bb_connection *bbc = SSL_get_ex_data(ssl, blastbeat.ssl_index); struct bb_acceptor *bba = bbc->acceptor; size_t servername_len = strlen(servername); struct bb_virtualhost *vhost = NULL; struct bb_hostname *bbhn = NULL; if (bba->addr.in4.sin_port != htons(443) && !strchr(servername, ':')) { size_t port_len = strlen(bba->port_str); char *new_sn = bb_alloc(servername_len+port_len); if (!new_sn) return SSL_TLSEXT_ERR_NOACK; memcpy(new_sn, servername, servername_len); memcpy(new_sn + servername_len, bba->port_str, port_len); vhost = bb_vhost_get(new_sn, servername_len+port_len, &bbhn); bb_free(new_sn, servername_len+port_len); } else { vhost = bb_vhost_get((char *)servername, servername_len, &bbhn); } if (!vhost) return SSL_TLSEXT_ERR_NOACK; // per vhost-context is required to decrypt keys sent by dealers if (!vhost->ctx) return SSL_TLSEXT_ERR_NOACK; // prefer dealer-defined context if (bbhn->ctx) { SSL_set_SSL_CTX(ssl, bbhn->ctx); return SSL_TLSEXT_ERR_OK; } SSL_set_SSL_CTX(ssl, vhost->ctx); return SSL_TLSEXT_ERR_OK; }
bool ServerNameIndication::setCTXFromMemory(SSL *ssl, const std::string &name) { if (!ssl || name.empty()) { return false; } hphp_string_map<SSL_CTX *>::iterator it = s_sn_ctxd_map.find(name); if (it != s_sn_ctxd_map.end()) { SSL_CTX *ctx = it->second; if (ctx && ctx == SSL_set_SSL_CTX(ssl, ctx)) { return true; } } return false; }
static int lws_ssl_server_name_cb(SSL *ssl, int *ad, void *arg) { struct lws_context *context = (struct lws_context *)arg; struct lws_vhost *vhost, *vh; const char *servername; if (!ssl) return SSL_TLSEXT_ERR_NOACK; /* * We can only get ssl accepted connections by using a vhost's ssl_ctx * find out which listening one took us and only match vhosts on the * same port. */ vh = context->vhost_list; while (vh) { if (!vh->being_destroyed && vh->tls.ssl_ctx == SSL_get_SSL_CTX(ssl)) break; vh = vh->vhost_next; } if (!vh) { assert(vh); /* can't match the incoming vh? */ return SSL_TLSEXT_ERR_OK; } servername = SSL_get_servername(ssl, TLSEXT_NAMETYPE_host_name); if (!servername) { /* the client doesn't know what hostname it wants */ lwsl_info("SNI: Unknown ServerName: %s\n", servername); return SSL_TLSEXT_ERR_OK; } vhost = lws_select_vhost(context, vh->listen_port, servername); if (!vhost) { lwsl_info("SNI: none: %s:%d\n", servername, vh->listen_port); return SSL_TLSEXT_ERR_OK; } lwsl_info("SNI: Found: %s:%d\n", servername, vh->listen_port); /* select the ssl ctx from the selected vhost for this conn */ SSL_set_SSL_CTX(ssl, vhost->tls.ssl_ctx); return SSL_TLSEXT_ERR_OK; }
static int openssl_ssl_ctx(lua_State*L) { SSL* s = CHECK_OBJECT(1, SSL, "openssl.ssl"); if (lua_isnoneornil(L, 2)) { SSL_CTX *ctx = SSL_get_SSL_CTX(s); openssl_refrence(L, ctx, +1); PUSH_OBJECT(ctx, "openssl.ssl_ctx"); } else { SSL_CTX *ctx = CHECK_OBJECT(2, SSL_CTX, "openssl.ssl_ctx"); ctx = SSL_set_SSL_CTX(s, ctx); PUSH_OBJECT(ctx, "openssl.ssl_ctx"); } return 1; }
static int lws_ssl_server_name_cb(SSL *ssl, int *ad, void *arg) { struct lws_context *context; struct lws_vhost *vhost, *vh; const char *servername; int port; if (!ssl) return SSL_TLSEXT_ERR_NOACK; context = (struct lws_context *)SSL_CTX_get_ex_data( SSL_get_SSL_CTX(ssl), openssl_SSL_CTX_private_data_index); /* * We can only get ssl accepted connections by using a vhost's ssl_ctx * find out which listening one took us and only match vhosts on the * same port. */ vh = context->vhost_list; while (vh) { if (!vh->being_destroyed && vh->ssl_ctx == SSL_get_SSL_CTX(ssl)) break; vh = vh->vhost_next; } assert(vh); /* we cannot get an ssl without using a vhost ssl_ctx */ port = vh->listen_port; servername = SSL_get_servername(ssl, TLSEXT_NAMETYPE_host_name); if (servername) { vhost = lws_select_vhost(context, port, servername); if (vhost) { lwsl_debug("SNI: Found: %s (port %d)\n", servername, port); SSL_set_SSL_CTX(ssl, vhost->ssl_ctx); return SSL_TLSEXT_ERR_OK; } lwsl_err("SNI: Unknown ServerName: %s\n", servername); } return SSL_TLSEXT_ERR_OK; }
static int lws_mbedtls_sni_cb(void *arg, mbedtls_ssl_context *mbedtls_ctx, const unsigned char *servername, size_t len) { SSL *ssl = SSL_SSL_from_mbedtls_ssl_context(mbedtls_ctx); struct lws_context *context = (struct lws_context *)arg; struct lws_vhost *vhost, *vh; lwsl_notice("%s: %s\n", __func__, servername); /* * We can only get ssl accepted connections by using a vhost's ssl_ctx * find out which listening one took us and only match vhosts on the * same port. */ vh = context->vhost_list; while (vh) { if (!vh->being_destroyed && vh->ssl_ctx == SSL_get_SSL_CTX(ssl)) break; vh = vh->vhost_next; } if (!vh) { assert(vh); /* can't match the incoming vh? */ return 0; } vhost = lws_select_vhost(context, vh->listen_port, (const char *)servername); if (!vhost) { lwsl_info("SNI: none: %s:%d\n", servername, vh->listen_port); return 0; } lwsl_info("SNI: Found: %s:%d at vhost '%s'\n", servername, vh->listen_port, vhost->name); /* select the ssl ctx from the selected vhost for this conn */ SSL_set_SSL_CTX(ssl, vhost->ssl_ctx); return 0; }
static int network_ssl_servername_callback(SSL *ssl, int *al, server *srv) { const char *servername; connection *con = (connection *) SSL_get_app_data(ssl); UNUSED(al); buffer_copy_string(con->uri.scheme, "https"); if (NULL == (servername = SSL_get_servername(ssl, TLSEXT_NAMETYPE_host_name))) { #if 0 /* this "error" just means the client didn't support it */ log_error_write(srv, __FILE__, __LINE__, "ss", "SSL:", "failed to get TLS server name"); #endif return SSL_TLSEXT_ERR_NOACK; } buffer_copy_string(con->tlsext_server_name, servername); buffer_to_lower(con->tlsext_server_name); /* Sometimes this is still set, confusing COMP_HTTP_HOST */ buffer_reset(con->uri.authority); config_cond_cache_reset(srv, con); config_setup_connection(srv, con); config_patch_connection(srv, con, COMP_SERVER_SOCKET); config_patch_connection(srv, con, COMP_HTTP_SCHEME); config_patch_connection(srv, con, COMP_HTTP_HOST); if (NULL == con->conf.ssl_ctx) { /* ssl_ctx <=> pemfile was set <=> ssl_ctx got patched: so this should never happen */ log_error_write(srv, __FILE__, __LINE__, "ssb", "SSL:", "null SSL_CTX for TLS server name", con->tlsext_server_name); return SSL_TLSEXT_ERR_ALERT_FATAL; } /* switch to new SSL_CTX in reaction to a client's server_name extension */ if (con->conf.ssl_ctx != SSL_set_SSL_CTX(ssl, con->conf.ssl_ctx)) { log_error_write(srv, __FILE__, __LINE__, "ssb", "SSL:", "failed to set SSL_CTX for TLS server name", con->tlsext_server_name); return SSL_TLSEXT_ERR_ALERT_FATAL; } return SSL_TLSEXT_ERR_OK; }
NOEXPORT int servername_cb(SSL *ssl, int *ad, void *arg) { SERVICE_OPTIONS *section=(SERVICE_OPTIONS *)arg; const char *servername=SSL_get_servername(ssl, TLSEXT_NAMETYPE_host_name); SERVERNAME_LIST *list; CLI *c; #ifdef USE_LIBWRAP char *accepted_address; #endif /* USE_LIBWRAP */ /* leave the alert type at SSL_AD_UNRECOGNIZED_NAME */ (void)ad; /* squash the unused parameter warning */ if(!section->servername_list_head) { s_log(LOG_DEBUG, "SNI: no virtual services defined"); return SSL_TLSEXT_ERR_OK; } if(!servername) { s_log(LOG_NOTICE, "SNI: no servername received"); return SSL_TLSEXT_ERR_NOACK; } s_log(LOG_INFO, "SNI: requested servername: %s", servername); for(list=section->servername_list_head; list; list=list->next) if(matches_wildcard((char *)servername, list->servername)) { s_log(LOG_DEBUG, "SNI: matched pattern: %s", list->servername); c=SSL_get_ex_data(ssl, index_cli); c->opt=list->opt; SSL_set_SSL_CTX(ssl, c->opt->ctx); SSL_set_verify(ssl, SSL_CTX_get_verify_mode(c->opt->ctx), SSL_CTX_get_verify_callback(c->opt->ctx)); s_log(LOG_NOTICE, "SNI: switched to service [%s]", c->opt->servname); #ifdef USE_LIBWRAP accepted_address=s_ntop(&c->peer_addr, c->peer_addr_len); libwrap_auth(c, accepted_address); /* retry on a service switch */ str_free(accepted_address); #endif /* USE_LIBWRAP */ return SSL_TLSEXT_ERR_OK; } s_log(LOG_ERR, "SNI: no pattern matched servername: %s", servername); return SSL_TLSEXT_ERR_ALERT_FATAL; }
//sni lookup server name int httpSSLServerName(SSL *ssl,int *ad,void *arg) { const char *servername = SSL_get_servername(ssl, TLSEXT_NAMETYPE_host_name); if (servername==NULL) { return SSL_TLSEXT_ERR_NOACK; } KConnectionSelectable *c = (KConnectionSelectable *)SSL_get_ex_data(ssl,kangle_ssl_conntion_index); if (c==NULL) { return SSL_TLSEXT_ERR_NOACK; } if (c->sni) { return SSL_TLSEXT_ERR_OK; } c->sni = new KSSLSniContext; if (query_vh_success != conf.gvm->queryVirtualHost(c->ls,&c->sni->svh,servername)) { return SSL_TLSEXT_ERR_OK; } if (c->sni->svh->vh && c->sni->svh->vh->ssl_ctx) { SSL_set_SSL_CTX(ssl,c->sni->svh->vh->ssl_ctx); } return SSL_TLSEXT_ERR_OK; }
static int sni_cb(SSL *ssl, int *ad, void *arg) { int strict; SSL_CTX *newctx = NULL; SSL_CTX *ctx = SSL_get_SSL_CTX(ssl); lua_State *L = ((p_context)SSL_CTX_get_app_data(ctx))->L; const char *name = SSL_get_servername(ssl, TLSEXT_NAMETYPE_host_name); /* No name, use default context */ if (!name) return SSL_TLSEXT_ERR_NOACK; /* Retrieve struct from registry */ luaL_getmetatable(L, "SSL:SNI:Registry"); lua_pushlightuserdata(L, (void*)ssl); lua_gettable(L, -2); /* Strict search? */ lua_pushstring(L, "strict"); lua_gettable(L, -2); strict = lua_toboolean(L, -1); lua_pop(L, 1); /* Search for the name in the map */ lua_pushstring(L, "map"); lua_gettable(L, -2); lua_pushstring(L, name); lua_gettable(L, -2); if (lua_isuserdata(L, -1)) newctx = lsec_checkcontext(L, -1); lua_pop(L, 4); /* Found, use this context */ if (newctx) { SSL_set_SSL_CTX(ssl, newctx); return SSL_TLSEXT_ERR_OK; } /* Not found, but use initial context */ if (!strict) return SSL_TLSEXT_ERR_OK; return SSL_TLSEXT_ERR_ALERT_FATAL; }
static int sniHostname(SSL *handle, int *ad, void *arg) { MprSocket *sp; MprSsl *ssl; OpenSocket *osp; OpenConfig *cfg; SSL_CTX *ctx; cchar *hostname; if (!handle) { return SSL_TLSEXT_ERR_NOACK; } osp = (OpenSocket*) SSL_get_app_data(handle); sp = osp->sock; hostname = SSL_get_servername(handle, TLSEXT_NAMETYPE_host_name); /* Select the appropriate SSL for this hostname */ if ((ssl = (sp->ssl->matchSsl)(sp, hostname)) == 0) { return SSL_TLSEXT_ERR_ALERT_FATAL; } lock(ssl); if (configOss(ssl, sp->flags, &sp->errorMsg) < 0) { unlock(ssl); return SSL_TLSEXT_ERR_ALERT_FATAL; } unlock(ssl); sp->ssl = ssl; cfg = ssl->config; ctx = cfg->ctx; SSL_set_SSL_CTX(handle, ctx); return SSL_TLSEXT_ERR_OK; }
int main(int argc, char *argv[]) { int ch, flags; flags = 0; #if !defined(KORE_SINGLE_BINARY) while ((ch = getopt(argc, argv, "c:dfhnrv")) != -1) { #else while ((ch = getopt(argc, argv, "dfhnrv")) != -1) { #endif flags++; switch (ch) { #if !defined(KORE_SINGLE_BINARY) case 'c': config_file = optarg; break; #endif #if defined(KORE_DEBUG) case 'd': kore_debug = 1; break; #endif case 'f': foreground = 1; break; case 'h': usage(); break; case 'n': skip_chroot = 1; break; case 'r': skip_runas = 1; break; case 'v': version(); break; default: usage(); } } argc -= optind; argv += optind; kore_mem_init(); #if !defined(KORE_SINGLE_BINARY) if (argc > 0) { if (flags) fatal("You cannot specify kore flags and a command"); return (kore_cli_main(argc, argv)); } #endif kore_pid = getpid(); nlisteners = 0; LIST_INIT(&listeners); kore_log_init(); #if !defined(KORE_NO_HTTP) kore_auth_init(); kore_validator_init(); #endif kore_domain_init(); kore_module_init(); kore_server_sslstart(); #if !defined(KORE_SINGLE_BINARY) if (config_file == NULL) usage(); #else kore_module_load(NULL, NULL); #endif kore_parse_config(); kore_platform_init(); #if !defined(KORE_NO_HTTP) kore_accesslog_init(); if (http_body_disk_offload > 0) { if (mkdir(http_body_disk_path, 0700) == -1 && errno != EEXIST) { printf("can't create http_body_disk_path '%s': %s\n", http_body_disk_path, errno_s); return (KORE_RESULT_ERROR); } } #endif sig_recv = 0; signal(SIGHUP, kore_signal); signal(SIGQUIT, kore_signal); signal(SIGTERM, kore_signal); if (foreground) signal(SIGINT, kore_signal); else signal(SIGINT, SIG_IGN); kore_server_start(); kore_log(LOG_NOTICE, "server shutting down"); kore_worker_shutdown(); if (!foreground) unlink(kore_pidfile); kore_listener_cleanup(); kore_log(LOG_NOTICE, "goodbye"); return (0); } #if !defined(KORE_NO_TLS) int kore_tls_sni_cb(SSL *ssl, int *ad, void *arg) { struct kore_domain *dom; const char *sname; sname = SSL_get_servername(ssl, TLSEXT_NAMETYPE_host_name); kore_debug("kore_tls_sni_cb(): received host %s", sname); if (sname != NULL && (dom = kore_domain_lookup(sname)) != NULL) { kore_debug("kore_ssl_sni_cb(): Using %s CTX", sname); SSL_set_SSL_CTX(ssl, dom->ssl_ctx); if (dom->cafile != NULL) { SSL_set_verify(ssl, SSL_VERIFY_PEER | SSL_VERIFY_FAIL_IF_NO_PEER_CERT, NULL); } else { SSL_set_verify(ssl, SSL_VERIFY_NONE, NULL); } return (SSL_TLSEXT_ERR_OK); } return (SSL_TLSEXT_ERR_NOACK); } void kore_tls_info_callback(const SSL *ssl, int flags, int ret) { struct connection *c; if (flags & SSL_CB_HANDSHAKE_START) { if ((c = SSL_get_app_data(ssl)) == NULL) fatal("no SSL_get_app_data"); c->tls_reneg++; } } #endif int kore_server_bind(const char *ip, const char *port, const char *ccb) { struct listener *l; int on, r; struct addrinfo hints, *results; kore_debug("kore_server_bind(%s, %s)", ip, port); memset(&hints, 0, sizeof(hints)); hints.ai_family = AF_UNSPEC; hints.ai_socktype = SOCK_STREAM; hints.ai_protocol = IPPROTO_TCP; hints.ai_flags = 0; r = getaddrinfo(ip, port, &hints, &results); if (r != 0) fatal("getaddrinfo(%s): %s", ip, gai_strerror(r)); l = kore_malloc(sizeof(struct listener)); l->type = KORE_TYPE_LISTENER; l->addrtype = results->ai_family; if (l->addrtype != AF_INET && l->addrtype != AF_INET6) fatal("getaddrinfo(): unknown address family %d", l->addrtype); if ((l->fd = socket(results->ai_family, SOCK_STREAM, 0)) == -1) { kore_free(l); freeaddrinfo(results); kore_debug("socket(): %s", errno_s); printf("failed to create socket: %s\n", errno_s); return (KORE_RESULT_ERROR); } if (!kore_connection_nonblock(l->fd, 1)) { kore_free(l); freeaddrinfo(results); printf("failed to make socket non blocking: %s\n", errno_s); return (KORE_RESULT_ERROR); } on = 1; if (setsockopt(l->fd, SOL_SOCKET, SO_REUSEADDR, (const char *)&on, sizeof(on)) == -1) { close(l->fd); kore_free(l); freeaddrinfo(results); kore_debug("setsockopt(): %s", errno_s); printf("failed to set SO_REUSEADDR: %s\n", errno_s); return (KORE_RESULT_ERROR); } if (bind(l->fd, results->ai_addr, results->ai_addrlen) == -1) { close(l->fd); kore_free(l); freeaddrinfo(results); kore_debug("bind(): %s", errno_s); printf("failed to bind to %s port %s: %s\n", ip, port, errno_s); return (KORE_RESULT_ERROR); } freeaddrinfo(results); if (listen(l->fd, kore_socket_backlog) == -1) { close(l->fd); kore_free(l); kore_debug("listen(): %s", errno_s); printf("failed to listen on socket: %s\n", errno_s); return (KORE_RESULT_ERROR); } if (ccb != NULL) { *(void **)&(l->connect) = kore_module_getsym(ccb); if (l->connect == NULL) { printf("no such callback: '%s'\n", ccb); close(l->fd); kore_free(l); return (KORE_RESULT_ERROR); } } else { l->connect = NULL; } nlisteners++; LIST_INSERT_HEAD(&listeners, l, list); if (foreground) { #if !defined(KORE_NO_TLS) kore_log(LOG_NOTICE, "running on https://%s:%s", ip, port); #else kore_log(LOG_NOTICE, "running on http://%s:%s", ip, port); #endif } return (KORE_RESULT_OK); } void kore_listener_cleanup(void) { struct listener *l; while (!LIST_EMPTY(&listeners)) { l = LIST_FIRST(&listeners); LIST_REMOVE(l, list); close(l->fd); kore_free(l); } } void kore_signal(int sig) { sig_recv = sig; } static void kore_server_sslstart(void) { #if !defined(KORE_NO_TLS) kore_debug("kore_server_sslstart()"); SSL_library_init(); SSL_load_error_strings(); #endif }
void bud_client_sni_cb(bud_http_request_t* req, bud_error_t err) { bud_client_t* client; bud_config_t* config; bud_client_error_t cerr; int r; STACK_OF(X509)* chain; SSL_CTX* ctx; X509* x509; EVP_PKEY* pkey; client = req->data; config = client->config; client->sni_req = NULL; client->async_hello = kBudProgressDone; if (!bud_is_ok(err)) { WARNING(&client->frontend, "SNI cb failed: \"%s\"", bud_error_to_str(err)); goto fatal; } if (req->code == 404) { /* Not found */ DBG(&client->frontend, "SNI name not found: \"%.*s\"", client->hello.servername_len, client->hello.servername); goto done; } /* Parse incoming JSON */ err = bud_sni_from_json(config, req->response, &client->sni_ctx); if (!bud_is_ok(err)) { WARNING(&client->frontend, "SNI from json failed: \"%s\"", bud_error_to_str(err)); goto fatal; } /* Success */ DBG(&client->frontend, "SNI name found: \"%.*s\"", client->hello.servername_len, client->hello.servername); if (!SSL_set_ex_data(client->ssl, kBudSSLSNIIndex, &client->sni_ctx)) { err = bud_error(kBudErrClientSetExData); goto fatal; } /* NOTE: reference count is not increased by this API methods */ ctx = client->sni_ctx.ctx; x509 = SSL_CTX_get0_certificate(ctx); pkey = SSL_CTX_get0_privatekey(ctx); r = SSL_CTX_get0_chain_certs(ctx, &chain); if (r == 1) r = SSL_use_certificate(client->ssl, x509); if (r == 1) r = SSL_use_PrivateKey(client->ssl, pkey); if (r == 1 && chain != NULL) r = SSL_set1_chain(client->ssl, chain); if (r != 1) { err = bud_error(kBudErrClientSetSNICert); goto fatal; } /* Update context, may be needed for early ticket key generation */ SSL_set_SSL_CTX(client->ssl, ctx); /* Do not loose the cert callback! */ SSL_set_cert_cb(client->ssl, bud_client_ssl_cert_cb, client); client->ssl->options = client->sni_ctx.ctx->options; done: /* Request stapling info if needed */ if (config->stapling.enabled && client->hello.ocsp_request != 0) { err = bud_client_ocsp_stapling(client); if (!bud_is_ok(err)) goto fatal; } json_value_free(req->response); if (client->async_hello == kBudProgressDone) { cerr = bud_client_cycle(client); if (!bud_is_ok(cerr.err)) bud_client_close(client, cerr); } return; fatal: bud_client_close(client, bud_client_error(err, &client->frontend)); }
static int ssl_servername_cb(SSL *cnx, int *al, void *arg) { CertResult result; const char *sni_name; (void) al; (void) arg; if ((sni_name = SSL_get_servername(cnx, TLSEXT_NAMETYPE_host_name)) == NULL || *sni_name == 0 || validate_sni_name(sni_name) != 0) { return SSL_TLSEXT_ERR_NOACK; } logfile(LOG_INFO, "SNI: [%s]", sni_name); if (chrooted != 0 || loggedin != 0) { return SSL_TLSEXT_ERR_NOACK; } if (use_extcert == 0) { return SSL_TLSEXT_ERR_OK; } memset(&result, 0, sizeof result); tls_extcert_get(&result, sni_name); if (result.cert_ok != 1) { die(400, LOG_ERR, "Cert handler not ready"); } if (result.action == CERT_ACTION_DENY) { die(400, LOG_INFO, MSG_LOGOUT); } if (result.action == CERT_ACTION_DEFAULT) { return SSL_TLSEXT_ERR_OK; } if (result.cert_file == NULL) { if (result.action == CERT_ACTION_STRICT) { die(400, LOG_ERR, "Missing certificate"); } else { return SSL_TLSEXT_ERR_OK; } } if (result.key_file == NULL) { result.key_file = result.cert_file; } SSL_CTX_free(tls_ctx); tls_ctx = NULL; if (tls_create_new_context(result.cert_file, result.key_file) != 0) { if (result.action != CERT_ACTION_FALLBACK) { die(400, LOG_ERR, "Invalid certificate"); } if (tls_create_new_context(cert_file, key_file) != 0) { die(400, LOG_ERR, "SSL error"); } } if ((client_sni_name = strdup(sni_name)) == NULL) { die_mem(); } if (tls_cnx != NULL) { const long ctx_options = SSL_CTX_get_options(tls_ctx); SSL_set_SSL_CTX(tls_cnx, tls_ctx); # ifdef SSL_CTRL_CLEAR_OPTIONS SSL_clear_options(tls_cnx, SSL_get_options(tls_cnx) & ~ctx_options); # endif SSL_set_options(tls_cnx, ctx_options); } if (tls_data_cnx != NULL) { const long ctx_options = SSL_CTX_get_options(tls_ctx); SSL_set_SSL_CTX(tls_data_cnx, tls_ctx); # ifdef SSL_CTRL_CLEAR_OPTIONS SSL_clear_options(tls_data_cnx, SSL_get_options(tls_cnx) & ~ctx_options); # endif SSL_set_options(tls_data_cnx, ctx_options); } return SSL_TLSEXT_ERR_OK; }