Skip to content
s_server.c 60.6 KiB
Newer Older
	SSL_load_error_strings();
	OpenSSL_add_ssl_algorithms();

Dr. Stephen Henson's avatar
Dr. Stephen Henson committed
	if (!app_passwd(bio_err, passarg, dpassarg, &pass, &dpass))
		{
		BIO_printf(bio_err, "Error getting password\n");
		goto end;
		}


	if (s_key_file == NULL)
		s_key_file = s_cert_file;
#ifndef OPENSSL_NO_TLSEXT
	if (s_key_file2 == NULL)
		s_key_file2 = s_cert_file2;
#endif
Dr. Stephen Henson's avatar
Dr. Stephen Henson committed

Dr. Stephen Henson's avatar
Dr. Stephen Henson committed
		{
		s_key = load_key(bio_err, s_key_file, s_key_format, 0, pass, e,
		       "server certificate private key file");
		if (!s_key)
			{
			ERR_print_errors(bio_err);
			goto end;
			}
Dr. Stephen Henson's avatar
Dr. Stephen Henson committed

		s_cert = load_cert(bio_err,s_cert_file,s_cert_format,
Dr. Stephen Henson's avatar
Dr. Stephen Henson committed
			NULL, e, "server certificate file");

		if (!s_cert)
			{
			ERR_print_errors(bio_err);
			goto end;
			}

#ifndef OPENSSL_NO_TLSEXT
Bodo Möller's avatar
Bodo Möller committed
		if (tlsextcbp.servername) 
			{
			s_key2 = load_key(bio_err, s_key_file2, s_key_format, 0, pass, e,
Bodo Möller's avatar
Bodo Möller committed
				"second server certificate private key file");
			if (!s_key2)
				{
				ERR_print_errors(bio_err);
				goto end;
				}
Bodo Möller's avatar
Bodo Möller committed
			
			s_cert2 = load_cert(bio_err,s_cert_file2,s_cert_format,
				NULL, e, "second server certificate file");
Bodo Möller's avatar
Bodo Möller committed
			
			if (!s_cert2)
				{
				ERR_print_errors(bio_err);
				goto end;
				}
			}
#endif
Dr. Stephen Henson's avatar
Dr. Stephen Henson committed
		}

Dr. Stephen Henson's avatar
Dr. Stephen Henson committed
	if (s_dcert_file)
		{

		if (s_dkey_file == NULL)
			s_dkey_file = s_dcert_file;

		s_dkey = load_key(bio_err, s_dkey_file, s_dkey_format,
				0, dpass, e,
			       "second certificate private key file");
		if (!s_dkey)
			{
			ERR_print_errors(bio_err);
			goto end;
			}

		s_dcert = load_cert(bio_err,s_dcert_file,s_dcert_format,
				NULL, e, "second server certificate file");

		if (!s_dcert)
			{
			ERR_print_errors(bio_err);
			goto end;
			}

		}

	if (!app_RAND_load_file(NULL, bio_err, 1) && inrand == NULL
		&& !RAND_status())
		{
		BIO_printf(bio_err,"warning, not much extra random data, consider using the -rand option\n");
		}
	if (inrand != NULL)
		BIO_printf(bio_err,"%ld semi-random bytes loaded\n",
			app_RAND_load_files(inrand));
		if (s_quiet && !s_debug && !s_msg)
			{
			bio_s_out=BIO_new(BIO_s_null());
			}
		else
			{
			if (bio_s_out == NULL)
				bio_s_out=BIO_new_fp(stdout,BIO_NOCLOSE);
			}
		}

Bodo Möller's avatar
Bodo Möller committed
#if !defined(OPENSSL_NO_RSA) || !defined(OPENSSL_NO_DSA) || !defined(OPENSSL_NO_ECDSA)
	if (nocert)
#endif
		{
		s_cert_file=NULL;
		s_key_file=NULL;
		s_dcert_file=NULL;
		s_dkey_file=NULL;
#ifndef OPENSSL_NO_TLSEXT
		s_cert_file2=NULL;
		s_key_file2=NULL;
#endif
		}

	ctx=SSL_CTX_new(meth);
	if (ctx == NULL)
		{
		ERR_print_errors(bio_err);
		goto end;
		}
	if (session_id_prefix)
		{
		if(strlen(session_id_prefix) >= 32)
			BIO_printf(bio_err,
"warning: id_prefix is too long, only one new session will be possible\n");
		else if(strlen(session_id_prefix) >= 16)
			BIO_printf(bio_err,
"warning: id_prefix is too long if you use SSLv2\n");
		if(!SSL_CTX_set_generate_session_id(ctx, generate_session_id))
			{
			BIO_printf(bio_err,"error setting 'id_prefix'\n");
			ERR_print_errors(bio_err);
			goto end;
			}
		BIO_printf(bio_err,"id_prefix '%s' set.\n", session_id_prefix);
		}
	SSL_CTX_set_quiet_shutdown(ctx,1);
	if (bugs) SSL_CTX_set_options(ctx,SSL_OP_ALL);
	if (hack) SSL_CTX_set_options(ctx,SSL_OP_NETSCAPE_DEMO_CIPHER_CHANGE_BUG);
	SSL_CTX_set_options(ctx,off);
Ben Laurie's avatar
Ben Laurie committed
	/* DTLS: partial reads end up discarding unread UDP bytes :-( 
	 * Setting read ahead solves this problem.
	 */
Bodo Möller's avatar
Bodo Möller committed
	if (socket_type == SOCK_DGRAM) SSL_CTX_set_read_ahead(ctx, 1);

	if (state) SSL_CTX_set_info_callback(ctx,apps_ssl_info_callback);

	SSL_CTX_sess_set_cache_size(ctx,128);

#if 0
	if (cipher == NULL) cipher=getenv("SSL_CIPHER");
#endif

#if 0
	if (s_cert_file == NULL)
		{
		BIO_printf(bio_err,"You must specify a certificate file for the server to use\n");
		goto end;
		}
#endif

	if ((!SSL_CTX_load_verify_locations(ctx,CAfile,CApath)) ||
		(!SSL_CTX_set_default_verify_paths(ctx)))
		{
		/* BIO_printf(bio_err,"X509_load_verify_locations\n"); */
		ERR_print_errors(bio_err);
	store = SSL_CTX_get_cert_store(ctx);
	X509_STORE_set_flags(store, vflags);
#ifndef OPENSSL_NO_TLSEXT
Bodo Möller's avatar
Bodo Möller committed
	if (s_cert2)
Bodo Möller's avatar
Bodo Möller committed
		ctx2=SSL_CTX_new(meth);
		if (ctx2 == NULL)
			{
			ERR_print_errors(bio_err);
			goto end;
			}
		}
Bodo Möller's avatar
Bodo Möller committed
	
	if (ctx2)
		{
		BIO_printf(bio_s_out,"Setting secondary ctx parameters\n");

		if (session_id_prefix)
			{
			if(strlen(session_id_prefix) >= 32)
				BIO_printf(bio_err,
					"warning: id_prefix is too long, only one new session will be possible\n");
			else if(strlen(session_id_prefix) >= 16)
				BIO_printf(bio_err,
					"warning: id_prefix is too long if you use SSLv2\n");
			if(!SSL_CTX_set_generate_session_id(ctx2, generate_session_id))
				{
				BIO_printf(bio_err,"error setting 'id_prefix'\n");
				ERR_print_errors(bio_err);
				goto end;
				}
			BIO_printf(bio_err,"id_prefix '%s' set.\n", session_id_prefix);
			}
		SSL_CTX_set_quiet_shutdown(ctx2,1);
		if (bugs) SSL_CTX_set_options(ctx2,SSL_OP_ALL);
		if (hack) SSL_CTX_set_options(ctx2,SSL_OP_NETSCAPE_DEMO_CIPHER_CHANGE_BUG);
		SSL_CTX_set_options(ctx2,off);
		/* DTLS: partial reads end up discarding unread UDP bytes :-( 
		 * Setting read ahead solves this problem.
		 */
		if (socket_type == SOCK_DGRAM) SSL_CTX_set_read_ahead(ctx2, 1);
Bodo Möller's avatar
Bodo Möller committed
		if (state) SSL_CTX_set_info_callback(ctx2,apps_ssl_info_callback);
Bodo Möller's avatar
Bodo Möller committed
		SSL_CTX_sess_set_cache_size(ctx2,128);
Bodo Möller's avatar
Bodo Möller committed
		if ((!SSL_CTX_load_verify_locations(ctx2,CAfile,CApath)) ||
			(!SSL_CTX_set_default_verify_paths(ctx2)))
			{
			ERR_print_errors(bio_err);
Bodo Möller's avatar
Bodo Möller committed
			}
		store = SSL_CTX_get_cert_store(ctx2);
		X509_STORE_set_flags(store, vflags);
Bodo Möller's avatar
Bodo Möller committed

	if (!no_dhe)
		DH *dh=NULL;

		if (dhfile)
			dh = load_dh_param(dhfile);
		else if (s_cert_file)
			dh = load_dh_param(s_cert_file);

		if (dh != NULL)
			{
			BIO_printf(bio_s_out,"Setting temp DH parameters\n");
			}
		else
			{
			BIO_printf(bio_s_out,"Using default temp DH parameters\n");
			dh=get_dh512();
			}
		(void)BIO_flush(bio_s_out);
		SSL_CTX_set_tmp_dh(ctx,dh);
#ifndef OPENSSL_NO_TLSEXT
Bodo Möller's avatar
Bodo Möller committed
		if (ctx2)
			{
			if (!dhfile)
				{ 
				DH *dh2=load_dh_param(s_cert_file2);
				if (dh2 != NULL)
Bodo Möller's avatar
Bodo Möller committed
					{
					BIO_printf(bio_s_out,"Setting temp DH parameters\n");
					(void)BIO_flush(bio_s_out);

					DH_free(dh);
					dh = dh2;
Bodo Möller's avatar
Bodo Möller committed
					}
				}
			SSL_CTX_set_tmp_dh(ctx2,dh);
Bodo Möller's avatar
Bodo Möller committed
			}
		DH_free(dh);
		}
Bodo Möller's avatar
Bodo Möller committed

#ifndef OPENSSL_NO_ECDH
	if (!no_ecdhe)
		{
		EC_KEY *ecdh=NULL;

		if (named_curve)
			{
			int nid = OBJ_sn2nid(named_curve);

			if (nid == 0)
				{
				BIO_printf(bio_err, "unknown curve name (%s)\n", 
					named_curve);
				goto end;
				}
Nils Larsch's avatar
Nils Larsch committed
			ecdh = EC_KEY_new_by_curve_name(nid);
			if (ecdh == NULL)
Bodo Möller's avatar
Bodo Möller committed
				{
				BIO_printf(bio_err, "unable to create curve (%s)\n", 
					named_curve);
				goto end;
				}
			}

Nils Larsch's avatar
Nils Larsch committed
		if (ecdh != NULL)
Bodo Möller's avatar
Bodo Möller committed
			{
			BIO_printf(bio_s_out,"Setting temp ECDH parameters\n");
			}
		else
			{
			BIO_printf(bio_s_out,"Using default temp ECDH parameters\n");
			ecdh = EC_KEY_new_by_curve_name(NID_X9_62_prime256v1);
Nils Larsch's avatar
Nils Larsch committed
			if (ecdh == NULL) 
				BIO_printf(bio_err, "unable to create curve (nistp256)\n");
Bodo Möller's avatar
Bodo Möller committed
				goto end;
				}
			}
		(void)BIO_flush(bio_s_out);

		SSL_CTX_set_tmp_ecdh(ctx,ecdh);
#ifndef OPENSSL_NO_TLSEXT
		if (ctx2) 
			SSL_CTX_set_tmp_ecdh(ctx2,ecdh);
#endif
Bodo Möller's avatar
Bodo Möller committed
		EC_KEY_free(ecdh);
		}
#endif
Dr. Stephen Henson's avatar
Dr. Stephen Henson committed
	if (!set_cert_key_stuff(ctx,s_cert,s_key))
#ifndef OPENSSL_NO_TLSEXT
	if (ctx2 && !set_cert_key_stuff(ctx2,s_cert2,s_key2))
		goto end; 
#endif
Dr. Stephen Henson's avatar
Dr. Stephen Henson committed
	if (s_dcert != NULL)
Dr. Stephen Henson's avatar
Dr. Stephen Henson committed
		if (!set_cert_key_stuff(ctx,s_dcert,s_dkey))
Bodo Möller's avatar
Bodo Möller committed
	if (!no_tmp_rsa)
		{
Bodo Möller's avatar
Bodo Möller committed
		SSL_CTX_set_tmp_rsa_callback(ctx,tmp_rsa_cb);
#ifndef OPENSSL_NO_TLSEXT
		if (ctx2) 
			SSL_CTX_set_tmp_rsa_callback(ctx2,tmp_rsa_cb);
#endif		
Bodo Möller's avatar
Bodo Möller committed
		}
#else
	if (!no_tmp_rsa && SSL_CTX_need_tmp_RSA(ctx))
		{
		RSA *rsa;

		BIO_printf(bio_s_out,"Generating temp (512 bit) RSA key...");
		BIO_flush(bio_s_out);

		rsa=RSA_generate_key(512,RSA_F4,NULL);

		if (!SSL_CTX_set_tmp_rsa(ctx,rsa))
			{
			ERR_print_errors(bio_err);
			goto end;
			}
#ifndef OPENSSL_NO_TLSEXT
Bodo Möller's avatar
Bodo Möller committed
			if (ctx2)
Bodo Möller's avatar
Bodo Möller committed
				if (!SSL_CTX_set_tmp_rsa(ctx2,rsa))
					{
					ERR_print_errors(bio_err);
					goto end;
Bodo Möller's avatar
Bodo Möller committed
					}
		RSA_free(rsa);
		BIO_printf(bio_s_out,"\n");
		}
#ifndef OPENSSL_NO_PSK
	if (psk_key != NULL)
		{
		if (s_debug)
			BIO_printf(bio_s_out, "PSK key given, setting server callback\n");
		SSL_CTX_set_psk_server_callback(ctx, psk_server_cb);
		}

	if (!SSL_CTX_use_psk_identity_hint(ctx, psk_identity_hint))
		{
		BIO_printf(bio_err,"error setting PSK identity hint to context\n");
		ERR_print_errors(bio_err);
		goto end;
		}
#endif

	if (cipher != NULL)
		{
		if(!SSL_CTX_set_cipher_list(ctx,cipher))
			{
			BIO_printf(bio_err,"error setting cipher list\n");
			ERR_print_errors(bio_err);
			goto end;
#ifndef OPENSSL_NO_TLSEXT
Bodo Möller's avatar
Bodo Möller committed
		if (ctx2 && !SSL_CTX_set_cipher_list(ctx2,cipher))
			{
			BIO_printf(bio_err,"error setting cipher list\n");
			ERR_print_errors(bio_err);
			goto end;
Bodo Möller's avatar
Bodo Möller committed
			}
	SSL_CTX_set_verify(ctx,s_server_verify,verify_callback);
	SSL_CTX_set_session_id_context(ctx,(void*)&s_server_session_id_context,
		sizeof s_server_session_id_context);
#ifndef OPENSSL_NO_TLSEXT
Bodo Möller's avatar
Bodo Möller committed
	if (ctx2)
		{
		SSL_CTX_set_verify(ctx2,s_server_verify,verify_callback);
		SSL_CTX_set_session_id_context(ctx2,(void*)&s_server_session_id_context,
			sizeof s_server_session_id_context);

		tlsextcbp.biodebug = bio_s_out;
		SSL_CTX_set_tlsext_servername_callback(ctx2, ssl_servername_cb);
		SSL_CTX_set_tlsext_servername_arg(ctx2, &tlsextcbp);
		SSL_CTX_set_tlsext_servername_callback(ctx, ssl_servername_cb);
		SSL_CTX_set_tlsext_servername_arg(ctx, &tlsextcbp);
Bodo Möller's avatar
Bodo Möller committed
		}
Bodo Möller's avatar
Bodo Möller committed
	if (CAfile != NULL)
		{
		SSL_CTX_set_client_CA_list(ctx,SSL_load_client_CA_file(CAfile));
#ifndef OPENSSL_NO_TLSEXT
		if (ctx2) 
Bodo Möller's avatar
Bodo Möller committed
			SSL_CTX_set_client_CA_list(ctx2,SSL_load_client_CA_file(CAfile));
Bodo Möller's avatar
Bodo Möller committed
		}

	BIO_printf(bio_s_out,"ACCEPT\n");
	if (www)
Bodo Möller's avatar
Bodo Möller committed
		do_server(port,socket_type,&accept_socket,www_body, context);
Bodo Möller's avatar
Bodo Möller committed
		do_server(port,socket_type,&accept_socket,sv_body, context);
	print_stats(bio_s_out,ctx);
	ret=0;
end:
	if (ctx != NULL) SSL_CTX_free(ctx);
Dr. Stephen Henson's avatar
Dr. Stephen Henson committed
	if (s_cert)
		X509_free(s_cert);
	if (s_dcert)
		X509_free(s_dcert);
	if (s_key)
		EVP_PKEY_free(s_key);
	if (s_dkey)
		EVP_PKEY_free(s_dkey);
	if (pass)
		OPENSSL_free(pass);
	if (dpass)
		OPENSSL_free(dpass);
#ifndef OPENSSL_NO_TLSEXT
	if (ctx2 != NULL) SSL_CTX_free(ctx2);
	if (s_cert2)
		X509_free(s_cert2);
	if (s_key2)
		EVP_PKEY_free(s_key2);
#endif
Ben Laurie's avatar
Ben Laurie committed
        BIO_free(bio_s_out);
Ulf Möller's avatar
Ulf Möller committed
static void print_stats(BIO *bio, SSL_CTX *ssl_ctx)
	{
	BIO_printf(bio,"%4ld items in the session cache\n",
		SSL_CTX_sess_number(ssl_ctx));
	BIO_printf(bio,"%4ld client connects (SSL_connect())\n",
		SSL_CTX_sess_connect(ssl_ctx));
	BIO_printf(bio,"%4ld client renegotiates (SSL_connect())\n",
		SSL_CTX_sess_connect_renegotiate(ssl_ctx));
	BIO_printf(bio,"%4ld client connects that finished\n",
		SSL_CTX_sess_connect_good(ssl_ctx));
	BIO_printf(bio,"%4ld server accepts (SSL_accept())\n",
		SSL_CTX_sess_accept(ssl_ctx));
	BIO_printf(bio,"%4ld server renegotiates (SSL_accept())\n",
		SSL_CTX_sess_accept_renegotiate(ssl_ctx));
	BIO_printf(bio,"%4ld server accepts that finished\n",
		SSL_CTX_sess_accept_good(ssl_ctx));
	BIO_printf(bio,"%4ld session cache hits\n",SSL_CTX_sess_hits(ssl_ctx));
	BIO_printf(bio,"%4ld session cache misses\n",SSL_CTX_sess_misses(ssl_ctx));
	BIO_printf(bio,"%4ld session cache timeouts\n",SSL_CTX_sess_timeouts(ssl_ctx));
	BIO_printf(bio,"%4ld callback cache hits\n",SSL_CTX_sess_cb_hits(ssl_ctx));
	BIO_printf(bio,"%4ld cache full overflows (%ld allowed)\n",
		SSL_CTX_sess_cache_full(ssl_ctx),
		SSL_CTX_sess_get_cache_size(ssl_ctx));
Ben Laurie's avatar
Ben Laurie committed
static int sv_body(char *hostname, int s, unsigned char *context)
	{
	char *buf=NULL;
	fd_set readfds;
	int ret=1,width;
	int k,i;
	unsigned long l;
	SSL *con=NULL;
	BIO *sbio;
Ulf Möller's avatar
Ulf Möller committed
#if defined(OPENSSL_SYS_WINDOWS) || defined(OPENSSL_SYS_MSDOS) || defined(OPENSSL_SYS_NETWARE) || defined(OPENSSL_SYS_BEOS_R5)
	if ((buf=OPENSSL_malloc(bufsize)) == NULL)
		{
		BIO_printf(bio_err,"out of memory\n");
		goto err;
		}
#ifdef FIONBIO	
	if (s_nbio)
		{
		unsigned long sl=1;

		if (!s_quiet)
			BIO_printf(bio_err,"turning on non blocking io\n");
		if (BIO_socket_ioctl(s,FIONBIO,&sl) < 0)
			ERR_print_errors(bio_err);
Ben Laurie's avatar
Ben Laurie committed
	if (con == NULL) {
Dr. Stephen Henson's avatar
 
Dr. Stephen Henson committed
		con=SSL_new(ctx);
		if ((con->kssl_ctx = kssl_ctx_new()) != NULL)
                        {
                        kssl_ctx_setstring(con->kssl_ctx, KSSL_SERVICE,
								KRB5SVC);
                        kssl_ctx_setstring(con->kssl_ctx, KSSL_KEYTAB,
								KRB5KEYTAB);
Ben Laurie's avatar
Ben Laurie committed
		if(context)
Ben Laurie's avatar
Ben Laurie committed
		      SSL_set_session_id_context(con, context,
						 strlen((char *)context));
Ben Laurie's avatar
Ben Laurie committed
	}
Ben Laurie's avatar
Ben Laurie committed
	if (SSL_version(con) == DTLS1_VERSION)
		{
		struct timeval timeout;

		sbio=BIO_new_dgram(s,BIO_NOCLOSE);

Bodo Möller's avatar
Bodo Möller committed
		if (enable_timeouts)
Ben Laurie's avatar
Ben Laurie committed
			{
			timeout.tv_sec = 0;
			timeout.tv_usec = DGRAM_RCV_TIMEOUT;
			BIO_ctrl(sbio, BIO_CTRL_DGRAM_SET_RECV_TIMEOUT, 0, &timeout);
			
			timeout.tv_sec = 0;
			timeout.tv_usec = DGRAM_SND_TIMEOUT;
			BIO_ctrl(sbio, BIO_CTRL_DGRAM_SET_SEND_TIMEOUT, 0, &timeout);
			}

Bodo Möller's avatar
Bodo Möller committed
		if (socket_mtu > 0)
Ben Laurie's avatar
Ben Laurie committed
			{
			SSL_set_options(con, SSL_OP_NO_QUERY_MTU);
Bodo Möller's avatar
Bodo Möller committed
			SSL_set_mtu(con, socket_mtu);
Ben Laurie's avatar
Ben Laurie committed
			}
		else
			/* want to do MTU discovery */
			BIO_ctrl(sbio, BIO_CTRL_DGRAM_MTU_DISCOVER, 0, NULL);

        /* turn on cookie exchange */
        SSL_set_options(con, SSL_OP_COOKIE_EXCHANGE);
		}
	else
		sbio=BIO_new_socket(s,BIO_NOCLOSE);

	if (s_nbio_test)
		{
		BIO *test;

		test=BIO_new(BIO_f_nbio_test());
		sbio=BIO_push(test,sbio);
		}
	SSL_set_bio(con,sbio,sbio);
	SSL_set_accept_state(con);
	/* SSL_set_fd(con,s); */

	if (s_debug)
		{
		con->debug=1;
		BIO_set_callback(SSL_get_rbio(con),bio_dump_callback);
		BIO_set_callback_arg(SSL_get_rbio(con),bio_s_out);
		}
	if (s_msg)
		{
		SSL_set_msg_callback(con, msg_cb);
		SSL_set_msg_callback_arg(con, bio_s_out);
		}
		int read_from_terminal;
		int read_from_sslcon;

		read_from_terminal = 0;
		read_from_sslcon = SSL_pending(con);

		if (!read_from_sslcon)
			{
			FD_ZERO(&readfds);
Ulf Möller's avatar
Ulf Möller committed
#if !defined(OPENSSL_SYS_WINDOWS) && !defined(OPENSSL_SYS_MSDOS) && !defined(OPENSSL_SYS_NETWARE) && !defined(OPENSSL_SYS_BEOS_R5)
			openssl_fdset(fileno(stdin),&readfds);
			/* Note: under VMS with SOCKETSHR the second parameter is
			 * currently of type (int *) whereas under other systems
			 * it is (void *) if you don't have a cast it will choke
			 * the compiler: if you do have a cast then you can either
			 * go for (int *) or (void *).
			 */
#if defined(OPENSSL_SYS_WINDOWS) || defined(OPENSSL_SYS_MSDOS) || defined(OPENSSL_SYS_NETWARE)
                        /* Under DOS (non-djgpp) and Windows we can't select on stdin: only
			 * on sockets. As a workaround we timeout the select every
			 * second and check for any keypress. In a proper Windows
			 * application we wouldn't do this because it is inefficient.
			 */
			tv.tv_sec = 1;
			tv.tv_usec = 0;
			i=select(width,(void *)&readfds,NULL,NULL,&tv);
			if((i < 0) || (!i && !_kbhit() ) )continue;
			if(_kbhit())
				read_from_terminal = 1;
Ulf Möller's avatar
Ulf Möller committed
#elif defined(OPENSSL_SYS_BEOS_R5)
			/* Under BeOS-R5 the situation is similar to DOS */
			tv.tv_sec = 1;
			tv.tv_usec = 0;
			(void)fcntl(fileno(stdin), F_SETFL, O_NONBLOCK);
			i=select(width,(void *)&readfds,NULL,NULL,&tv);
			if ((i < 0) || (!i && read(fileno(stdin), buf, 0) < 0))
				continue;
			if (read(fileno(stdin), buf, 0) >= 0)
				read_from_terminal = 1;
			(void)fcntl(fileno(stdin), F_SETFL, 0);
			i=select(width,(void *)&readfds,NULL,NULL,NULL);
			if (i <= 0) continue;
			if (FD_ISSET(fileno(stdin),&readfds))
				read_from_terminal = 1;
			if (FD_ISSET(s,&readfds))
				read_from_sslcon = 1;
			}
		if (read_from_terminal)
				i=raw_read_stdin(buf, bufsize/2);
				lf_num = 0;
				/* both loops are skipped when i <= 0 */
				for (j = 0; j < i; j++)
					if (buf[j] == '\n')
						lf_num++;
				for (j = i-1; j >= 0; j--)
					{
					buf[j+lf_num] = buf[j];
					if (buf[j] == '\n')
						{
						lf_num--;
						i++;
						buf[j+lf_num] = '\r';
						}
					}
				assert(lf_num == 0);
				}
			else
				i=raw_read_stdin(buf,bufsize);
			if (!s_quiet)
				{
				if ((i <= 0) || (buf[0] == 'Q'))
					{
					BIO_printf(bio_s_out,"DONE\n");
					SHUTDOWN(s);
					close_accept_socket();
					ret= -11;
					goto err;
					}
				if ((i <= 0) || (buf[0] == 'q'))
					{
					BIO_printf(bio_s_out,"DONE\n");
Ben Laurie's avatar
Ben Laurie committed
					if (SSL_version(con) != DTLS1_VERSION)
                        SHUTDOWN(s);
	/*				close_accept_socket();
					ret= -11;*/
					goto err;
					}
				if ((buf[0] == 'r') && 
					((buf[1] == '\n') || (buf[1] == '\r')))
					i=SSL_do_handshake(con);
					printf("SSL_do_handshake -> %d\n",i);
					/* strcpy(buf,"server side RE-NEGOTIATE\n"); */
				if ((buf[0] == 'R') &&
					((buf[1] == '\n') || (buf[1] == '\r')))
					{
					SSL_set_verify(con,
						SSL_VERIFY_PEER|SSL_VERIFY_CLIENT_ONCE,NULL);
					SSL_renegotiate(con);
					i=SSL_do_handshake(con);
					printf("SSL_do_handshake -> %d\n",i);
					/* strcpy(buf,"server side RE-NEGOTIATE asking for client cert\n"); */
Nils Larsch's avatar
Nils Larsch committed
					static const char *str="Lets print some clear text\n";
					BIO_write(SSL_get_wbio(con),str,strlen(str));
					}
				if (buf[0] == 'S')
					{
					print_stats(bio_s_out,SSL_get_SSL_CTX(con));
					}
				}
#ifdef CHARSET_EBCDIC
			ebcdic2ascii(buf,buf,i);
#endif
			l=k=0;
			for (;;)
				{
				/* should do a select for the write */
#ifdef RENEG
{ static count=0; if (++count == 100) { count=0; SSL_renegotiate(con); } }
				k=SSL_write(con,&(buf[l]),(unsigned int)i);
				switch (SSL_get_error(con,k))
				case SSL_ERROR_NONE:
					break;
				case SSL_ERROR_WANT_WRITE:
				case SSL_ERROR_WANT_READ:
				case SSL_ERROR_WANT_X509_LOOKUP:
					BIO_printf(bio_s_out,"Write BLOCK\n");
					break;
				case SSL_ERROR_SYSCALL:
				case SSL_ERROR_SSL:
					BIO_printf(bio_s_out,"ERROR\n");
					ERR_print_errors(bio_err);
				case SSL_ERROR_ZERO_RETURN:
					BIO_printf(bio_s_out,"DONE\n");
					ret=1;
					goto err;
					}
				l+=k;
				i-=k;
				if (i <= 0) break;
				}
			}
		if (read_from_sslcon)
			{
			if (!SSL_is_init_finished(con))
				{
				i=init_ssl_connection(con);
				
				if (i < 0)
					{
					ret=0;
					goto err;
					}
				else if (i == 0)
					{
					ret=1;
					goto err;
					}
				}
			else
				{
again:	
				i=SSL_read(con,(char *)buf,bufsize);
				switch (SSL_get_error(con,i))
				case SSL_ERROR_NONE:
#ifdef CHARSET_EBCDIC
					ascii2ebcdic(buf,buf,i);
#endif
					if (SSL_pending(con)) goto again;
					break;
				case SSL_ERROR_WANT_WRITE:
				case SSL_ERROR_WANT_READ:
				case SSL_ERROR_WANT_X509_LOOKUP:
					BIO_printf(bio_s_out,"Read BLOCK\n");
					break;
				case SSL_ERROR_SYSCALL:
				case SSL_ERROR_SSL:
					BIO_printf(bio_s_out,"ERROR\n");
					ERR_print_errors(bio_err);
					ret=1;
					goto err;
				case SSL_ERROR_ZERO_RETURN:
					BIO_printf(bio_s_out,"DONE\n");
					ret=1;
					goto err;
					}
				}
			}
		}
err:
	if (con != NULL)
		{
		BIO_printf(bio_s_out,"shutting down SSL\n");
		SSL_set_shutdown(con,SSL_SENT_SHUTDOWN|SSL_RECEIVED_SHUTDOWN);
		SSL_shutdown(con);
		SSL_free(con);
		}
	BIO_printf(bio_s_out,"CONNECTION CLOSED\n");
	if (buf != NULL)
		{
		OPENSSL_cleanse(buf,bufsize);
		}
	if (ret >= 0)
		BIO_printf(bio_s_out,"ACCEPT\n");
	return(ret);
	}

Ulf Möller's avatar
Ulf Möller committed
static void close_accept_socket(void)
	{
	BIO_printf(bio_err,"shutdown accept socket\n");
	if (accept_socket >= 0)
		{
		SHUTDOWN2(accept_socket);
		}
	}

Ulf Möller's avatar
Ulf Möller committed
static int init_ssl_connection(SSL *con)
Ben Laurie's avatar
Ben Laurie committed
	const char *str;
	MS_STATIC char buf[BUFSIZ];

	if ((i=SSL_accept(con)) <= 0)
		{
		if (BIO_sock_should_retry(i))
			{
			BIO_printf(bio_s_out,"DELAY\n");
			return(1);
			}

		BIO_printf(bio_err,"ERROR\n");
		verify_error=SSL_get_verify_result(con);
		if (verify_error != X509_V_OK)
			{
			BIO_printf(bio_err,"verify error:%s\n",
				X509_verify_cert_error_string(verify_error));
			}
		else
			ERR_print_errors(bio_err);
		return(0);
		}

	PEM_write_bio_SSL_SESSION(bio_s_out,SSL_get_session(con));

	peer=SSL_get_peer_certificate(con);
	if (peer != NULL)
		{
		BIO_printf(bio_s_out,"Client certificate\n");
		PEM_write_bio_X509(bio_s_out,peer);
		X509_NAME_oneline(X509_get_subject_name(peer),buf,sizeof buf);
		BIO_printf(bio_s_out,"subject=%s\n",buf);
		X509_NAME_oneline(X509_get_issuer_name(peer),buf,sizeof buf);
		BIO_printf(bio_s_out,"issuer=%s\n",buf);
		X509_free(peer);
		}

	if (SSL_get_shared_ciphers(con,buf,sizeof buf) != NULL)
		BIO_printf(bio_s_out,"Shared ciphers:%s\n",buf);
	str=SSL_CIPHER_get_name(SSL_get_current_cipher(con));
	BIO_printf(bio_s_out,"CIPHER is %s\n",(str != NULL)?str:"(NONE)");
	if (con->hit) BIO_printf(bio_s_out,"Reused session-id\n");
	if (SSL_ctrl(con,SSL_CTRL_GET_FLAGS,0,NULL) &
		TLS1_FLAGS_TLS_PADDING_BUG)
		BIO_printf(bio_s_out,"Peer has incorrect TLSv1 block padding\n");
#ifndef OPENSSL_NO_KRB5
	if (con->kssl_ctx->client_princ != NULL)
		{
		BIO_printf(bio_s_out,"Kerberos peer principal is %s\n",
			con->kssl_ctx->client_princ);
		}
#endif /* OPENSSL_NO_KRB5 */
Nils Larsch's avatar
Nils Larsch committed
static DH *load_dh_param(const char *dhfile)
	if ((bio=BIO_new_file(dhfile,"r")) == NULL)
	ret=PEM_read_bio_DHparams(bio,NULL,NULL,NULL);
err:
	if (bio != NULL) BIO_free(bio);
	return(ret);
	}
Ulf Möller's avatar
Ulf Möller committed
static int load_CA(SSL_CTX *ctx, char *file)
	{
	FILE *in;
	X509 *x=NULL;

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

	for (;;)
		{
		if (PEM_read_X509(in,&x,NULL) == NULL)
			break;
		SSL_CTX_add_client_CA(ctx,x);
		}
	if (x != NULL) X509_free(x);
	fclose(in);
	return(1);
	}
#endif

Ben Laurie's avatar
Ben Laurie committed
static int www_body(char *hostname, int s, unsigned char *context)
	int ret=1;
	int i,j,k,blank,dot;
	SSL *con;
	SSL_CIPHER *c;
	BIO *io,*ssl_bio,*sbio;
	io=BIO_new(BIO_f_buffer());
	ssl_bio=BIO_new(BIO_f_ssl());
	if ((io == NULL) || (ssl_bio == NULL)) goto err;

#ifdef FIONBIO	
	if (s_nbio)
		{

		if (!s_quiet)
			BIO_printf(bio_err,"turning on non blocking io\n");
		if (BIO_socket_ioctl(s,FIONBIO,&sl) < 0)
			ERR_print_errors(bio_err);
		}
#endif

	/* lets make the output buffer a reasonable size */
	if (!BIO_set_write_buffer_size(io,bufsize)) goto err;
Dr. Stephen Henson's avatar
 
Dr. Stephen Henson committed
	if ((con=SSL_new(ctx)) == NULL) goto err;
#ifndef OPENSSL_NO_KRB5
	if ((con->kssl_ctx = kssl_ctx_new()) != NULL)
		{
		kssl_ctx_setstring(con->kssl_ctx, KSSL_SERVICE, KRB5SVC);
		kssl_ctx_setstring(con->kssl_ctx, KSSL_KEYTAB, KRB5KEYTAB);
		}
#endif	/* OPENSSL_NO_KRB5 */
Ben Laurie's avatar
Ben Laurie committed
	if(context) SSL_set_session_id_context(con, context,
					       strlen((char *)context));

	sbio=BIO_new_socket(s,BIO_NOCLOSE);
	if (s_nbio_test)