Skip to content
s_client.c 64.2 KiB
Newer Older
			}
		else if	(strcmp(*argv,"-verifyCAfile") == 0)
			{
			if (--argc < 1) goto bad;
			vfyCAfile= *(++argv);
			}
# ifndef OPENSSL_NO_NEXTPROTONEG
		else if (strcmp(*argv,"-nextprotoneg") == 0)
			{
			if (--argc < 1) goto bad;
			next_proto_neg_in = *(++argv);
			}
Adam Langley's avatar
Adam Langley committed
		else if (strcmp(*argv,"-alpn") == 0)
			{
			if (--argc < 1) goto bad;
			alpn_in = *(++argv);
			}
		else if (strcmp(*argv,"-serverinfo") == 0)
			{
			char *c;
			int start = 0;
			int len;

			if (--argc < 1) goto bad;
			c = *(++argv);
			serverinfo_types_count = 0;
			len = strlen(c);
			for (i = 0; i <= len; ++i)
				{
				if (i == len || c[i] == ',')
					{
					serverinfo_types[serverinfo_types_count]
					    = atoi(c+start);
					serverinfo_types_count++;
					start = i+1;
					}
				if (serverinfo_types_count == MAX_SI_TYPES)
					break;
				}
			}
#ifdef FIONBIO
		else if (strcmp(*argv,"-nbio") == 0)
			{ c_nbio=1; }
#endif
		else if	(strcmp(*argv,"-starttls") == 0)
			{
			if (--argc < 1) goto bad;
			++argv;
			if (strcmp(*argv,"smtp") == 0)
				starttls_proto = PROTO_SMTP;
				starttls_proto = PROTO_POP3;
			else if (strcmp(*argv,"imap") == 0)
				starttls_proto = PROTO_IMAP;
			else if (strcmp(*argv,"ftp") == 0)
				starttls_proto = PROTO_FTP;
Ben Laurie's avatar
Ben Laurie committed
			else if (strcmp(*argv, "xmpp") == 0)
				starttls_proto = PROTO_XMPP;
		else if	(strcmp(*argv,"-engine") == 0)
			{
			if (--argc < 1) goto bad;
			engine_id = *(++argv);
			}
		else if	(strcmp(*argv,"-ssl_client_engine") == 0)
			{
			if (--argc < 1) goto bad;
			ssl_client_engine_id = *(++argv);
			}
		else if (strcmp(*argv,"-rand") == 0)
			{
			if (--argc < 1) goto bad;
			inrand= *(++argv);
			}
#ifndef OPENSSL_NO_TLSEXT
		else if (strcmp(*argv,"-servername") == 0)
			{
			if (--argc < 1) goto bad;
			servername= *(++argv);
			/* meth=TLSv1_client_method(); */
			}
#endif
#ifndef OPENSSL_NO_JPAKE
Ben Laurie's avatar
Ben Laurie committed
		else if (strcmp(*argv,"-jpake") == 0)
			{
			if (--argc < 1) goto bad;
			jpake_secret = *++argv;
			}
Ben Laurie's avatar
Ben Laurie committed
		else if (strcmp(*argv,"-use_srtp") == 0)
			{
			if (--argc < 1) goto bad;
			srtp_profiles = *(++argv);
			}
Ben Laurie's avatar
Ben Laurie committed
		else if (strcmp(*argv,"-keymatexport") == 0)
			{
			if (--argc < 1) goto bad;
			keymatexportlabel= *(++argv);
			}
		else if (strcmp(*argv,"-keymatexportlen") == 0)
			{
			if (--argc < 1) goto bad;
			keymatexportlen=atoi(*(++argv));
			if (keymatexportlen == 0) goto bad;
			}
Ben Laurie's avatar
Ben Laurie committed
                else
			{
			BIO_printf(bio_err,"unknown option %s\n",*argv);
			badop=1;
			break;
			}
		argc--;
		argv++;
		}
	if (badop)
		{
bad:
		sc_usage();
		goto end;
		}

	if (unix_path && (socket_type != SOCK_STREAM))
		{
		BIO_printf(bio_err, "Can't use unix sockets and datagrams together\n");
			goto end;
		}
#if !defined(OPENSSL_NO_JPAKE) && !defined(OPENSSL_NO_PSK)
	if (jpake_secret)
		{
		if (psk_key)
			{
			BIO_printf(bio_err,
				   "Can't use JPAKE and PSK together\n");
			goto end;
			}
		psk_identity = "JPAKE";
		}
#endif

	OpenSSL_add_ssl_algorithms();
	SSL_load_error_strings();

#if !defined(OPENSSL_NO_TLSEXT) && !defined(OPENSSL_NO_NEXTPROTONEG)
	next_proto.status = -1;
	if (next_proto_neg_in)
		{
		next_proto.data = next_protos_parse(&next_proto.len, next_proto_neg_in);
		if (next_proto.data == NULL)
			{
			BIO_printf(bio_err, "Error parsing -nextprotoneg argument\n");
			goto end;
			}
		}
	else
		next_proto.data = NULL;
#endif

	if (ssl_client_engine_id)
		{
		ssl_client_engine = ENGINE_by_id(ssl_client_engine_id);
		if (!ssl_client_engine)
			{
			BIO_printf(bio_err,
					"Error getting client auth engine\n");
			goto end;
			}
		}

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

	if (key_file == NULL)
		key_file = cert_file;

Dr. Stephen Henson's avatar
Dr. Stephen Henson committed
		{

		key = load_key(bio_err, key_file, key_format, 0, pass, e,
			       "client certificate private key file");
		if (!key)
			{
			ERR_print_errors(bio_err);
			goto end;
			}

Dr. Stephen Henson's avatar
Dr. Stephen Henson committed
		}

Dr. Stephen Henson's avatar
Dr. Stephen Henson committed

		{
		cert = load_cert(bio_err,cert_file,cert_format,
				NULL, e, "client certificate file");

		if (!cert)
			{
			ERR_print_errors(bio_err);
			goto end;
			}
Dr. Stephen Henson's avatar
Dr. Stephen Henson committed
		}
	if (chain_file)
		{
		chain = load_certs(bio_err, chain_file,FORMAT_PEM,
					NULL, e, "client certificate chain");
		if (!chain)
			goto end;
		}

	if (crl_file)
		{
		X509_CRL *crl;
		crl = load_crl(crl_file, crl_format);
		if (!crl)
			{
			BIO_puts(bio_err, "Error loading CRL\n");
			ERR_print_errors(bio_err);
			goto end;
			}
		crls = sk_X509_CRL_new_null();
		if (!crls || !sk_X509_CRL_push(crls, crl))
			{
			BIO_puts(bio_err, "Error adding CRL\n");
			ERR_print_errors(bio_err);
			X509_CRL_free(crl);
			goto end;
			}
		}

	if (!load_excert(&exc, 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 (c_quiet && !c_debug)
			{
			bio_c_out=BIO_new(BIO_s_null());
			if (c_msg && !bio_c_msg)
				bio_c_msg=BIO_new_fp(stdout,BIO_NOCLOSE);
			}
		else
			{
			if (bio_c_out == NULL)
				bio_c_out=BIO_new_fp(stdout,BIO_NOCLOSE);
			}
		}

Ben Laurie's avatar
Ben Laurie committed
#ifndef OPENSSL_NO_SRP
	if(!app_passwd(bio_err, srppass, NULL, &srp_arg.srppassin, NULL))
		{
		BIO_printf(bio_err, "Error getting password\n");
		goto end;
		}
#endif

	ctx=SSL_CTX_new(meth);
	if (ctx == NULL)
		{
		ERR_print_errors(bio_err);
		goto end;
		}

	if (sdebug)
		ssl_ctx_security_debug(ctx, bio_err, sdebug);

	if (!args_ssl_call(ctx, bio_err, cctx, ssl_args, 1, no_jpake))
	if (!ssl_load_stores(ctx, vfyCApath, vfyCAfile, chCApath, chCAfile,
						crls, crl_download))
		{
		BIO_printf(bio_err, "Error loading store locations\n");
		ERR_print_errors(bio_err);
		goto end;
		}

#ifndef OPENSSL_NO_ENGINE
	if (ssl_client_engine)
		{
		if (!SSL_CTX_set_client_cert_engine(ctx, ssl_client_engine))
			{
			BIO_puts(bio_err, "Error setting client auth engine\n");
			ERR_print_errors(bio_err);
			ENGINE_free(ssl_client_engine);
			goto end;
			}
		ENGINE_free(ssl_client_engine);
		}
#endif

#ifndef OPENSSL_NO_PSK
#ifdef OPENSSL_NO_JPAKE
	if (psk_key != NULL)
#else
	if (psk_key != NULL || jpake_secret)
			BIO_printf(bio_c_out, "PSK key given or JPAKE in use, setting client callback\n");
		SSL_CTX_set_psk_client_callback(ctx, psk_client_cb);
		}
Ben Laurie's avatar
Ben Laurie committed
	if (srtp_profiles != NULL)
		SSL_CTX_set_tlsext_use_srtp(ctx, srtp_profiles);
	if (exc) ssl_ctx_set_excert(ctx, exc);
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);
Adam Langley's avatar
Adam Langley committed
#if !defined(OPENSSL_NO_TLSEXT)
# if !defined(OPENSSL_NO_NEXTPROTONEG)
	if (next_proto.data)
		SSL_CTX_set_next_proto_select_cb(ctx, next_proto_cb, &next_proto);
Adam Langley's avatar
Adam Langley committed
# endif
	if (alpn_in)
		{
		unsigned short alpn_len;
		unsigned char *alpn = next_protos_parse(&alpn_len, alpn_in);

		if (alpn == NULL)
			{
			BIO_printf(bio_err, "Error parsing -alpn argument\n");
			goto end;
			}
		SSL_CTX_set_alpn_protos(ctx, alpn, alpn_len);
		OPENSSL_free(alpn);
Adam Langley's avatar
Adam Langley committed
		}
#endif
#ifndef OPENSSL_NO_TLSEXT
		if (serverinfo_types_count)
			{
			for (i = 0; i < serverinfo_types_count; i++)
				{
				SSL_CTX_set_custom_cli_ext(ctx,
							   serverinfo_types[i],
							   NULL, NULL, NULL,
							   serverinfo_cli_cb,
							   NULL);
				}
			}
#endif
	if (state) SSL_CTX_set_info_callback(ctx,apps_ssl_info_callback);
#if 0
	else
		SSL_CTX_set_cipher_list(ctx,getenv("SSL_CIPHER"));
#endif

	SSL_CTX_set_verify(ctx,verify,verify_callback);

	if ((!SSL_CTX_load_verify_locations(ctx,CAfile,CApath)) ||
		(!SSL_CTX_set_default_verify_paths(ctx)))
		{
		/* BIO_printf(bio_err,"error setting default verify locations\n"); */
		ERR_print_errors(bio_err);
	ssl_ctx_add_crls(ctx, crls, crl_download);
	if (!set_cert_key_stuff(ctx,cert,key,chain,build_chain))
#ifndef OPENSSL_NO_TLSEXT
Bodo Möller's avatar
Bodo Möller committed
	if (servername != NULL)
		{
		tlsextcbp.biodebug = bio_err;
		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
		}
Ben Laurie's avatar
Ben Laurie committed
#ifndef OPENSSL_NO_SRP
        if (srp_arg.srplogin)
		{
Dr. Stephen Henson's avatar
Dr. Stephen Henson committed
		if (!srp_lateuser && !SSL_CTX_set_srp_username(ctx, srp_arg.srplogin))
Ben Laurie's avatar
Ben Laurie committed
			{
			BIO_printf(bio_err,"Unable to set SRP username\n");
			goto end;
			}
		srp_arg.msg = c_msg;
		srp_arg.debug = c_debug ;
		SSL_CTX_set_srp_cb_arg(ctx,&srp_arg);
		SSL_CTX_set_srp_client_pwd_callback(ctx, ssl_give_srp_client_pwd_cb);
		SSL_CTX_set_srp_strength(ctx, srp_arg.strength);
		if (c_msg || c_debug || srp_arg.amp == 0)
			SSL_CTX_set_srp_verify_param_callback(ctx, ssl_srp_verify_param_cb);
		}

#endif
Dr. Stephen Henson's avatar
 
Dr. Stephen Henson committed
	con=SSL_new(ctx);
	if (sess_in)
		{
		SSL_SESSION *sess;
		BIO *stmp = BIO_new_file(sess_in, "r");
		if (!stmp)
			{
			BIO_printf(bio_err, "Can't open session file %s\n",
						sess_in);
			ERR_print_errors(bio_err);
			goto end;
			}
		sess = PEM_read_bio_SSL_SESSION(stmp, NULL, 0, NULL);
		BIO_free(stmp);
		if (!sess)
			{
			BIO_printf(bio_err, "Can't open session file %s\n",
						sess_in);
			ERR_print_errors(bio_err);
			goto end;
			}
		SSL_set_session(con, sess);
		SSL_SESSION_free(sess);
		}
#ifndef OPENSSL_NO_TLSEXT
Bodo Möller's avatar
Bodo Möller committed
	if (servername != NULL)
		{
		if (!SSL_set_tlsext_host_name(con,servername))
Bodo Möller's avatar
Bodo Möller committed
			{
			BIO_printf(bio_err,"Unable to set TLS servername extension.\n");
			ERR_print_errors(bio_err);
			goto end;
Bodo Möller's avatar
Bodo Möller committed
			}
	if (con  &&  (kctx = kssl_ctx_new()) != NULL)
		SSL_set0_kssl_ctx(con, kctx);
                kssl_ctx_setstring(kctx, KSSL_SERVER, host);
/*	SSL_set_cipher_list(con,"RC4-MD5"); */
#if 0
#ifdef TLSEXT_TYPE_opaque_prf_input
	SSL_set_tlsext_opaque_prf_input(con, "Test client", 11);
#ifdef NO_SYS_UN_H
	if (init_client(&s,host,port,socket_type) == 0)
#else
	if ((!unix_path && (init_client(&s,host,port,socket_type) == 0)) ||
			(unix_path && (init_client_unix(&s,unix_path) == 0)))
		BIO_printf(bio_err,"connect:errno=%d\n",get_last_socket_error());
		SHUTDOWN(s);
		goto end;
		}
	BIO_printf(bio_c_out,"CONNECTED(%08X)\n",s);

#ifdef FIONBIO
	if (c_nbio)
		{
		unsigned long l=1;
		BIO_printf(bio_c_out,"turning on non blocking io\n");
		if (BIO_socket_ioctl(s,FIONBIO,&l) < 0)
			{
			ERR_print_errors(bio_err);
			goto end;
			}
	if (c_Pause & 0x01) SSL_set_debug(con, 1);
Ben Laurie's avatar
Ben Laurie committed

	if (socket_type == SOCK_DGRAM)
Ben Laurie's avatar
Ben Laurie committed
		{

		sbio=BIO_new_dgram(s,BIO_NOCLOSE);
		if (getsockname(s, &peer, (void *)&peerlen) < 0)
Ben Laurie's avatar
Ben Laurie committed
			{
			BIO_printf(bio_err, "getsockname:errno=%d\n",
				get_last_socket_error());
			SHUTDOWN(s);
			goto end;
			}

Dr. Stephen Henson's avatar
Dr. Stephen Henson committed
		(void)BIO_ctrl_set_connected(sbio, 1, &peer);
Ben Laurie's avatar
Ben Laurie committed

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);
			}

		if (socket_mtu > 28)
Ben Laurie's avatar
Ben Laurie committed
			{
			SSL_set_options(con, SSL_OP_NO_QUERY_MTU);
			SSL_set_mtu(con, socket_mtu - 28);
Ben Laurie's avatar
Ben Laurie committed
			}
		else
			/* want to do MTU discovery */
			BIO_ctrl(sbio, BIO_CTRL_DGRAM_MTU_DISCOVER, 0, NULL);
		}
	else
		sbio=BIO_new_socket(s,BIO_NOCLOSE);

	if (nbio_test)
		{
		BIO *test;

		test=BIO_new(BIO_f_nbio_test());
		sbio=BIO_push(test,sbio);
		}

	if (c_debug)
		{
		BIO_set_callback(sbio,bio_dump_callback);
		BIO_set_callback_arg(sbio,(char *)bio_c_out);
#ifndef OPENSSL_NO_SSL_TRACE
		if (c_msg == 2)
			SSL_set_msg_callback(con, SSL_trace);
		else
#endif
			SSL_set_msg_callback(con, msg_cb);
		SSL_set_msg_callback_arg(con, bio_c_msg ? bio_c_msg : bio_c_out);
#ifndef OPENSSL_NO_TLSEXT
	if (c_tlsextdebug)
		{
		SSL_set_tlsext_debug_callback(con, tlsext_cb);
		SSL_set_tlsext_debug_arg(con, bio_c_out);
		}
	if (c_status_req)
		{
		SSL_set_tlsext_status_type(con, TLSEXT_STATUSTYPE_ocsp);
		SSL_CTX_set_tlsext_status_cb(ctx, ocsp_resp_cb);
		SSL_CTX_set_tlsext_status_arg(ctx, bio_c_out);
#if 0
{
STACK_OF(OCSP_RESPID) *ids = sk_OCSP_RESPID_new_null();
OCSP_RESPID *id = OCSP_RESPID_new();
id->value.byKey = ASN1_OCTET_STRING_new();
id->type = V_OCSP_RESPID_KEY;
ASN1_STRING_set(id->value.byKey, "Hello World", -1);
sk_OCSP_RESPID_push(ids, id);
SSL_set_tlsext_status_ids(con, ids);
}
#endif
		}
#ifndef OPENSSL_NO_JPAKE
Ben Laurie's avatar
Ben Laurie committed
	if (jpake_secret)
		jpake_client_auth(bio_c_out, sbio, jpake_secret);
Ben Laurie's avatar
Ben Laurie committed

	SSL_set_bio(con,sbio,sbio);
	SSL_set_connect_state(con);

	/* ok, lets connect */
	width=SSL_get_fd(con)+1;

	read_tty=1;
	write_tty=0;
	tty_on=0;
	read_ssl=1;
	write_ssl=1;
	
	cbuf_len=0;
	cbuf_off=0;
	sbuf_len=0;
	sbuf_off=0;

	/* This is an ugly hack that does a lot of assumptions */
	/* We do have to handle multi-line responses which may come
 	   in a single packet or not. We therefore have to use
	   BIO_gets() which does need a buffering BIO. So during
	   the initial chitchat we do push a buffering BIO into the
	   chain that is removed again later on to not disturb the
	   rest of the s_client operation. */
	if (starttls_proto == PROTO_SMTP)
		BIO *fbio = BIO_new(BIO_f_buffer());
		BIO_push(fbio, sbio);
		/* wait for multi-line response to end from SMTP */
		do
			{
			mbuf_len = BIO_gets(fbio,mbuf,BUFSIZZ);
			}
		while (mbuf_len>3 && mbuf[3]=='-');
		/* STARTTLS command requires EHLO... */
		BIO_printf(fbio,"EHLO openssl.client.net\r\n");
Dr. Stephen Henson's avatar
Dr. Stephen Henson committed
		(void)BIO_flush(fbio);
		/* wait for multi-line response to end EHLO SMTP response */
		do
			{
			mbuf_len = BIO_gets(fbio,mbuf,BUFSIZZ);
			if (strstr(mbuf,"STARTTLS"))
				foundit=1;
			}
		while (mbuf_len>3 && mbuf[3]=='-');
Dr. Stephen Henson's avatar
Dr. Stephen Henson committed
		(void)BIO_flush(fbio);
		if (!foundit)
			BIO_printf(bio_err,
				   "didn't found starttls in server response,"
				   " try anyway...\n");
		BIO_printf(sbio,"STARTTLS\r\n");
		BIO_read(sbio,sbuf,BUFSIZZ);
		}
	else if (starttls_proto == PROTO_POP3)
		{
		BIO_read(sbio,mbuf,BUFSIZZ);
		BIO_printf(sbio,"STLS\r\n");
		BIO_read(sbio,sbuf,BUFSIZZ);
		}
	else if (starttls_proto == PROTO_IMAP)
		{
		BIO *fbio = BIO_new(BIO_f_buffer());
		BIO_push(fbio, sbio);
		BIO_gets(fbio,mbuf,BUFSIZZ);
		/* STARTTLS command requires CAPABILITY... */
		BIO_printf(fbio,". CAPABILITY\r\n");
Dr. Stephen Henson's avatar
Dr. Stephen Henson committed
		(void)BIO_flush(fbio);
		/* wait for multi-line CAPABILITY response */
		do
			{
			mbuf_len = BIO_gets(fbio,mbuf,BUFSIZZ);
			if (strstr(mbuf,"STARTTLS"))
				foundit=1;
			}
		while (mbuf_len>3 && mbuf[0]!='.');
Dr. Stephen Henson's avatar
Dr. Stephen Henson committed
		(void)BIO_flush(fbio);
		if (!foundit)
			BIO_printf(bio_err,
				   "didn't found STARTTLS in server response,"
				   " try anyway...\n");
		BIO_printf(sbio,". STARTTLS\r\n");
		BIO_read(sbio,sbuf,BUFSIZZ);
		}
	else if (starttls_proto == PROTO_FTP)
		{
		BIO *fbio = BIO_new(BIO_f_buffer());
		BIO_push(fbio, sbio);
		/* wait for multi-line response to end from FTP */
		do
			{
			mbuf_len = BIO_gets(fbio,mbuf,BUFSIZZ);
			}
		while (mbuf_len>3 && mbuf[3]=='-');
Dr. Stephen Henson's avatar
Dr. Stephen Henson committed
		(void)BIO_flush(fbio);
		BIO_printf(sbio,"AUTH TLS\r\n");
		BIO_read(sbio,sbuf,BUFSIZZ);
		}
Ben Laurie's avatar
Ben Laurie committed
	if (starttls_proto == PROTO_XMPP)
		{
		int seen = 0;
		BIO_printf(sbio,"<stream:stream "
		    "xmlns:stream='http://etherx.jabber.org/streams' "
Ben Laurie's avatar
Ben Laurie committed
		    "xmlns='jabber:client' to='%s' version='1.0'>", xmpphost ?
			   xmpphost : host);
Ben Laurie's avatar
Ben Laurie committed
		seen = BIO_read(sbio,mbuf,BUFSIZZ);
		mbuf[seen] = 0;
		while (!strstr(mbuf, "<starttls xmlns='urn:ietf:params:xml:ns:xmpp-tls'") &&
				!strstr(mbuf, "<starttls xmlns=\"urn:ietf:params:xml:ns:xmpp-tls\""))
Ben Laurie's avatar
Ben Laurie committed
			{
			seen = BIO_read(sbio,mbuf,BUFSIZZ);
Ben Laurie's avatar
Ben Laurie committed
			mbuf[seen] = 0;
			}
		BIO_printf(sbio, "<starttls xmlns='urn:ietf:params:xml:ns:xmpp-tls'/>");
		seen = BIO_read(sbio,sbuf,BUFSIZZ);
		sbuf[seen] = 0;
		if (!strstr(sbuf, "<proceed"))
			goto shut;
		mbuf[0] = 0;
		}
	for (;;)
		{
		FD_ZERO(&readfds);
		FD_ZERO(&writefds);

Dr. Stephen Henson's avatar
Dr. Stephen Henson committed
		if ((SSL_version(con) == DTLS1_VERSION) &&
			DTLSv1_get_timeout(con, &timeout))
			timeoutp = &timeout;
		else
			timeoutp = NULL;

		if (SSL_in_init(con) && !SSL_total_renegotiations(con))
			{
			in_init=1;
			tty_on=0;
			}
		else
			{
			tty_on=1;
			if (in_init)
				{
				in_init=0;
#if 0 /* This test doesn't really work as intended (needs to be fixed) */
#ifndef OPENSSL_NO_TLSEXT
				if (servername != NULL && !SSL_session_reused(con))
					{
					BIO_printf(bio_c_out,"Server did %sacknowledge servername extension.\n",tlsextcbp.ack?"":"not ");
					}
				if (sess_out)
					{
					BIO *stmp = BIO_new_file(sess_out, "w");
					if (stmp)
						{
						PEM_write_bio_SSL_SESSION(stmp, SSL_get_session(con));
						BIO_free(stmp);
						}
					else 
						BIO_printf(bio_err, "Error writing session file %s\n", sess_out);
					}
				if (c_brief)
					{
					BIO_puts(bio_err,
						"CONNECTION ESTABLISHED\n");
					print_ssl_summary(bio_err, con);
					}
				print_stuff(bio_c_out,con,full_log);
				if (full_log > 0) full_log--;

					{
					BIO_printf(bio_err,"%s",mbuf);
					/* We don't need to know any more */
					starttls_proto = PROTO_OFF;
				if (reconnect)
					{
					reconnect--;
					BIO_printf(bio_c_out,"drop connection and then reconnect\n");
					SSL_shutdown(con);
					SSL_set_connect_state(con);
					SHUTDOWN(SSL_get_fd(con));
					goto re_start;
					}
				}
			}

		ssl_pending = read_ssl && SSL_pending(con);

		if (!ssl_pending)
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 (read_tty)  openssl_fdset(fileno(stdin),&readfds);
				if (write_tty) openssl_fdset(fileno(stdout),&writefds);
				openssl_fdset(SSL_get_fd(con),&readfds);
				openssl_fdset(SSL_get_fd(con),&writefds);
					openssl_fdset(SSL_get_fd(con),&readfds);
					openssl_fdset(SSL_get_fd(con),&writefds);
/*			printf("mode tty(%d %d%d) ssl(%d%d)\n",
				tty_on,read_tty,write_tty,read_ssl,write_ssl);*/
Ulf Möller's avatar
Ulf Möller committed
			/* Note: under VMS with SOCKETSHR the second parameter
Ulf Möller's avatar
Ulf Möller committed
			 * 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)
                        /* Under Windows/DOS we make the assumption that we can
			 * always write to the tty: therefore if we need to
			 * write to the tty we just fall through. Otherwise
			 * we timeout the select every second and see if there
			 * are any keypresses. Note: this is a hack, in a proper
			 * Windows application we wouldn't do this.
			 */
Ulf Möller's avatar
Ulf Möller committed
			i=0;
			if(!write_tty) {
				if(read_tty) {
					tv.tv_sec = 1;
					tv.tv_usec = 0;
					i=select(width,(void *)&readfds,(void *)&writefds,
						 NULL,&tv);
#if defined(OPENSSL_SYS_WINCE) || defined(OPENSSL_SYS_MSDOS)
Richard Levitte's avatar
Richard Levitte committed
					if(!i && (!_kbhit() || !read_tty) ) continue;
#else
					if(!i && (!((_kbhit()) || (WAIT_OBJECT_0 == WaitForSingleObject(GetStdHandle(STD_INPUT_HANDLE), 0))) || !read_tty) ) continue;
Richard Levitte's avatar
Richard Levitte committed
#endif
				} else 	i=select(width,(void *)&readfds,(void *)&writefds,
Dr. Stephen Henson's avatar
Dr. Stephen Henson committed
					 NULL,timeoutp);
#elif defined(OPENSSL_SYS_NETWARE)
			if(!write_tty) {
				if(read_tty) {
					tv.tv_sec = 1;
					tv.tv_usec = 0;
					i=select(width,(void *)&readfds,(void *)&writefds,
						NULL,&tv);
				} else 	i=select(width,(void *)&readfds,(void *)&writefds,
Dr. Stephen Henson's avatar
Dr. Stephen Henson committed
					NULL,timeoutp);
Ulf Möller's avatar
Ulf Möller committed
#elif defined(OPENSSL_SYS_BEOS_R5)
			/* Under BeOS-R5 the situation is similar to DOS */
			i=0;
			stdin_set = 0;
			(void)fcntl(fileno(stdin), F_SETFL, O_NONBLOCK);
			if(!write_tty) {
				if(read_tty) {
					tv.tv_sec = 1;
					tv.tv_usec = 0;
					i=select(width,(void *)&readfds,(void *)&writefds,
						 NULL,&tv);
					if (read(fileno(stdin), sbuf, 0) >= 0)
						stdin_set = 1;
					if (!i && (stdin_set != 1 || !read_tty))
						continue;
				} else 	i=select(width,(void *)&readfds,(void *)&writefds,
Dr. Stephen Henson's avatar
Dr. Stephen Henson committed
					 NULL,timeoutp);
Ulf Möller's avatar
Ulf Möller committed
			}
			(void)fcntl(fileno(stdin), F_SETFL, 0);
Ulf Möller's avatar
Ulf Möller committed
			i=select(width,(void *)&readfds,(void *)&writefds,
Dr. Stephen Henson's avatar
Dr. Stephen Henson committed
				 NULL,timeoutp);
			if ( i < 0)
				{
				BIO_printf(bio_err,"bad select %d\n",
				get_last_socket_error());
Dr. Stephen Henson's avatar
Dr. Stephen Henson committed
		if ((SSL_version(con) == DTLS1_VERSION) && DTLSv1_handle_timeout(con) > 0)
			{
			BIO_printf(bio_err,"TIMEOUT occurred\n");
Dr. Stephen Henson's avatar
Dr. Stephen Henson committed
			}

		if (!ssl_pending && FD_ISSET(SSL_get_fd(con),&writefds))
			{
			k=SSL_write(con,&(cbuf[cbuf_off]),
				(unsigned int)cbuf_len);
			switch (SSL_get_error(con,k))
				{
			case SSL_ERROR_NONE:
				cbuf_off+=k;
				cbuf_len-=k;
				if (k <= 0) goto end;
				/* we have done a  write(con,NULL,0); */
				if (cbuf_len <= 0)
					{
					read_tty=1;
					write_ssl=0;
					}
				else /* if (cbuf_len > 0) */
					{
					read_tty=0;
					write_ssl=1;
					}
				break;
			case SSL_ERROR_WANT_WRITE:
				BIO_printf(bio_c_out,"write W BLOCK\n");
				write_ssl=1;
				read_tty=0;
				break;
			case SSL_ERROR_WANT_READ:
				BIO_printf(bio_c_out,"write R BLOCK\n");
				write_tty=0;
				read_ssl=1;
				write_ssl=0;
				break;
			case SSL_ERROR_WANT_X509_LOOKUP:
				BIO_printf(bio_c_out,"write X BLOCK\n");
				break;
			case SSL_ERROR_ZERO_RETURN:
				if (cbuf_len != 0)
					{
					BIO_printf(bio_c_out,"shutdown\n");
					goto shut;
					}
				else
					{
					read_tty=1;
					write_ssl=0;
					break;
					}
				
			case SSL_ERROR_SYSCALL:
				if ((k != 0) || (cbuf_len != 0))
					{
					BIO_printf(bio_err,"write:errno=%d\n",
						get_last_socket_error());
					goto shut;
					}
				else
					{
					read_tty=1;
					write_ssl=0;
					}
				break;
			case SSL_ERROR_SSL:
				ERR_print_errors(bio_err);
				goto shut;
				}
			}
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)
		/* Assume Windows/DOS/BeOS can always write */
		else if (!ssl_pending && FD_ISSET(fileno(stdout),&writefds))
#ifdef CHARSET_EBCDIC
			ascii2ebcdic(&(sbuf[sbuf_off]),&(sbuf[sbuf_off]),sbuf_len);
#endif
			i=raw_write_stdout(&(sbuf[sbuf_off]),sbuf_len);

			if (i <= 0)
				{
				BIO_printf(bio_c_out,"DONE\n");
				goto shut;
				/* goto end; */
				}

			sbuf_len-=i;;
			sbuf_off+=i;
			if (sbuf_len <= 0)
				{
				read_ssl=1;
				write_tty=0;
				}
			}
		else if (ssl_pending || FD_ISSET(SSL_get_fd(con),&readfds))
#ifdef RENEG
{ static int iiii; if (++iiii == 52) { SSL_renegotiate(con); iiii=0; } }
#endif
			k=SSL_read(con,sbuf,1024 /* BUFSIZZ */ );
#else
/* Demo for pending and peek :-) */
			k=SSL_read(con,sbuf,16);
{ char zbuf[10240]; 
printf("read=%d pending=%d peek=%d\n",k,SSL_pending(con),SSL_peek(con,zbuf,10240));
}
#endif