int TlsInit( char* cacertPath ) { e_TlsError vl_Error; char a_DefaultCertPath[] = DEFAULT_CERT_PATH; char *p_CertToUse; DEBUG_LOG_PRINT_LEV2(("TlsInit : Entry")); SSL_load_error_strings(); SSL_library_init(); gp_SSL_CTX = SSL_CTX_new(TLSv1_method()); if( NULL == gp_SSL_CTX ) { DEBUG_LOG_PRINT_LEV2(("SSL_CTX_new returned NULL!\n")); return FALSE; } if ( SSL_CTX_set_cipher_list(gp_SSL_CTX, DEFAULT_CIPHER_LIST ) != 1 ) { DEBUG_LOG_PRINT_LEV2(("SSL_CTX_set_cipher_list returned NULL!\n")); SSL_CTX_free(gp_SSL_CTX); return FALSE; // ERROR selecting SUPL cipher list } SSL_CTX_set_info_callback(gp_SSL_CTX, Tls_openssl_info_callback); #ifdef AGPS_DISABLE_TLS_CA_CERT_VERIFY /* In this mode, even if a CA cert is not found, a secure connection is established */ SSL_CTX_set_verify( gp_SSL_CTX , SSL_VERIFY_NONE , NULL ); #else /* If a CA cert is not found matching the server certificate, the handshake is shutdown */ SSL_CTX_set_verify( gp_SSL_CTX , SSL_VERIFY_PEER , Tls_openssl_certificate_verify_callback ); #endif p_CertToUse = ( cacertPath == NULL ) ? a_DefaultCertPath : cacertPath; DEBUG_LOG_PRINT_LEV2(("TlsInit : Certificate %s\n" , p_CertToUse)); if( SSL_CTX_load_verify_locations(gp_SSL_CTX, p_CertToUse ,NULL) != 1 ) { DEBUG_LOG_PRINT_LEV2(("SSL_CTX_load_verify_locations failed!\n")); return FALSE; } DEBUG_LOG_PRINT_LEV2(("SSL_CTX_get_options : %ld" , SSL_CTX_get_options( gp_SSL_CTX ) )); SSL_CTX_set_options( gp_SSL_CTX,SSL_OP_NO_TICKET|SSL_OP_NO_SSLv2|SSL_OP_NO_SSLv3) ; DEBUG_LOG_PRINT_LEV2(("SSL_CTX_get_options : %ld" , SSL_CTX_get_options( gp_SSL_CTX ) )); DEBUG_LOG_PRINT_LEV2(("TlsInit : Exit")); return TRUE; }
/* 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; } }
/* OpenSSL < 0.9.8m does not have SSL_CTX_clear_options() */ long HsOpenSSL_SSL_CTX_clear_options(SSL_CTX* ctx, long options) { #if defined(SSL_CTX_clear_options) return SSL_CTX_clear_options(ctx, options); #else long tmp = SSL_CTX_get_options(ctx); return SSL_CTX_set_options(ctx, tmp & ~options); #endif }
CURLcode curl_tls_workarounds_cb(CURL *curl, void *sslctx, void *parm) { // Check to see if workarounds are enabled. if (RuntimeOption::TLSDisableTLS1_2) { SSL_CTX* ctx = (SSL_CTX*)sslctx; SSL_CTX_set_options(ctx, SSL_CTX_get_options (ctx) | SSL_OP_NO_TLSv1_2); } return CURLE_OK; }
static int checksslv2(int test, int sslv2) { int options; if (test == TEST_SSL_CTX) { options = SSL_CTX_get_options(ctx); } else { options = SSL_get_options(ssl); } return ((options & SSL_OP_NO_SSLv2) == 0) ^ (sslv2 == SSLV2OFF); }
static int openssl_ssl_ctx_options(lua_State*L) { SSL_CTX* ctx = CHECK_OBJECT(1, SSL_CTX, "openssl.ssl_ctx"); long options = 0; int ret; int i; if (!lua_isnoneornil(L, 2)) { int top = lua_gettop(L); int clear = lua_isboolean(L, 2) ? lua_toboolean(L, 2) : 0; i = lua_isboolean(L, 2) ? 3 : 2; for (; i <= top; i++) { if (lua_isnumber(L, i)) options |= (long)luaL_checkinteger(L, i); else { const char* s = luaL_checkstring(L, i); int j; for (j = 0; ssl_options[j].name; j++) { LuaL_Enum e = ssl_options[j]; if (strcasecmp(s, e.name)) { options |= e.val; break; } } } } if (clear != 0) options = SSL_CTX_clear_options(ctx, options); else options = SSL_CTX_set_options(ctx, options); } else options = SSL_CTX_get_options(ctx); lua_newtable(L); ret = 0; for (i = 0; ssl_options[i].name; i++) { LuaL_Enum e = ssl_options[i]; if (options && e.val) { lua_pushstring(L, e.name); ret++; lua_rawseti(L, -2, ret); } } return 1; }
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; }
CURLcode curl_tls_workarounds_cb(CURL* /*curl*/, void* sslctx, void* /*parm*/) { // Check to see if workarounds are enabled. SSL_CTX* ctx = (SSL_CTX*)sslctx; if (RuntimeOption::TLSDisableTLS1_2) { #ifdef SSL_OP_NO_TLSv1_2 SSL_CTX_set_options(ctx, SSL_CTX_get_options (ctx) | SSL_OP_NO_TLSv1_2); #else raise_notice("TLSDisableTLS1_2 enabled, but this version of " "SSL does not support that option"); #endif } if (!RuntimeOption::TLSClientCipherSpec.empty()) { SSL_CTX_set_cipher_list(ctx, RuntimeOption::TLSClientCipherSpec.c_str()); } return CURLE_OK; }
static void get_ssl_certificate (ice_config_t *config) { ssl_ok = 0; do { long ssl_opts; ssl_ctx = NULL; if (config->cert_file == NULL) break; ssl_ctx = SSL_CTX_new (SSLv23_server_method()); ssl_opts = SSL_CTX_get_options (ssl_ctx); SSL_CTX_set_options (ssl_ctx, ssl_opts|SSL_OP_NO_SSLv2); if (SSL_CTX_use_certificate_chain_file (ssl_ctx, config->cert_file) <= 0) { WARN1 ("Invalid cert file %s", config->cert_file); break; } if (SSL_CTX_use_PrivateKey_file (ssl_ctx, config->cert_file, SSL_FILETYPE_PEM) <= 0) { WARN1 ("Invalid private key file %s", config->cert_file); break; } if (!SSL_CTX_check_private_key (ssl_ctx)) { ERROR1 ("Invalid %s - Private key does not match cert public key", config->cert_file); break; } if (SSL_CTX_set_cipher_list(ssl_ctx, config->cipher_list) <= 0) { WARN1 ("Invalid cipher list: %s", config->cipher_list); } ssl_ok = 1; INFO1 ("SSL certificate found at %s", config->cert_file); INFO1 ("SSL using ciphers %s", config->cipher_list); return; } while (0); if (ssl_ctx) { WARN2 ("failed to load cert %s (%s)", config->cert_file, ERR_reason_error_string (ERR_peek_last_error())); SSL_CTX_free (ssl_ctx); ssl_ctx = NULL; } INFO0 ("No SSL capability on any configured ports"); }
static void get_ssl_certificate (ice_config_t *config) { SSL_METHOD *method; long ssl_opts; ssl_ok = 0; SSL_load_error_strings(); /* readable error messages */ SSL_library_init(); /* initialize library */ method = SSLv23_server_method(); ssl_ctx = SSL_CTX_new (method); ssl_opts = SSL_CTX_get_options (ssl_ctx); SSL_CTX_set_options (ssl_ctx, ssl_opts|SSL_OP_NO_SSLv2); do { if (config->cert_file == NULL) break; if (SSL_CTX_use_certificate_chain_file (ssl_ctx, config->cert_file) <= 0) { WARN1 ("Invalid cert file %s", config->cert_file); break; } if (SSL_CTX_use_PrivateKey_file (ssl_ctx, config->cert_file, SSL_FILETYPE_PEM) <= 0) { WARN1 ("Invalid private key file %s", config->cert_file); break; } if (!SSL_CTX_check_private_key (ssl_ctx)) { ERROR1 ("Invalid %s - Private key does not match cert public key", config->cert_file); break; } if (SSL_CTX_set_cipher_list(ssl_ctx, config->cipher_list) <= 0) { WARN1 ("Invalid cipher list: %s", config->cipher_list); } ssl_ok = 1; INFO1 ("SSL certificate found at %s", config->cert_file); INFO1 ("SSL using ciphers %s", config->cipher_list); return; } while (0); INFO0 ("No SSL capability on any configured ports"); }
int rb_init_ssl(void) { int ret = 1; char librb_data[] = "librb data"; const char librb_ciphers[] = "kEECDH+HIGH:kEDH+HIGH:HIGH:!RC4:!aNULL"; SSL_load_error_strings(); SSL_library_init(); librb_index = SSL_get_ex_new_index(0, librb_data, NULL, NULL, NULL); #ifndef LRB_HAVE_TLS_METHOD_API 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); #ifndef LRB_HAVE_TLS_METHOD_API 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, librb_ciphers); /* Set ECDHE on OpenSSL 1.00+, but make sure it's actually available * (it's not by default on Solaris or Red Hat... f**k Red Hat and Oracle) */ #if (OPENSSL_VERSION_NUMBER >= 0x10000000L) && !defined(OPENSSL_NO_ECDH) 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 #ifndef LRB_HAVE_TLS_METHOD_API ssl_client_ctx = SSL_CTX_new(SSLv23_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; } #ifndef LRB_HAVE_TLS_METHOD_API SSL_CTX_set_options(ssl_client_ctx, SSL_OP_NO_SSLv2 | SSL_OP_NO_SSLv3); #endif #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, librb_ciphers); return ret; }
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 */ }
long SSL_CTX_get_options_shim(SSL_CTX *ctx) { return SSL_CTX_get_options(ctx); }
rb_ssl_ctx * rb_setup_ssl_server(const char *cacert, const char *cert, const char *keyfile, const char *dhfile, const char *ssl_cipher_list, const char *named_curve, rb_tls_ver_t tls_min_ver) { const char *libratbox_data = "libratbox tls session"; const char *ciphers = "kEECDH+HIGH:kEDH+HIGH:HIGH:!RC4:!aNULL"; unsigned long err; rb_ssl_ctx *sctx; long tls_opts; sctx = rb_malloc(sizeof(rb_ssl_ctx)); sctx->refcount = 1; sctx->ssl_ctx = SSL_CTX_new(SSLv23_server_method()); if(sctx->ssl_ctx == NULL) { rb_lib_log("rb_init_openssl: Unable to initialize OpenSSL server context: %s", ERR_error_string(ERR_get_error(), NULL)); rb_free(sctx); return NULL; } tls_opts = SSL_CTX_get_options(sctx->ssl_ctx); /* Disable SSLv2, make the client use our settings */ tls_opts |= SSL_OP_NO_SSLv2 | SSL_OP_NO_COMPRESSION | SSL_OP_CIPHER_SERVER_PREFERENCE; switch(tls_min_ver) { case RB_TLS_VER_SSL3: /* we default to SSLv3..sadly */ break; case RB_TLS_VER_TLS1: #ifdef SSL_OP_NO_SSLv3 tls_opts |= SSL_OP_NO_SSLv3; #endif break; case RB_TLS_VER_TLS1_1: #ifdef SSL_OP_NO_TLSv1 tls_opts |= SSL_OP_NO_TLSv1; #endif break; case RB_TLS_VER_TLS1_2: #ifdef SSL_OP_NO_TLSv1 tls_opts |= SSL_OP_NO_TLSv1; #endif #ifdef SSL_OP_NO_TLSv1_1 tls_opts |= SSL_OP_NO_TLSv1_1; #endif break; case RB_TLS_VER_LAST: break; } #ifdef SSL_OP_SINGLE_DH_USE tls_opts |= SSL_OP_SINGLE_DH_USE; #endif #ifdef SSL_OP_SINGLE_ECDH_USE tls_opts |= SSL_OP_SINGLE_ECDH_USE; #endif #ifdef SSL_OP_NO_TICKET tls_opts |= SSL_OP_NO_TICKET; #endif SSL_CTX_set_options(sctx->ssl_ctx, tls_opts); if(ssl_cipher_list != NULL) ciphers = ssl_cipher_list; if(!SSL_CTX_set_cipher_list(sctx->ssl_ctx, ciphers)) { rb_lib_log("rb_setup_ssl_server: Error setting ssl_cipher_list=\"%s\": %s", ciphers, ERR_error_string(ERR_get_error(), NULL)); goto cleanup;; } if(cert == NULL) { rb_lib_log("rb_setup_ssl_server: No certificate file"); goto cleanup; } if(!SSL_CTX_use_certificate_chain_file(sctx->ssl_ctx, cert)) { err = ERR_get_error(); rb_lib_log("rb_setup_ssl_server: Error loading certificate file [%s]: %s", cert, ERR_error_string(err, NULL)); goto cleanup; } if(cacert != NULL) { if (!SSL_CTX_load_verify_locations(sctx->ssl_ctx, cacert, NULL)) { err = ERR_get_error(); rb_lib_log("rb_setup_ssl_server: Error loading CA file [%s]: %s", cacert, ERR_error_string(err, NULL)); goto cleanup; } } if(keyfile == NULL) { rb_lib_log("rb_setup_ssl_server: No key file"); goto cleanup; } if(!SSL_CTX_use_PrivateKey_file(sctx->ssl_ctx, keyfile, SSL_FILETYPE_PEM)) { err = ERR_get_error(); rb_lib_log("rb_setup_ssl_server: Error loading keyfile [%s]: %s", keyfile, ERR_error_string(err, NULL)); goto cleanup;; } if(dhfile != NULL) { /* DH parameters aren't necessary, but they are nice..if they didn't pass one..that is their problem */ BIO *bio = BIO_new_file(dhfile, "r"); if(bio != NULL) { DH *dh = PEM_read_bio_DHparams(bio, NULL, NULL, NULL); if(dh == NULL) { err = ERR_get_error(); rb_lib_log ("rb_setup_ssl_server: Error loading DH params file [%s]: %s", dhfile, ERR_error_string(err, NULL)); BIO_free(bio); goto cleanup; } BIO_free(bio); SSL_CTX_set_tmp_dh(sctx->ssl_ctx, dh); DH_free(dh); } else { err = ERR_get_error(); rb_lib_log("rb_setup_ssl_server: Error loading DH params file [%s]: %s", dhfile, ERR_error_string(err, NULL)); goto cleanup; } } #if OPENSSL_VERSION_NUMBER >= 0x0090800fL #ifndef OPENSSL_NO_ECDH if(named_curve != NULL) { int nid; EC_KEY *ecdh; nid = OBJ_sn2nid(named_curve); if(nid == 0) { err = ERR_get_error(); rb_lib_log("rb_setup_ssl_server: Unknown curve named [%s]: %s", named_curve, ERR_error_string(err, NULL)); goto cleanup; } ecdh = EC_KEY_new_by_curve_name(nid); if(ecdh == NULL) { err = ERR_get_error(); rb_lib_log("rb_setup_ssl_server: Curve creation failed for [%s]: %s", named_curve, ERR_error_string(err, NULL)); goto cleanup; } SSL_CTX_set_options(sctx->ssl_ctx, SSL_OP_SINGLE_ECDH_USE); SSL_CTX_set_tmp_ecdh(sctx->ssl_ctx, ecdh); EC_KEY_free(ecdh); } #endif #endif SSL_CTX_set_verify(sctx->ssl_ctx, SSL_VERIFY_PEER | SSL_VERIFY_CLIENT_ONCE, verify_accept_all_cb); SSL_CTX_set_session_id_context(sctx->ssl_ctx, (const unsigned char *)libratbox_data, strlen(libratbox_data)); return sctx; cleanup: SSL_CTX_free(sctx->ssl_ctx); rb_free(sctx); return NULL; }
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; }
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; }
static Ecore_Con_Ssl_Error _ecore_con_ssl_server_prepare_openssl(Ecore_Con_Server *svr, int ssl_type) { long options; int dh = 0; if (ssl_type & ECORE_CON_USE_SSL2) return ECORE_CON_SSL_ERROR_SSL2_NOT_SUPPORTED; switch (ssl_type) { case ECORE_CON_USE_SSL3: case ECORE_CON_USE_SSL3 | ECORE_CON_LOAD_CERT: if (!svr->created) SSL_ERROR_CHECK_GOTO_ERROR(!(svr->ssl_ctx = SSL_CTX_new(SSLv3_client_method()))); else SSL_ERROR_CHECK_GOTO_ERROR(!(svr->ssl_ctx = SSL_CTX_new(SSLv3_server_method()))); break; case ECORE_CON_USE_TLS: case ECORE_CON_USE_TLS | ECORE_CON_LOAD_CERT: if (!svr->created) SSL_ERROR_CHECK_GOTO_ERROR(!(svr->ssl_ctx = SSL_CTX_new(TLSv1_client_method()))); else SSL_ERROR_CHECK_GOTO_ERROR(!(svr->ssl_ctx = SSL_CTX_new(TLSv1_server_method()))); break; case ECORE_CON_USE_MIXED: case ECORE_CON_USE_MIXED | ECORE_CON_LOAD_CERT: if (!svr->created) SSL_ERROR_CHECK_GOTO_ERROR(!(svr->ssl_ctx = SSL_CTX_new(SSLv23_client_method()))); else SSL_ERROR_CHECK_GOTO_ERROR(!(svr->ssl_ctx = SSL_CTX_new(SSLv23_server_method()))); options = SSL_CTX_get_options(svr->ssl_ctx); SSL_CTX_set_options(svr->ssl_ctx, options | SSL_OP_NO_SSLv2 | SSL_OP_SINGLE_DH_USE); break; default: return ECORE_CON_SSL_ERROR_NONE; } if ((!svr->use_cert) && svr->created) { DH *dh_params; INF("Generating DH params"); SSL_ERROR_CHECK_GOTO_ERROR(!(dh_params = DH_new())); SSL_ERROR_CHECK_GOTO_ERROR(!DH_generate_parameters_ex(dh_params, 1024, DH_GENERATOR_5, NULL)); SSL_ERROR_CHECK_GOTO_ERROR(!DH_check(dh_params, &dh)); SSL_ERROR_CHECK_GOTO_ERROR((dh & DH_CHECK_P_NOT_PRIME) || (dh & DH_CHECK_P_NOT_SAFE_PRIME)); SSL_ERROR_CHECK_GOTO_ERROR(!DH_generate_key(dh_params)); SSL_ERROR_CHECK_GOTO_ERROR(!SSL_CTX_set_tmp_dh(svr->ssl_ctx, dh_params)); DH_free(dh_params); INF("DH params successfully generated and applied!"); SSL_ERROR_CHECK_GOTO_ERROR(!SSL_CTX_set_cipher_list(svr->ssl_ctx, "aNULL:!eNULL:!LOW:!EXPORT:@STRENGTH")); } else if (!svr->use_cert) SSL_ERROR_CHECK_GOTO_ERROR(!SSL_CTX_set_cipher_list(svr->ssl_ctx, "aNULL:!eNULL:!LOW:!EXPORT:!ECDH:RSA:AES:!PSK:@STRENGTH")); return ECORE_CON_SSL_ERROR_NONE; error: if (dh) { if (dh & DH_CHECK_P_NOT_PRIME) ERR("openssl error: dh_params could not generate a prime!"); else ERR("openssl error: dh_params could not generate a safe prime!"); } else _openssl_print_errors(); _ecore_con_ssl_server_shutdown_openssl(svr); return ECORE_CON_SSL_ERROR_SERVER_INIT_FAILED; }
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; }
long SslContext::getOptions() { return SSL_CTX_get_options(m_pCtx); }
/* * 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); }