Beispiel #1
0
static int __ssl_setup(struct ast_tls_config *cfg, int client)
{
#ifndef DO_SSL
	cfg->enabled = 0;
	return 0;
#else
	if (!cfg->enabled)
		return 0;

	/* Get rid of an old SSL_CTX since we're about to
	 * allocate a new one
	 */
	if (cfg->ssl_ctx) {
		SSL_CTX_free(cfg->ssl_ctx);
		cfg->ssl_ctx = NULL;
	}

	if (client) {
#ifndef OPENSSL_NO_SSL2
		if (ast_test_flag(&cfg->flags, AST_SSL_SSLV2_CLIENT)) {
			cfg->ssl_ctx = SSL_CTX_new(SSLv2_client_method());
		} else
#endif
		if (ast_test_flag(&cfg->flags, AST_SSL_SSLV3_CLIENT)) {
			cfg->ssl_ctx = SSL_CTX_new(SSLv3_client_method());
		} else if (ast_test_flag(&cfg->flags, AST_SSL_TLSV1_CLIENT)) {
			cfg->ssl_ctx = SSL_CTX_new(TLSv1_client_method());
		} else {
			/* SSLv23_client_method() sends SSLv2, this was the original
			 * default for ssl clients before the option was given to
			 * pick what protocol a client should use.  In order not
			 * to break expected behavior it remains the default. */
			cfg->ssl_ctx = SSL_CTX_new(SSLv23_client_method());
		}
	} else {
		/* SSLv23_server_method() supports TLSv1, SSLv2, and SSLv3 inbound connections. */
		cfg->ssl_ctx = SSL_CTX_new(SSLv23_server_method());
	}

	if (!cfg->ssl_ctx) {
		ast_debug(1, "Sorry, SSL_CTX_new call returned null...\n");
		cfg->enabled = 0;
		return 0;
	}
	if (!ast_strlen_zero(cfg->certfile)) {
		char *tmpprivate = ast_strlen_zero(cfg->pvtfile) ? cfg->certfile : cfg->pvtfile;
		if (SSL_CTX_use_certificate_file(cfg->ssl_ctx, cfg->certfile, SSL_FILETYPE_PEM) == 0) {
			if (!client) {
				/* Clients don't need a certificate, but if its setup we can use it */
				ast_verb(0, "SSL error loading cert file. <%s>", cfg->certfile);
				cfg->enabled = 0;
				SSL_CTX_free(cfg->ssl_ctx);
				cfg->ssl_ctx = NULL;
				return 0;
			}
		}
		if ((SSL_CTX_use_PrivateKey_file(cfg->ssl_ctx, tmpprivate, SSL_FILETYPE_PEM) == 0) || (SSL_CTX_check_private_key(cfg->ssl_ctx) == 0 )) {
			if (!client) {
				/* Clients don't need a private key, but if its setup we can use it */
				ast_verb(0, "SSL error loading private key file. <%s>", tmpprivate);
				cfg->enabled = 0;
				SSL_CTX_free(cfg->ssl_ctx);
				cfg->ssl_ctx = NULL;
				return 0;
			}
		}
	}
	if (!ast_strlen_zero(cfg->cipher)) {
		if (SSL_CTX_set_cipher_list(cfg->ssl_ctx, cfg->cipher) == 0 ) {
			if (!client) {
				ast_verb(0, "SSL cipher error <%s>", cfg->cipher);
				cfg->enabled = 0;
				SSL_CTX_free(cfg->ssl_ctx);
				cfg->ssl_ctx = NULL;
				return 0;
			}
		}
	}
	if (!ast_strlen_zero(cfg->cafile) || !ast_strlen_zero(cfg->capath)) {
		if (SSL_CTX_load_verify_locations(cfg->ssl_ctx, S_OR(cfg->cafile, NULL), S_OR(cfg->capath,NULL)) == 0)
			ast_verb(0, "SSL CA file(%s)/path(%s) error\n", cfg->cafile, cfg->capath);
	}

	ast_verb(0, "SSL certificate ok\n");
	return 1;
#endif
}
Beispiel #2
0
static int __ssl_setup(struct ast_tls_config *cfg, int client)
{
#ifndef DO_SSL
	cfg->enabled = 0;
	return 0;
#else
	int disable_ssl = 0;
 
	if (!cfg->enabled) {
		return 0;
	}

	/* Get rid of an old SSL_CTX since we're about to
	 * allocate a new one
	 */
	if (cfg->ssl_ctx) {
		SSL_CTX_free(cfg->ssl_ctx);
		cfg->ssl_ctx = NULL;
	}

	if (client) {
#ifndef OPENSSL_NO_SSL2
		if (ast_test_flag(&cfg->flags, AST_SSL_SSLV2_CLIENT)) {
			ast_log(LOG_WARNING, "Usage of SSLv2 is discouraged due to known vulnerabilities. Please use 'tlsv1' or leave the TLS method unspecified!\n");
			cfg->ssl_ctx = SSL_CTX_new(SSLv2_client_method());
		} else
#endif
#ifndef OPENSSL_NO_SSL3_METHOD
		if (ast_test_flag(&cfg->flags, AST_SSL_SSLV3_CLIENT)) {
			ast_log(LOG_WARNING, "Usage of SSLv3 is discouraged due to known vulnerabilities. Please use 'tlsv1' or leave the TLS method unspecified!\n");
			cfg->ssl_ctx = SSL_CTX_new(SSLv3_client_method());
		} else
#endif
		if (ast_test_flag(&cfg->flags, AST_SSL_TLSV1_CLIENT)) {
			cfg->ssl_ctx = SSL_CTX_new(TLSv1_client_method());
		} else {
			disable_ssl = 1;
			cfg->ssl_ctx = SSL_CTX_new(SSLv23_client_method());
		}
	} else {
		disable_ssl = 1;
		cfg->ssl_ctx = SSL_CTX_new(SSLv23_server_method());
	}

	if (!cfg->ssl_ctx) {
		ast_debug(1, "Sorry, SSL_CTX_new call returned null...\n");
		cfg->enabled = 0;
		return 0;
	}

	/* Due to the POODLE vulnerability, completely disable
	 * SSLv2 and SSLv3 if we are not explicitly told to use
	 * them. SSLv23_*_method supports TLSv1+.
	 */
	if (disable_ssl) {
		long ssl_opts;

		ssl_opts = SSL_OP_NO_SSLv2 | SSL_OP_NO_SSLv3;
		SSL_CTX_set_options(cfg->ssl_ctx, ssl_opts);
	}

	SSL_CTX_set_verify(cfg->ssl_ctx,
		ast_test_flag(&cfg->flags, AST_SSL_VERIFY_CLIENT) ? SSL_VERIFY_PEER | SSL_VERIFY_FAIL_IF_NO_PEER_CERT : SSL_VERIFY_NONE,
		NULL);

	if (!ast_strlen_zero(cfg->certfile)) {
		char *tmpprivate = ast_strlen_zero(cfg->pvtfile) ? cfg->certfile : cfg->pvtfile;
		if (SSL_CTX_use_certificate_chain_file(cfg->ssl_ctx, cfg->certfile) == 0) {
			if (!client) {
				/* Clients don't need a certificate, but if its setup we can use it */
				ast_log(LOG_ERROR, "TLS/SSL error loading cert file. <%s>\n", cfg->certfile);
				cfg->enabled = 0;
				SSL_CTX_free(cfg->ssl_ctx);
				cfg->ssl_ctx = NULL;
				return 0;
			}
		}
		if ((SSL_CTX_use_PrivateKey_file(cfg->ssl_ctx, tmpprivate, SSL_FILETYPE_PEM) == 0) || (SSL_CTX_check_private_key(cfg->ssl_ctx) == 0 )) {
			if (!client) {
				/* Clients don't need a private key, but if its setup we can use it */
				ast_log(LOG_ERROR, "TLS/SSL error loading private key file. <%s>\n", tmpprivate);
				cfg->enabled = 0;
				SSL_CTX_free(cfg->ssl_ctx);
				cfg->ssl_ctx = NULL;
				return 0;
			}
		}
	}
	if (!ast_strlen_zero(cfg->cipher)) {
		if (SSL_CTX_set_cipher_list(cfg->ssl_ctx, cfg->cipher) == 0 ) {
			if (!client) {
				ast_log(LOG_ERROR, "TLS/SSL cipher error <%s>\n", cfg->cipher);
				cfg->enabled = 0;
				SSL_CTX_free(cfg->ssl_ctx);
				cfg->ssl_ctx = NULL;
				return 0;
			}
		}
	}
	if (!ast_strlen_zero(cfg->cafile) || !ast_strlen_zero(cfg->capath)) {
		if (SSL_CTX_load_verify_locations(cfg->ssl_ctx, S_OR(cfg->cafile, NULL), S_OR(cfg->capath,NULL)) == 0) {
			ast_log(LOG_ERROR, "TLS/SSL CA file(%s)/path(%s) error\n", cfg->cafile, cfg->capath);
		}
	}

#ifdef HAVE_OPENSSL_EC

	if (!ast_strlen_zero(cfg->pvtfile)) {
		BIO *bio = BIO_new_file(cfg->pvtfile, "r");
		if (bio != NULL) {
			DH *dh = PEM_read_bio_DHparams(bio, NULL, NULL, NULL);
			if (dh != NULL) {
				if (SSL_CTX_set_tmp_dh(cfg->ssl_ctx, dh)) {
					long options = SSL_OP_CIPHER_SERVER_PREFERENCE | SSL_OP_SINGLE_DH_USE | SSL_OP_SINGLE_ECDH_USE;
					options = SSL_CTX_set_options(cfg->ssl_ctx, options);
					ast_verb(2, "TLS/SSL DH initialized, PFS cipher-suites enabled\n");
				}
				DH_free(dh);
			}
			BIO_free(bio);
		}
	}
	#ifndef SSL_CTRL_SET_ECDH_AUTO
		#define SSL_CTRL_SET_ECDH_AUTO 94
	#endif
	/* SSL_CTX_set_ecdh_auto(cfg->ssl_ctx, on); requires OpenSSL 1.0.2 which wraps: */
	if (SSL_CTX_ctrl(cfg->ssl_ctx, SSL_CTRL_SET_ECDH_AUTO, 1, NULL)) {
		ast_verb(2, "TLS/SSL ECDH initialized (automatic), faster PFS ciphers enabled\n");
	} else {
		/* enables AES-128 ciphers, to get AES-256 use NID_secp384r1 */
		EC_KEY *ecdh = EC_KEY_new_by_curve_name(NID_X9_62_prime256v1);
		if (ecdh != NULL) {
			if (SSL_CTX_set_tmp_ecdh(cfg->ssl_ctx, ecdh)) {
				ast_verb(2, "TLS/SSL ECDH initialized (secp256r1), faster PFS cipher-suites enabled\n");
			}
			EC_KEY_free(ecdh);
		}
	}

#endif /* #ifdef HAVE_OPENSSL_EC */

	ast_verb(2, "TLS/SSL certificate ok\n");	/* We should log which one that is ok. This message doesn't really make sense in production use */
	return 1;
#endif
}
Beispiel #3
0
int
rb_init_ssl(void)
{
	int ret = 1;
	char libratbox_data[] = "libratbox data";
	const char libratbox_ciphers[] = "kEECDH+HIGH:kEDH+HIGH:HIGH:!RC4:!aNULL";
	SSL_load_error_strings();
	SSL_library_init();
	libratbox_index = SSL_get_ex_new_index(0, libratbox_data, NULL, NULL, NULL);

#if defined(LIBRESSL_VERSION_NUMBER) || (OPENSSL_VERSION_NUMBER < 0x10100000L)
	ssl_server_ctx = SSL_CTX_new(SSLv23_server_method());
#else
	ssl_server_ctx = SSL_CTX_new(TLS_server_method());
#endif

	if(ssl_server_ctx == NULL)
	{
		rb_lib_log("rb_init_openssl: Unable to initialize OpenSSL server context: %s",
			   get_ssl_error(ERR_get_error()));
		ret = 0;
	}

	long server_options = SSL_CTX_get_options(ssl_server_ctx);

#if defined(LIBRESSL_VERSION_NUMBER) || (OPENSSL_VERSION_NUMBER < 0x10100000L)
	server_options |= SSL_OP_NO_SSLv2;
	server_options |= SSL_OP_NO_SSLv3;
#endif

#ifdef SSL_OP_SINGLE_DH_USE
	server_options |= SSL_OP_SINGLE_DH_USE;
#endif

#ifdef SSL_OP_SINGLE_ECDH_USE
	server_options |= SSL_OP_SINGLE_ECDH_USE;
#endif

#ifdef SSL_OP_NO_TICKET
	server_options |= SSL_OP_NO_TICKET;
#endif

	server_options |= SSL_OP_CIPHER_SERVER_PREFERENCE;

	SSL_CTX_set_options(ssl_server_ctx, server_options);
	SSL_CTX_set_verify(ssl_server_ctx, SSL_VERIFY_PEER | SSL_VERIFY_CLIENT_ONCE, verify_accept_all_cb);
	SSL_CTX_set_session_cache_mode(ssl_server_ctx, SSL_SESS_CACHE_OFF);
	SSL_CTX_set_cipher_list(ssl_server_ctx, libratbox_ciphers);

	/* Set ECDHE on OpenSSL 1.00+, but make sure it's actually available because redhat are dicks
	   and bastardise their OpenSSL for stupid reasons... */
	#if (OPENSSL_VERSION_NUMBER >= 0x10000000L) && defined(NID_secp384r1)
		EC_KEY *key = EC_KEY_new_by_curve_name(NID_secp384r1);
		if (key) {
			SSL_CTX_set_tmp_ecdh(ssl_server_ctx, key);
			EC_KEY_free(key);
		}
	#endif

#if defined(LIBRESSL_VERSION_NUMBER) || (OPENSSL_VERSION_NUMBER < 0x10100000L)
	ssl_client_ctx = SSL_CTX_new(TLSv1_client_method());
#else
	ssl_client_ctx = SSL_CTX_new(TLS_client_method());
#endif

	if(ssl_client_ctx == NULL)
	{
		rb_lib_log("rb_init_openssl: Unable to initialize OpenSSL client context: %s",
			   get_ssl_error(ERR_get_error()));
		ret = 0;
	}

#ifdef SSL_OP_NO_TICKET
	SSL_CTX_set_options(ssl_client_ctx, SSL_OP_NO_TICKET);
#endif

	SSL_CTX_set_cipher_list(ssl_client_ctx, libratbox_ciphers);

	return ret;
}
Beispiel #4
0
int ssl_server_init(char* ca_file, char *crt_file, char *key_file, char *dhp_file, char *ssl_cipher_list)
{
	static const char *ssl_ctx_id = "httpd";
	long ssl_options;

	if (!crt_file || !f_exists(crt_file)) {
		httpd_log("%s: Server certificate (%s) is not found!", SYSLOG_ID_SSL, crt_file);
		httpd_log("Please manual build the certificate via \"%s\" script.", "https-cert.sh");
		return -1;
	}

	if (!key_file || !f_exists(key_file)) {
		httpd_log("%s: Server private key (%s) is not found!", SYSLOG_ID_SSL, key_file);
		httpd_log("Please manual build the certificate via \"%s\" script.", "https-cert.sh");
		return -1;
	}

	SSL_load_error_strings();
	SSL_library_init();

	ssl_ctx = SSL_CTX_new(SSLv23_server_method());
	if (!ssl_ctx) {
		httpd_log("%s: Unable to create SSL context!", SYSLOG_ID_SSL);
		return -1;
	}

	ssl_options = SSL_OP_ALL | SSL_OP_NO_COMPRESSION | SSL_OP_NO_SSLv2 |
			SSL_OP_NO_SESSION_RESUMPTION_ON_RENEGOTIATION;

	SSL_CTX_set_options(ssl_ctx, ssl_options);
	SSL_CTX_set_verify(ssl_ctx, SSL_VERIFY_NONE, NULL);

	if (ssl_cipher_list && strlen(ssl_cipher_list) > 2) {
		if (SSL_CTX_set_cipher_list(ssl_ctx, ssl_cipher_list) != 1) {
			httpd_log("%s: Cannot set SSL cipher list (%s)!", SYSLOG_ID_SSL, ssl_cipher_list);
		} else {
			SSL_CTX_set_options(ssl_ctx, SSL_OP_CIPHER_SERVER_PREFERENCE);
		}
	}

	if (ca_file && f_exists(ca_file)) {
		if (SSL_CTX_load_verify_locations(ssl_ctx, ca_file, NULL) != 1) {
			httpd_log("%s: Cannot load CA certificate (%s)!", SYSLOG_ID_SSL, ca_file);
		}
	}

	if (SSL_CTX_use_certificate_file(ssl_ctx, crt_file, SSL_FILETYPE_PEM) != 1) {
		httpd_log("%s: Cannot load server certificate (%s)!", SYSLOG_ID_SSL, crt_file);
		ssl_server_uninit();
		return 1;
	}

	if (SSL_CTX_use_PrivateKey_file(ssl_ctx, key_file, SSL_FILETYPE_PEM) != 1) {
		httpd_log("%s: Cannot load server private key (%s)!", SYSLOG_ID_SSL, key_file);
		ssl_server_uninit();
		return 1;
	}

	if (SSL_CTX_check_private_key(ssl_ctx) != 1) {
		httpd_log("%s: Private key does not match the certificate!", SYSLOG_ID_SSL);
		ssl_server_uninit();
		return 1;
	}

	if (dhp_file && f_exists(dhp_file)) {
		/* DH parameters from file */
		BIO *bio = BIO_new_file(dhp_file, "r");
		if (bio) {
			DH *dh = PEM_read_bio_DHparams(bio, NULL, NULL, NULL);
			BIO_free(bio);
			if (dh) {
				SSL_CTX_set_tmp_dh(ssl_ctx, dh);
				SSL_CTX_set_options(ssl_ctx, SSL_OP_SINGLE_DH_USE);
				DH_free(dh);
			} else {
				httpd_log("%s: Cannot load DH parameters (%s)!", SYSLOG_ID_SSL, dhp_file);
			}
		}
	} else {
		/* Default DH parameters from RFC5114 */
		DH *dh = DH_new();
		if (dh) {
			dh->p = BN_bin2bn(dh1024_p, sizeof(dh1024_p), NULL);
			dh->g = BN_bin2bn(dh1024_g, sizeof(dh1024_g), NULL);
			dh->length = 160;
			if (dh->p && dh->g) {
				SSL_CTX_set_tmp_dh(ssl_ctx, dh);
				SSL_CTX_set_options(ssl_ctx, SSL_OP_SINGLE_DH_USE);
			}
			DH_free(dh);
		}
	}

	SSL_CTX_set_default_read_ahead(ssl_ctx, 1);

	SSL_CTX_set_session_cache_mode(ssl_ctx, SSL_SESS_CACHE_SERVER);
	SSL_CTX_set_session_id_context(ssl_ctx, (unsigned char *)ssl_ctx_id, strlen(ssl_ctx_id));
	SSL_CTX_sess_set_cache_size(ssl_ctx, 10);

	SSL_CTX_set_info_callback(ssl_ctx, http_ssl_info_cb);

	return 0;
}
Beispiel #5
0
int main(int argc, char *argv[])
	{
	char *port = "*:4433";
	BIO *in=NULL;
	BIO *ssl_bio,*tmp;
	SSL_CTX *ctx;
	SSL_CONF_CTX *cctx = NULL;
	CONF *conf = NULL;
	STACK_OF(CONF_VALUE) *sect = NULL;
	CONF_VALUE *cnf;
	long errline = -1;
	char buf[512];
	int ret=1,i;

	SSL_load_error_strings();

	/* Add ciphers and message digests */
	OpenSSL_add_ssl_algorithms();

	conf = NCONF_new(NULL);

	if (NCONF_load(conf, "accept.cnf", &errline) <= 0)
		{
		if (errline <= 0)
			fprintf(stderr, "Error processing config file\n");
		else
			fprintf(stderr, "Error on line %ld\n", errline);
		goto err;
		}

	sect = NCONF_get_section(conf, "default");

	if (sect == NULL)
		{
		fprintf(stderr, "Error retrieving default section\n");
		goto err;
		}

	ctx=SSL_CTX_new(SSLv23_server_method());
	cctx = SSL_CONF_CTX_new();
	SSL_CONF_CTX_set_flags(cctx, SSL_CONF_FLAG_SERVER);
	SSL_CONF_CTX_set_flags(cctx, SSL_CONF_FLAG_CERTIFICATE);
	SSL_CONF_CTX_set_flags(cctx, SSL_CONF_FLAG_FILE);
	SSL_CONF_CTX_set_ssl_ctx(cctx, ctx);
	for (i = 0; i < sk_CONF_VALUE_num(sect); i++)
		{
		int rv;
		cnf = sk_CONF_VALUE_value(sect, i);
		rv = SSL_CONF_cmd(cctx, cnf->name, cnf->value);
		if (rv > 0)
			continue;
		if (rv != -2)
			{
			fprintf(stderr, "Error processing %s = %s\n",
						cnf->name, cnf->value);
			ERR_print_errors_fp(stderr);
			goto err;
			}
		if (!strcmp(cnf->name, "Port"))
			{
			port = cnf->value;
			}
		else
			{
			fprintf(stderr, "Unknown configuration option %s\n",
							cnf->name);
			goto err;
			}
		}

	if (!SSL_CONF_CTX_finish(cctx))
		{
		fprintf(stderr, "Finish error\n");
		ERR_print_errors_fp(stderr);
		goto err;
		}

	/* Setup server side SSL bio */
	ssl_bio=BIO_new_ssl(ctx,0);

	if ((in=BIO_new_accept(port)) == NULL) goto err;

	/* This means that when a new connection is accepted on 'in',
	 * The ssl_bio will be 'duplicated' and have the new socket
	 * BIO push into it.  Basically it means the SSL BIO will be
	 * automatically setup */
	BIO_set_accept_bios(in,ssl_bio);

again:
	/* The first call will setup the accept socket, and the second
	 * will get a socket.  In this loop, the first actual accept
	 * will occur in the BIO_read() function. */

	if (BIO_do_accept(in) <= 0) goto err;

	for (;;)
		{
		i=BIO_read(in,buf,512);
		if (i == 0)
			{
			/* If we have finished, remove the underlying
			 * BIO stack so the next time we call any function
			 * for this BIO, it will attempt to do an
			 * accept */
			printf("Done\n");
			tmp=BIO_pop(in);
			BIO_free_all(tmp);
			goto again;
			}
		if (i < 0)
			{
			if (BIO_should_retry(in))
				continue;
			goto err;
			}
		fwrite(buf,1,i,stdout);
		fflush(stdout);
		}

	ret=0;
err:
	if (ret)
		{
		ERR_print_errors_fp(stderr);
		}
	if (in != NULL) BIO_free(in);
	exit(ret);
	return(!ret);
	}
Beispiel #6
0
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;
}
Beispiel #7
0
int InitSSLStuff(void)
{
	dbg("Enabling SSL security system\n");
#ifdef INET6
	if ((server_ssl = socket(AF_INET6, SOCK_STREAM, IPPROTO_TCP)) == -1)
	{
		DIE("NO_CREATE_SOCKET");
		return 0;
	}
#else
	if ((server_ssl = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP)) == -1){
		dbg("Couldn't create socket for ssl\n");
		DIE("NO_CREATE_SOCKET");
		return 0;
	}
#endif /*INET6*/

	/* server socket is nonblocking */
	if (fcntl(server_ssl, F_SETFL, NOBLOCK) == -1){
		dbg("%s, %i:Couldn't fcntl\n", __FILE__, __LINE__);
		DIE("NO_FCNTL");
		return 0;
	}

	if ((setsockopt(server_ssl, SOL_SOCKET, SO_REUSEADDR, (void *) &sock_opt,
		sizeof(sock_opt))) == -1){
		dbg("%s, %i:Couldn't sockopt\n", __FILE__,__LINE__);
		DIE("NO_SETSOCKOPT");
		return 0;
	}

	/* internet socket */
#ifdef INET6
	server_sockaddr.sin6_family = AF_INET6;
	memcpy(&server_sockaddr.sin6_addr,&in6addr_any,sizeof(in6addr_any));
	server_sockaddr.sin6_port = htons(ssl_server_port);
#else
	server_sockaddr.sin_family = AF_INET;
	server_sockaddr.sin_addr.s_addr = htonl(INADDR_ANY);
	server_sockaddr.sin_port = htons(ssl_server_port);
#endif

	if (bind(server_ssl, (struct sockaddr *) &server_sockaddr,
		sizeof(server_sockaddr)) == -1){
		dbg("Couldn't bind ssl to port %d\n", ntohs(server_sockaddr.sin_port));
		DIE("NO_BIND");
		return 0;
	}

	/* listen: large number just in case your kernel is nicely tweaked */
	if (listen(server_ssl, backlog) == -1){
		DIE("NO_LISTEN");
		return 0;
	}

	if (server_ssl > max_fd)
		max_fd = server_ssl;

	/*Init all of the ssl stuff*/
//	i don't know why this line is commented out... i found it like that - damion may-02
/*	SSL_load_error_strings();*/
	SSLeay_add_ssl_algorithms();
	meth = SSLv23_server_method();
	if(meth == NULL){
		ERR_print_errors_fp(stderr);
		dbg("Couldn't create the SSL method\n");
		DIE("NO_SSL");
		return 0;
	}
	ctx = SSL_CTX_new(meth);
	if(!ctx){
		dbg("Couldn't create a connection context\n");
		ERR_print_errors_fp(stderr);
		DIE("NO_SSL");
		return 0;
	}

	if (SSL_CTX_use_certificate_file(ctx, SSL_CERTF, SSL_FILETYPE_PEM) <= 0) {
		dbg("Failure reading SSL certificate file: %s\n",SSL_CERTF);
		close(server_ssl);
		return 0;
	}
	dbg("Loaded SSL certificate file: %s\n",SSL_CERTF);

	if (SSL_CTX_use_PrivateKey_file(ctx, SSL_KEYF, SSL_FILETYPE_PEM) <= 0) {
		dbg("Failure reading private key file: %s\n",SSL_KEYF);
		close(server_ssl);
		return 0;
	}
	dbg("Opened private key file: %s\n",SSL_KEYF);

	if (!SSL_CTX_check_private_key(ctx)) {
		dbg("Private key does not match the certificate public key\n");
		close(server_ssl);
		return 0;
	}

	/*load and check that the key files are appropriate.*/
	dbg("SSL security system enabled\n");
	return 1;
}
Beispiel #8
0
/*主线程处理函数*/
void mainThread()
{
	int reuse=1;
	int i=0;
	signal(SIGPIPE,receivePipBroken);
/*------------------------SSL--------------------------------*/
  
//  SSL *ssl;
  char pwd[100];
  char* temp;
  /* SSL 库初始化 */
  SSL_library_init();
  /* 载入所有 SSL 算法 */
  OpenSSL_add_all_algorithms();
  /* 载入所有 SSL 错误消息 */
  SSL_load_error_strings();
  /* 以 SSL V2 和 V3 标准兼容方式产生一个 SSL_CTX ,即 SSL Content Text */
  ctx = SSL_CTX_new(SSLv23_server_method());
  /* 也可以用 SSLv2_server_method() 或 SSLv3_server_method() 单独表示 V2 或 V3标准 */
  if (ctx == NULL)
  {
    ERR_print_errors_fp(stdout);
    exit(1);
  }
  /* 载入用户的数字证书, 此证书用来发送给客户端。 证书里包含有公钥 */
  getcwd(pwd,100);
  if(strlen(pwd)==1)
    pwd[0]='\0';
  if (SSL_CTX_use_certificate_file(ctx, temp=strcat(pwd,"/cacert.pem"), SSL_FILETYPE_PEM) <= 0)
  {
    ERR_print_errors_fp(stdout);
    exit(1);
  }
  /* 载入用户私钥 */
  getcwd(pwd,100);
  if(strlen(pwd)==1)
    pwd[0]='\0';
  if (SSL_CTX_use_PrivateKey_file(ctx, temp=strcat(pwd,"/privkey.pem"), SSL_FILETYPE_PEM) <= 0)
  {
    ERR_print_errors_fp(stdout);
    exit(1);
  }
  /* 检查用户私钥是否正确 */
  if (!SSL_CTX_check_private_key(ctx))
  {
    ERR_print_errors_fp(stdout);
    exit(1);
  }
  
/*------------------------SSL--------------------------------*/
	
	if((sockfd=socket(AF_INET,SOCK_STREAM,0))<0)
	{
		fprintf(stderr,"\033[33mSocket error:%s\033[0m\n\a",strerror(errno));	
		exit(-1);
	}

	bzero(&server_addr,sizeof(struct sockaddr_in));
	server_addr.sin_family=AF_INET;
	server_addr.sin_addr.s_addr=htonl(INADDR_ANY);
	server_addr.sin_port=htons(portnumber);
	setsockopt(sockfd,SOL_SOCKET,SO_REUSEADDR,&reuse,sizeof(int));	
	if(bind(sockfd,(struct sockaddr*)(&server_addr),sizeof(struct sockaddr))<0)
	{
	   	fprintf(stderr,"\033[33mBind error:%s\033[0m\n\a",strerror(errno));
	    exit(1);		
	}
	
	if(listen(sockfd, MaxClientNum)==-1)
	{
	   	fprintf(stderr,"\033[33mListen error:%s\033[0m\n\a",strerror(errno));
	    exit(1);
	}	
	
	CreateThreadPool();   /*创建线程池*/
	
	
	while(1)
	{
		
		if(IsExit==1)						/*判断是否退出服务器*/
		{
			int i;
			printf("\033[31m\nclosing server\n\033[0m"); 

			for(i = 0;i < 60; i += 10)
			{
				printf("\033[31m.\033[0m");
				fflush(stdout);
				usleep(100000);
			}
			printf("\033[31m\nserver closed\n\033[0m");
			
			pthread_exit(0);	
		}	
		if(IsRun == 1)           /*判断服务器是否正常运行*/
		{
			if((new_fd = accept(sockfd,(struct sockaddr *)(&client_addr),&sin_size)) == -1)
			{
					perror("accept error!");
					exit(-1);
			}
			tempsockfd=new_fd;
			strcpy(clientIP,inet_ntoa(client_addr.sin_addr)); 				/*保存当前连接客服端IP*/
		 
//		  if((pthread_create(&id,NULL,(void *)process,&new_fd)) != 0)
//			{
//				printf("\033[33mCreate thread error!\033[0m\n");
//			}
//			 MoveToBusy(ThreadIdleId[]);
			 pthread_cond_signal(&pthreadCond);
//  		printf("11111111111111111111111111\n");		  
		}		
	}
		close(sockfd);
	/* 释放 CTX Start*/
  SSL_CTX_free(ctx);
  /* 释放 CTX End*/
	pthread_join(id,NULL);
}
Beispiel #9
0
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;
}
Beispiel #10
0
int main(int argc, char **argv)
{
  int sockfd, new_fd, fd;
  socklen_t len;
  struct sockaddr_in my_addr, their_addr;
  unsigned int myport, lisnum;
  char buf[MAXBUF + 1];
  char new_fileName[50]="./testfile/";
  SSL_CTX *ctx;
  mode_t mode;
  char pwd[100];
  char* temp;

  mkdir("./testfile",mode);

  if (argv[1])
    myport = atoi(argv[1]);
  else
  {
    myport = 7838;
    argv[2]=argv[3]=NULL;
  }

  if (argv[2])
    lisnum = atoi(argv[2]);
  else
  {
    lisnum = 2;
    argv[3]=NULL;
  }

  SSL_library_init();

  OpenSSL_add_all_algorithms();

  SSL_load_error_strings();

  ctx = SSL_CTX_new(SSLv23_server_method());

  if (ctx == NULL)
  {
    ERR_print_errors_fp(stdout);
    exit(1);
  }
  /* load certificate */
  getcwd(pwd,100);
  if(strlen(pwd)==1)
    pwd[0]='\0';
  if (SSL_CTX_use_certificate_file(ctx, temp=strcat(pwd,"/ca.pem"), SSL_FILETYPE_PEM) <= 0)
  {
    ERR_print_errors_fp(stdout);
    exit(1);
  }
  /* load private key */
  getcwd(pwd,100);
  if(strlen(pwd)==1)
    pwd[0]='\0';
  if (SSL_CTX_use_PrivateKey_file(ctx, temp=strcat(pwd,"/privkey.pem"), SSL_FILETYPE_PEM) <= 0)
  {
    ERR_print_errors_fp(stdout);
    exit(1);
  }

  if (!SSL_CTX_check_private_key(ctx))
  {
    ERR_print_errors_fp(stdout);
    exit(1);
  }

  if ((sockfd = socket(PF_INET, SOCK_STREAM, 0)) == -1)
  {
    perror("socket");
    exit(1);
  }
  else
    printf("socket created\n");

  bzero(&my_addr, sizeof(my_addr));
  my_addr.sin_family = PF_INET;
  my_addr.sin_port = htons(myport);
  if (argv[3])
    my_addr.sin_addr.s_addr = inet_addr(argv[3]);
  else
    my_addr.sin_addr.s_addr = INADDR_ANY;

  if (bind(sockfd, (struct sockaddr *) &my_addr, sizeof(struct sockaddr)) == -1)
  {
    perror("bind");
    exit(1);
  }
  else
    printf("binded\n");

  if (listen(sockfd, lisnum) == -1)
  {
    perror("listen");
    exit(1);
  }
  else
    printf("begin listen\n");

  while (1)
  {
    SSL *ssl;
    len = sizeof(struct sockaddr);
    /* connection from clients */
    if ((new_fd = accept(sockfd, (struct sockaddr *) &their_addr, &len)) == -1)
    {
      perror("accept");
      exit(errno);
    }
    else
    {
		printf("server: got connection from %s, port %d, socket %d\n", inet_ntoa(their_addr.sin_addr), ntohs(their_addr.sin_port), new_fd);
        //ShowCerts(ssl);
	}
    ssl = SSL_new(ctx);

    SSL_set_fd(ssl, new_fd);

    if (SSL_accept(ssl) == -1)
    {
      perror("accept");
      close(new_fd);
      break;
    }

    ShowCerts(ssl);
    while(1)
    {
      bzero(buf, MAXBUF + 1);
      len = SSL_read(ssl, buf, MAXBUF);
      if(len == 0)
      {
        printf("Receive Complete !\n");
        break;
      }
      else if(len < 0)
      {
        printf("Failure to receive message ! Error code is %d,Error messages are '%s'\n", errno, strerror(errno));
        exit(1);
      }
	
	printf("Received: %s \n",buf);
	SSL_write(ssl, buf, strlen(buf));
    }


    close(fd);

    SSL_shutdown(ssl);

    SSL_free(ssl);

    close(new_fd);
  }


  close(sockfd);
  SSL_CTX_free(ctx);
  
  return 0;
}
Beispiel #11
0
static apr_status_t
init_ssl_context(serv_ctx_t *serv_ctx,
                 const char *keyfile,
                 const char **certfiles,
                 const char *client_cn)
{
    ssl_context_t *ssl_ctx = apr_pcalloc(serv_ctx->pool, sizeof(*ssl_ctx));
    serv_ctx->ssl_ctx = ssl_ctx;
    serv_ctx->client_cn = client_cn;
    serv_ctx->bio_read_status = APR_SUCCESS;

    /* Init OpenSSL globally */
    if (!init_done)
    {
        CRYPTO_malloc_init();
        ERR_load_crypto_strings();
        SSL_load_error_strings();
        SSL_library_init();
        OpenSSL_add_all_algorithms();
        init_done = 1;
    }

    /* Init this connection */
    if (!ssl_ctx->ctx) {
        X509_STORE *store;
        const char *certfile;
        int i;
        int rv;

        ssl_ctx->ctx = SSL_CTX_new(SSLv23_server_method());
        SSL_CTX_set_default_passwd_cb(ssl_ctx->ctx, pem_passwd_cb);
        rv = SSL_CTX_use_PrivateKey_file(ssl_ctx->ctx, keyfile,
                                         SSL_FILETYPE_PEM);
        if (rv != 1) {
            fprintf(stderr, "Cannot load private key from file '%s'\n", keyfile);
            exit(1);
        }

        /* Set server certificate, add ca certificates if provided. */
        certfile = certfiles[0];
        rv = SSL_CTX_use_certificate_file(ssl_ctx->ctx, certfile, SSL_FILETYPE_PEM);
        if (rv != 1) {
            fprintf(stderr, "Cannot load certficate from file '%s'\n", keyfile);
            exit(1);
        }

        i = 1;
        certfile = certfiles[i++];
        store = SSL_CTX_get_cert_store(ssl_ctx->ctx);

        while(certfile) {
            FILE *fp = fopen(certfile, "r");
            if (fp) {
                X509 *ssl_cert = PEM_read_X509(fp, NULL, NULL, NULL);
                fclose(fp);

                SSL_CTX_add_extra_chain_cert(ssl_ctx->ctx, ssl_cert);

                X509_STORE_add_cert(store, ssl_cert);
            }
            certfile = certfiles[i++];
        }

        /* This makes the server send a client certificate request during
           handshake. The client certificate is optional (most tests don't
           send one) by default, but mandatory if client_cn was specified. */
        SSL_CTX_set_verify(ssl_ctx->ctx, SSL_VERIFY_PEER,
                           validate_client_certificate);

        SSL_CTX_set_mode(ssl_ctx->ctx, SSL_MODE_ENABLE_PARTIAL_WRITE);

        ssl_ctx->bio = BIO_new(&bio_apr_socket_method);
        ssl_ctx->bio->ptr = serv_ctx;
        init_ssl(serv_ctx);
    }

    return APR_SUCCESS;
}
Beispiel #12
0
boolean tls_accept(rdpTls* tls, const char* cert_file, const char* privatekey_file)
{
	CryptoCert cert;
	int connection_status;

	tls->ctx = SSL_CTX_new(SSLv23_server_method());

	if (tls->ctx == NULL)
	{
		printf("SSL_CTX_new failed\n");
		return false;
	}

	/*
	 * We only want SSLv3 and TLSv1, so disable SSLv2.
	 * SSLv3 is used by, eg. Microsoft RDC for Mac OS X.
	 */
	SSL_CTX_set_options(tls->ctx, SSL_OP_NO_SSLv2);

	if (SSL_CTX_use_RSAPrivateKey_file(tls->ctx, privatekey_file, SSL_FILETYPE_PEM) <= 0)
	{
		printf("SSL_CTX_use_RSAPrivateKey_file failed\n");
		return false;
	}

	tls->ssl = SSL_new(tls->ctx);

	if (tls->ssl == NULL)
	{
		printf("SSL_new failed\n");
		return false;
	}

	if (SSL_use_certificate_file(tls->ssl, cert_file, SSL_FILETYPE_PEM) <= 0)
	{
		printf("SSL_use_certificate_file failed\n");
		return false;
	}

	cert = tls_get_certificate(tls, false);

	if (cert == NULL)
	{
		printf("tls_connect: tls_get_certificate failed to return the server certificate.\n");
		return false;
	}

	if (!crypto_cert_get_public_key(cert, &tls->public_key))
	{
		printf("tls_connect: crypto_cert_get_public_key failed to return the server public key.\n");
		tls_free_certificate(cert);
		return false;
	}

	if (SSL_set_fd(tls->ssl, tls->sockfd) < 1)
	{
		printf("SSL_set_fd failed\n");
		return false;
	}

	connection_status = SSL_accept(tls->ssl);

	if (connection_status <= 0)
	{
		if (tls_print_error("SSL_accept", tls->ssl, connection_status))
			return false;
	}

	printf("TLS connection accepted\n");

	return true;
}
Beispiel #13
0
SSL_CTX *uwsgi_ssl_new_server_context(char *name, char *crt, char *key, char *ciphers, char *client_ca) {

        SSL_CTX *ctx = SSL_CTX_new(SSLv23_server_method());
        if (!ctx) {
                uwsgi_log("[uwsgi-ssl] unable to initialize context \"%s\"\n", name);
                return NULL;
        }

        // this part is taken from nginx and stud, removing unneeded functionality
        // stud (for me) has made the best choice on choosing DH approach

        long ssloptions = SSL_OP_NO_SSLv2 | SSL_OP_ALL | SSL_OP_NO_SESSION_RESUMPTION_ON_RENEGOTIATION;
// disable compression (if possibile)
#ifdef SSL_OP_NO_COMPRESSION
        ssloptions |= SSL_OP_NO_COMPRESSION;
#endif

// release/reuse buffers as soon as possibile
#ifdef SSL_MODE_RELEASE_BUFFERS
        SSL_CTX_set_mode(ctx, SSL_MODE_RELEASE_BUFFERS);
#endif

        if (SSL_CTX_use_certificate_chain_file(ctx, crt) <= 0) {
                uwsgi_log("[uwsgi-ssl] unable to assign certificate %s for context \"%s\"\n", crt, name);
                SSL_CTX_free(ctx);
                return NULL;
        }

// this part is based from stud
        BIO *bio = BIO_new_file(crt, "r");
        if (bio) {
                DH *dh = PEM_read_bio_DHparams(bio, NULL, NULL, NULL);
                BIO_free(bio);
                if (dh) {
                        SSL_CTX_set_tmp_dh(ctx, dh);
                        DH_free(dh);
#if OPENSSL_VERSION_NUMBER >= 0x0090800fL
#ifndef OPENSSL_NO_ECDH
#ifdef NID_X9_62_prime256v1
                        EC_KEY *ecdh = EC_KEY_new_by_curve_name(NID_X9_62_prime256v1);
                        SSL_CTX_set_tmp_ecdh(ctx, ecdh);
                        EC_KEY_free(ecdh);
#endif
#endif
#endif
                }
        }

        if (SSL_CTX_use_PrivateKey_file(ctx, key, SSL_FILETYPE_PEM) <= 0) {
                uwsgi_log("[uwsgi-ssl] unable to assign key %s for context \"%s\"\n", key, name);
                SSL_CTX_free(ctx);
                return NULL;
        }


	// if ciphers are specified, prefer server ciphers
        if (ciphers && strlen(ciphers) > 0) {
                if (SSL_CTX_set_cipher_list(ctx, ciphers) == 0) {
                        uwsgi_log("[uwsgi-ssl] unable to set requested ciphers (%s) for context \"%s\"\n", ciphers, name);
                        SSL_CTX_free(ctx);
                        return NULL;
                }

                ssloptions |= SSL_OP_CIPHER_SERVER_PREFERENCE;
        }

        // set session context (if possibile), this is required for client certificate authentication
        if (name) {
                SSL_CTX_set_session_id_context(ctx, (unsigned char *) name, strlen(name));
        }

        if (client_ca) {
                if (client_ca[0] == '!') {
                        SSL_CTX_set_verify(ctx, SSL_VERIFY_PEER | SSL_VERIFY_FAIL_IF_NO_PEER_CERT, uwsgi_ssl_verify_callback);
                        client_ca++;
                }
                else {
                        SSL_CTX_set_verify(ctx, SSL_VERIFY_PEER, uwsgi_ssl_verify_callback);
                }
                // in the future we should allow to set the verify depth
                SSL_CTX_set_verify_depth(ctx, 1);
                if (SSL_CTX_load_verify_locations(ctx, client_ca, NULL) == 0) {
                        uwsgi_log("[uwsgi-ssl] unable to set ssl verify locations (%s) for context \"%s\"\n", client_ca, name);
                        SSL_CTX_free(ctx);
                        return NULL;
                }
                STACK_OF(X509_NAME) * list = SSL_load_client_CA_file(client_ca);
                if (!list) {
                        uwsgi_log("unable to load client CA certificate (%s) for context \"%s\"\n", client_ca, name);
                        SSL_CTX_free(ctx);
                        return NULL;
                }

                SSL_CTX_set_client_CA_list(ctx, list);
        }


        SSL_CTX_set_info_callback(ctx, uwsgi_ssl_info_cb);
#ifdef SSL_CTRL_SET_TLSEXT_HOSTNAME
        SSL_CTX_set_tlsext_servername_callback(ctx, uwsgi_sni_cb);
#endif

        // disable session caching by default
        SSL_CTX_set_session_cache_mode(ctx, SSL_SESS_CACHE_OFF);

	if (uwsgi.ssl_sessions_use_cache) {

		// we need to early initialize locking and caching
		uwsgi_setup_locking();
		uwsgi_cache_create_all();

		uwsgi.ssl_sessions_cache = uwsgi_cache_by_name(uwsgi.ssl_sessions_use_cache);
		if (!uwsgi.ssl_sessions_cache) {
			// check for default cache
			if (!strcmp(uwsgi.ssl_sessions_use_cache, "true") && uwsgi.caches) {
				uwsgi.ssl_sessions_cache = uwsgi.caches;
			}
			else {
				uwsgi_log("unable to find cache \"%s\"\n", uwsgi.ssl_sessions_use_cache ? uwsgi.ssl_sessions_use_cache : "default");
				exit(1);
			}
		}

                if (!uwsgi.ssl_sessions_cache->max_items) {
                        uwsgi_log("you have to enable uWSGI cache to use it as SSL session store !!!\n");
                        exit(1);
                }

                if (uwsgi.ssl_sessions_cache->blocksize < 4096) {
                        uwsgi_log("cache blocksize for SSL session store must be at least 4096 bytes\n");
                        exit(1);
                }

                SSL_CTX_set_session_cache_mode(ctx, SSL_SESS_CACHE_SERVER|
                        SSL_SESS_CACHE_NO_INTERNAL|
                        SSL_SESS_CACHE_NO_AUTO_CLEAR);

#ifdef SSL_OP_NO_TICKET
                ssloptions |= SSL_OP_NO_TICKET;
#endif

                // just for fun
                SSL_CTX_sess_set_cache_size(ctx, 0);

                // set the callback for ssl sessions
                SSL_CTX_sess_set_new_cb(ctx, uwsgi_ssl_session_new_cb);
                SSL_CTX_sess_set_get_cb(ctx, uwsgi_ssl_session_get_cb);
                SSL_CTX_sess_set_remove_cb(ctx, uwsgi_ssl_session_remove_cb);
        }

        SSL_CTX_set_timeout(ctx, uwsgi.ssl_sessions_timeout);

        SSL_CTX_set_options(ctx, ssloptions);


        return ctx;
}
Beispiel #14
0
LWS_VISIBLE int
lws_context_init_server_ssl(struct lws_context_creation_info *info,
		     struct libwebsocket_context *context)
{
	SSL_METHOD *method;
	int error;
	int n;

	if (info->port != CONTEXT_PORT_NO_LISTEN) {

		context->use_ssl = info->ssl_cert_filepath != NULL;

#ifdef USE_CYASSL
		lwsl_notice(" Compiled with CYASSL support\n");
#else
		lwsl_notice(" Compiled with OpenSSL support\n");
#endif
		
		if (info->ssl_cipher_list)
			lwsl_notice(" SSL ciphers: '%s'\n", info->ssl_cipher_list);

		if (context->use_ssl)
			lwsl_notice(" Using SSL mode\n");
		else
			lwsl_notice(" Using non-SSL mode\n");
	}

	/* basic openssl init */

	SSL_library_init();

	OpenSSL_add_all_algorithms();
	SSL_load_error_strings();

	openssl_websocket_private_data_index =
		SSL_get_ex_new_index(0, "libwebsockets", NULL, NULL, NULL);

	/*
	 * 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->service_buffer));
		return 1;
	}
	context->ssl_ctx = SSL_CTX_new(method);	/* create context */
	if (!context->ssl_ctx) {
		error = ERR_get_error();
		lwsl_err("problem creating ssl context %lu: %s\n",
			error, ERR_error_string(error,
					      (char *)context->service_buffer));
		return 1;
	}

	/* Disable SSLv2 and SSLv3 */
	SSL_CTX_set_options(context->ssl_ctx, SSL_OP_NO_SSLv2 | SSL_OP_NO_SSLv3);
#ifdef SSL_OP_NO_COMPRESSION
	SSL_CTX_set_options(context->ssl_ctx, SSL_OP_NO_COMPRESSION);
#endif
	SSL_CTX_set_options(context->ssl_ctx, SSL_OP_CIPHER_SERVER_PREFERENCE);
	if (info->ssl_cipher_list)
		SSL_CTX_set_cipher_list(context->ssl_ctx,
						info->ssl_cipher_list);

	/* as a server, are we requiring clients to identify themselves? */

	if (info->options &
			LWS_SERVER_OPTION_REQUIRE_VALID_OPENSSL_CLIENT_CERT) {

		/* absolutely require the client cert */

		/*
		 * Must set session-id when using a client certificate, or
		 * ssl fails with a fatal error and the error code isn't
		 * helpful. It's a session caching issue.
 		 * The session ID must be unique per session, that's the only
		 * constraint on what you set it to. So, just use the context
		 * address as the session ID.
		 */
		SSL_CTX_set_session_id_context(context->ssl_ctx, (const unsigned char *)&context, sizeof(context));
		/*
		 * Kludge for Katena: Don't fail if there is no peer cert.
		 * FIX: Give that an API.
		 */
		SSL_CTX_set_verify(context->ssl_ctx,
		       SSL_VERIFY_PEER /* | SSL_VERIFY_FAIL_IF_NO_PEER_CERT */,
						       OpenSSL_verify_callback);

		/*
		 * give user code a chance to load certs into the server
		 * allowing it to verify incoming client certs
		 */

		context->protocols[0].callback(context, NULL,
			LWS_CALLBACK_OPENSSL_LOAD_EXTRA_SERVER_VERIFY_CERTS,
						     context->ssl_ctx, NULL, 0);
	}

	if (info->options & LWS_SERVER_OPTION_ALLOW_NON_SSL_ON_SSL_PORT) {
		/* Normally SSL listener rejects non-ssl, optionally allow */
		context->allow_non_ssl_on_ssl_port = 1;
	}

	if (context->use_ssl) {

		/* openssl init for server sockets */

		/* set the local certificate from CertFile */
		n = SSL_CTX_use_certificate_chain_file(context->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->service_buffer));
			return 1;
		}
		lws_ssl_bind_passphrase(context->ssl_ctx, info);

		if (info->ssl_private_key_filepath != NULL) {
			/* set the private key from KeyFile */
			if (SSL_CTX_use_PrivateKey_file(context->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->service_buffer));
				return 1;
			}
		}
		else {
			if (context->protocols[0].callback(context, NULL,
				LWS_CALLBACK_OPENSSL_CONTEXT_REQUIRES_PRIVATE_KEY,
						context->ssl_ctx, NULL, 0)) {
				lwsl_err("ssl private key not set\n");
				return 1;
			}
		}

		/* verify private key */
		if (!SSL_CTX_check_private_key(context->ssl_ctx)) {
			lwsl_err("Private SSL key doesn't match cert\n");
			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;
}
Beispiel #15
0
PUBLIC int sslOpen()
{
    RandBuf     randBuf;

    trace(7, "Initializing SSL"); 

    randBuf.now = time(0);
    randBuf.pid = getpid();
    RAND_seed((void*) &randBuf, sizeof(randBuf));
#if BIT_UNIX_LIKE
    trace(6, "OpenSsl: Before calling RAND_load_file");
    RAND_load_file("/dev/urandom", 256);
    trace(6, "OpenSsl: After calling RAND_load_file");
#endif

    CRYPTO_malloc_init(); 
#if !BIT_WIN_LIKE
    OpenSSL_add_all_algorithms();
#endif
    SSL_library_init();
    SSL_load_error_strings();
    SSLeay_add_ssl_algorithms();

    if ((sslctx = SSL_CTX_new(SSLv23_server_method())) == 0) {
        error("Unable to create SSL context"); 
        return -1;
    }

    /*
          Set the client certificate verification locations
     */
    if (*BIT_GOAHEAD_CA) {
        if ((!SSL_CTX_load_verify_locations(sslctx, BIT_GOAHEAD_CA, NULL)) || (!SSL_CTX_set_default_verify_paths(sslctx))) {
            error("Unable to read cert verification locations");
            sslClose();
            return -1;
        }
    }
    /*
          Set the server certificate and key files
     */
    if (*BIT_GOAHEAD_KEY && sslSetKeyFile(BIT_GOAHEAD_KEY) < 0) {
        sslClose();
        return -1;
    }
    if (*BIT_GOAHEAD_CERTIFICATE && sslSetCertFile(BIT_GOAHEAD_CERTIFICATE) < 0) {
        sslClose();
        return -1;
    }
    SSL_CTX_set_tmp_rsa_callback(sslctx, rsaCallback);

#if VERIFY_CLIENT
    if (verifyPeer) {
        SSL_CTX_set_verify(context, SSL_VERIFY_PEER | SSL_VERIFY_FAIL_IF_NO_PEER_CERT, verifyX509Certificate);
#if FUTURE && KEEP
        SSL_CTX_set_verify_depth(context, VERIFY_DEPTH);
#endif
    } else {
        SSL_CTX_set_verify(sslctx, SSL_VERIFY_NONE, verifyX509Certificate);
    }
#else
    SSL_CTX_set_verify(sslctx, SSL_VERIFY_NONE, verifyX509Certificate);
#endif
    /*
          Set the certificate authority list for the client
     */
    if (BIT_GOAHEAD_CA && *BIT_GOAHEAD_CA) {
        SSL_CTX_set_client_CA_list(sslctx, SSL_load_client_CA_file(BIT_GOAHEAD_CA));
    }
    SSL_CTX_set_cipher_list(sslctx, BIT_GOAHEAD_CIPHERS);
    SSL_CTX_set_options(sslctx, SSL_OP_ALL);
    SSL_CTX_sess_set_cache_size(sslctx, 128);
#ifdef SSL_OP_NO_TICKET
    SSL_CTX_set_options(sslctx, SSL_OP_NO_TICKET);
#endif
#ifdef SSL_OP_NO_SESSION_RESUMPTION_ON_RENEGOTIATION                                                       
    SSL_CTX_set_options(sslctx, SSL_OP_NO_SESSION_RESUMPTION_ON_RENEGOTIATION);
#endif                                                                                                     
    SSL_CTX_set_mode(sslctx, SSL_MODE_ENABLE_PARTIAL_WRITE | SSL_MODE_AUTO_RETRY);
    SSL_CTX_set_options(sslctx, SSL_OP_NO_SSLv2);

    /* 
        Ensure we generate a new private key for each connection
     */
    SSL_CTX_set_options(sslctx, SSL_OP_SINGLE_DH_USE);
    return 0;
}
Beispiel #16
0
/*
    Open the SSL module
 */
PUBLIC int sslOpen()
{
    RandBuf     randBuf;
    X509_STORE  *store;
    uchar       resume[16];
    char        *ciphers;

    trace(7, "Initializing SSL");

    randBuf.now = time(0);
    randBuf.pid = getpid();
    RAND_seed((void*) &randBuf, sizeof(randBuf));
#if ME_UNIX_LIKE
    trace(6, "OpenSsl: Before calling RAND_load_file");
    RAND_load_file("/dev/urandom", 256);
    trace(6, "OpenSsl: After calling RAND_load_file");
#endif

    CRYPTO_malloc_init();
#if !ME_WIN_LIKE
    OpenSSL_add_all_algorithms();
#endif
    SSL_library_init();
    SSL_load_error_strings();
    SSLeay_add_ssl_algorithms();

    if ((sslctx = SSL_CTX_new(SSLv23_server_method())) == 0) {
        error("Unable to create SSL context");
        return -1;
    }

    /*
          Set the server certificate and key files
     */
    if (*ME_GOAHEAD_SSL_KEY && sslSetKeyFile(ME_GOAHEAD_SSL_KEY) < 0) {
        sslClose();
        return -1;
    }
    if (*ME_GOAHEAD_SSL_CERTIFICATE && sslSetCertFile(ME_GOAHEAD_SSL_CERTIFICATE) < 0) {
        sslClose();
        return -1;
    }

    if (ME_GOAHEAD_SSL_VERIFY_PEER) {
        SSL_CTX_set_verify(sslctx, SSL_VERIFY_PEER | SSL_VERIFY_FAIL_IF_NO_PEER_CERT, verifyClientCertificate);
        SSL_CTX_set_verify_depth(sslctx, VERIFY_DEPTH);
    } else {
        SSL_CTX_set_verify(sslctx, SSL_VERIFY_NONE, verifyClientCertificate);
    }
    /*
          Set the client certificate verification locations
     */
    if (ME_GOAHEAD_SSL_AUTHORITY && *ME_GOAHEAD_SSL_AUTHORITY) {
        if ((!SSL_CTX_load_verify_locations(sslctx, ME_GOAHEAD_SSL_AUTHORITY, NULL)) ||
                (!SSL_CTX_set_default_verify_paths(sslctx))) {
            error("Unable to read cert verification locations");
            sslClose();
            return -1;
        }
        /*
            Define the list of CA certificates to send to the client before they send their client
            certificate for validation
         */
        SSL_CTX_set_client_CA_list(sslctx, SSL_load_client_CA_file(ME_GOAHEAD_SSL_AUTHORITY));
    }
    if (ME_GOAHEAD_SSL_REVOKE && *ME_GOAHEAD_SSL_REVOKE) {
        store = SSL_CTX_get_cert_store(sslctx);
        if (!X509_STORE_load_locations(store, ME_GOAHEAD_SSL_REVOKE, 0)) {
            error("Cannot load certificate revoke list: %s", ME_GOAHEAD_SSL_REVOKE);
            sslClose();
            return -1;
        }
    }

    /*
        Configure DH parameters
     */
    dhKey = getDhKey();
    SSL_CTX_set_tmp_dh_callback(sslctx, dhcallback);

    /*
        Configure cipher suite
     */
    if (ME_GOAHEAD_SSL_CIPHERS && *ME_GOAHEAD_SSL_CIPHERS) {
        ciphers = ME_GOAHEAD_SSL_CIPHERS;
    } else {
        ciphers = OPENSSL_DEFAULT_CIPHERS;
    }
    ciphers = mapCipherNames(ciphers);
    trace(5, "Using OpenSSL ciphers: %s", ciphers);
    if (SSL_CTX_set_cipher_list(sslctx, ciphers) != 1) {
        error("Unable to set cipher list \"%s\"", ciphers);
        sslClose();
        wfree(ciphers);
        return -1;
    }
    wfree(ciphers);

    /*
        Define default OpenSSL options
     */
    SSL_CTX_set_options(sslctx, SSL_OP_ALL);

    /*
        Ensure we generate a new private key for each connection
     */
    SSL_CTX_set_options(sslctx, SSL_OP_SINGLE_DH_USE);

    /*
        Define a session reuse context
     */
    RAND_bytes(resume, sizeof(resume));
    SSL_CTX_set_session_id_context(sslctx, resume, sizeof(resume));

    /*
        Elliptic Curve initialization
     */
#if SSL_OP_SINGLE_ECDH_USE
#ifdef SSL_CTX_set_ecdh_auto
    SSL_CTX_set_ecdh_auto(sslctx, 1);
#else
    {
        EC_KEY  *ecdh;
        cchar   *name;
        int      nid;

        name = ME_GOAHEAD_SSL_CURVE;
        if ((nid = OBJ_sn2nid(name)) == 0) {
            error("Unknown curve name \"%s\"", name);
            sslClose();
            return -1;
        }
        if ((ecdh = EC_KEY_new_by_curve_name(nid)) == 0) {
            error("Unable to create curve \"%s\"", name);
            sslClose();
            return -1;
        }
        SSL_CTX_set_options(sslctx, SSL_OP_SINGLE_ECDH_USE);
        SSL_CTX_set_tmp_ecdh(sslctx, ecdh);
        EC_KEY_free(ecdh);
    }
#endif
#endif

    SSL_CTX_set_mode(sslctx, SSL_MODE_ENABLE_PARTIAL_WRITE | SSL_MODE_AUTO_RETRY | SSL_MODE_ACCEPT_MOVING_WRITE_BUFFER);
#ifdef SSL_OP_MSIE_SSLV2_RSA_PADDING
    SSL_CTX_set_options(sslctx, SSL_OP_MSIE_SSLV2_RSA_PADDING);
#endif
#ifdef SSL_MODE_RELEASE_BUFFERS
    SSL_CTX_set_mode(sslctx, SSL_MODE_RELEASE_BUFFERS);
#endif
#ifdef SSL_OP_CIPHER_SERVER_PREFERENCE
    SSL_CTX_set_mode(sslctx, SSL_OP_CIPHER_SERVER_PREFERENCE);
#endif

    /*
        Select the required protocols
        Disable both SSLv2 and SSLv3 by default - they are insecure
     */
    SSL_CTX_set_options(sslctx, SSL_OP_NO_SSLv2);
    SSL_CTX_set_options(sslctx, SSL_OP_NO_SSLv3);

#if defined(SSL_OP_NO_TLSv1) && ME_GOAHEAD_SSL_NO_V1
    SSL_CTX_set_options(sslctx, SSL_OP_NO_TLSv1);
#endif
#if defined(SSL_OP_NO_TLSv1_1) && ME_GOAHEAD_SSL_NO_V1_1
    SSL_CTX_set_options(sslctx, SSL_OP_NO_TLSv1_1);
#endif
#if defined(SSL_OP_NO_TLSv1_2) && ME_GOAHEAD_SSL_NO_V1_2
    SSL_CTX_set_options(sslctx, SSL_OP_NO_TLSv1_2);
#endif


#if defined(SSL_OP_NO_TICKET)
    /*
        Ticket based session reuse is enabled by default
     */
#if defined(ME_GOAHEAD_SSL_TICKET)
    if (ME_GOAHEAD_SSL_TICKET) {
        SSL_CTX_clear_options(sslctx, SSL_OP_NO_TICKET);
    } else {
        SSL_CTX_set_options(sslctx, SSL_OP_NO_TICKET);
    }
#else
    SSL_CTX_clear_options(sslctx, SSL_OP_NO_TICKET);
#endif
#endif

#if defined(SSL_OP_NO_COMPRESSION)
    /*
        CRIME attack targets compression
     */
    SSL_CTX_clear_options(sslctx, SSL_OP_NO_COMPRESSION);
#endif

#if defined(SSL_OP_DONT_INSERT_EMPTY_FRAGMENTS)
    /*
        Disables a countermeasure against a SSL 3.0/TLS 1.0 protocol vulnerability affecting CBC ciphers.
        Defaults to true.
     */
#if defined(ME_GOAHEAD_SSL_EMPTY_FRAGMENTS)
    if (ME_GOAHEAD_SSL_EMPTY_FRAGMENTS) {
        /* SSL_OP_ALL disables empty fragments. Only needed for ancient browsers like IE-6 on SSL-3.0/TLS-1.0 */
        SSL_CTX_clear_options(sslctx, SSL_OP_DONT_INSERT_EMPTY_FRAGMENTS);
    } else {
        SSL_CTX_set_options(sslctx, SSL_OP_DONT_INSERT_EMPTY_FRAGMENTS);
    }
#else
    SSL_CTX_set_options(sslctx, SSL_OP_DONT_INSERT_EMPTY_FRAGMENTS);
#endif
#endif

#if defined(ME_GOAHEAD_SSL_CACHE)
    /*
        Set the number of sessions supported. Default in OpenSSL is 20K.
     */
    SSL_CTX_sess_set_cache_size(sslctx, ME_GOAHEAD_SSL_CACHE);
#else
    SSL_CTX_sess_set_cache_size(sslctx, 256);
#endif

    return 0;
}
Beispiel #17
0
/*
 * This starts a minimal TLS server that only does a
 * handshake and then closes the connection.  This is
 * strictly used to test TLS session negotiation
 * behavior with EST.
 */
static void us1060_start_tls_server (char *cipherstring)
{
    BIO *conn;
    BIO *listener;
    BIO *berr;
    char h_p[25];
    SSL *ssl;
    SSL_CTX *ssl_ctx = NULL;
    int nid, rv;
    EC_KEY *ecdh = NULL;

    berr = BIO_new_fp(stderr, BIO_NOCLOSE);

    ssl_ctx = SSL_CTX_new(SSLv23_server_method());
    if (!ssl_ctx) {
	printf("Failed to create SSL context\n");
	ERR_print_errors(berr);
	return;
    }

    SSL_CTX_set_mode(ssl_ctx, SSL_MODE_AUTO_RETRY);

    if (SSL_CTX_use_certificate_chain_file(ssl_ctx, US1060_RSA_CERT) != 1) {
	printf("Failed to load server certificate\n");
	ERR_print_errors(berr);
	return;
    }
    if (SSL_CTX_use_PrivateKey_file(ssl_ctx, US1060_RSA_KEY, SSL_FILETYPE_PEM) != 1) {
	printf("Failed to load server private key\n");
	ERR_print_errors(berr);
	return;
    }

    SSL_CTX_set_options(ssl_ctx, SSL_OP_NO_SSLv2 |
	                         SSL_OP_NO_SSLv3 |
				 SSL_OP_NO_TLSv1 |
                                 SSL_OP_SINGLE_ECDH_USE | 
				 SSL_OP_SINGLE_DH_USE |
			         SSL_OP_NO_TICKET);

    nid = OBJ_sn2nid("prime256v1");
    ecdh = EC_KEY_new_by_curve_name(nid);
    if (ecdh == NULL) {
	printf("Failed to retreive ECDH curve\n");
	ERR_print_errors(berr);
	return;
    }
    SSL_CTX_set_tmp_ecdh(ssl_ctx, ecdh);
    EC_KEY_free(ecdh);

    if (SSL_CTX_set_cipher_list(ssl_ctx, cipherstring) != 1) {
	printf("Failed to set server cipher list\n");
	ERR_print_errors(berr);
	return;
    }
    SSL_CTX_set_srp_username_callback(ssl_ctx, us1060_srp_cb);

    sprintf(h_p, "%s:%d", US1060_SERVER_IP, US1060_TLS_PORT);
    listener = BIO_new_accept(h_p);
    if (listener == NULL) {
	printf("IP connection failed\n");
	return;
    }
    BIO_set_bind_mode(listener, BIO_BIND_REUSEADDR);

    /*
     * The first call to do_accept binds the socket
     */
    if (BIO_do_accept(listener) <= 0) {
	printf("TCP bind failed\n");
	BIO_free_all(listener);
	return;
    }

    /*
     * The second call to do_accept waits for a new
     * connection request on the listener.
     * Note that we are in blocking mode for this socket
     */
    if (BIO_do_accept(listener) <= 0) {
	printf("TCP accept failed\n");
	BIO_free_all(listener);
	return;
    }
    conn = BIO_pop(listener);

    ssl = SSL_new(ssl_ctx);
    SSL_set_bio(ssl, conn, conn);
    /*
     * Now that we have everything ready, let's start waiting for
     * a client to contact us.  Normally we might using a pthread
     * or some other construct to avoid blocking on the main 
     * thread while waiting for an incoming connection.  This
     * code is simply a contrived example, we will wait on the
     * main thread for an incoming connection.
     */
    rv = SSL_accept(ssl);
    if (rv <= 0) {
	printf("\nFailed to complete TLS handshake %d\n", rv);
	ERR_print_errors(berr);
    }
    SSL_shutdown(ssl);
    SSL_free(ssl);
    SSL_CTX_free(ssl_ctx);
    BIO_free(berr);
    (void)BIO_reset(listener);
    BIO_free_all(listener);
    pthread_exit(0);
}
Beispiel #18
0
	/* basic openssl init */

	SSL_library_init();

	OpenSSL_add_all_algorithms();
	SSL_load_error_strings();

	openssl_websocket_private_data_index =
		SSL_get_ex_new_index(0, "libwebsockets", NULL, NULL, NULL);

	/*
	 * Firefox insists on SSLv23 not SSLv3
	 * Konq disables SSLv2 by default now, SSLv23 works
	 */

	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->service_buffer));
		return 1;
	}
	context->ssl_ctx = SSL_CTX_new(method);	/* create context */
	if (!context->ssl_ctx) {
		error = ERR_get_error();
		lwsl_err("problem creating ssl context %lu: %s\n",
			error, ERR_error_string(error,
					      (char *)context->service_buffer));
		return 1;
	}
Beispiel #19
0
static int tport_ws_init_primary_secure(tport_primary_t *pri,
				 tp_name_t tpn[1],
				 su_addrinfo_t *ai,
				 tagi_t const *tags,
				 char const **return_culprit)
{
  tport_ws_primary_t *wspri = (tport_ws_primary_t *)pri;
  const char *cert = "/ssl.pem";
  const char *key = "/ssl.pem";
  char *homedir;
  char *tbf = NULL;
  su_home_t autohome[SU_HOME_AUTO_SIZE(1024)];
  char const *path = NULL;
  int ret = -1;

  su_home_auto(autohome, sizeof autohome);

  tl_gets(tags,
	  TPTAG_CERTIFICATE_REF(path),
	  TAG_END());

  if (!path) {
    homedir = getenv("HOME");
    if (!homedir)
      homedir = "";
    path = tbf = su_sprintf(autohome, "%s/.sip/auth", homedir);
  }

  if (path) {
    key  = su_sprintf(autohome, "%s/%s", path, "wss.key");
	if (access(key, R_OK) != 0) key = NULL;
	cert = su_sprintf(autohome, "%s/%s", path, "wss.crt");
	if (access(cert, R_OK) != 0) cert = NULL;
	if ( !key )  key  = su_sprintf(autohome, "%s/%s", path, "wss.pem");
	if ( !cert ) cert = su_sprintf(autohome, "%s/%s", path, "wss.pem");
	if (access(key, R_OK) != 0) key = NULL;
	if (access(cert, R_OK) != 0) cert = NULL;
  }

  init_ssl();

  //  OpenSSL_add_all_algorithms();   /* load & register cryptos */                                                                                       
  //  SSL_load_error_strings();     /* load all error messages */                                                                                         
  wspri->ssl_method = SSLv23_server_method();   /* create server instance */
  wspri->ssl_ctx = SSL_CTX_new((SSL_METHOD *)wspri->ssl_method);         /* create context */
  SSL_CTX_sess_set_remove_cb(wspri->ssl_ctx, NULL);
  wspri->ws_secure = 1;

  if ( !wspri->ssl_ctx ) goto done;

  /* set the local certificate from CertFile */
  SSL_CTX_use_certificate_file(wspri->ssl_ctx, cert, SSL_FILETYPE_PEM);
  /* set the private key from KeyFile */
  SSL_CTX_use_PrivateKey_file(wspri->ssl_ctx, key, SSL_FILETYPE_PEM);
  /* verify private key */
  if ( !SSL_CTX_check_private_key(wspri->ssl_ctx) ) {
	  goto done;
  }

  SSL_CTX_set_cipher_list(wspri->ssl_ctx, "HIGH:!DSS:!aNULL@STRENGTH");

  ret = tport_ws_init_primary(pri, tpn, ai, tags, return_culprit);

 done:
  su_home_zap(autohome);
  return ret;
}
Beispiel #20
0
static int _tnet_transport_ssl_init(tnet_transport_t* transport)
{
    if (!transport){
        TSK_DEBUG_ERROR("Invalid parameter");
        return -1;
    }
#if HAVE_OPENSSL
    {
        tnet_socket_type_t type = tnet_transport_get_type(transport);
        tsk_bool_t is_tls = (TNET_SOCKET_TYPE_IS_TLS(type) || TNET_SOCKET_TYPE_IS_WSS(type));
        tsk_bool_t is_dtls = transport->dtls.enabled/* TNET_SOCKET_TYPE_IS_DTLS(type)*/; // DTLS-RTP, not raw DTLS
        if (is_dtls && !tnet_dtls_is_supported()){
            TSK_DEBUG_ERROR("Requesting to create DTLS transport but source code not built with support for this feature");
            return -1;
        }
        if (is_tls && !tnet_tls_is_supported()){
            TSK_DEBUG_ERROR("Requesting to create TLS transport but source code not built with support for this feature");
            return -1;
        }
        if ((transport->tls.enabled = is_tls)){
            if (!transport->tls.ctx_client && !(transport->tls.ctx_client = SSL_CTX_new(SSLv23_client_method()))){
                TSK_DEBUG_ERROR("Failed to create SSL client context");
                return -2;
            }
            if (!transport->tls.ctx_server && !(transport->tls.ctx_server = SSL_CTX_new(SSLv23_server_method()))){
                TSK_DEBUG_ERROR("Failed to create SSL server context");
                return -3;
            }
            SSL_CTX_set_mode(transport->tls.ctx_client, SSL_MODE_AUTO_RETRY);
            SSL_CTX_set_mode(transport->tls.ctx_server, SSL_MODE_AUTO_RETRY);
            SSL_CTX_set_verify(transport->tls.ctx_server, SSL_VERIFY_NONE, tsk_null); // to be updated by tnet_transport_tls_set_certs()
            SSL_CTX_set_verify(transport->tls.ctx_client, SSL_VERIFY_NONE, tsk_null); // to be updated by tnet_transport_tls_set_certs()
            if (SSL_CTX_set_cipher_list(transport->tls.ctx_client, TNET_CIPHER_LIST) <= 0 || SSL_CTX_set_cipher_list(transport->tls.ctx_server, TNET_CIPHER_LIST) <= 0){
                TSK_DEBUG_ERROR("SSL_CTX_set_cipher_list failed [%s]", ERR_error_string(ERR_get_error(), tsk_null));
                return -4;
            }
        }
#if HAVE_OPENSSL_DTLS
		if ((transport->dtls.enabled = is_dtls)){
			if (!transport->dtls.ctx && !(transport->dtls.ctx = SSL_CTX_new(DTLSv1_method()))){
				TSK_DEBUG_ERROR("Failed to create DTLSv1 context");
				TSK_OBJECT_SAFE_FREE(transport);
				return -5;
			}
			SSL_CTX_set_read_ahead(transport->dtls.ctx, 1);
			// SSL_CTX_set_options(transport->dtls.ctx, SSL_OP_ALL);
			// SSL_CTX_set_mode(transport->dtls.ctx, SSL_MODE_AUTO_RETRY);
			SSL_CTX_set_verify(transport->dtls.ctx, SSL_VERIFY_PEER | SSL_VERIFY_FAIL_IF_NO_PEER_CERT, tsk_null); // to be updated by tnet_transport_tls_set_certs()
			if (SSL_CTX_set_cipher_list(transport->dtls.ctx, TNET_CIPHER_LIST) <= 0){
				TSK_DEBUG_ERROR("SSL_CTX_set_cipher_list failed [%s]", ERR_error_string(ERR_get_error(), tsk_null));
				return -6;
			}
			//!\ This is required even if the local transport is TCP/TLS because the relayed (TURN) transport could be UDP
			// Up to the DTLS socket to set the default MTU value
			SSL_CTX_set_options(transport->dtls.ctx, SSL_OP_NO_QUERY_MTU);
			SSL_CTX_ctrl(transport->dtls.ctx, SSL_CTRL_SET_MTU, TNET_DTLS_MTU - 28, NULL);
			
			transport->dtls.activated = tsk_true;
		}
#endif /* HAVE_OPENSSL_DTLS */
    }
#endif /* HAVE_OPENSSL */
    
    return 0;
}
Beispiel #21
0
bud_error_t bud_config_new_ssl_ctx(bud_config_t* config,
                                   bud_context_t* context) {
  SSL_CTX* ctx;
  bud_error_t err;
  int options;

  /* Choose method, tlsv1_2 by default */
  if (config->frontend.method == NULL) {
    if (strcmp(config->frontend.security, "tls1.1") == 0)
      config->frontend.method = TLSv1_1_server_method();
    else if (strcmp(config->frontend.security, "tls1.0") == 0)
      config->frontend.method = TLSv1_server_method();
    else if (strcmp(config->frontend.security, "tls1.2") == 0)
      config->frontend.method = TLSv1_2_server_method();
    else if (strcmp(config->frontend.security, "ssl3") == 0)
      config->frontend.method = SSLv3_server_method();
    else
      config->frontend.method = SSLv23_server_method();
  }

  ctx = SSL_CTX_new(config->frontend.method);
  if (ctx == NULL)
    return bud_error_str(kBudErrNoMem, "SSL_CTX");
  SSL_CTX_set_session_cache_mode(ctx,
                                 SSL_SESS_CACHE_SERVER |
                                 SSL_SESS_CACHE_NO_INTERNAL |
                                 SSL_SESS_CACHE_NO_AUTO_CLEAR);
  if (context->ciphers != NULL)
    SSL_CTX_set_cipher_list(ctx, context->ciphers);
  else if (config->frontend.ciphers != NULL)
    SSL_CTX_set_cipher_list(ctx, config->frontend.ciphers);

  /* Disable SSL2 */
  options = SSL_OP_NO_SSLv2 | SSL_OP_ALL;
  if (!config->frontend.ssl3)
    options |= SSL_OP_NO_SSLv3;

  if (config->frontend.server_preference)
    options |= SSL_OP_CIPHER_SERVER_PREFERENCE;
  SSL_CTX_set_options(ctx, options);

#ifdef SSL_CTRL_SET_TLSEXT_SERVERNAME_CB
  if (config->context_count != 0) {
    SSL_CTX_set_tlsext_servername_callback(ctx,
                                           bud_config_select_sni_context);
    SSL_CTX_set_tlsext_servername_arg(ctx, config);
  }
#endif  /* SSL_CTRL_SET_TLSEXT_SERVERNAME_CB */

#ifdef OPENSSL_NPN_NEGOTIATED
  context->npn_line = bud_config_encode_npn(config,
                                            context->npn,
                                            &context->npn_line_len,
                                            &err);
  if (!bud_is_ok(err))
    goto fatal;

  if (context->npn_line != NULL) {
    SSL_CTX_set_next_protos_advertised_cb(ctx,
                                          bud_config_advertise_next_proto,
                                          context);
  }
#else  /* !OPENSSL_NPN_NEGOTIATED */
  err = bud_error(kBudErrNPNNotSupported);
  goto fatal;
#endif  /* OPENSSL_NPN_NEGOTIATED */

  SSL_CTX_set_tlsext_status_cb(ctx, bud_client_stapling_cb);

  context->ctx = ctx;
  return bud_ok();

fatal:
  SSL_CTX_free(ctx);
  return err;
}
Beispiel #22
0
    SSL_CTX *
tls_server_setup( int authlevel, const char *caFile,
	const char *caDir, const char *cert, const char *privatekey,
	const char *ciphers )
{
    SSL_CTX		*ssl_ctx;
    int                 ssl_mode = 0;
    static unsigned char dh4096_p[ ] = {
	0x91, 0x6B, 0xA1, 0x6D, 0xC7, 0xE7, 0x1C, 0x21, 0x69, 0xCE, 0x7C, 0x3D,
	0x72, 0x28, 0x01, 0x56, 0xAE, 0x71, 0xFE, 0xEF, 0x29, 0x4B, 0xDC, 0xD1,
	0x23, 0x37, 0x9E, 0xA5, 0x80, 0x45, 0xEF, 0x51, 0x7A, 0x65, 0x77, 0x41,
	0x90, 0x5D, 0xEA, 0xAB, 0x52, 0x39, 0xF0, 0xE1, 0xA9, 0x77, 0xA1, 0xCD,
	0x14, 0xB1, 0x8B, 0x07, 0x4F, 0xC5, 0x44, 0xD9, 0x2F, 0x7A, 0x74, 0xFD,
	0xBB, 0xEA, 0x6C, 0x4A, 0x22, 0xD0, 0x78, 0xCA, 0xCF, 0x51, 0x04, 0x0E,
	0x88, 0x44, 0x65, 0x41, 0xD9, 0x10, 0x6A, 0x11, 0x66, 0x21, 0x0E, 0xE7,
	0x9B, 0x39, 0x36, 0xF6, 0x59, 0x15, 0x83, 0xFB, 0x57, 0x51, 0x02, 0xE2,
	0x95, 0xBE, 0x85, 0xDA, 0x78, 0x40, 0xC1, 0x9A, 0x0A, 0xE6, 0x43, 0x95,
	0xD8, 0x7A, 0x30, 0x50, 0x15, 0x9F, 0x37, 0x5E, 0xAA, 0x27, 0x50, 0xA4,
	0x15, 0x1C, 0x6E, 0xFE, 0x3B, 0xA5, 0xD9, 0xF6, 0x0F, 0xE3, 0xA5, 0xFF,
	0xE7, 0xDA, 0xD9, 0x68, 0x64, 0x40, 0xF3, 0x54, 0x32, 0x84, 0xF3, 0x12,
	0xC4, 0xD3, 0x77, 0x25, 0x00, 0x60, 0x0D, 0x95, 0xEA, 0x16, 0xE0, 0x51,
	0x91, 0x8F, 0xF4, 0x40, 0x1B, 0x8A, 0x2D, 0x84, 0x0E, 0xAC, 0x53, 0x58,
	0x08, 0x4E, 0x52, 0xC8, 0xE4, 0x6E, 0xA1, 0xCB, 0xA6, 0xF8, 0x3B, 0xE0,
	0x1F, 0x35, 0xA6, 0x37, 0x6A, 0x62, 0x61, 0xDE, 0x6D, 0x5A, 0x70, 0x70,
	0x71, 0xC9, 0x24, 0x41, 0x70, 0x7C, 0xCD, 0x3F, 0xD9, 0x38, 0xDB, 0x7B,
	0x26, 0xFA, 0xB5, 0x6B, 0xAC, 0xF0, 0x2D, 0x45, 0xD8, 0x55, 0x68, 0xCB,
	0x89, 0x04, 0x1F, 0xA0, 0xAD, 0x6F, 0xCB, 0x05, 0x04, 0xB3, 0x26, 0xF4,
	0x53, 0x02, 0x9E, 0xB8, 0x76, 0x8D, 0xC6, 0xE8, 0x12, 0x24, 0x38, 0x4E,
	0x46, 0x27, 0x30, 0xAE, 0x55, 0x1A, 0xD0, 0xDB, 0xCE, 0x4C, 0x35, 0xFA,
	0x7D, 0x9D, 0x40, 0x3E, 0x66, 0x7A, 0xBA, 0xEA, 0x78, 0x6C, 0x6E, 0x47,
	0x81, 0xBD, 0xB0, 0x57, 0x5D, 0x1C, 0x94, 0xCC, 0x4F, 0x08, 0xF3, 0x5E,
	0xB1, 0x6E, 0x0B, 0xD5, 0x55, 0x45, 0x3F, 0x8B, 0xFD, 0x01, 0x4E, 0x01,
	0x21, 0x34, 0x20, 0xA8, 0x49, 0xB0, 0x75, 0x40, 0xB4, 0x55, 0x17, 0x3A,
	0x55, 0x1E, 0xBA, 0xF2, 0x31, 0x1D, 0x89, 0x81, 0x7A, 0xB3, 0x87, 0xC9,
	0xFB, 0xBB, 0x8A, 0x26, 0x66, 0x99, 0x19, 0x7E, 0x3C, 0xB1, 0x6A, 0x9A,
	0x4A, 0xDC, 0xE9, 0x3C, 0xF0, 0x7C, 0x29, 0xC9, 0xA1, 0xE1, 0x78, 0x3A,
	0x73, 0x8F, 0xEF, 0x2B, 0x33, 0xDF, 0x0C, 0x53, 0xCE, 0x98, 0x91, 0x7C,
	0xE3, 0xC9, 0xE2, 0x26, 0xD8, 0x2F, 0x1A, 0x69, 0xCA, 0xB8, 0x64, 0x3B,
	0x43, 0x38, 0xBB, 0xFA, 0x89, 0x59, 0xE0, 0x3C, 0xDA, 0xED, 0x93, 0x65,
	0x8B, 0x12, 0xED, 0xDB, 0x6F, 0x8F, 0xC5, 0xFE, 0x9C, 0xEB, 0x88, 0xD2,
	0xAB, 0x89, 0xAF, 0xAF, 0x60, 0xFF, 0xFC, 0x40, 0x69, 0x3C, 0xD0, 0x22,
	0x02, 0xB8, 0x2C, 0x1D, 0x9A, 0x26, 0x19, 0x33, 0xCB, 0x5A, 0x9D, 0x91,
	0xDD, 0x05, 0x39, 0x68, 0xBA, 0x15, 0x2B, 0x14, 0xFD, 0x5D, 0xB8, 0x87,
	0x90, 0xAF, 0xAA, 0x5F, 0x54, 0xC7, 0x43, 0x04, 0xF4, 0xE1, 0x49, 0x91,
	0x42, 0x27, 0x23, 0xCC, 0x5A, 0xFC, 0xF1, 0xA6, 0x2A, 0x39, 0x19, 0xC1,
	0x31, 0xBF, 0xE5, 0x89, 0x8C, 0x48, 0xA7, 0xCE, 0x0E, 0x67, 0x18, 0xA1,
	0x07, 0x8E, 0xBD, 0xFE, 0x2A, 0x9F, 0xF0, 0xA3, 0x19, 0xAA, 0xBC, 0xD7,
	0x6D, 0x43, 0x1C, 0x3D, 0x31, 0xBA, 0x9B, 0xD4, 0xF7, 0xDF, 0x2C, 0x7F,
	0x37, 0x7B, 0xD9, 0x7B, 0xDE, 0x62, 0x5C, 0xDE, 0x21, 0x38, 0x4D, 0xB7,
	0x4A, 0x45, 0x04, 0x7D, 0x76, 0x4A, 0x93, 0xFE, 0x8E, 0x49, 0x04, 0xD0,
	0xAD, 0x99, 0xCD, 0xF0, 0x86, 0x24, 0x5E, 0x73, };
    static unsigned char    dh4096_g[ ] = { 0x02, };
    DH			*dh = NULL;

    /* OpenSSL 1.1.0 added auto-init */
#if OPENSSL_VERSION_NUMBER < 0x10100000L || defined(LIBRESSL_VERSION_NUMBER)
    SSL_load_error_strings();
    SSL_library_init();
#endif /* OpenSSL < 1.1.0 */

    if (( ssl_ctx = SSL_CTX_new( SSLv23_server_method())) == NULL ) {
	syslog( LOG_ERR, "Liberror: tls_server_setup SSL_CTX_new: %s",
		ERR_error_string( ERR_get_error(), NULL ));
	return( NULL );
    }

    if (( dh = DH_new( )) == NULL ) {
	syslog( LOG_ERR, "Liberror: tls_server_setup DH_new: %s",
		ERR_error_string( ERR_get_error(), NULL ));
	goto error;
    }

#if OPENSSL_VERSION_NUMBER >= 0x10100000L && !defined(LIBRESSL_VERSION_NUMBER)
    if ( DH_set0_pqg( dh,
	    BN_bin2bn( dh4096_p, sizeof( dh4096_p ), NULL ),
	    NULL,
	    BN_bin2bn( dh4096_g, sizeof( dh4096_g ), NULL )) != 1 ) {
	syslog( LOG_ERR, "Liberror: tls_server_setup DH_set0_pqg: %s",
		ERR_error_string( ERR_get_error(), NULL ));
    }
#else
    dh->p = BN_bin2bn( dh4096_p, sizeof( dh4096_p ), NULL );
    dh->g = BN_bin2bn( dh4096_g, sizeof( dh4096_g ), NULL );
    if (( dh->p == NULL ) || ( dh->g == NULL )) {
	syslog( LOG_ERR, "Liberror: tls_server_setup BN_bin2bn: %s",
		ERR_error_string( ERR_get_error(), NULL ));
        goto error;
    }
#endif /* OpenSSL 1.1.0 */

    if ( SSL_CTX_set_tmp_dh( ssl_ctx, dh ) != 1 ) {
	syslog( LOG_ERR, "Liberror: tls_server_setup SSL_CTX_set_tmp_dh: %s",
		ERR_error_string( ERR_get_error(), NULL ));
	goto error;
    }

    /* Disable SSLv2 and SSLv3, prefer server cipher ordering */
    SSL_CTX_set_options( ssl_ctx,
	    SSL_OP_NO_SSLv2 | SSL_OP_NO_SSLv3 |
	    SSL_OP_CIPHER_SERVER_PREFERENCE );

    if ( ciphers == NULL ) {
	SSL_CTX_set_cipher_list( ssl_ctx,
		"EECDH+CHACHA20:EECDH+AES128:RSA+AES128:EECDH+AES256:"
		"RSA+AES256:DH+CHACHA20:DH+AES128:DH+AES256:!MD5" );
    } else {
	SSL_CTX_set_cipher_list( ssl_ctx, ciphers );
    }

    if ( SSL_CTX_use_PrivateKey_file( ssl_ctx, privatekey,
	    SSL_FILETYPE_PEM ) != 1 ) {
	syslog( LOG_ERR, "Liberror: tls_server_setup "
		"SSL_CTX_use_PrivateKey_file: %s: %s",
		privatekey, ERR_error_string( ERR_get_error(), NULL ));
	goto error;
    }
    if ( SSL_CTX_use_certificate_chain_file( ssl_ctx, cert ) != 1 ) {
	syslog( LOG_ERR, "Liberror: tls_server_setup "
		"SSL_CTX_use_certificate_chain_file: %s: %s",
		cert, ERR_error_string( ERR_get_error(), NULL ));
	goto error;
    }
    /* Verify that private key matches cert */
    if ( SSL_CTX_check_private_key( ssl_ctx ) != 1 ) {
	syslog( LOG_ERR, "Liberror: tls_server_setup "
		"SSL_CTX_check_private_key: %s",
		ERR_error_string( ERR_get_error(), NULL ));
	goto error;
    }

    /* Load CA */
    if ( caFile != NULL ) {
	if ( SSL_CTX_load_verify_locations( ssl_ctx, caFile, NULL ) != 1 ) {
	    syslog( LOG_ERR, "Liberror: tls_server_setup "
		    "SSL_CTX_load_verify_locations: %s: %s",
		    caFile, ERR_error_string( ERR_get_error(), NULL ));
	    goto error;
	}
    }
    if ( caDir != NULL ) {
	if ( SSL_CTX_load_verify_locations( ssl_ctx, NULL, caDir ) != 1 ) {
	    syslog( LOG_ERR, "Liberror: tls_server_setup "
		    "SSL_CTX_load_verify_locations: %s: %s",
		    caDir, ERR_error_string( ERR_get_error(), NULL ));
	    goto error;
	}
    }

    /* Set level of security expecations */
    if ( authlevel <= 1 ) {
	ssl_mode = SSL_VERIFY_NONE;
    } else {
	/* authlevel == 2 */
	ssl_mode = SSL_VERIFY_PEER | SSL_VERIFY_FAIL_IF_NO_PEER_CERT;
    }
    SSL_CTX_set_verify( ssl_ctx, ssl_mode, NULL );

#ifndef OPENSSL_NO_ECDH
    /* Do not reuse the same ECDH key pair */
    SSL_CTX_set_options(ssl_ctx, SSL_OP_SINGLE_ECDH_USE);

#if defined(OPENSSL_IS_BORINGSSL) || (OPENSSL_VERSION_NUMBER >= 0x10100000L && !defined(LIBRESSL_VERSION_NUMBER))
    /* OpenSSL >= 1.1.0 automatically enables automatic handling of parameter
     * selection and makes SSL_CTX_set_ecdh_auto a noop, so we don't want
     * to do anything.
     */
#elif OPENSSL_VERSION_NUMBER >= 0x10002000L
    /* OpenSSL >= 1.0.2 automatically handles parameter selection */
    SSL_CTX_set_ecdh_auto(ssl_ctx, 1);

#elif OPENSSL_VERSION_NUMBER >= 0x10000000L
    /* Manually select the curve. This selection is compliant with RFC 6460
     * when AES-256 cipher suites are in use, but noncompliant when AES-128
     * cipher suites are used. Oh, well. */
    EC_KEY *ecdh;
    if (( ecdh = EC_KEY_new_by_curve_name( NID_secp384r1 )) != NULL ) {
	SSL_CTX_set_tmp_ecdh(ssl_ctx, ecdh);
	EC_KEY_free(ecdh);
    } else {
	syslog( LOG_ERR, "Liberror: tls_server_setup EC_KEY_new failed: %s",
		ERR_error_string( ERR_get_error(), NULL ));
    }
#endif /* openssl 1.0 - 1.0.1 */
#endif /* OPENSSL_NO_ECDH */

    return( ssl_ctx );

    error:
    SSL_CTX_free( ssl_ctx );
    if ( dh != NULL ) {
	DH_free( dh );
    }
    return( NULL );
}
Beispiel #23
0
int network_init(server *srv) {
	buffer *b;
	size_t i, j;
	network_backend_t backend;

#if OPENSSL_VERSION_NUMBER >= 0x0090800fL
#ifndef OPENSSL_NO_ECDH
	EC_KEY *ecdh;
	int nid;
#endif
#endif

#ifdef USE_OPENSSL
# ifndef OPENSSL_NO_DH
	DH *dh;
# endif
	BIO *bio;

       /* 1024-bit MODP Group with 160-bit prime order subgroup (RFC5114)
	* -----BEGIN DH PARAMETERS-----
	* MIIBDAKBgQCxC4+WoIDgHd6S3l6uXVTsUsmfvPsGo8aaap3KUtI7YWBz4oZ1oj0Y
	* mDjvHi7mUsAT7LSuqQYRIySXXDzUm4O/rMvdfZDEvXCYSI6cIZpzck7/1vrlZEc4
	* +qMaT/VbzMChUa9fDci0vUW/N982XBpl5oz9p21NpwjfH7K8LkpDcQKBgQCk0cvV
	* w/00EmdlpELvuZkF+BBN0lisUH/WQGz/FCZtMSZv6h5cQVZLd35pD1UE8hMWAhe0
	* sBuIal6RVH+eJ0n01/vX07mpLuGQnQ0iY/gKdqaiTAh6CR9THb8KAWm2oorWYqTR
	* jnOvoy13nVkY0IvIhY9Nzvl8KiSFXm7rIrOy5QICAKA=
	* -----END DH PARAMETERS-----
	*/

	static const unsigned char dh1024_p[]={
		0xB1,0x0B,0x8F,0x96,0xA0,0x80,0xE0,0x1D,0xDE,0x92,0xDE,0x5E,
		0xAE,0x5D,0x54,0xEC,0x52,0xC9,0x9F,0xBC,0xFB,0x06,0xA3,0xC6,
		0x9A,0x6A,0x9D,0xCA,0x52,0xD2,0x3B,0x61,0x60,0x73,0xE2,0x86,
		0x75,0xA2,0x3D,0x18,0x98,0x38,0xEF,0x1E,0x2E,0xE6,0x52,0xC0,
		0x13,0xEC,0xB4,0xAE,0xA9,0x06,0x11,0x23,0x24,0x97,0x5C,0x3C,
		0xD4,0x9B,0x83,0xBF,0xAC,0xCB,0xDD,0x7D,0x90,0xC4,0xBD,0x70,
		0x98,0x48,0x8E,0x9C,0x21,0x9A,0x73,0x72,0x4E,0xFF,0xD6,0xFA,
		0xE5,0x64,0x47,0x38,0xFA,0xA3,0x1A,0x4F,0xF5,0x5B,0xCC,0xC0,
		0xA1,0x51,0xAF,0x5F,0x0D,0xC8,0xB4,0xBD,0x45,0xBF,0x37,0xDF,
		0x36,0x5C,0x1A,0x65,0xE6,0x8C,0xFD,0xA7,0x6D,0x4D,0xA7,0x08,
		0xDF,0x1F,0xB2,0xBC,0x2E,0x4A,0x43,0x71,
	};

	static const unsigned char dh1024_g[]={
		0xA4,0xD1,0xCB,0xD5,0xC3,0xFD,0x34,0x12,0x67,0x65,0xA4,0x42,
		0xEF,0xB9,0x99,0x05,0xF8,0x10,0x4D,0xD2,0x58,0xAC,0x50,0x7F,
		0xD6,0x40,0x6C,0xFF,0x14,0x26,0x6D,0x31,0x26,0x6F,0xEA,0x1E,
		0x5C,0x41,0x56,0x4B,0x77,0x7E,0x69,0x0F,0x55,0x04,0xF2,0x13,
		0x16,0x02,0x17,0xB4,0xB0,0x1B,0x88,0x6A,0x5E,0x91,0x54,0x7F,
		0x9E,0x27,0x49,0xF4,0xD7,0xFB,0xD7,0xD3,0xB9,0xA9,0x2E,0xE1,
		0x90,0x9D,0x0D,0x22,0x63,0xF8,0x0A,0x76,0xA6,0xA2,0x4C,0x08,
		0x7A,0x09,0x1F,0x53,0x1D,0xBF,0x0A,0x01,0x69,0xB6,0xA2,0x8A,
		0xD6,0x62,0xA4,0xD1,0x8E,0x73,0xAF,0xA3,0x2D,0x77,0x9D,0x59,
		0x18,0xD0,0x8B,0xC8,0x85,0x8F,0x4D,0xCE,0xF9,0x7C,0x2A,0x24,
		0x85,0x5E,0x6E,0xEB,0x22,0xB3,0xB2,0xE5,
	};
#endif

	struct nb_map {
		network_backend_t nb;
		const char *name;
	} network_backends[] = {
		/* lowest id wins */
#if defined USE_SENDFILE
		{ NETWORK_BACKEND_SENDFILE,   "sendfile" },
#endif
#if defined USE_LINUX_SENDFILE
		{ NETWORK_BACKEND_SENDFILE,   "linux-sendfile" },
#endif
#if defined USE_FREEBSD_SENDFILE
		{ NETWORK_BACKEND_SENDFILE,   "freebsd-sendfile" },
#endif
#if defined USE_SOLARIS_SENDFILEV
		{ NETWORK_BACKEND_SENDFILE,   "solaris-sendfilev" },
#endif
#if defined USE_WRITEV
		{ NETWORK_BACKEND_WRITEV,     "writev" },
#endif
		{ NETWORK_BACKEND_WRITE,      "write" },
		{ NETWORK_BACKEND_UNSET,       NULL }
	};

#ifdef USE_OPENSSL
	/* load SSL certificates */
	for (i = 0; i < srv->config_context->used; i++) {
		specific_config *s = srv->config_storage[i];
#ifndef SSL_OP_NO_COMPRESSION
# define SSL_OP_NO_COMPRESSION 0
#endif
		long ssloptions =
			SSL_OP_ALL | SSL_OP_NO_SESSION_RESUMPTION_ON_RENEGOTIATION | SSL_OP_NO_COMPRESSION;

		if (buffer_string_is_empty(s->ssl_pemfile) && buffer_string_is_empty(s->ssl_ca_file)) continue;

		if (srv->ssl_is_init == 0) {
			SSL_load_error_strings();
			SSL_library_init();
			OpenSSL_add_all_algorithms();
			srv->ssl_is_init = 1;

			if (0 == RAND_status()) {
				log_error_write(srv, __FILE__, __LINE__, "ss", "SSL:",
						"not enough entropy in the pool");
				return -1;
			}
		}

		if (!buffer_string_is_empty(s->ssl_pemfile)) {
#ifdef OPENSSL_NO_TLSEXT
			data_config *dc = (data_config *)srv->config_context->data[i];
			if (COMP_HTTP_HOST == dc->comp) {
				log_error_write(srv, __FILE__, __LINE__, "ss", "SSL:",
						"can't use ssl.pemfile with $HTTP[\"host\"], openssl version does not support TLS extensions");
				return -1;
			}
#endif
			if (network_openssl_load_pemfile(srv, i)) return -1;
		}


		if (!buffer_string_is_empty(s->ssl_ca_file)) {
			s->ssl_ca_file_cert_names = SSL_load_client_CA_file(s->ssl_ca_file->ptr);
			if (NULL == s->ssl_ca_file_cert_names) {
				log_error_write(srv, __FILE__, __LINE__, "ssb", "SSL:",
						ERR_error_string(ERR_get_error(), NULL), s->ssl_ca_file);
			}
		}

		if (buffer_string_is_empty(s->ssl_pemfile) || !s->ssl_enabled) continue;

		if (NULL == (s->ssl_ctx = SSL_CTX_new(SSLv23_server_method()))) {
			log_error_write(srv, __FILE__, __LINE__, "ss", "SSL:",
					ERR_error_string(ERR_get_error(), NULL));
			return -1;
		}

		/* completely useless identifier; required for client cert verification to work with sessions */
		if (0 == SSL_CTX_set_session_id_context(s->ssl_ctx, (const unsigned char*) CONST_STR_LEN("lighttpd"))) {
			log_error_write(srv, __FILE__, __LINE__, "ss:s", "SSL:",
				"failed to set session context",
				ERR_error_string(ERR_get_error(), NULL));
			return -1;
		}

		if (s->ssl_empty_fragments) {
#ifdef SSL_OP_DONT_INSERT_EMPTY_FRAGMENTS
			ssloptions &= ~SSL_OP_DONT_INSERT_EMPTY_FRAGMENTS;
#else
			ssloptions &= ~0x00000800L; /* hardcode constant */
			log_error_write(srv, __FILE__, __LINE__, "ss", "WARNING: SSL:",
					"'insert empty fragments' not supported by the openssl version used to compile lighttpd with");
#endif
		}

		SSL_CTX_set_options(s->ssl_ctx, ssloptions);
		SSL_CTX_set_info_callback(s->ssl_ctx, ssl_info_callback);

		if (!s->ssl_use_sslv2) {
			/* disable SSLv2 */
			if ((SSL_OP_NO_SSLv2 & SSL_CTX_set_options(s->ssl_ctx, SSL_OP_NO_SSLv2)) != SSL_OP_NO_SSLv2) {
				log_error_write(srv, __FILE__, __LINE__, "ss", "SSL:",
						ERR_error_string(ERR_get_error(), NULL));
				return -1;
			}
		}

		if (!s->ssl_use_sslv3) {
			/* disable SSLv3 */
			if ((SSL_OP_NO_SSLv3 & SSL_CTX_set_options(s->ssl_ctx, SSL_OP_NO_SSLv3)) != SSL_OP_NO_SSLv3) {
				log_error_write(srv, __FILE__, __LINE__, "ss", "SSL:",
						ERR_error_string(ERR_get_error(), NULL));
				return -1;
			}
		}

		if (!buffer_string_is_empty(s->ssl_cipher_list)) {
			/* Disable support for low encryption ciphers */
			if (SSL_CTX_set_cipher_list(s->ssl_ctx, s->ssl_cipher_list->ptr) != 1) {
				log_error_write(srv, __FILE__, __LINE__, "ss", "SSL:",
						ERR_error_string(ERR_get_error(), NULL));
				return -1;
			}

			if (s->ssl_honor_cipher_order) {
				SSL_CTX_set_options(s->ssl_ctx, SSL_OP_CIPHER_SERVER_PREFERENCE);
			}
		}

#ifndef OPENSSL_NO_DH
		/* Support for Diffie-Hellman key exchange */
		if (!buffer_string_is_empty(s->ssl_dh_file)) {
			/* DH parameters from file */
			bio = BIO_new_file((char *) s->ssl_dh_file->ptr, "r");
			if (bio == NULL) {
				log_error_write(srv, __FILE__, __LINE__, "ss", "SSL: Unable to open file", s->ssl_dh_file->ptr);
				return -1;
			}
			dh = PEM_read_bio_DHparams(bio, NULL, NULL, NULL);
			BIO_free(bio);
			if (dh == NULL) {
				log_error_write(srv, __FILE__, __LINE__, "ss", "SSL: PEM_read_bio_DHparams failed", s->ssl_dh_file->ptr);
				return -1;
			}
		} else {
			BIGNUM *dh_p, *dh_g;
			/* Default DH parameters from RFC5114 */
			dh = DH_new();
			if (dh == NULL) {
				log_error_write(srv, __FILE__, __LINE__, "s", "SSL: DH_new () failed");
				return -1;
			}
			dh_p = BN_bin2bn(dh1024_p,sizeof(dh1024_p), NULL);
			dh_g = BN_bin2bn(dh1024_g,sizeof(dh1024_g), NULL);
			if ((dh_p == NULL) || (dh_g == NULL)) {
				DH_free(dh);
				log_error_write(srv, __FILE__, __LINE__, "s", "SSL: BN_bin2bn () failed");
				return -1;
			}
		      #if OPENSSL_VERSION_NUMBER < 0x10100000L \
			|| defined(LIBRESSL_VERSION_NUMBER)
			dh->p = dh_p;
			dh->g = dh_g;
			dh->length = 160;
		      #else
			DH_set0_pqg(dh, dh_p, NULL, dh_g);
			DH_set_length(dh, 160);
		      #endif
		}
		SSL_CTX_set_tmp_dh(s->ssl_ctx,dh);
		SSL_CTX_set_options(s->ssl_ctx,SSL_OP_SINGLE_DH_USE);
		DH_free(dh);
#else
		if (!buffer_string_is_empty(s->ssl_dh_file)) {
			log_error_write(srv, __FILE__, __LINE__, "ss", "SSL: openssl compiled without DH support, can't load parameters from", s->ssl_dh_file->ptr);
		}
#endif

#if OPENSSL_VERSION_NUMBER >= 0x0090800fL
#ifndef OPENSSL_NO_ECDH
		/* Support for Elliptic-Curve Diffie-Hellman key exchange */
		if (!buffer_string_is_empty(s->ssl_ec_curve)) {
			/* OpenSSL only supports the "named curves" from RFC 4492, section 5.1.1. */
			nid = OBJ_sn2nid((char *) s->ssl_ec_curve->ptr);
			if (nid == 0) {
				log_error_write(srv, __FILE__, __LINE__, "ss", "SSL: Unknown curve name", s->ssl_ec_curve->ptr);
				return -1;
			}
		} else {
			/* Default curve */
			nid = OBJ_sn2nid("prime256v1");
		}
		ecdh = EC_KEY_new_by_curve_name(nid);
		if (ecdh == NULL) {
			log_error_write(srv, __FILE__, __LINE__, "ss", "SSL: Unable to create curve", s->ssl_ec_curve->ptr);
			return -1;
		}
		SSL_CTX_set_tmp_ecdh(s->ssl_ctx,ecdh);
		SSL_CTX_set_options(s->ssl_ctx,SSL_OP_SINGLE_ECDH_USE);
		EC_KEY_free(ecdh);
#endif
#endif

		/* load all ssl.ca-files specified in the config into each SSL_CTX to be prepared for SNI */
		for (j = 0; j < srv->config_context->used; j++) {
			specific_config *s1 = srv->config_storage[j];

			if (!buffer_string_is_empty(s1->ssl_ca_file)) {
				if (1 != SSL_CTX_load_verify_locations(s->ssl_ctx, s1->ssl_ca_file->ptr, NULL)) {
					log_error_write(srv, __FILE__, __LINE__, "ssb", "SSL:",
							ERR_error_string(ERR_get_error(), NULL), s1->ssl_ca_file);
					return -1;
				}
			}
		}

		if (s->ssl_verifyclient) {
			if (NULL == s->ssl_ca_file_cert_names) {
				log_error_write(srv, __FILE__, __LINE__, "s",
					"SSL: You specified ssl.verifyclient.activate but no ca_file"
				);
				return -1;
			}
			SSL_CTX_set_client_CA_list(s->ssl_ctx, SSL_dup_CA_list(s->ssl_ca_file_cert_names));
			SSL_CTX_set_verify(
				s->ssl_ctx,
				SSL_VERIFY_PEER | (s->ssl_verifyclient_enforce ? SSL_VERIFY_FAIL_IF_NO_PEER_CERT : 0),
				NULL
			);
			SSL_CTX_set_verify_depth(s->ssl_ctx, s->ssl_verifyclient_depth);
		}

		if (SSL_CTX_use_certificate(s->ssl_ctx, s->ssl_pemfile_x509) < 0) {
			log_error_write(srv, __FILE__, __LINE__, "ssb", "SSL:",
					ERR_error_string(ERR_get_error(), NULL), s->ssl_pemfile);
			return -1;
		}

		if (SSL_CTX_use_PrivateKey(s->ssl_ctx, s->ssl_pemfile_pkey) < 0) {
			log_error_write(srv, __FILE__, __LINE__, "ssb", "SSL:",
					ERR_error_string(ERR_get_error(), NULL), s->ssl_pemfile);
			return -1;
		}

		if (SSL_CTX_check_private_key(s->ssl_ctx) != 1) {
			log_error_write(srv, __FILE__, __LINE__, "sssb", "SSL:",
					"Private key does not match the certificate public key, reason:",
					ERR_error_string(ERR_get_error(), NULL),
					s->ssl_pemfile);
			return -1;
		}
		SSL_CTX_set_default_read_ahead(s->ssl_ctx, 1);
		SSL_CTX_set_mode(s->ssl_ctx, SSL_CTX_get_mode(s->ssl_ctx) | SSL_MODE_ACCEPT_MOVING_WRITE_BUFFER);

# ifndef OPENSSL_NO_TLSEXT
		if (!SSL_CTX_set_tlsext_servername_callback(s->ssl_ctx, network_ssl_servername_callback) ||
		    !SSL_CTX_set_tlsext_servername_arg(s->ssl_ctx, srv)) {
			log_error_write(srv, __FILE__, __LINE__, "ss", "SSL:",
					"failed to initialize TLS servername callback, openssl library does not support TLS servername extension");
			return -1;
		}
# endif
	}
#endif

	b = buffer_init();

	buffer_copy_buffer(b, srv->srvconf.bindhost);
	buffer_append_string_len(b, CONST_STR_LEN(":"));
	buffer_append_int(b, srv->srvconf.port);

	if (0 != network_server_init(srv, b, srv->config_storage[0])) {
		buffer_free(b);
		return -1;
	}
	buffer_free(b);

#ifdef USE_OPENSSL
	srv->network_ssl_backend_write = network_write_chunkqueue_openssl;
#endif

	/* get a usefull default */
	backend = network_backends[0].nb;

	/* match name against known types */
	if (!buffer_string_is_empty(srv->srvconf.network_backend)) {
		for (i = 0; network_backends[i].name; i++) {
			/**/
			if (buffer_is_equal_string(srv->srvconf.network_backend, network_backends[i].name, strlen(network_backends[i].name))) {
				backend = network_backends[i].nb;
				break;
			}
		}
		if (NULL == network_backends[i].name) {
			/* we don't know it */

			log_error_write(srv, __FILE__, __LINE__, "sb",
					"server.network-backend has a unknown value:",
					srv->srvconf.network_backend);

			return -1;
		}
	}

	switch(backend) {
	case NETWORK_BACKEND_WRITE:
		srv->network_backend_write = network_write_chunkqueue_write;
		break;
#if defined(USE_WRITEV)
	case NETWORK_BACKEND_WRITEV:
		srv->network_backend_write = network_write_chunkqueue_writev;
		break;
#endif
#if defined(USE_SENDFILE)
	case NETWORK_BACKEND_SENDFILE:
		srv->network_backend_write = network_write_chunkqueue_sendfile;
		break;
#endif
	default:
		return -1;
	}

	/* check for $SERVER["socket"] */
	for (i = 1; i < srv->config_context->used; i++) {
		data_config *dc = (data_config *)srv->config_context->data[i];
		specific_config *s = srv->config_storage[i];

		/* not our stage */
		if (COMP_SERVER_SOCKET != dc->comp) continue;

		if (dc->cond != CONFIG_COND_EQ) continue;

		/* check if we already know this socket,
		 * if yes, don't init it */
		for (j = 0; j < srv->srv_sockets.used; j++) {
			if (buffer_is_equal(srv->srv_sockets.ptr[j]->srv_token, dc->string)) {
				break;
			}
		}

		if (j == srv->srv_sockets.used) {
			if (0 != network_server_init(srv, dc->string, s)) return -1;
		}
	}

	return 0;
}
Beispiel #24
0
/** Initialize the SSL context.
 * \return pointer to SSL context object.
 */
SSL_CTX *
ssl_init(char *private_key_file, char *ca_file, int req_client_cert)
{
  const SSL_METHOD *meth;       /* If this const gives you a warning, you're
                                   using an old version of OpenSSL. Walker, this means you! */
  /* uint8_t context[128]; */
  DH *dh;
  unsigned int reps = 1;

  if (!bio_err) {
    if (!SSL_library_init())
      return NULL;
    SSL_load_error_strings();
    /* Error write context */
    bio_err = BIO_new_fp(stderr, BIO_NOCLOSE);
  }

  lock_file(stderr);
  fputs("Seeding OpenSSL random number pool.\n", stderr);
  unlock_file(stderr);
  while (!RAND_status()) {
    /* At this point, a system with /dev/urandom or a EGD file in the usual
       places will have enough entropy. Otherwise, be lazy and use random numbers
       until it's satisfied. */
    uint32_t gibberish[4];
    int n;

    /* sfmt_fill_array32 requires a much larger array. */
    for (n = 0; n < 4; n++)
      gibberish[n] = sfmt_genrand_uint32(&rand_state);

    RAND_seed(gibberish, sizeof gibberish);

    reps += 1;
  }

  lock_file(stderr);
  fprintf(stderr, "Seeded after %u %s.\n", reps, reps > 1 ? "cycles" : "cycle");
  unlock_file(stderr);

  /* Set up SIGPIPE handler here? */

  /* Create context */
  meth = SSLv23_server_method();
  ctx = SSL_CTX_new(meth);

  /* Load keys/certs */
  if (private_key_file && *private_key_file) {
    if (!SSL_CTX_use_certificate_chain_file(ctx, private_key_file)) {
      ssl_errordump
        ("Unable to load server certificate - only anonymous ciphers supported.");
    }
    if (!SSL_CTX_use_PrivateKey_file(ctx, private_key_file, SSL_FILETYPE_PEM)) {
      ssl_errordump
        ("Unable to load private key - only anonymous ciphers supported.");
    }
  }

  /* Load trusted CAs */
  if (ca_file && *ca_file) {
    if (!SSL_CTX_load_verify_locations(ctx, ca_file, NULL)) {
      ssl_errordump("Unable to load CA certificates");
    } else {
      if (req_client_cert)
        SSL_CTX_set_verify(ctx,
                           SSL_VERIFY_PEER | SSL_VERIFY_FAIL_IF_NO_PEER_CERT,
                           client_verify_callback);
      else
        SSL_CTX_set_verify(ctx, SSL_VERIFY_PEER, client_verify_callback);
#if (OPENSSL_VERSION_NUMBER < 0x0090600fL)
      SSL_CTX_set_verify_depth(ctx, 1);
#endif
    }
  }

  SSL_CTX_set_options(ctx, SSL_OP_SINGLE_DH_USE | SSL_OP_ALL);
  SSL_CTX_set_mode(ctx,
                   SSL_MODE_ENABLE_PARTIAL_WRITE |
                   SSL_MODE_ACCEPT_MOVING_WRITE_BUFFER);

  /* Set up DH callback */
  dh = get_dh1024();
  SSL_CTX_set_tmp_dh(ctx, dh);
  /* The above function makes a private copy of this */
  DH_free(dh);

  /* Set the cipher list to the usual default list, except that
   * we'll allow anonymous diffie-hellman, too.
   */
  SSL_CTX_set_cipher_list(ctx, "ALL:ADH:RC4+RSA:+SSLv2:@STRENGTH");

  /* Set up session cache if we can */
  /*
     strncpy((char *) context, MUDNAME, 128);
     SSL_CTX_set_session_id_context(ctx, context, strlen(context));
   */

  return ctx;
}
void context_init(void) { /* init SSL */
    int i;

#if SSLEAY_VERSION_NUMBER >= 0x00907000L
    /* Load all bundled ENGINEs into memory and make them visible */
    ENGINE_load_builtin_engines();
    /* Register all of them for every algorithm they collectively implement */
    ENGINE_register_all_complete();
#endif
    if(!init_prng())
        log(LOG_INFO, "PRNG seeded successfully");
    SSLeay_add_ssl_algorithms();
    SSL_load_error_strings();
    if(options.option.client) {
        ctx=SSL_CTX_new(SSLv3_client_method());
    } else { /* Server mode */
        ctx=SSL_CTX_new(SSLv23_server_method());
#ifndef NO_RSA
        SSL_CTX_set_tmp_rsa_callback(ctx, tmp_rsa_cb);
#endif /* NO_RSA */
        if(init_dh())
            log(LOG_WARNING, "Diffie-Hellman initialization failed");
    }
    if(options.ssl_options) {
        log(LOG_DEBUG, "Configuration SSL options: 0x%08lX",
            options.ssl_options);
        log(LOG_DEBUG, "SSL options set: 0x%08lX", 
            SSL_CTX_set_options(ctx, options.ssl_options));
    }
#if SSLEAY_VERSION_NUMBER >= 0x00906000L
    SSL_CTX_set_mode(ctx,
        SSL_MODE_ENABLE_PARTIAL_WRITE|SSL_MODE_ACCEPT_MOVING_WRITE_BUFFER);
#endif /* OpenSSL-0.9.6 */

    SSL_CTX_set_session_cache_mode(ctx, SSL_SESS_CACHE_BOTH);
    SSL_CTX_set_timeout(ctx, options.session_timeout);
    if(options.option.cert) {
        if(!SSL_CTX_use_certificate_chain_file(ctx, options.cert)) {
            log(LOG_ERR, "Error reading certificate file: %s", options.cert);
            sslerror("SSL_CTX_use_certificate_chain_file");
            exit(1);
        }
        log(LOG_DEBUG, "Certificate: %s", options.cert);
        log(LOG_DEBUG, "Key file: %s", options.key);
#ifdef USE_WIN32
        SSL_CTX_set_default_passwd_cb(ctx, pem_passwd_cb);
#endif
        for(i=0; i<3; i++) {
#ifdef NO_RSA
            if(SSL_CTX_use_PrivateKey_file(ctx, options.key,
                    SSL_FILETYPE_PEM))
#else /* NO_RSA */
            if(SSL_CTX_use_RSAPrivateKey_file(ctx, options.key,
                    SSL_FILETYPE_PEM))
#endif /* NO_RSA */
                break;
            if(i<2 && ERR_GET_REASON(ERR_peek_error())==EVP_R_BAD_DECRYPT) {
                sslerror_stack(); /* dump the error stack */
                log(LOG_ERR, "Wrong pass phrase: retrying");
                continue;
            }
#ifdef NO_RSA
            sslerror("SSL_CTX_use_PrivateKey_file");
#else /* NO_RSA */
            sslerror("SSL_CTX_use_RSAPrivateKey_file");
#endif /* NO_RSA */
            exit(1);
        }
        if(!SSL_CTX_check_private_key(ctx)) {
            sslerror("Private key does not match the certificate");
            exit(1);
        }
    }

    verify_init(); /* Initialize certificate verification */

    SSL_CTX_set_info_callback(ctx, info_callback);

    if(options.cipher_list) {
        if (!SSL_CTX_set_cipher_list(ctx, options.cipher_list)) {
            sslerror("SSL_CTX_set_cipher_list");
            exit(1);
        }
    }
}
Beispiel #26
0
/**
 * Initializes a ssl connection for server use.
 * @param pemfilename Filename for the key/cert file
 * @return An ssl connection, or NULL if an error occured.
 */
ssl_server_connection *init_ssl_server (char *pemfile, char *clientpemfile) {

#ifdef HAVE_OPENSSL

    ssl_server_connection *ssl_server = new_ssl_server_connection(pemfile,
                                        clientpemfile);

    ASSERT(pemfile);

    if (!ssl_initilized) {

        start_ssl();

    }

    if ((ssl_server->method= SSLv23_server_method()) == NULL ) {

        handle_ssl_error("init_ssl_server()");
        log("%s: init_ssl_server (): Cannot initialize the SSL method!\n", prog);
        goto sslerror;

    }

    if ((ssl_server->ctx= SSL_CTX_new(ssl_server->method)) == NULL ) {

        handle_ssl_error("init_ssl_server()");
        log("%s: init_ssl_server (): Cannot initialize SSL server"
            " certificate handler!\n"
            , prog);
        goto sslerror;

    }

    if (SSL_CTX_use_certificate_file(ssl_server->ctx, pemfile,
                                     SSL_FILETYPE_PEM) <= 0) {

        handle_ssl_error("init_ssl_server()");
        log("%s: init_ssl_server(): Cannot initialize SSL server"
            " certificate!\n", prog);
        goto sslerror;

    }

    if (SSL_CTX_use_PrivateKey_file(ssl_server->ctx, pemfile,
                                    SSL_FILETYPE_PEM) <= 0) {

        handle_ssl_error("init_ssl_server()");
        log("%s: init_ssl_server(): Cannot initialize SSL server"
            " private key!\n", prog);
        goto sslerror;

    }

    if (!SSL_CTX_check_private_key(ssl_server->ctx)) {

        handle_ssl_error("init_ssl_server()");
        log("%s: init_ssl_server(): The private key does not match the"
            " certificate public key!\n", prog);
        goto sslerror;

    }

    /*
     * We need this to force transmission of client certs
     */
    if (!verify_init(ssl_server)) {

        handle_ssl_error("init_ssl_server()");
        log("%s: init_ssl_server(): Verification engine was not"
            " properly initilized!\n", prog);
        goto sslerror;

    }

    if (ssl_server->clientpemfile != NULL) {

        verify_info(ssl_server);

    }

    return ssl_server;

sslerror:

    cleanup_ssl_server_socket(ssl_server);
    return NULL;

#else

    return NULL;

#endif

}
Beispiel #27
0
static int openssl_ssl_ctx_new(lua_State*L)
{
  const char* meth = luaL_optstring(L, 1, "TLSv1");
#if OPENSSL_VERSION_NUMBER >= 0x01000000L
  const
#endif
  SSL_METHOD* method = NULL;
  const char* ciphers;
  SSL_CTX* ctx;
  if (strcmp(meth, "SSLv3") == 0)
    method = SSLv3_method();    /* SSLv3 */
  else if (strcmp(meth, "SSLv3_server") == 0)
    method = SSLv3_server_method(); /* SSLv3 */
  else if (strcmp(meth, "SSLv3_client") == 0)
    method = SSLv3_client_method(); /* SSLv3 */
  else if (strcmp(meth, "SSLv23") == 0)
    method = SSLv23_method();   /* SSLv3 but can rollback to v2 */
  else if (strcmp(meth, "SSLv23_server") == 0)
    method = SSLv23_server_method();  /* SSLv3 but can rollback to v2 */
  else if (strcmp(meth, "SSLv23_client") == 0)
    method = SSLv23_client_method();  /* SSLv3 but can rollback to v2 */

  else if (strcmp(meth, "TLSv1_1") == 0)
    method = TLSv1_1_method();    /* TLSv1.0 */
  else if (strcmp(meth, "TLSv1_1_server") == 0)
    method = TLSv1_1_server_method(); /* TLSv1.0 */
  else if (strcmp(meth, "TLSv1_1_client") == 0)
    method = TLSv1_1_client_method(); /* TLSv1.0 */

  else if (strcmp(meth, "TLSv1_2") == 0)
    method = TLSv1_2_method();    /* TLSv1.0 */
  else if (strcmp(meth, "TLSv1_2_server") == 0)
    method = TLSv1_2_server_method(); /* TLSv1.0 */
  else if (strcmp(meth, "TLSv1_2_client") == 0)
    method = TLSv1_2_client_method(); /* TLSv1.0 */

  else if (strcmp(meth, "TLSv1") == 0)
    method = TLSv1_method();    /* TLSv1.0 */
  else if (strcmp(meth, "TLSv1_server") == 0)
    method = TLSv1_server_method(); /* TLSv1.0 */
  else if (strcmp(meth, "TLSv1_client") == 0)
    method = TLSv1_client_method(); /* TLSv1.0 */

  else if (strcmp(meth, "DTLSv1") == 0)
    method = DTLSv1_method();   /* DTLSv1.0 */
  else if (strcmp(meth, "DTLSv1_server") == 0)
    method = DTLSv1_server_method();  /* DTLSv1.0 */
  else if (strcmp(meth, "DTLSv1_client") == 0)
    method = DTLSv1_client_method();  /* DTLSv1.0 */
#ifndef OPENSSL_NO_SSL2
#if OPENSSL_VERSION_NUMBER < 0x10100000L
  else if (strcmp(meth, "SSLv2") == 0)
    method = SSLv2_method();    /* SSLv2 */
  else if (strcmp(meth, "SSLv2_server") == 0)
    method = SSLv2_server_method(); /* SSLv2 */
  else if (strcmp(meth, "SSLv2_client") == 0)
    method = SSLv2_client_method();
#endif
#ifdef LOAD_SSL_CUSTOM
  LOAD_SSL_CUSTOM
#endif

#endif
  else
    luaL_error(L, "#1:%s not supported\n"
               "Maybe SSLv3 SSLv23 TLSv1 TLSv1_1 TLSv1_2 DTLSv1 [SSLv2], option followed by _client or _server\n",
               "default is SSLv3",
               meth);
  ciphers = luaL_optstring(L, 2, SSL_DEFAULT_CIPHER_LIST);
  ctx = SSL_CTX_new(method);
  if (!ctx)
    luaL_error(L, "#1:%s not supported\n"
               "Maybe SSLv3 SSLv23 TLSv1 TLSv1_1 TLSv1_2 DTLSv1 [SSLv2], option followed by _client or _server\n",
               "default is SSLv3",
               meth);
  openssl_newvalue(L, ctx);
  SSL_CTX_set_cipher_list(ctx, ciphers);
  PUSH_OBJECT(ctx, "openssl.ssl_ctx");
  SSL_CTX_set_app_data(ctx, L);

  return 1;
}
Beispiel #28
0
int MAIN(int argc, char **argv)
{
    int ret = 1, i;
    int verbose = 0, Verbose = 0;
    const char **pp;
    const char *p;
    int badops = 0;
    SSL_CTX *ctx = NULL;
    SSL *ssl = NULL;
    char *ciphers = NULL;
    const SSL_METHOD *meth = NULL;
    STACK_OF(SSL_CIPHER) *sk;
    char buf[512];
    BIO *STDout = NULL;

    meth = SSLv23_server_method();

    apps_startup();

    if (bio_err == NULL)
        bio_err = BIO_new_fp(stderr, BIO_NOCLOSE);
    STDout = BIO_new_fp(stdout, BIO_NOCLOSE);
#ifdef OPENSSL_SYS_VMS
    {
        BIO *tmpbio = BIO_new(BIO_f_linebuffer());
        STDout = BIO_push(tmpbio, STDout);
    }
#endif
    if (!load_config(bio_err, NULL))
        goto end;

    argc--;
    argv++;
    while (argc >= 1) {
        if (strcmp(*argv, "-v") == 0)
            verbose = 1;
        else if (strcmp(*argv, "-V") == 0)
            verbose = Verbose = 1;
#ifndef OPENSSL_NO_SSL2
        else if (strcmp(*argv, "-ssl2") == 0)
            meth = SSLv2_client_method();
#endif
#ifndef OPENSSL_NO_SSL3
        else if (strcmp(*argv, "-ssl3") == 0)
            meth = SSLv3_client_method();
#endif
#ifndef OPENSSL_NO_TLS1
        else if (strcmp(*argv, "-tls1") == 0)
            meth = TLSv1_client_method();
#endif
        else if ((strncmp(*argv, "-h", 2) == 0) || (strcmp(*argv, "-?") == 0)) {
            badops = 1;
            break;
        } else {
            ciphers = *argv;
        }
        argc--;
        argv++;
    }

    if (badops) {
        for (pp = ciphers_usage; (*pp != NULL); pp++)
            BIO_printf(bio_err, "%s", *pp);
        goto end;
    }

    OpenSSL_add_ssl_algorithms();

    ctx = SSL_CTX_new(meth);
    if (ctx == NULL)
        goto err;
    if (ciphers != NULL) {
        if (!SSL_CTX_set_cipher_list(ctx, ciphers)) {
            BIO_printf(bio_err, "Error in cipher list\n");
            goto err;
        }
    }
    ssl = SSL_new(ctx);
    if (ssl == NULL)
        goto err;

    if (!verbose) {
        for (i = 0;; i++) {
            p = SSL_get_cipher_list(ssl, i);
            if (p == NULL)
                break;
            if (i != 0)
                BIO_printf(STDout, ":");
            BIO_printf(STDout, "%s", p);
        }
        BIO_printf(STDout, "\n");
    } else {                    /* verbose */

        sk = SSL_get_ciphers(ssl);

        for (i = 0; i < sk_SSL_CIPHER_num(sk); i++) {
            SSL_CIPHER *c;

            c = sk_SSL_CIPHER_value(sk, i);

            if (Verbose) {
                unsigned long id = c->id;
                int id0 = (int)(id >> 24);
                int id1 = (int)((id >> 16) & 0xffL);
                int id2 = (int)((id >> 8) & 0xffL);
                int id3 = (int)(id & 0xffL);

                if ((id & 0xff000000L) == 0x02000000L) {
                    /* SSL2 cipher */
                    BIO_printf(STDout, "     0x%02X,0x%02X,0x%02X - ", id1,
                               id2, id3);
                } else if ((id & 0xff000000L) == 0x03000000L) {
                    /* SSL3 cipher */
                    BIO_printf(STDout, "          0x%02X,0x%02X - ", id2,
                               id3);
                } else {
                    /* whatever */
                    BIO_printf(STDout, "0x%02X,0x%02X,0x%02X,0x%02X - ", id0,
                               id1, id2, id3);
                }
            }

            BIO_puts(STDout, SSL_CIPHER_description(c, buf, sizeof buf));
        }
    }

    ret = 0;
    if (0) {
 err:
        SSL_load_error_strings();
        ERR_print_errors(bio_err);
    }
 end:
    if (ctx != NULL)
        SSL_CTX_free(ctx);
    if (ssl != NULL)
        SSL_free(ssl);
    if (STDout != NULL)
        BIO_free_all(STDout);
    apps_shutdown();
    OPENSSL_EXIT(ret);
}
Beispiel #29
0
int
mowgli_vio_openssl_default_listen(mowgli_vio_t *vio, int backlog)
{
	return_val_if_fail(vio, -255);

	mowgli_ssl_connection_t *connection = vio->privdata;
	const SSL_METHOD *method;
	const int fd = mowgli_vio_getfd(vio);

	vio->error.op = MOWGLI_VIO_ERR_OP_LISTEN;

	switch (connection->settings.ssl_version)
	{
	case MOWGLI_VIO_SSLFLAGS_SSLV2:
		method = SSLv23_server_method();
		break;
	case MOWGLI_VIO_SSLFLAGS_SSLV3:
		method = SSLv3_server_method();
		break;
	case MOWGLI_VIO_SSLFLAGS_TLSV10:
	case MOWGLI_VIO_SSLFLAGS_TLSV11:
	case MOWGLI_VIO_SSLFLAGS_TLSV12:
		method = TLSv1_server_method();
		break;
	default:

		/* Compat method */
		method = SSLv23_server_method();
	}

	connection->ssl_context = SSL_CTX_new((SSL_METHOD *) method);

	if (connection->ssl_context == NULL)
		return mowgli_vio_err_sslerrcode(vio, ERR_get_error());

	connection->ssl_handle = SSL_new(connection->ssl_context);

	if (connection->ssl_handle == NULL)
		return mowgli_vio_err_sslerrcode(vio, ERR_get_error());

	SSL_set_accept_state(connection->ssl_handle);
	SSL_CTX_set_options(connection->ssl_context, SSL_OP_SINGLE_DH_USE);

	if (connection->settings.password_func)
	{
		SSL_CTX_set_default_passwd_cb(connection->ssl_context, connection->settings.password_func);
		SSL_CTX_set_default_passwd_cb_userdata(connection->ssl_context, vio->userdata);
	}

	if (SSL_CTX_use_certificate_file(connection->ssl_context, connection->settings.cert_path, SSL_FILETYPE_PEM) != 1)
		return mowgli_vio_err_sslerrcode(vio, ERR_get_error());

	if (SSL_CTX_use_PrivateKey_file(connection->ssl_context, connection->settings.privatekey_path, SSL_FILETYPE_PEM) != 1)
		return mowgli_vio_err_sslerrcode(vio, ERR_get_error());

	if (listen(fd, backlog) != 0)
		return mowgli_vio_err_errcode(vio, strerror, errno);

	if (!SSL_set_fd(connection->ssl_handle, fd))
		return mowgli_vio_err_sslerrcode(vio, ERR_get_error());

	mowgli_vio_setflag(vio, MOWGLI_VIO_FLAGS_ISSERVER, true);
	vio->error.op = MOWGLI_VIO_ERR_OP_NONE;

	return 0;
}
Beispiel #30
0
Datei: ctx.c Projekt: tiran/deo
ctx *
ctx_init(const char *tls, const char *enc, const char *dec)
{
    AUTO(EVP_PKEY, prv);
    AUTO(FILE, file);
    AUTO(ctx, ctx);

    if (tls == NULL || enc == NULL || dec == NULL)
        return NULL;

    ctx = OPENSSL_malloc(sizeof(*ctx));
    if (ctx == NULL)
        return NULL;
    memset(ctx, 0, sizeof(*ctx));

    ctx->ctx = SSL_CTX_new(SSLv23_server_method());
    if (ctx->ctx == NULL)
        return NULL;

    if (SSL_CTX_use_certificate_chain_file(ctx->ctx, tls) <= 0)
        return NULL;

    prv = load_prv(tls);
    if (prv == NULL)
        return NULL;

    if (SSL_CTX_use_PrivateKey(ctx->ctx, prv) <= 0)
        return NULL;

    file = fopen(enc, "r");
    if (file == NULL)
        return NULL;

    ctx->crt = sk_X509_new_null();
    if (ctx->crt == NULL)
        return NULL;

    if (!deo_load(file, ctx->crt))
        return NULL;

    ctx->dec = load_decryption_certs_keys(dec);
    if (ctx->dec == NULL)
        return NULL;

    /* Check to ensure that the TLS connection key is not also listed
     * in the decryption keys. This prevents an attack where, upon
     * misconfiguration, this service could be used to decrypt its own
     * traffic. */
    for (int i = 0; i < sk_X509_INFO_num(ctx->dec); i++) {
        X509_INFO *info = sk_X509_INFO_value(ctx->dec, i);

        if (info->x_pkey == NULL)
            continue;

        if (EVP_PKEY_cmp(prv, info->x_pkey->dec_pkey) == 1) {
            fprintf(stderr, "TLS private key is exposed!\n");
            return NULL;
        }
    }

    return STEAL(ctx);
}