xref: /openbsd-src/usr.bin/openssl/s_client.c (revision 276e91b29af6039e8cabdd5579518fa632fcb7f6)
1*276e91b2Stb /* $OpenBSD: s_client.c,v 1.67 2025/01/02 16:07:41 tb Exp $ */
2dab3f910Sjsing /* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com)
3dab3f910Sjsing  * All rights reserved.
4dab3f910Sjsing  *
5dab3f910Sjsing  * This package is an SSL implementation written
6dab3f910Sjsing  * by Eric Young (eay@cryptsoft.com).
7dab3f910Sjsing  * The implementation was written so as to conform with Netscapes SSL.
8dab3f910Sjsing  *
9dab3f910Sjsing  * This library is free for commercial and non-commercial use as long as
10dab3f910Sjsing  * the following conditions are aheared to.  The following conditions
11dab3f910Sjsing  * apply to all code found in this distribution, be it the RC4, RSA,
12dab3f910Sjsing  * lhash, DES, etc., code; not just the SSL code.  The SSL documentation
13dab3f910Sjsing  * included with this distribution is covered by the same copyright terms
14dab3f910Sjsing  * except that the holder is Tim Hudson (tjh@cryptsoft.com).
15dab3f910Sjsing  *
16dab3f910Sjsing  * Copyright remains Eric Young's, and as such any Copyright notices in
17dab3f910Sjsing  * the code are not to be removed.
18dab3f910Sjsing  * If this package is used in a product, Eric Young should be given attribution
19dab3f910Sjsing  * as the author of the parts of the library used.
20dab3f910Sjsing  * This can be in the form of a textual message at program startup or
21dab3f910Sjsing  * in documentation (online or textual) provided with the package.
22dab3f910Sjsing  *
23dab3f910Sjsing  * Redistribution and use in source and binary forms, with or without
24dab3f910Sjsing  * modification, are permitted provided that the following conditions
25dab3f910Sjsing  * are met:
26dab3f910Sjsing  * 1. Redistributions of source code must retain the copyright
27dab3f910Sjsing  *    notice, this list of conditions and the following disclaimer.
28dab3f910Sjsing  * 2. Redistributions in binary form must reproduce the above copyright
29dab3f910Sjsing  *    notice, this list of conditions and the following disclaimer in the
30dab3f910Sjsing  *    documentation and/or other materials provided with the distribution.
31dab3f910Sjsing  * 3. All advertising materials mentioning features or use of this software
32dab3f910Sjsing  *    must display the following acknowledgement:
33dab3f910Sjsing  *    "This product includes cryptographic software written by
34dab3f910Sjsing  *     Eric Young (eay@cryptsoft.com)"
35dab3f910Sjsing  *    The word 'cryptographic' can be left out if the rouines from the library
36dab3f910Sjsing  *    being used are not cryptographic related :-).
37dab3f910Sjsing  * 4. If you include any Windows specific code (or a derivative thereof) from
38dab3f910Sjsing  *    the apps directory (application code) you must include an acknowledgement:
39dab3f910Sjsing  *    "This product includes software written by Tim Hudson (tjh@cryptsoft.com)"
40dab3f910Sjsing  *
41dab3f910Sjsing  * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND
42dab3f910Sjsing  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
43dab3f910Sjsing  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
44dab3f910Sjsing  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
45dab3f910Sjsing  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
46dab3f910Sjsing  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
47dab3f910Sjsing  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
48dab3f910Sjsing  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
49dab3f910Sjsing  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
50dab3f910Sjsing  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
51dab3f910Sjsing  * SUCH DAMAGE.
52dab3f910Sjsing  *
53dab3f910Sjsing  * The licence and distribution terms for any publically available version or
54dab3f910Sjsing  * derivative of this code cannot be changed.  i.e. this code cannot simply be
55dab3f910Sjsing  * copied and put under another distribution licence
56dab3f910Sjsing  * [including the GNU Public Licence.]
57dab3f910Sjsing  */
58dab3f910Sjsing /* ====================================================================
59dab3f910Sjsing  * Copyright (c) 1998-2006 The OpenSSL Project.  All rights reserved.
60dab3f910Sjsing  *
61dab3f910Sjsing  * Redistribution and use in source and binary forms, with or without
62dab3f910Sjsing  * modification, are permitted provided that the following conditions
63dab3f910Sjsing  * are met:
64dab3f910Sjsing  *
65dab3f910Sjsing  * 1. Redistributions of source code must retain the above copyright
66dab3f910Sjsing  *    notice, this list of conditions and the following disclaimer.
67dab3f910Sjsing  *
68dab3f910Sjsing  * 2. Redistributions in binary form must reproduce the above copyright
69dab3f910Sjsing  *    notice, this list of conditions and the following disclaimer in
70dab3f910Sjsing  *    the documentation and/or other materials provided with the
71dab3f910Sjsing  *    distribution.
72dab3f910Sjsing  *
73dab3f910Sjsing  * 3. All advertising materials mentioning features or use of this
74dab3f910Sjsing  *    software must display the following acknowledgment:
75dab3f910Sjsing  *    "This product includes software developed by the OpenSSL Project
76dab3f910Sjsing  *    for use in the OpenSSL Toolkit. (http://www.openssl.org/)"
77dab3f910Sjsing  *
78dab3f910Sjsing  * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to
79dab3f910Sjsing  *    endorse or promote products derived from this software without
80dab3f910Sjsing  *    prior written permission. For written permission, please contact
81dab3f910Sjsing  *    openssl-core@openssl.org.
82dab3f910Sjsing  *
83dab3f910Sjsing  * 5. Products derived from this software may not be called "OpenSSL"
84dab3f910Sjsing  *    nor may "OpenSSL" appear in their names without prior written
85dab3f910Sjsing  *    permission of the OpenSSL Project.
86dab3f910Sjsing  *
87dab3f910Sjsing  * 6. Redistributions of any form whatsoever must retain the following
88dab3f910Sjsing  *    acknowledgment:
89dab3f910Sjsing  *    "This product includes software developed by the OpenSSL Project
90dab3f910Sjsing  *    for use in the OpenSSL Toolkit (http://www.openssl.org/)"
91dab3f910Sjsing  *
92dab3f910Sjsing  * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY
93dab3f910Sjsing  * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
94dab3f910Sjsing  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
95dab3f910Sjsing  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE OpenSSL PROJECT OR
96dab3f910Sjsing  * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
97dab3f910Sjsing  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
98dab3f910Sjsing  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
99dab3f910Sjsing  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
100dab3f910Sjsing  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
101dab3f910Sjsing  * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
102dab3f910Sjsing  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
103dab3f910Sjsing  * OF THE POSSIBILITY OF SUCH DAMAGE.
104dab3f910Sjsing  * ====================================================================
105dab3f910Sjsing  *
106dab3f910Sjsing  * This product includes cryptographic software written by Eric Young
107dab3f910Sjsing  * (eay@cryptsoft.com).  This product includes software written by Tim
108dab3f910Sjsing  * Hudson (tjh@cryptsoft.com).
109dab3f910Sjsing  *
110dab3f910Sjsing  */
111dab3f910Sjsing /* ====================================================================
112dab3f910Sjsing  * Copyright 2005 Nokia. All rights reserved.
113dab3f910Sjsing  *
114dab3f910Sjsing  * The portions of the attached software ("Contribution") is developed by
115dab3f910Sjsing  * Nokia Corporation and is licensed pursuant to the OpenSSL open source
116dab3f910Sjsing  * license.
117dab3f910Sjsing  *
118dab3f910Sjsing  * The Contribution, originally written by Mika Kousa and Pasi Eronen of
119dab3f910Sjsing  * Nokia Corporation, consists of the "PSK" (Pre-Shared Key) ciphersuites
120dab3f910Sjsing  * support (see RFC 4279) to OpenSSL.
121dab3f910Sjsing  *
122dab3f910Sjsing  * No patent licenses or other rights except those expressly stated in
123dab3f910Sjsing  * the OpenSSL open source license shall be deemed granted or received
124dab3f910Sjsing  * expressly, by implication, estoppel, or otherwise.
125dab3f910Sjsing  *
126dab3f910Sjsing  * No assurances are provided by Nokia that the Contribution does not
127dab3f910Sjsing  * infringe the patent or other intellectual property rights of any third
128dab3f910Sjsing  * party or that the license provides you with all the necessary rights
129dab3f910Sjsing  * to make use of the Contribution.
130dab3f910Sjsing  *
131dab3f910Sjsing  * THE SOFTWARE IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY KIND. IN
132dab3f910Sjsing  * ADDITION TO THE DISCLAIMERS INCLUDED IN THE LICENSE, NOKIA
133dab3f910Sjsing  * SPECIFICALLY DISCLAIMS ANY LIABILITY FOR CLAIMS BROUGHT BY YOU OR ANY
134dab3f910Sjsing  * OTHER ENTITY BASED ON INFRINGEMENT OF INTELLECTUAL PROPERTY RIGHTS OR
135dab3f910Sjsing  * OTHERWISE.
136dab3f910Sjsing  */
137dab3f910Sjsing 
138dab3f910Sjsing #include <sys/types.h>
139dab3f910Sjsing #include <sys/socket.h>
140dab3f910Sjsing 
141dab3f910Sjsing #include <netinet/in.h>
142dab3f910Sjsing 
143dab3f910Sjsing #include <assert.h>
144dab3f910Sjsing #include <ctype.h>
145dab3f910Sjsing #include <limits.h>
146dab3f910Sjsing #include <netdb.h>
147dab3f910Sjsing #include <stdio.h>
148dab3f910Sjsing #include <stdlib.h>
149dab3f910Sjsing #include <string.h>
150dab3f910Sjsing #include <unistd.h>
1519c8ea7b6Sderaadt #include <poll.h>
152dab3f910Sjsing 
153dab3f910Sjsing #include "apps.h"
154dab3f910Sjsing 
155dab3f910Sjsing #include <openssl/bn.h>
156dab3f910Sjsing #include <openssl/err.h>
157dab3f910Sjsing #include <openssl/ocsp.h>
158dab3f910Sjsing #include <openssl/pem.h>
159dab3f910Sjsing #include <openssl/ssl.h>
160dab3f910Sjsing #include <openssl/x509.h>
161dab3f910Sjsing 
162dab3f910Sjsing #define SSL_HOST_NAME	"localhost"
163dab3f910Sjsing 
164dab3f910Sjsing #define BUFSIZZ 1024*8
165dab3f910Sjsing 
166dab3f910Sjsing static void sc_usage(void);
167dab3f910Sjsing static void print_stuff(BIO *berr, SSL *con, int full);
168dab3f910Sjsing static int ocsp_resp_cb(SSL *s, void *arg);
169a2111520Sinoguchi static int ssl_servername_cb(SSL *s, int *ad, void *arg);
170dab3f910Sjsing 
17110281ad2Sinoguchi enum {
17210281ad2Sinoguchi 	PROTO_OFF = 0,
17310281ad2Sinoguchi 	PROTO_SMTP,
17410281ad2Sinoguchi 	PROTO_LMTP,
17510281ad2Sinoguchi 	PROTO_POP3,
17610281ad2Sinoguchi 	PROTO_IMAP,
17710281ad2Sinoguchi 	PROTO_FTP,
17810281ad2Sinoguchi 	PROTO_XMPP,
17910281ad2Sinoguchi };
18010281ad2Sinoguchi 
181a2111520Sinoguchi /* This is a context that we pass to callbacks */
182a2111520Sinoguchi typedef struct tlsextctx_st {
183a2111520Sinoguchi 	BIO *biodebug;
184a2111520Sinoguchi 	int ack;
185a2111520Sinoguchi } tlsextctx;
186a2111520Sinoguchi 
18710281ad2Sinoguchi static struct {
18810281ad2Sinoguchi 	int af;
18910281ad2Sinoguchi 	char *alpn_in;
19010281ad2Sinoguchi 	int bugs;
19110281ad2Sinoguchi 	char *CAfile;
19210281ad2Sinoguchi 	char *CApath;
19310281ad2Sinoguchi 	char *cert_file;
19410281ad2Sinoguchi 	int cert_format;
19510281ad2Sinoguchi 	char *cipher;
19610281ad2Sinoguchi 	unsigned int clr;
19710281ad2Sinoguchi 	char *connect;
19810281ad2Sinoguchi 	int crlf;
1996dcdcd8fSinoguchi 	int debug;
20010281ad2Sinoguchi 	int enable_timeouts;
20110281ad2Sinoguchi 	const char *errstr;
20210281ad2Sinoguchi 	char *groups_in;
20310281ad2Sinoguchi 	char *host;
2046dcdcd8fSinoguchi 	int ign_eof;
20510281ad2Sinoguchi 	char *key_file;
20610281ad2Sinoguchi 	int key_format;
20710281ad2Sinoguchi 	char *keymatexportlabel;
20810281ad2Sinoguchi 	int keymatexportlen;
20910281ad2Sinoguchi 	uint16_t max_version;
21010281ad2Sinoguchi 	uint16_t min_version;
21110281ad2Sinoguchi 	const SSL_METHOD *meth;
2126dcdcd8fSinoguchi 	int msg;
2136dcdcd8fSinoguchi 	int nbio;
21410281ad2Sinoguchi 	int nbio_test;
215cb7cbc09Sjsing 	int no_servername;
21610281ad2Sinoguchi 	char *npn_in;
21710281ad2Sinoguchi 	unsigned int off;
21810281ad2Sinoguchi 	char *passarg;
21910281ad2Sinoguchi 	int peekaboo;
22010281ad2Sinoguchi 	char *port;
22110281ad2Sinoguchi 	int prexit;
22210281ad2Sinoguchi 	char *proxy;
2236dcdcd8fSinoguchi 	int quiet;
22410281ad2Sinoguchi 	int reconnect;
22510281ad2Sinoguchi 	char *servername;
22610281ad2Sinoguchi 	char *sess_in;
22710281ad2Sinoguchi 	char *sess_out;
2286dcdcd8fSinoguchi 	int showcerts;
22910281ad2Sinoguchi 	int socket_type;
23010281ad2Sinoguchi 	long socket_mtu;
23110281ad2Sinoguchi #ifndef OPENSSL_NO_SRTP
23210281ad2Sinoguchi 	char *srtp_profiles;
23310281ad2Sinoguchi #endif
23410281ad2Sinoguchi 	int starttls_proto;
23510281ad2Sinoguchi 	int state;
2366dcdcd8fSinoguchi 	int status_req;
2376dcdcd8fSinoguchi 	int tlsextdebug;
23810281ad2Sinoguchi 	int verify;
23910281ad2Sinoguchi 	X509_VERIFY_PARAM *vpm;
24010281ad2Sinoguchi 	char *xmpphost;
241e7718adaStb } cfg;
24210281ad2Sinoguchi 
24310281ad2Sinoguchi static int
24410281ad2Sinoguchi s_client_opt_keymatexportlen(char *arg)
24510281ad2Sinoguchi {
246e7718adaStb 	cfg.keymatexportlen = strtonum(arg, 1, INT_MAX,
247e7718adaStb 	    &cfg.errstr);
248e7718adaStb 	if (cfg.errstr != NULL) {
24910281ad2Sinoguchi 		BIO_printf(bio_err, "invalid argument %s: %s\n",
250e7718adaStb 		    arg, cfg.errstr);
25110281ad2Sinoguchi 		return (1);
25210281ad2Sinoguchi 	}
25310281ad2Sinoguchi 	return (0);
25410281ad2Sinoguchi }
25510281ad2Sinoguchi 
25693dafd19Sjsing #ifndef OPENSSL_NO_DTLS
25710281ad2Sinoguchi static int
25810281ad2Sinoguchi s_client_opt_mtu(char *arg)
25910281ad2Sinoguchi {
260e7718adaStb 	cfg.socket_mtu = strtonum(arg, 0, LONG_MAX,
261e7718adaStb 	    &cfg.errstr);
262e7718adaStb 	if (cfg.errstr != NULL) {
26310281ad2Sinoguchi 		BIO_printf(bio_err, "invalid argument %s: %s\n",
264e7718adaStb 		    arg, cfg.errstr);
26510281ad2Sinoguchi 		return (1);
26610281ad2Sinoguchi 	}
26710281ad2Sinoguchi 	return (0);
26810281ad2Sinoguchi }
26910281ad2Sinoguchi #endif
27010281ad2Sinoguchi 
27110281ad2Sinoguchi static int
27210281ad2Sinoguchi s_client_opt_port(char *arg)
27310281ad2Sinoguchi {
27410281ad2Sinoguchi 	if (*arg == '\0')
27510281ad2Sinoguchi 		return (1);
27610281ad2Sinoguchi 
277e7718adaStb 	cfg.port = arg;
27810281ad2Sinoguchi 	return (0);
27910281ad2Sinoguchi }
28010281ad2Sinoguchi 
28193dafd19Sjsing #ifndef OPENSSL_NO_DTLS
28293dafd19Sjsing static int
28393dafd19Sjsing s_client_opt_protocol_version_dtls(void)
28493dafd19Sjsing {
285e7718adaStb 	cfg.meth = DTLS_client_method();
286e7718adaStb 	cfg.socket_type = SOCK_DGRAM;
28793dafd19Sjsing 	return (0);
28893dafd19Sjsing }
28993dafd19Sjsing #endif
29093dafd19Sjsing 
29193dafd19Sjsing #ifndef OPENSSL_NO_DTLS1_2
29293dafd19Sjsing static int
29393dafd19Sjsing s_client_opt_protocol_version_dtls1_2(void)
29493dafd19Sjsing {
295e7718adaStb 	cfg.meth = DTLS_client_method();
296e7718adaStb 	cfg.min_version = DTLS1_2_VERSION;
297e7718adaStb 	cfg.max_version = DTLS1_2_VERSION;
298e7718adaStb 	cfg.socket_type = SOCK_DGRAM;
29910281ad2Sinoguchi 	return (0);
30010281ad2Sinoguchi }
30110281ad2Sinoguchi #endif
30210281ad2Sinoguchi 
30310281ad2Sinoguchi static int
30410281ad2Sinoguchi s_client_opt_protocol_version_tls1_2(void)
30510281ad2Sinoguchi {
306e7718adaStb 	cfg.min_version = TLS1_2_VERSION;
307e7718adaStb 	cfg.max_version = TLS1_2_VERSION;
30810281ad2Sinoguchi 	return (0);
30910281ad2Sinoguchi }
31010281ad2Sinoguchi 
31110281ad2Sinoguchi static int
31210281ad2Sinoguchi s_client_opt_protocol_version_tls1_3(void)
31310281ad2Sinoguchi {
314e7718adaStb 	cfg.min_version = TLS1_3_VERSION;
315e7718adaStb 	cfg.max_version = TLS1_3_VERSION;
31610281ad2Sinoguchi 	return (0);
31710281ad2Sinoguchi }
31810281ad2Sinoguchi 
31910281ad2Sinoguchi static int
32010281ad2Sinoguchi s_client_opt_quiet(void)
32110281ad2Sinoguchi {
322e7718adaStb 	cfg.quiet = 1;
323e7718adaStb 	cfg.ign_eof = 1;
32410281ad2Sinoguchi 	return (0);
32510281ad2Sinoguchi }
32610281ad2Sinoguchi 
32710281ad2Sinoguchi static int
32810281ad2Sinoguchi s_client_opt_starttls(char *arg)
32910281ad2Sinoguchi {
33010281ad2Sinoguchi 	if (strcmp(arg, "smtp") == 0)
331e7718adaStb 		cfg.starttls_proto = PROTO_SMTP;
33210281ad2Sinoguchi 	else if (strcmp(arg, "lmtp") == 0)
333e7718adaStb 		cfg.starttls_proto = PROTO_LMTP;
33410281ad2Sinoguchi 	else if (strcmp(arg, "pop3") == 0)
335e7718adaStb 		cfg.starttls_proto = PROTO_POP3;
33610281ad2Sinoguchi 	else if (strcmp(arg, "imap") == 0)
337e7718adaStb 		cfg.starttls_proto = PROTO_IMAP;
33810281ad2Sinoguchi 	else if (strcmp(arg, "ftp") == 0)
339e7718adaStb 		cfg.starttls_proto = PROTO_FTP;
34010281ad2Sinoguchi 	else if (strcmp(arg, "xmpp") == 0)
341e7718adaStb 		cfg.starttls_proto = PROTO_XMPP;
34210281ad2Sinoguchi 	else
34310281ad2Sinoguchi 		return (1);
34410281ad2Sinoguchi 	return (0);
34510281ad2Sinoguchi }
34610281ad2Sinoguchi 
34710281ad2Sinoguchi static int
34810281ad2Sinoguchi s_client_opt_verify(char *arg)
34910281ad2Sinoguchi {
350e7718adaStb 	cfg.verify = SSL_VERIFY_PEER;
35110281ad2Sinoguchi 
352e7718adaStb 	verify_depth = strtonum(arg, 0, INT_MAX, &cfg.errstr);
353e7718adaStb 	if (cfg.errstr != NULL) {
35410281ad2Sinoguchi 		BIO_printf(bio_err, "invalid argument %s: %s\n",
355e7718adaStb 		    arg, cfg.errstr);
35610281ad2Sinoguchi 		return (1);
35710281ad2Sinoguchi 	}
35810281ad2Sinoguchi 	BIO_printf(bio_err, "verify depth is %d\n", verify_depth);
35910281ad2Sinoguchi 	return (0);
36010281ad2Sinoguchi }
36110281ad2Sinoguchi 
36210281ad2Sinoguchi static int
36310281ad2Sinoguchi s_client_opt_verify_param(int argc, char **argv, int *argsused)
36410281ad2Sinoguchi {
36510281ad2Sinoguchi 	char **pargs = argv;
36610281ad2Sinoguchi 	int pargc = argc;
36710281ad2Sinoguchi 	int badarg = 0;
36810281ad2Sinoguchi 
36910281ad2Sinoguchi 	if (!args_verify(&pargs, &pargc, &badarg, bio_err,
370e7718adaStb 	    &cfg.vpm)) {
37110281ad2Sinoguchi 		BIO_printf(bio_err, "unknown option %s\n", *argv);
37210281ad2Sinoguchi 		return (1);
37310281ad2Sinoguchi 	}
37410281ad2Sinoguchi 	if (badarg)
37510281ad2Sinoguchi 		return (1);
37610281ad2Sinoguchi 
37710281ad2Sinoguchi 	*argsused = argc - pargc;
37810281ad2Sinoguchi 	return (0);
37910281ad2Sinoguchi }
38010281ad2Sinoguchi 
38110281ad2Sinoguchi static const struct option s_client_options[] = {
38210281ad2Sinoguchi 	{
38310281ad2Sinoguchi 		.name = "4",
38410281ad2Sinoguchi 		.desc = "Use IPv4 only",
38510281ad2Sinoguchi 		.type = OPTION_VALUE,
386e7718adaStb 		.opt.value = &cfg.af,
38710281ad2Sinoguchi 		.value = AF_INET,
38810281ad2Sinoguchi 	},
38910281ad2Sinoguchi 	{
39010281ad2Sinoguchi 		.name = "6",
39110281ad2Sinoguchi 		.desc = "Use IPv6 only",
39210281ad2Sinoguchi 		.type = OPTION_VALUE,
393e7718adaStb 		.opt.value = &cfg.af,
39410281ad2Sinoguchi 		.value = AF_INET6,
39510281ad2Sinoguchi 	},
39610281ad2Sinoguchi 	{
39710281ad2Sinoguchi 		.name = "alpn",
39810281ad2Sinoguchi 		.argname = "protocols",
39910281ad2Sinoguchi 		.desc = "Set the advertised protocols for ALPN"
40010281ad2Sinoguchi 			" (comma-separated list)",
40110281ad2Sinoguchi 		.type = OPTION_ARG,
402e7718adaStb 		.opt.arg = &cfg.alpn_in,
40310281ad2Sinoguchi 	},
40410281ad2Sinoguchi 	{
40510281ad2Sinoguchi 		.name = "bugs",
40610281ad2Sinoguchi 		.desc = "Enable various workarounds for buggy implementations",
40710281ad2Sinoguchi 		.type = OPTION_FLAG,
408e7718adaStb 		.opt.flag = &cfg.bugs,
40910281ad2Sinoguchi 	},
41010281ad2Sinoguchi 	{
41110281ad2Sinoguchi 		.name = "CAfile",
41210281ad2Sinoguchi 		.argname = "file",
41310281ad2Sinoguchi 		.desc = "PEM format file of CA certificates",
41410281ad2Sinoguchi 		.type = OPTION_ARG,
415e7718adaStb 		.opt.arg = &cfg.CAfile,
41610281ad2Sinoguchi 	},
41710281ad2Sinoguchi 	{
41810281ad2Sinoguchi 		.name = "CApath",
41910281ad2Sinoguchi 		.argname = "directory",
42010281ad2Sinoguchi 		.desc = "PEM format directory of CA certificates",
42110281ad2Sinoguchi 		.type = OPTION_ARG,
422e7718adaStb 		.opt.arg = &cfg.CApath,
42310281ad2Sinoguchi 	},
42410281ad2Sinoguchi 	{
42510281ad2Sinoguchi 		.name = "cert",
42610281ad2Sinoguchi 		.argname = "file",
42710281ad2Sinoguchi 		.desc = "Certificate file to use, PEM format assumed",
42810281ad2Sinoguchi 		.type = OPTION_ARG,
429e7718adaStb 		.opt.arg = &cfg.cert_file,
43010281ad2Sinoguchi 	},
43110281ad2Sinoguchi 	{
43210281ad2Sinoguchi 		.name = "certform",
43310281ad2Sinoguchi 		.argname = "fmt",
43410281ad2Sinoguchi 		.desc = "Certificate format (PEM or DER) PEM default",
43510281ad2Sinoguchi 		.type = OPTION_ARG_FORMAT,
436e7718adaStb 		.opt.value = &cfg.cert_format,
43710281ad2Sinoguchi 	},
43810281ad2Sinoguchi 	{
43910281ad2Sinoguchi 		.name = "cipher",
44010281ad2Sinoguchi 		.argname = "cipherlist",
44110281ad2Sinoguchi 		.desc = "Preferred cipher to use (see 'openssl ciphers')",
44210281ad2Sinoguchi 		.type = OPTION_ARG,
443e7718adaStb 		.opt.arg = &cfg.cipher,
44410281ad2Sinoguchi 	},
44510281ad2Sinoguchi 	{
44610281ad2Sinoguchi 		.name = "connect",
44710281ad2Sinoguchi 		.argname = "host:port",
44810281ad2Sinoguchi 		.desc = "Who to connect to (default is localhost:4433)",
44910281ad2Sinoguchi 		.type = OPTION_ARG,
450e7718adaStb 		.opt.arg = &cfg.connect,
45110281ad2Sinoguchi 	},
45210281ad2Sinoguchi 	{
45310281ad2Sinoguchi 		.name = "crlf",
45410281ad2Sinoguchi 		.desc = "Convert LF from terminal into CRLF",
45510281ad2Sinoguchi 		.type = OPTION_FLAG,
456e7718adaStb 		.opt.flag = &cfg.crlf,
45710281ad2Sinoguchi 	},
45810281ad2Sinoguchi 	{
45910281ad2Sinoguchi 		.name = "debug",
46010281ad2Sinoguchi 		.desc = "Print extensive debugging information",
46110281ad2Sinoguchi 		.type = OPTION_FLAG,
462e7718adaStb 		.opt.flag = &cfg.debug,
46310281ad2Sinoguchi 	},
46493dafd19Sjsing #ifndef OPENSSL_NO_DTLS
46593dafd19Sjsing 	{
46693dafd19Sjsing 		.name = "dtls",
46793dafd19Sjsing 		.desc = "Use any version of DTLS",
46893dafd19Sjsing 		.type = OPTION_FUNC,
46993dafd19Sjsing 		.opt.func = s_client_opt_protocol_version_dtls,
47093dafd19Sjsing 	},
47193dafd19Sjsing #endif
47293dafd19Sjsing #ifndef OPENSSL_NO_DTLS1_2
47393dafd19Sjsing 	{
47493dafd19Sjsing 		.name = "dtls1_2",
47593dafd19Sjsing 		.desc = "Just use DTLSv1.2",
47693dafd19Sjsing 		.type = OPTION_FUNC,
47793dafd19Sjsing 		.opt.func = s_client_opt_protocol_version_dtls1_2,
47893dafd19Sjsing 	},
47993dafd19Sjsing #endif
48010281ad2Sinoguchi 	{
48110281ad2Sinoguchi 		.name = "groups",
48210281ad2Sinoguchi 		.argname = "list",
48310281ad2Sinoguchi 		.desc = "Specify EC groups (colon-separated list)",
48410281ad2Sinoguchi 		.type = OPTION_ARG,
485e7718adaStb 		.opt.arg = &cfg.groups_in,
48610281ad2Sinoguchi 	},
48710281ad2Sinoguchi 	{
48810281ad2Sinoguchi 		.name = "host",
48910281ad2Sinoguchi 		.argname = "host",
49010281ad2Sinoguchi 		.desc = "Use -connect instead",
49110281ad2Sinoguchi 		.type = OPTION_ARG,
492e7718adaStb 		.opt.arg = &cfg.host,
49310281ad2Sinoguchi 	},
49410281ad2Sinoguchi 	{
49510281ad2Sinoguchi 		.name = "ign_eof",
49610281ad2Sinoguchi 		.desc = "Ignore input EOF (default when -quiet)",
49710281ad2Sinoguchi 		.type = OPTION_VALUE,
498e7718adaStb 		.opt.value = &cfg.ign_eof,
49910281ad2Sinoguchi 		.value = 1,
50010281ad2Sinoguchi 	},
50110281ad2Sinoguchi 	{
50210281ad2Sinoguchi 		.name = "key",
50310281ad2Sinoguchi 		.argname = "file",
50410281ad2Sinoguchi 		.desc = "Private key file to use, if not, -cert file is used",
50510281ad2Sinoguchi 		.type = OPTION_ARG,
506e7718adaStb 		.opt.arg = &cfg.key_file,
50710281ad2Sinoguchi 	},
50810281ad2Sinoguchi 	{
50910281ad2Sinoguchi 		.name = "keyform",
51010281ad2Sinoguchi 		.argname = "fmt",
51110281ad2Sinoguchi 		.desc = "Key format (PEM or DER) PEM default",
51210281ad2Sinoguchi 		.type = OPTION_ARG_FORMAT,
513e7718adaStb 		.opt.value = &cfg.key_format,
51410281ad2Sinoguchi 	},
51510281ad2Sinoguchi 	{
51610281ad2Sinoguchi 		.name = "keymatexport",
51710281ad2Sinoguchi 		.argname = "label",
51810281ad2Sinoguchi 		.desc = "Export keying material using label",
51910281ad2Sinoguchi 		.type = OPTION_ARG,
520e7718adaStb 		.opt.arg = &cfg.keymatexportlabel,
52110281ad2Sinoguchi 	},
52210281ad2Sinoguchi 	{
52310281ad2Sinoguchi 		.name = "keymatexportlen",
52410281ad2Sinoguchi 		.argname = "len",
52510281ad2Sinoguchi 		.desc = "Export len bytes of keying material (default 20)",
52610281ad2Sinoguchi 		.type = OPTION_ARG_FUNC,
52710281ad2Sinoguchi 		.opt.argfunc = s_client_opt_keymatexportlen,
52810281ad2Sinoguchi 	},
52910281ad2Sinoguchi 	{
53010281ad2Sinoguchi 		.name = "legacy_renegotiation",
53110281ad2Sinoguchi 		.type = OPTION_DISCARD,
53210281ad2Sinoguchi 	},
53310281ad2Sinoguchi 	{
53410281ad2Sinoguchi 		.name = "legacy_server_connect",
53510281ad2Sinoguchi 		.desc = "Allow initial connection to servers that don't support RI",
53610281ad2Sinoguchi 		.type = OPTION_VALUE_OR,
537e7718adaStb 		.opt.value = &cfg.off,
53810281ad2Sinoguchi 		.value = SSL_OP_LEGACY_SERVER_CONNECT,
53910281ad2Sinoguchi 	},
54010281ad2Sinoguchi 	{
54110281ad2Sinoguchi 		.name = "msg",
54210281ad2Sinoguchi 		.desc = "Show all protocol messages with hex dump",
54310281ad2Sinoguchi 		.type = OPTION_FLAG,
544e7718adaStb 		.opt.flag = &cfg.msg,
54510281ad2Sinoguchi 	},
54693dafd19Sjsing #ifndef OPENSSL_NO_DTLS
54710281ad2Sinoguchi 	{
54810281ad2Sinoguchi 		.name = "mtu",
54910281ad2Sinoguchi 		.argname = "mtu",
55010281ad2Sinoguchi 		.desc = "Set the link layer MTU on DTLS connections",
55110281ad2Sinoguchi 		.type = OPTION_ARG_FUNC,
55210281ad2Sinoguchi 		.opt.argfunc = s_client_opt_mtu,
55310281ad2Sinoguchi 	},
55410281ad2Sinoguchi #endif
55510281ad2Sinoguchi 	{
55610281ad2Sinoguchi 		.name = "nbio",
55710281ad2Sinoguchi 		.desc = "Turn on non-blocking I/O",
55810281ad2Sinoguchi 		.type = OPTION_FLAG,
559e7718adaStb 		.opt.flag = &cfg.nbio,
56010281ad2Sinoguchi 	},
56110281ad2Sinoguchi 	{
56210281ad2Sinoguchi 		.name = "nbio_test",
56310281ad2Sinoguchi 		.desc = "Test non-blocking I/O",
56410281ad2Sinoguchi 		.type = OPTION_FLAG,
565e7718adaStb 		.opt.flag = &cfg.nbio_test,
56610281ad2Sinoguchi 	},
56710281ad2Sinoguchi 	{
56810281ad2Sinoguchi 		.name = "nextprotoneg",
56910281ad2Sinoguchi 		.argname = "protocols",
57010281ad2Sinoguchi 		.type = OPTION_ARG,
571e7718adaStb 		.opt.arg = &cfg.npn_in, /* Ignored. */
57210281ad2Sinoguchi 	},
57310281ad2Sinoguchi 	{
57410281ad2Sinoguchi 		.name = "no_comp",
57510281ad2Sinoguchi 		.type = OPTION_VALUE_OR,
576e7718adaStb 		.opt.value = &cfg.off,
57710281ad2Sinoguchi 		.value = SSL_OP_NO_COMPRESSION,
57810281ad2Sinoguchi 	},
57910281ad2Sinoguchi 	{
58010281ad2Sinoguchi 		.name = "no_ign_eof",
58110281ad2Sinoguchi 		.desc = "Don't ignore input EOF",
58210281ad2Sinoguchi 		.type = OPTION_VALUE,
583e7718adaStb 		.opt.value = &cfg.ign_eof,
58410281ad2Sinoguchi 		.value = 0,
58510281ad2Sinoguchi 	},
58610281ad2Sinoguchi 	{
58710281ad2Sinoguchi 		.name = "no_legacy_server_connect",
58810281ad2Sinoguchi 		.desc = "Disallow initial connection to servers that don't support RI",
58910281ad2Sinoguchi 		.type = OPTION_VALUE_OR,
590e7718adaStb 		.opt.value = &cfg.clr,
59110281ad2Sinoguchi 		.value = SSL_OP_LEGACY_SERVER_CONNECT,
59210281ad2Sinoguchi 	},
59310281ad2Sinoguchi 	{
594cb7cbc09Sjsing 		.name = "no_servername",
595cb7cbc09Sjsing 		.desc = "Do not send a Server Name Indication (SNI) extension",
596cb7cbc09Sjsing 		.type = OPTION_FLAG,
597e7718adaStb 		.opt.value = &cfg.no_servername,
598cb7cbc09Sjsing 	},
599cb7cbc09Sjsing 	{
60010281ad2Sinoguchi 		.name = "no_ssl2",
60110281ad2Sinoguchi 		.type = OPTION_VALUE_OR,
602e7718adaStb 		.opt.value = &cfg.off,
60310281ad2Sinoguchi 		.value = SSL_OP_NO_SSLv2,
60410281ad2Sinoguchi 	},
60510281ad2Sinoguchi 	{
60610281ad2Sinoguchi 		.name = "no_ssl3",
60710281ad2Sinoguchi 		.type = OPTION_VALUE_OR,
608e7718adaStb 		.opt.value = &cfg.off,
60910281ad2Sinoguchi 		.value = SSL_OP_NO_SSLv3,
61010281ad2Sinoguchi 	},
61110281ad2Sinoguchi 	{
61210281ad2Sinoguchi 		.name = "no_ticket",
61310281ad2Sinoguchi 		.desc = "Disable use of RFC4507 session ticket support",
61410281ad2Sinoguchi 		.type = OPTION_VALUE_OR,
615e7718adaStb 		.opt.value = &cfg.off,
61610281ad2Sinoguchi 		.value = SSL_OP_NO_TICKET,
61710281ad2Sinoguchi 	},
61810281ad2Sinoguchi 	{
619b5c24d4fSbeck 		.name = "no_tls1",
620b5c24d4fSbeck 		.type = OPTION_DISCARD,
621b5c24d4fSbeck 	},
622b5c24d4fSbeck 	{
623b5c24d4fSbeck 		.name = "no_tls1_1",
624b5c24d4fSbeck 		.type = OPTION_DISCARD,
625b5c24d4fSbeck 	},
626b5c24d4fSbeck 	{
62710281ad2Sinoguchi 		.name = "no_tls1_2",
62810281ad2Sinoguchi 		.desc = "Disable the use of TLSv1.2",
62910281ad2Sinoguchi 		.type = OPTION_VALUE_OR,
630e7718adaStb 		.opt.value = &cfg.off,
63110281ad2Sinoguchi 		.value = SSL_OP_NO_TLSv1_2,
63210281ad2Sinoguchi 	},
63310281ad2Sinoguchi 	{
63410281ad2Sinoguchi 		.name = "no_tls1_3",
63510281ad2Sinoguchi 		.desc = "Disable the use of TLSv1.3",
63610281ad2Sinoguchi 		.type = OPTION_VALUE_OR,
637e7718adaStb 		.opt.value = &cfg.off,
63810281ad2Sinoguchi 		.value = SSL_OP_NO_TLSv1_3,
63910281ad2Sinoguchi 	},
64010281ad2Sinoguchi 	{
641cb7cbc09Sjsing 		.name = "noservername",
642cb7cbc09Sjsing 		.type = OPTION_FLAG,
643e7718adaStb 		.opt.value = &cfg.no_servername,
644cb7cbc09Sjsing 	},
645cb7cbc09Sjsing 	{
64610281ad2Sinoguchi 		.name = "pass",
64710281ad2Sinoguchi 		.argname = "arg",
64810281ad2Sinoguchi 		.desc = "Private key file pass phrase source",
64910281ad2Sinoguchi 		.type = OPTION_ARG,
650e7718adaStb 		.opt.arg = &cfg.passarg,
65110281ad2Sinoguchi 	},
65210281ad2Sinoguchi 	{
65310281ad2Sinoguchi 		.name = "pause",
6544578675dStb 		.type = OPTION_DISCARD,
65510281ad2Sinoguchi 	},
65610281ad2Sinoguchi 	{
65710281ad2Sinoguchi 		.name = "peekaboo",
65810281ad2Sinoguchi 		.type = OPTION_FLAG,
659e7718adaStb 		.opt.flag = &cfg.peekaboo,
66010281ad2Sinoguchi 	},
66110281ad2Sinoguchi 	{
66210281ad2Sinoguchi 		.name = "port",
66310281ad2Sinoguchi 		.argname = "port",
66410281ad2Sinoguchi 		.desc = "Use -connect instead",
66510281ad2Sinoguchi 		.type = OPTION_ARG_FUNC,
66610281ad2Sinoguchi 		.opt.argfunc = s_client_opt_port,
66710281ad2Sinoguchi 	},
66810281ad2Sinoguchi 	{
66910281ad2Sinoguchi 		.name = "prexit",
67010281ad2Sinoguchi 		.desc = "Print session information when the program exits",
67110281ad2Sinoguchi 		.type = OPTION_FLAG,
672e7718adaStb 		.opt.flag = &cfg.prexit,
67310281ad2Sinoguchi 	},
67410281ad2Sinoguchi 	{
67510281ad2Sinoguchi 		.name = "proxy",
67610281ad2Sinoguchi 		.argname = "host:port",
67710281ad2Sinoguchi 		.desc = "Connect to http proxy",
67810281ad2Sinoguchi 		.type = OPTION_ARG,
679e7718adaStb 		.opt.arg = &cfg.proxy,
68010281ad2Sinoguchi 	},
68110281ad2Sinoguchi 	{
68210281ad2Sinoguchi 		.name = "quiet",
68310281ad2Sinoguchi 		.desc = "Inhibit printing of session and certificate info",
68410281ad2Sinoguchi 		.type = OPTION_FUNC,
68510281ad2Sinoguchi 		.opt.func = s_client_opt_quiet,
68610281ad2Sinoguchi 	},
68710281ad2Sinoguchi 	{
68810281ad2Sinoguchi 		.name = "reconnect",
68910281ad2Sinoguchi 		.desc = "Drop and re-make the connection with the same Session-ID",
69010281ad2Sinoguchi 		.type = OPTION_VALUE,
691e7718adaStb 		.opt.value = &cfg.reconnect,
69210281ad2Sinoguchi 		.value = 5,
69310281ad2Sinoguchi 	},
69410281ad2Sinoguchi 	{
69510281ad2Sinoguchi 		.name = "servername",
69610281ad2Sinoguchi 		.argname = "name",
69710281ad2Sinoguchi 		.desc = "Set TLS extension servername in ClientHello (SNI)",
69810281ad2Sinoguchi 		.type = OPTION_ARG,
699e7718adaStb 		.opt.arg = &cfg.servername,
70010281ad2Sinoguchi 	},
70110281ad2Sinoguchi 	{
70210281ad2Sinoguchi 		.name = "serverpref",
70310281ad2Sinoguchi 		.desc = "Use server's cipher preferences",
70410281ad2Sinoguchi 		.type = OPTION_VALUE_OR,
705e7718adaStb 		.opt.value = &cfg.off,
70610281ad2Sinoguchi 		.value = SSL_OP_CIPHER_SERVER_PREFERENCE,
70710281ad2Sinoguchi 	},
70810281ad2Sinoguchi 	{
70910281ad2Sinoguchi 		.name = "sess_in",
71010281ad2Sinoguchi 		.argname = "file",
71110281ad2Sinoguchi 		.desc = "File to read TLS session from",
71210281ad2Sinoguchi 		.type = OPTION_ARG,
713e7718adaStb 		.opt.arg = &cfg.sess_in,
71410281ad2Sinoguchi 	},
71510281ad2Sinoguchi 	{
71610281ad2Sinoguchi 		.name = "sess_out",
71710281ad2Sinoguchi 		.argname = "file",
71810281ad2Sinoguchi 		.desc = "File to write TLS session to",
71910281ad2Sinoguchi 		.type = OPTION_ARG,
720e7718adaStb 		.opt.arg = &cfg.sess_out,
72110281ad2Sinoguchi 	},
72210281ad2Sinoguchi 	{
72310281ad2Sinoguchi 		.name = "showcerts",
72410281ad2Sinoguchi 		.desc = "Show all server certificates in the chain",
72510281ad2Sinoguchi 		.type = OPTION_FLAG,
726e7718adaStb 		.opt.flag = &cfg.showcerts,
72710281ad2Sinoguchi 	},
72810281ad2Sinoguchi 	{
72910281ad2Sinoguchi 		.name = "starttls",
73010281ad2Sinoguchi 		.argname = "protocol",
73110281ad2Sinoguchi 		.desc = "Use the STARTTLS command before starting TLS,\n"
73210281ad2Sinoguchi 		        "smtp, lmtp, pop3, imap, ftp and xmpp are supported.",
73310281ad2Sinoguchi 		.type = OPTION_ARG_FUNC,
73410281ad2Sinoguchi 		.opt.argfunc = s_client_opt_starttls,
73510281ad2Sinoguchi 	},
73610281ad2Sinoguchi 	{
73710281ad2Sinoguchi 		.name = "state",
73810281ad2Sinoguchi 		.desc = "Print the TLS session states",
73910281ad2Sinoguchi 		.type = OPTION_FLAG,
740e7718adaStb 		.opt.flag = &cfg.state,
74110281ad2Sinoguchi 	},
74210281ad2Sinoguchi 	{
74310281ad2Sinoguchi 		.name = "status",
74410281ad2Sinoguchi 		.desc = "Send a certificate status request to the server (OCSP)",
74510281ad2Sinoguchi 		.type = OPTION_FLAG,
746e7718adaStb 		.opt.flag = &cfg.status_req,
74710281ad2Sinoguchi 	},
74893dafd19Sjsing #ifndef OPENSSL_NO_DTLS
74910281ad2Sinoguchi 	{
75010281ad2Sinoguchi 		.name = "timeout",
75110281ad2Sinoguchi 		.desc = "Enable send/receive timeout on DTLS connections",
75210281ad2Sinoguchi 		.type = OPTION_FLAG,
753e7718adaStb 		.opt.flag = &cfg.enable_timeouts,
75410281ad2Sinoguchi 	},
75510281ad2Sinoguchi #endif
75610281ad2Sinoguchi 	{
75710281ad2Sinoguchi 		.name = "tls1_2",
75810281ad2Sinoguchi 		.desc = "Just use TLSv1.2",
75910281ad2Sinoguchi 		.type = OPTION_FUNC,
76010281ad2Sinoguchi 		.opt.func = s_client_opt_protocol_version_tls1_2,
76110281ad2Sinoguchi 	},
76210281ad2Sinoguchi 	{
76310281ad2Sinoguchi 		.name = "tls1_3",
76410281ad2Sinoguchi 		.desc = "Just use TLSv1.3",
76510281ad2Sinoguchi 		.type = OPTION_FUNC,
76610281ad2Sinoguchi 		.opt.func = s_client_opt_protocol_version_tls1_3,
76710281ad2Sinoguchi 	},
76810281ad2Sinoguchi 	{
76910281ad2Sinoguchi 		.name = "tlsextdebug",
77010281ad2Sinoguchi 		.desc = "Hex dump of all TLS extensions received",
77110281ad2Sinoguchi 		.type = OPTION_FLAG,
772e7718adaStb 		.opt.flag = &cfg.tlsextdebug,
77310281ad2Sinoguchi 	},
77410281ad2Sinoguchi #ifndef OPENSSL_NO_SRTP
77510281ad2Sinoguchi 	{
77610281ad2Sinoguchi 		.name = "use_srtp",
77710281ad2Sinoguchi 		.argname = "profiles",
77810281ad2Sinoguchi 		.desc = "Offer SRTP key management with a colon-separated profiles",
77910281ad2Sinoguchi 		.type = OPTION_ARG,
780e7718adaStb 		.opt.arg = &cfg.srtp_profiles,
78110281ad2Sinoguchi 	},
78210281ad2Sinoguchi #endif
78310281ad2Sinoguchi 	{
78410281ad2Sinoguchi 		.name = "verify",
78510281ad2Sinoguchi 		.argname = "depth",
78610281ad2Sinoguchi 		.desc = "Turn on peer certificate verification, with a max of depth",
78710281ad2Sinoguchi 		.type = OPTION_ARG_FUNC,
78810281ad2Sinoguchi 		.opt.argfunc = s_client_opt_verify,
78910281ad2Sinoguchi 	},
79010281ad2Sinoguchi 	{
79110281ad2Sinoguchi 		.name = "verify_return_error",
79210281ad2Sinoguchi 		.desc = "Return verification error",
79310281ad2Sinoguchi 		.type = OPTION_FLAG,
79410281ad2Sinoguchi 		.opt.flag = &verify_return_error,
79510281ad2Sinoguchi 	},
79610281ad2Sinoguchi 	{
79710281ad2Sinoguchi 		.name = "xmpphost",
79810281ad2Sinoguchi 		.argname = "host",
79910281ad2Sinoguchi 		.desc = "Connect to this virtual host on the xmpp server",
80010281ad2Sinoguchi 		.type = OPTION_ARG,
801e7718adaStb 		.opt.arg = &cfg.xmpphost,
80210281ad2Sinoguchi 	},
80310281ad2Sinoguchi 	{
80410281ad2Sinoguchi 		.name = NULL,
80510281ad2Sinoguchi 		.desc = "",
80610281ad2Sinoguchi 		.type = OPTION_ARGV_FUNC,
80710281ad2Sinoguchi 		.opt.argvfunc = s_client_opt_verify_param,
80810281ad2Sinoguchi 	},
80910281ad2Sinoguchi 	{ NULL },
81010281ad2Sinoguchi };
811dab3f910Sjsing 
812dab3f910Sjsing static void
813dab3f910Sjsing sc_usage(void)
814dab3f910Sjsing {
81510281ad2Sinoguchi 	fprintf(stderr, "usage: s_client "
81610281ad2Sinoguchi 	    "[-4 | -6] [-alpn protocols] [-bugs] [-CAfile file]\n"
81710281ad2Sinoguchi 	    "    [-CApath directory] [-cert file] [-certform der | pem] [-check_ss_sig]\n"
81810281ad2Sinoguchi 	    "    [-cipher cipherlist] [-connect host[:port]] [-crl_check]\n"
81991e7614aSbeck 	    "    [-crl_check_all] [-crlf] [-debug] [-dtls] [-dtls1_2] [-extended_crl]\n"
82010281ad2Sinoguchi 	    "    [-groups list] [-host host] [-ign_eof] [-ignore_critical]\n"
82110281ad2Sinoguchi 	    "    [-issuer_checks] [-key keyfile] [-keyform der | pem]\n"
82210281ad2Sinoguchi 	    "    [-keymatexport label] [-keymatexportlen len] [-legacy_server_connect]\n"
82310281ad2Sinoguchi 	    "    [-msg] [-mtu mtu] [-nbio] [-nbio_test] [-no_comp] [-no_ign_eof]\n"
82491e7614aSbeck 	    "    [-no_legacy_server_connect] [-no_ticket] \n"
8254578675dStb 	    "    [-no_tls1_2] [-no_tls1_3] [-pass arg] [-policy_check]\n"
82610281ad2Sinoguchi 	    "    [-port port] [-prexit] [-proxy host:port] [-quiet] [-reconnect]\n"
82710281ad2Sinoguchi 	    "    [-servername name] [-serverpref] [-sess_in file] [-sess_out file]\n"
82810281ad2Sinoguchi 	    "    [-showcerts] [-starttls protocol] [-state] [-status] [-timeout]\n"
82991e7614aSbeck 	    "    [-tls1_2] [-tls1_3] [-tlsextdebug]\n"
83010281ad2Sinoguchi 	    "    [-use_srtp profiles] [-verify depth] [-verify_return_error]\n"
83110281ad2Sinoguchi 	    "    [-x509_strict] [-xmpphost host]\n");
83210281ad2Sinoguchi 	fprintf(stderr, "\n");
83310281ad2Sinoguchi 	options_usage(s_client_options);
83410281ad2Sinoguchi 	fprintf(stderr, "\n");
835dab3f910Sjsing }
836dab3f910Sjsing 
837dab3f910Sjsing int
838dab3f910Sjsing s_client_main(int argc, char **argv)
839dab3f910Sjsing {
840dab3f910Sjsing 	SSL *con = NULL;
84110281ad2Sinoguchi 	int s, k, p = 0, pending = 0;
8429c84cee0Sbeck 	char *cbuf = NULL, *sbuf = NULL, *mbuf = NULL, *pbuf = NULL;
843dab3f910Sjsing 	int cbuf_len, cbuf_off;
844dab3f910Sjsing 	int sbuf_len, sbuf_off;
845dab3f910Sjsing 	int full_log = 1;
846cb7cbc09Sjsing 	const char *servername;
84710281ad2Sinoguchi 	char *pass = NULL;
848dab3f910Sjsing 	X509 *cert = NULL;
849dab3f910Sjsing 	EVP_PKEY *key = NULL;
85010281ad2Sinoguchi 	int badop = 0;
851dab3f910Sjsing 	int write_tty, read_tty, write_ssl, read_ssl, tty_on, ssl_pending;
852dab3f910Sjsing 	SSL_CTX *ctx = NULL;
85310281ad2Sinoguchi 	int ret = 1, in_init = 1, i;
8545042ef37Sinoguchi 	BIO *bio_c_out = NULL;
855dab3f910Sjsing 	BIO *sbio;
856dab3f910Sjsing 	int mbuf_len = 0;
8579c8ea7b6Sderaadt 	struct timeval timeout;
85841eb9d41Sjsing 	tlsextctx tlsextcbp = {NULL, 0};
859f91d157aSderaadt 	struct sockaddr_storage peer;
860dab3f910Sjsing 	int peerlen = sizeof(peer);
861dab3f910Sjsing 
86251811eadSderaadt 	if (pledge("stdio cpath wpath rpath inet dns tty", NULL) == -1) {
8639bc487adSdoug 		perror("pledge");
864e370f0eeSdoug 		exit(1);
865e370f0eeSdoug 	}
8669bc487adSdoug 
867e7718adaStb 	memset(&cfg, 0, sizeof(cfg));
868e7718adaStb 	cfg.af = AF_UNSPEC;
869e7718adaStb 	cfg.cert_format = FORMAT_PEM;
870e7718adaStb 	cfg.host = SSL_HOST_NAME;
871e7718adaStb 	cfg.key_format = FORMAT_PEM;
872e7718adaStb 	cfg.keymatexportlen = 20;
873e7718adaStb 	cfg.meth = TLS_client_method();
874e7718adaStb 	cfg.port = PORT_STR;
875e7718adaStb 	cfg.socket_type = SOCK_STREAM;
876e7718adaStb 	cfg.starttls_proto = PROTO_OFF;
877e7718adaStb 	cfg.verify = SSL_VERIFY_NONE;
878dab3f910Sjsing 
879dab3f910Sjsing 	if (((cbuf = malloc(BUFSIZZ)) == NULL) ||
880dab3f910Sjsing 	    ((sbuf = malloc(BUFSIZZ)) == NULL) ||
8819c84cee0Sbeck 	    ((pbuf = malloc(BUFSIZZ)) == NULL) ||
882dab3f910Sjsing 	    ((mbuf = malloc(BUFSIZZ + 1)) == NULL)) {	/* NUL byte */
883dab3f910Sjsing 		BIO_printf(bio_err, "out of memory\n");
884dab3f910Sjsing 		goto end;
885dab3f910Sjsing 	}
886dab3f910Sjsing 	verify_depth = 0;
887dab3f910Sjsing 
88810281ad2Sinoguchi 	if (options_parse(argc, argv, s_client_options, NULL, NULL) != 0) {
889dab3f910Sjsing 		badop = 1;
890eb4b0597Sbluhm 		goto bad;
89110281ad2Sinoguchi 	}
892e7718adaStb 	if (cfg.proxy != NULL) {
893e7718adaStb 		if (!extract_host_port(cfg.proxy,
894e7718adaStb 		    &cfg.host, NULL, &cfg.port))
89510281ad2Sinoguchi 			goto bad;
896e7718adaStb 		if (cfg.connect == NULL)
897e7718adaStb 			cfg.connect = SSL_HOST_NAME;
898e7718adaStb 	} else if (cfg.connect != NULL) {
899e7718adaStb 		if (!extract_host_port(cfg.connect,
900e7718adaStb 		    &cfg.host, NULL, &cfg.port))
901eb4b0597Sbluhm 			goto bad;
902eb4b0597Sbluhm 	}
903dab3f910Sjsing 	if (badop) {
904dab3f910Sjsing  bad:
905e7718adaStb 		if (cfg.errstr == NULL)
906dab3f910Sjsing 			sc_usage();
907dab3f910Sjsing 		goto end;
908dab3f910Sjsing 	}
909dab3f910Sjsing 
910e7718adaStb 	if (!app_passwd(bio_err, cfg.passarg, NULL, &pass, NULL)) {
911dab3f910Sjsing 		BIO_printf(bio_err, "Error getting password\n");
912dab3f910Sjsing 		goto end;
913dab3f910Sjsing 	}
914e7718adaStb 	if (cfg.key_file == NULL)
915e7718adaStb 		cfg.key_file = cfg.cert_file;
916dab3f910Sjsing 
917dab3f910Sjsing 
918e7718adaStb 	if (cfg.key_file) {
919dab3f910Sjsing 
920e7718adaStb 		key = load_key(bio_err, cfg.key_file,
921e7718adaStb 		    cfg.key_format, 0, pass,
922dab3f910Sjsing 		    "client certificate private key file");
923dab3f910Sjsing 		if (!key) {
924dab3f910Sjsing 			ERR_print_errors(bio_err);
925dab3f910Sjsing 			goto end;
926dab3f910Sjsing 		}
927dab3f910Sjsing 	}
928e7718adaStb 	if (cfg.cert_file) {
929e7718adaStb 		cert = load_cert(bio_err, cfg.cert_file,
930e7718adaStb 		    cfg.cert_format,
9315284dfeaSbcook 		    NULL, "client certificate file");
932dab3f910Sjsing 
933dab3f910Sjsing 		if (!cert) {
934dab3f910Sjsing 			ERR_print_errors(bio_err);
935dab3f910Sjsing 			goto end;
936dab3f910Sjsing 		}
937dab3f910Sjsing 	}
938e7718adaStb 	if (cfg.quiet && !cfg.debug &&
939e7718adaStb 	    !cfg.msg) {
9405042ef37Sinoguchi 		if ((bio_c_out = BIO_new(BIO_s_null())) == NULL)
9415042ef37Sinoguchi 			goto end;
942dab3f910Sjsing 	} else {
9435042ef37Sinoguchi 		if ((bio_c_out = BIO_new_fp(stdout, BIO_NOCLOSE)) == NULL)
9445042ef37Sinoguchi 			goto end;
945dab3f910Sjsing 	}
946dab3f910Sjsing 
947e7718adaStb 	ctx = SSL_CTX_new(cfg.meth);
948dab3f910Sjsing 	if (ctx == NULL) {
949dab3f910Sjsing 		ERR_print_errors(bio_err);
950dab3f910Sjsing 		goto end;
951dab3f910Sjsing 	}
952f4cc3564Stb 
953f4cc3564Stb 	SSL_CTX_clear_mode(ctx, SSL_MODE_AUTO_RETRY);
954f4cc3564Stb 
955e7718adaStb 	if (cfg.vpm)
956e7718adaStb 		SSL_CTX_set1_param(ctx, cfg.vpm);
957dab3f910Sjsing 
958e7718adaStb 	if (!SSL_CTX_set_min_proto_version(ctx, cfg.min_version))
959428703dcSjsing 		goto end;
960e7718adaStb 	if (!SSL_CTX_set_max_proto_version(ctx, cfg.max_version))
961428703dcSjsing 		goto end;
962428703dcSjsing 
963dab3f910Sjsing #ifndef OPENSSL_NO_SRTP
964e7718adaStb 	if (cfg.srtp_profiles != NULL)
965e7718adaStb 		SSL_CTX_set_tlsext_use_srtp(ctx, cfg.srtp_profiles);
966dab3f910Sjsing #endif
967e7718adaStb 	if (cfg.bugs)
968e7718adaStb 		SSL_CTX_set_options(ctx, SSL_OP_ALL | cfg.off);
969dab3f910Sjsing 	else
970e7718adaStb 		SSL_CTX_set_options(ctx, cfg.off);
971dab3f910Sjsing 
972e7718adaStb 	if (cfg.clr)
973e7718adaStb 		SSL_CTX_clear_options(ctx, cfg.clr);
974dab3f910Sjsing 
975e7718adaStb 	if (cfg.alpn_in) {
9761b4c9cadSjsing 		unsigned short alpn_len;
9776369f9f8Sinoguchi 		unsigned char *alpn;
9781b4c9cadSjsing 
979e7718adaStb 		alpn = next_protos_parse(&alpn_len, cfg.alpn_in);
9801b4c9cadSjsing 		if (alpn == NULL) {
9811b4c9cadSjsing 			BIO_printf(bio_err, "Error parsing -alpn argument\n");
9821b4c9cadSjsing 			goto end;
9831b4c9cadSjsing 		}
9841b4c9cadSjsing 		SSL_CTX_set_alpn_protos(ctx, alpn, alpn_len);
9851b4c9cadSjsing 		free(alpn);
9861b4c9cadSjsing 	}
987e7718adaStb 	if (cfg.groups_in != NULL) {
988e7718adaStb 		if (SSL_CTX_set1_groups_list(ctx, cfg.groups_in) != 1) {
989c4d6b74bSjsing 			BIO_printf(bio_err, "Failed to set groups '%s'\n",
990e7718adaStb 			    cfg.groups_in);
991c4d6b74bSjsing 			goto end;
992c4d6b74bSjsing 		}
993c4d6b74bSjsing 	}
994dab3f910Sjsing 
995e7718adaStb 	if (cfg.state)
996dab3f910Sjsing 		SSL_CTX_set_info_callback(ctx, apps_ssl_info_callback);
997e7718adaStb 	if (cfg.cipher != NULL)
998e7718adaStb 		if (!SSL_CTX_set_cipher_list(ctx, cfg.cipher)) {
999dab3f910Sjsing 			BIO_printf(bio_err, "error setting cipher list\n");
1000dab3f910Sjsing 			ERR_print_errors(bio_err);
1001dab3f910Sjsing 			goto end;
1002dab3f910Sjsing 		}
1003dab3f910Sjsing 
1004e7718adaStb 	SSL_CTX_set_verify(ctx, cfg.verify, verify_callback);
1005dab3f910Sjsing 	if (!set_cert_key_stuff(ctx, cert, key))
1006dab3f910Sjsing 		goto end;
1007dab3f910Sjsing 
1008e7718adaStb 	if ((cfg.CAfile || cfg.CApath)
1009e7718adaStb 	    && !SSL_CTX_load_verify_locations(ctx, cfg.CAfile,
1010e7718adaStb 	    cfg.CApath))
1011dab3f910Sjsing 		ERR_print_errors(bio_err);
1012bbc7462fSbcook 
1013bbc7462fSbcook 	if (!SSL_CTX_set_default_verify_paths(ctx))
1014bbc7462fSbcook 		ERR_print_errors(bio_err);
1015bbc7462fSbcook 
1016dab3f910Sjsing 	con = SSL_new(ctx);
1017e7718adaStb 	if (cfg.sess_in) {
1018dab3f910Sjsing 		SSL_SESSION *sess;
1019e7718adaStb 		BIO *stmp = BIO_new_file(cfg.sess_in, "r");
1020dab3f910Sjsing 		if (!stmp) {
1021dab3f910Sjsing 			BIO_printf(bio_err, "Can't open session file %s\n",
1022e7718adaStb 			    cfg.sess_in);
1023dab3f910Sjsing 			ERR_print_errors(bio_err);
1024dab3f910Sjsing 			goto end;
1025dab3f910Sjsing 		}
1026dab3f910Sjsing 		sess = PEM_read_bio_SSL_SESSION(stmp, NULL, 0, NULL);
1027dab3f910Sjsing 		BIO_free(stmp);
1028dab3f910Sjsing 		if (!sess) {
1029dab3f910Sjsing 			BIO_printf(bio_err, "Can't open session file %s\n",
1030e7718adaStb 			    cfg.sess_in);
1031dab3f910Sjsing 			ERR_print_errors(bio_err);
1032dab3f910Sjsing 			goto end;
1033dab3f910Sjsing 		}
1034dab3f910Sjsing 		SSL_set_session(con, sess);
1035dab3f910Sjsing 		SSL_SESSION_free(sess);
1036dab3f910Sjsing 	}
1037cb7cbc09Sjsing 
1038cb7cbc09Sjsing 	/* Attempt to opportunistically use the host name for SNI. */
1039e7718adaStb 	servername = cfg.servername;
1040cb7cbc09Sjsing 	if (servername == NULL)
1041e7718adaStb 		servername = cfg.host;
1042cb7cbc09Sjsing 
1043e7718adaStb 	if (!cfg.no_servername && servername != NULL &&
1044cb7cbc09Sjsing 	    !SSL_set_tlsext_host_name(con, servername)) {
1045cb7cbc09Sjsing 		long ssl_err = ERR_peek_error();
1046cb7cbc09Sjsing 
1047e7718adaStb 		if (cfg.servername != NULL ||
1048cb7cbc09Sjsing 		    ERR_GET_LIB(ssl_err) != ERR_LIB_SSL ||
1049cb7cbc09Sjsing 		    ERR_GET_REASON(ssl_err) != SSL_R_SSL3_EXT_INVALID_SERVERNAME) {
10506369f9f8Sinoguchi 			BIO_printf(bio_err,
10516369f9f8Sinoguchi 			    "Unable to set TLS servername extension.\n");
1052dab3f910Sjsing 			ERR_print_errors(bio_err);
1053dab3f910Sjsing 			goto end;
1054dab3f910Sjsing 		}
1055cb7cbc09Sjsing 		servername = NULL;
1056cb7cbc09Sjsing 		ERR_clear_error();
1057dab3f910Sjsing 	}
1058e7718adaStb 	if (!cfg.no_servername && servername != NULL) {
1059cb7cbc09Sjsing 		tlsextcbp.biodebug = bio_err;
1060cb7cbc09Sjsing 		SSL_CTX_set_tlsext_servername_callback(ctx, ssl_servername_cb);
1061cb7cbc09Sjsing 		SSL_CTX_set_tlsext_servername_arg(ctx, &tlsextcbp);
1062cb7cbc09Sjsing 	}
1063dab3f910Sjsing 
1064dab3f910Sjsing  re_start:
1065dab3f910Sjsing 
1066e7718adaStb 	if (init_client(&s, cfg.host, cfg.port,
1067e7718adaStb 	    cfg.socket_type, cfg.af) == 0) {
1068dab3f910Sjsing 		BIO_printf(bio_err, "connect:errno=%d\n", errno);
1069dab3f910Sjsing 		goto end;
1070dab3f910Sjsing 	}
1071dab3f910Sjsing 	BIO_printf(bio_c_out, "CONNECTED(%08X)\n", s);
1072dab3f910Sjsing 
1073e7718adaStb 	if (cfg.nbio) {
1074e7718adaStb 		if (!cfg.quiet)
1075dab3f910Sjsing 			BIO_printf(bio_c_out, "turning on non blocking io\n");
1076fcc700e7Sbcook 		if (!BIO_socket_nbio(s, 1)) {
1077dab3f910Sjsing 			ERR_print_errors(bio_err);
1078dab3f910Sjsing 			goto end;
1079dab3f910Sjsing 		}
1080dab3f910Sjsing 	}
1081dab3f910Sjsing 
108293dafd19Sjsing 	if (SSL_is_dtls(con)) {
1083dab3f910Sjsing 		sbio = BIO_new_dgram(s, BIO_NOCLOSE);
1084f91d157aSderaadt 		if (getsockname(s, (struct sockaddr *)&peer,
1085f91d157aSderaadt 		    (void *)&peerlen) == -1) {
1086dab3f910Sjsing 			BIO_printf(bio_err, "getsockname:errno=%d\n",
1087dab3f910Sjsing 			    errno);
1088dab3f910Sjsing 			shutdown(s, SHUT_RD);
1089dab3f910Sjsing 			close(s);
1090dab3f910Sjsing 			goto end;
1091dab3f910Sjsing 		}
1092dab3f910Sjsing 		(void) BIO_ctrl_set_connected(sbio, 1, &peer);
1093dab3f910Sjsing 
1094e7718adaStb 		if (cfg.enable_timeouts) {
1095dab3f910Sjsing 			timeout.tv_sec = 0;
1096dab3f910Sjsing 			timeout.tv_usec = DGRAM_RCV_TIMEOUT;
10976369f9f8Sinoguchi 			BIO_ctrl(sbio, BIO_CTRL_DGRAM_SET_RECV_TIMEOUT, 0,
10986369f9f8Sinoguchi 			    &timeout);
1099dab3f910Sjsing 
1100dab3f910Sjsing 			timeout.tv_sec = 0;
1101dab3f910Sjsing 			timeout.tv_usec = DGRAM_SND_TIMEOUT;
11026369f9f8Sinoguchi 			BIO_ctrl(sbio, BIO_CTRL_DGRAM_SET_SEND_TIMEOUT, 0,
11036369f9f8Sinoguchi 			    &timeout);
1104dab3f910Sjsing 		}
1105e7718adaStb 		if (cfg.socket_mtu > 28) {
1106dab3f910Sjsing 			SSL_set_options(con, SSL_OP_NO_QUERY_MTU);
1107e7718adaStb 			SSL_set_mtu(con, cfg.socket_mtu - 28);
1108dab3f910Sjsing 		} else
1109dab3f910Sjsing 			/* want to do MTU discovery */
1110dab3f910Sjsing 			BIO_ctrl(sbio, BIO_CTRL_DGRAM_MTU_DISCOVER, 0, NULL);
1111dab3f910Sjsing 	} else
1112dab3f910Sjsing 		sbio = BIO_new_socket(s, BIO_NOCLOSE);
1113dab3f910Sjsing 
1114e7718adaStb 	if (cfg.nbio_test) {
1115dab3f910Sjsing 		BIO *test;
1116dab3f910Sjsing 
1117dab3f910Sjsing 		test = BIO_new(BIO_f_nbio_test());
1118dab3f910Sjsing 		sbio = BIO_push(test, sbio);
1119dab3f910Sjsing 	}
1120e7718adaStb 	if (cfg.debug) {
1121dab3f910Sjsing 		BIO_set_callback(sbio, bio_dump_callback);
1122dab3f910Sjsing 		BIO_set_callback_arg(sbio, (char *) bio_c_out);
1123dab3f910Sjsing 	}
1124e7718adaStb 	if (cfg.msg) {
1125dab3f910Sjsing 		SSL_set_msg_callback(con, msg_cb);
1126dab3f910Sjsing 		SSL_set_msg_callback_arg(con, bio_c_out);
1127dab3f910Sjsing 	}
1128e7718adaStb 	if (cfg.tlsextdebug) {
1129dab3f910Sjsing 		SSL_set_tlsext_debug_callback(con, tlsext_cb);
1130dab3f910Sjsing 		SSL_set_tlsext_debug_arg(con, bio_c_out);
1131dab3f910Sjsing 	}
1132e7718adaStb 	if (cfg.status_req) {
1133dab3f910Sjsing 		SSL_set_tlsext_status_type(con, TLSEXT_STATUSTYPE_ocsp);
1134dab3f910Sjsing 		SSL_CTX_set_tlsext_status_cb(ctx, ocsp_resp_cb);
1135dab3f910Sjsing 		SSL_CTX_set_tlsext_status_arg(ctx, bio_c_out);
1136dab3f910Sjsing 	}
1137dab3f910Sjsing 
1138dab3f910Sjsing 	SSL_set_bio(con, sbio, sbio);
1139dab3f910Sjsing 	SSL_set_connect_state(con);
1140dab3f910Sjsing 
1141dab3f910Sjsing 	/* ok, lets connect */
1142dab3f910Sjsing 	read_tty = 1;
1143dab3f910Sjsing 	write_tty = 0;
1144dab3f910Sjsing 	tty_on = 0;
1145dab3f910Sjsing 	read_ssl = 1;
1146dab3f910Sjsing 	write_ssl = 1;
1147dab3f910Sjsing 
1148dab3f910Sjsing 	cbuf_len = 0;
1149dab3f910Sjsing 	cbuf_off = 0;
1150dab3f910Sjsing 	sbuf_len = 0;
1151dab3f910Sjsing 	sbuf_off = 0;
1152dab3f910Sjsing 
1153dab3f910Sjsing 	/* This is an ugly hack that does a lot of assumptions */
1154dab3f910Sjsing 	/*
1155dab3f910Sjsing 	 * We do have to handle multi-line responses which may come in a
1156dab3f910Sjsing 	 * single packet or not. We therefore have to use BIO_gets() which
1157dab3f910Sjsing 	 * does need a buffering BIO. So during the initial chitchat we do
1158dab3f910Sjsing 	 * push a buffering BIO into the chain that is removed again later on
1159dab3f910Sjsing 	 * to not disturb the rest of the s_client operation.
1160dab3f910Sjsing 	 */
1161e7718adaStb 	if (cfg.starttls_proto == PROTO_SMTP ||
1162e7718adaStb 	    cfg.starttls_proto == PROTO_LMTP) {
1163dab3f910Sjsing 		int foundit = 0;
1164dab3f910Sjsing 		BIO *fbio = BIO_new(BIO_f_buffer());
1165dab3f910Sjsing 		BIO_push(fbio, sbio);
1166dab3f910Sjsing 		/* wait for multi-line response to end from SMTP */
1167dab3f910Sjsing 		do {
1168dab3f910Sjsing 			mbuf_len = BIO_gets(fbio, mbuf, BUFSIZZ);
1169dab3f910Sjsing 		}
1170dab3f910Sjsing 		while (mbuf_len > 3 && mbuf[3] == '-');
1171dab3f910Sjsing 		/* STARTTLS command requires EHLO... */
1172dab3f910Sjsing 		BIO_printf(fbio, "%cHLO openssl.client.net\r\n",
1173e7718adaStb 		    cfg.starttls_proto == PROTO_SMTP ? 'E' : 'L');
1174dab3f910Sjsing 		(void) BIO_flush(fbio);
1175dab3f910Sjsing 		/* wait for multi-line response to end EHLO SMTP response */
1176dab3f910Sjsing 		do {
1177dab3f910Sjsing 			mbuf_len = BIO_gets(fbio, mbuf, BUFSIZZ);
1178dab3f910Sjsing 			if (strstr(mbuf, "STARTTLS"))
1179dab3f910Sjsing 				foundit = 1;
1180dab3f910Sjsing 		}
1181dab3f910Sjsing 		while (mbuf_len > 3 && mbuf[3] == '-');
1182dab3f910Sjsing 		(void) BIO_flush(fbio);
1183dab3f910Sjsing 		BIO_pop(fbio);
1184dab3f910Sjsing 		BIO_free(fbio);
1185dab3f910Sjsing 		if (!foundit)
1186dab3f910Sjsing 			BIO_printf(bio_err,
11875651377cSjmc 			    "didn't find starttls in server response,"
1188dab3f910Sjsing 			    " try anyway...\n");
1189dab3f910Sjsing 		BIO_printf(sbio, "STARTTLS\r\n");
1190dab3f910Sjsing 		BIO_read(sbio, sbuf, BUFSIZZ);
1191e7718adaStb 	} else if (cfg.starttls_proto == PROTO_POP3) {
1192dab3f910Sjsing 		mbuf_len = BIO_read(sbio, mbuf, BUFSIZZ);
1193dab3f910Sjsing 		if (mbuf_len == -1) {
1194dab3f910Sjsing 			BIO_printf(bio_err, "BIO_read failed\n");
1195dab3f910Sjsing 			goto end;
1196dab3f910Sjsing 		}
1197dab3f910Sjsing 		BIO_printf(sbio, "STLS\r\n");
1198dab3f910Sjsing 		BIO_read(sbio, sbuf, BUFSIZZ);
1199e7718adaStb 	} else if (cfg.starttls_proto == PROTO_IMAP) {
1200dab3f910Sjsing 		int foundit = 0;
1201dab3f910Sjsing 		BIO *fbio = BIO_new(BIO_f_buffer());
1202dab3f910Sjsing 		BIO_push(fbio, sbio);
1203dab3f910Sjsing 		BIO_gets(fbio, mbuf, BUFSIZZ);
1204dab3f910Sjsing 		/* STARTTLS command requires CAPABILITY... */
1205dab3f910Sjsing 		BIO_printf(fbio, ". CAPABILITY\r\n");
1206dab3f910Sjsing 		(void) BIO_flush(fbio);
1207dab3f910Sjsing 		/* wait for multi-line CAPABILITY response */
1208dab3f910Sjsing 		do {
1209dab3f910Sjsing 			mbuf_len = BIO_gets(fbio, mbuf, BUFSIZZ);
1210dab3f910Sjsing 			if (strstr(mbuf, "STARTTLS"))
1211dab3f910Sjsing 				foundit = 1;
1212dab3f910Sjsing 		}
1213dab3f910Sjsing 		while (mbuf_len > 3 && mbuf[0] != '.');
1214dab3f910Sjsing 		(void) BIO_flush(fbio);
1215dab3f910Sjsing 		BIO_pop(fbio);
1216dab3f910Sjsing 		BIO_free(fbio);
1217dab3f910Sjsing 		if (!foundit)
1218dab3f910Sjsing 			BIO_printf(bio_err,
1219f60aeedaStb 			    "didn't find STARTTLS in server response,"
1220dab3f910Sjsing 			    " try anyway...\n");
1221dab3f910Sjsing 		BIO_printf(sbio, ". STARTTLS\r\n");
1222dab3f910Sjsing 		BIO_read(sbio, sbuf, BUFSIZZ);
1223e7718adaStb 	} else if (cfg.starttls_proto == PROTO_FTP) {
1224dab3f910Sjsing 		BIO *fbio = BIO_new(BIO_f_buffer());
1225dab3f910Sjsing 		BIO_push(fbio, sbio);
1226dab3f910Sjsing 		/* wait for multi-line response to end from FTP */
1227dab3f910Sjsing 		do {
1228dab3f910Sjsing 			mbuf_len = BIO_gets(fbio, mbuf, BUFSIZZ);
1229dab3f910Sjsing 		}
1230dab3f910Sjsing 		while (mbuf_len > 3 && mbuf[3] == '-');
1231dab3f910Sjsing 		(void) BIO_flush(fbio);
1232dab3f910Sjsing 		BIO_pop(fbio);
1233dab3f910Sjsing 		BIO_free(fbio);
1234dab3f910Sjsing 		BIO_printf(sbio, "AUTH TLS\r\n");
1235dab3f910Sjsing 		BIO_read(sbio, sbuf, BUFSIZZ);
1236e7718adaStb 	} else if (cfg.starttls_proto == PROTO_XMPP) {
1237dab3f910Sjsing 		int seen = 0;
1238dab3f910Sjsing 		BIO_printf(sbio, "<stream:stream "
1239dab3f910Sjsing 		    "xmlns:stream='http://etherx.jabber.org/streams' "
12406369f9f8Sinoguchi 		    "xmlns='jabber:client' to='%s' version='1.0'>",
1241e7718adaStb 		    cfg.xmpphost ?
1242e7718adaStb 		    cfg.xmpphost : cfg.host);
1243dab3f910Sjsing 		seen = BIO_read(sbio, mbuf, BUFSIZZ);
12442c0bb1ecSlandry 
12452c0bb1ecSlandry 		if (seen <= 0)
1246dab3f910Sjsing 			goto shut;
12472c0bb1ecSlandry 
12482c0bb1ecSlandry 		mbuf[seen] = 0;
12492c0bb1ecSlandry 		while (!strstr(mbuf, "<starttls xmlns='urn:ietf:params:xml:ns:xmpp-tls'") &&
12502c0bb1ecSlandry 		       !strstr(mbuf, "<starttls xmlns=\"urn:ietf:params:xml:ns:xmpp-tls\"")) {
1251dab3f910Sjsing 			seen = BIO_read(sbio, mbuf, BUFSIZZ);
12522c0bb1ecSlandry 
12532c0bb1ecSlandry 			if (seen <= 0)
12542c0bb1ecSlandry 				goto shut;
12552c0bb1ecSlandry 
1256dab3f910Sjsing 			mbuf[seen] = 0;
1257dab3f910Sjsing 		}
12586369f9f8Sinoguchi 		BIO_printf(sbio,
12596369f9f8Sinoguchi 		    "<starttls xmlns='urn:ietf:params:xml:ns:xmpp-tls'/>");
1260dab3f910Sjsing 		seen = BIO_read(sbio, sbuf, BUFSIZZ);
1261dab3f910Sjsing 		sbuf[seen] = 0;
1262dab3f910Sjsing 		if (!strstr(sbuf, "<proceed"))
1263dab3f910Sjsing 			goto shut;
1264dab3f910Sjsing 		mbuf[0] = 0;
1265e7718adaStb 	} else if (cfg.proxy != NULL) {
12666369f9f8Sinoguchi 		BIO_printf(sbio, "CONNECT %s HTTP/1.0\r\n\r\n",
1267e7718adaStb 		    cfg.connect);
1268eb4b0597Sbluhm 		mbuf_len = BIO_read(sbio, mbuf, BUFSIZZ);
1269eb4b0597Sbluhm 		if (mbuf_len == -1) {
1270eb4b0597Sbluhm 			BIO_printf(bio_err, "BIO_read failed\n");
1271eb4b0597Sbluhm 			goto end;
1272eb4b0597Sbluhm 		}
1273dab3f910Sjsing 	}
1274dab3f910Sjsing 	for (;;) {
12759c8ea7b6Sderaadt 		struct pollfd pfd[3];	/* stdin, stdout, socket */
12769c8ea7b6Sderaadt 		int ptimeout = -1;
1277dab3f910Sjsing 
127893dafd19Sjsing 		if (SSL_is_dtls(con) && DTLSv1_get_timeout(con, &timeout))
12796369f9f8Sinoguchi 			ptimeout = timeout.tv_sec * 1000 +
12806369f9f8Sinoguchi 			    timeout.tv_usec / 1000;
1281dab3f910Sjsing 
1282dab3f910Sjsing 		if (SSL_in_init(con) && !SSL_total_renegotiations(con)) {
1283dab3f910Sjsing 			in_init = 1;
1284dab3f910Sjsing 			tty_on = 0;
1285dab3f910Sjsing 		} else {
1286dab3f910Sjsing 			tty_on = 1;
1287dab3f910Sjsing 			if (in_init) {
1288dab3f910Sjsing 				in_init = 0;
1289e7718adaStb 				if (cfg.sess_out) {
12906369f9f8Sinoguchi 					BIO *stmp = BIO_new_file(
1291e7718adaStb 					    cfg.sess_out, "w");
1292dab3f910Sjsing 					if (stmp) {
12936369f9f8Sinoguchi 						PEM_write_bio_SSL_SESSION(stmp,
12946369f9f8Sinoguchi 						    SSL_get_session(con));
1295dab3f910Sjsing 						BIO_free(stmp);
1296dab3f910Sjsing 					} else
12976369f9f8Sinoguchi 						BIO_printf(bio_err,
12986369f9f8Sinoguchi 						    "Error writing session file %s\n",
1299e7718adaStb 						    cfg.sess_out);
1300dab3f910Sjsing 				}
1301dab3f910Sjsing 				print_stuff(bio_c_out, con, full_log);
1302dab3f910Sjsing 				if (full_log > 0)
1303dab3f910Sjsing 					full_log--;
1304dab3f910Sjsing 
1305e7718adaStb 				if (cfg.starttls_proto) {
1306dab3f910Sjsing 					BIO_write(bio_err, mbuf, mbuf_len);
1307dab3f910Sjsing 					/* We don't need to know any more */
1308e7718adaStb 					cfg.starttls_proto = PROTO_OFF;
1309dab3f910Sjsing 				}
1310e7718adaStb 				if (cfg.reconnect) {
1311e7718adaStb 					cfg.reconnect--;
13126369f9f8Sinoguchi 					BIO_printf(bio_c_out,
13136369f9f8Sinoguchi 					    "drop connection and then reconnect\n");
1314dab3f910Sjsing 					SSL_shutdown(con);
1315dab3f910Sjsing 					SSL_set_connect_state(con);
1316dab3f910Sjsing 					shutdown(SSL_get_fd(con), SHUT_RD);
1317dab3f910Sjsing 					close(SSL_get_fd(con));
1318dab3f910Sjsing 					goto re_start;
1319dab3f910Sjsing 				}
1320dab3f910Sjsing 			}
1321dab3f910Sjsing 		}
1322dab3f910Sjsing 
1323dab3f910Sjsing 		ssl_pending = read_ssl && SSL_pending(con);
1324dab3f910Sjsing 
13259c8ea7b6Sderaadt 		pfd[0].fd = -1;
13269c8ea7b6Sderaadt 		pfd[1].fd = -1;
1327dab3f910Sjsing 		if (!ssl_pending) {
1328dab3f910Sjsing 			if (tty_on) {
13299c8ea7b6Sderaadt 				if (read_tty) {
13309c8ea7b6Sderaadt 					pfd[0].fd = fileno(stdin);
13319c8ea7b6Sderaadt 					pfd[0].events = POLLIN;
1332dab3f910Sjsing 				}
13339c8ea7b6Sderaadt 				if (write_tty) {
13349c8ea7b6Sderaadt 					pfd[1].fd = fileno(stdout);
13359c8ea7b6Sderaadt 					pfd[1].events = POLLOUT;
13369c8ea7b6Sderaadt 				}
13379c8ea7b6Sderaadt 			}
13389c8ea7b6Sderaadt 
13399c8ea7b6Sderaadt 			pfd[2].fd = SSL_get_fd(con);
13409c8ea7b6Sderaadt 			pfd[2].events = 0;
1341dab3f910Sjsing 			if (read_ssl)
13429c8ea7b6Sderaadt 				pfd[2].events |= POLLIN;
1343dab3f910Sjsing 			if (write_ssl)
13449c8ea7b6Sderaadt 				pfd[2].events |= POLLOUT;
13459c8ea7b6Sderaadt 
1346dab3f910Sjsing /*			printf("mode tty(%d %d%d) ssl(%d%d)\n",
1347dab3f910Sjsing 				tty_on,read_tty,write_tty,read_ssl,write_ssl);*/
1348dab3f910Sjsing 
13499c8ea7b6Sderaadt 			i = poll(pfd, 3, ptimeout);
13503aaa63ebSderaadt 			if (i == -1) {
1351dab3f910Sjsing 				BIO_printf(bio_err, "bad select %d\n",
1352dab3f910Sjsing 				    errno);
1353dab3f910Sjsing 				goto shut;
1354dab3f910Sjsing 				/* goto end; */
1355dab3f910Sjsing 			}
1356dab3f910Sjsing 		}
135793dafd19Sjsing 		if (SSL_is_dtls(con) &&
135893dafd19Sjsing 		    DTLSv1_handle_timeout(con) > 0)
1359dab3f910Sjsing 			BIO_printf(bio_err, "TIMEOUT occured\n");
13606369f9f8Sinoguchi 		if (!ssl_pending &&
13616369f9f8Sinoguchi 		    (pfd[2].revents & (POLLOUT|POLLERR|POLLNVAL))) {
13629c8ea7b6Sderaadt 			if (pfd[2].revents & (POLLERR|POLLNVAL)) {
13639c8ea7b6Sderaadt 				BIO_printf(bio_err, "poll error");
13649c8ea7b6Sderaadt 				goto shut;
13659c8ea7b6Sderaadt 			}
1366dab3f910Sjsing 			k = SSL_write(con, &(cbuf[cbuf_off]),
1367dab3f910Sjsing 			    (unsigned int) cbuf_len);
1368dab3f910Sjsing 			switch (SSL_get_error(con, k)) {
1369dab3f910Sjsing 			case SSL_ERROR_NONE:
1370dab3f910Sjsing 				cbuf_off += k;
1371dab3f910Sjsing 				cbuf_len -= k;
1372dab3f910Sjsing 				if (k <= 0)
1373dab3f910Sjsing 					goto end;
1374dab3f910Sjsing 				/* we have done a  write(con,NULL,0); */
1375dab3f910Sjsing 				if (cbuf_len <= 0) {
1376dab3f910Sjsing 					read_tty = 1;
1377dab3f910Sjsing 					write_ssl = 0;
1378dab3f910Sjsing 				} else {	/* if (cbuf_len > 0) */
1379dab3f910Sjsing 					read_tty = 0;
1380dab3f910Sjsing 					write_ssl = 1;
1381dab3f910Sjsing 				}
1382dab3f910Sjsing 				break;
1383dab3f910Sjsing 			case SSL_ERROR_WANT_WRITE:
1384dab3f910Sjsing 				BIO_printf(bio_c_out, "write W BLOCK\n");
1385dab3f910Sjsing 				write_ssl = 1;
1386dab3f910Sjsing 				read_tty = 0;
1387dab3f910Sjsing 				break;
1388dab3f910Sjsing 			case SSL_ERROR_WANT_READ:
1389dab3f910Sjsing 				BIO_printf(bio_c_out, "write R BLOCK\n");
1390dab3f910Sjsing 				write_tty = 0;
1391dab3f910Sjsing 				read_ssl = 1;
1392dab3f910Sjsing 				write_ssl = 0;
1393dab3f910Sjsing 				break;
1394dab3f910Sjsing 			case SSL_ERROR_WANT_X509_LOOKUP:
1395dab3f910Sjsing 				BIO_printf(bio_c_out, "write X BLOCK\n");
1396dab3f910Sjsing 				break;
1397dab3f910Sjsing 			case SSL_ERROR_ZERO_RETURN:
1398dab3f910Sjsing 				if (cbuf_len != 0) {
1399dab3f910Sjsing 					BIO_printf(bio_c_out, "shutdown\n");
1400dab3f910Sjsing 					ret = 0;
1401dab3f910Sjsing 					goto shut;
1402dab3f910Sjsing 				} else {
1403dab3f910Sjsing 					read_tty = 1;
1404dab3f910Sjsing 					write_ssl = 0;
1405dab3f910Sjsing 					break;
1406dab3f910Sjsing 				}
1407dab3f910Sjsing 
1408dab3f910Sjsing 			case SSL_ERROR_SYSCALL:
1409dab3f910Sjsing 				if ((k != 0) || (cbuf_len != 0)) {
1410dab3f910Sjsing 					BIO_printf(bio_err, "write:errno=%d\n",
1411dab3f910Sjsing 					    errno);
1412dab3f910Sjsing 					goto shut;
1413dab3f910Sjsing 				} else {
1414dab3f910Sjsing 					read_tty = 1;
1415dab3f910Sjsing 					write_ssl = 0;
1416dab3f910Sjsing 				}
1417dab3f910Sjsing 				break;
1418dab3f910Sjsing 			case SSL_ERROR_SSL:
1419dab3f910Sjsing 				ERR_print_errors(bio_err);
1420dab3f910Sjsing 				goto shut;
1421dab3f910Sjsing 			}
14229c8ea7b6Sderaadt 		} else if (!ssl_pending &&
14239c8ea7b6Sderaadt 		    (pfd[1].revents & (POLLOUT|POLLERR|POLLNVAL))) {
14249c8ea7b6Sderaadt 			if (pfd[1].revents & (POLLERR|POLLNVAL)) {
14259c8ea7b6Sderaadt 				BIO_printf(bio_err, "poll error");
14269c8ea7b6Sderaadt 				goto shut;
14279c8ea7b6Sderaadt 			}
1428dab3f910Sjsing 			i = write(fileno(stdout), &(sbuf[sbuf_off]), sbuf_len);
1429dab3f910Sjsing 
1430dab3f910Sjsing 			if (i <= 0) {
1431dab3f910Sjsing 				BIO_printf(bio_c_out, "DONE\n");
1432dab3f910Sjsing 				ret = 0;
1433dab3f910Sjsing 				goto shut;
1434dab3f910Sjsing 				/* goto end; */
1435dab3f910Sjsing 			}
1436dab3f910Sjsing 			sbuf_len -= i;
1437dab3f910Sjsing 			sbuf_off += i;
1438dab3f910Sjsing 			if (sbuf_len <= 0) {
1439dab3f910Sjsing 				read_ssl = 1;
1440dab3f910Sjsing 				write_tty = 0;
1441dab3f910Sjsing 			}
14429c8ea7b6Sderaadt 		} else if (ssl_pending || (pfd[2].revents & (POLLIN|POLLHUP))) {
1443dab3f910Sjsing #ifdef RENEG
1444dab3f910Sjsing 			{
1445dab3f910Sjsing 				static int iiii;
1446dab3f910Sjsing 				if (++iiii == 52) {
1447dab3f910Sjsing 					SSL_renegotiate(con);
1448dab3f910Sjsing 					iiii = 0;
1449dab3f910Sjsing 				}
1450dab3f910Sjsing 			}
1451dab3f910Sjsing #endif
1452e7718adaStb 			if (cfg.peekaboo) {
1453bfef4384Sjsing 				k = p = SSL_peek(con, pbuf, 1024 /* BUFSIZZ */ );
1454586463feSbeck 				pending = SSL_pending(con);
1455bfef4384Sjsing 				if (SSL_get_error(con, p) == SSL_ERROR_NONE) {
14569c84cee0Sbeck 					if (p <= 0)
14579c84cee0Sbeck 						goto end;
14589c84cee0Sbeck 
1459bfef4384Sjsing 					k = SSL_read(con, sbuf, p);
14609c84cee0Sbeck 				}
1461bfef4384Sjsing 			} else {
1462dab3f910Sjsing 				k = SSL_read(con, sbuf, 1024 /* BUFSIZZ */ );
1463bfef4384Sjsing 			}
1464dab3f910Sjsing 
1465dab3f910Sjsing 			switch (SSL_get_error(con, k)) {
1466dab3f910Sjsing 			case SSL_ERROR_NONE:
1467dab3f910Sjsing 				if (k <= 0)
1468dab3f910Sjsing 					goto end;
1469dab3f910Sjsing 				sbuf_off = 0;
1470dab3f910Sjsing 				sbuf_len = k;
1471e7718adaStb 				if (cfg.peekaboo) {
1472586463feSbeck 					if (p != pending) {
1473586463feSbeck 						ret = -1;
1474586463feSbeck 						BIO_printf(bio_err,
14756369f9f8Sinoguchi 						    "peeked %d but pending %d!\n",
14766369f9f8Sinoguchi 						    p, pending);
1477586463feSbeck 						goto shut;
1478586463feSbeck 					}
14799c84cee0Sbeck 					if (k < p) {
14809c84cee0Sbeck 						ret = -1;
14819c84cee0Sbeck 						BIO_printf(bio_err,
14829c84cee0Sbeck 						    "read less than peek!\n");
14839c84cee0Sbeck 						goto shut;
14849c84cee0Sbeck 					}
14856369f9f8Sinoguchi 					if (p > 0 &&
14866369f9f8Sinoguchi 					    (memcmp(sbuf, pbuf, p) != 0)) {
14879c84cee0Sbeck 						ret = -1;
14889c84cee0Sbeck 						BIO_printf(bio_err,
14899c84cee0Sbeck 						    "peek of %d different from read of %d!\n",
14909c84cee0Sbeck 						    p, k);
14919c84cee0Sbeck 						goto shut;
14929c84cee0Sbeck 					}
14939c84cee0Sbeck 				}
1494dab3f910Sjsing 				read_ssl = 0;
1495dab3f910Sjsing 				write_tty = 1;
1496dab3f910Sjsing 				break;
1497dab3f910Sjsing 			case SSL_ERROR_WANT_WRITE:
1498dab3f910Sjsing 				BIO_printf(bio_c_out, "read W BLOCK\n");
1499dab3f910Sjsing 				write_ssl = 1;
1500dab3f910Sjsing 				read_tty = 0;
1501dab3f910Sjsing 				break;
1502dab3f910Sjsing 			case SSL_ERROR_WANT_READ:
1503dab3f910Sjsing 				BIO_printf(bio_c_out, "read R BLOCK\n");
1504dab3f910Sjsing 				write_tty = 0;
1505dab3f910Sjsing 				read_ssl = 1;
1506dab3f910Sjsing 				if ((read_tty == 0) && (write_ssl == 0))
1507dab3f910Sjsing 					write_ssl = 1;
1508dab3f910Sjsing 				break;
1509dab3f910Sjsing 			case SSL_ERROR_WANT_X509_LOOKUP:
1510dab3f910Sjsing 				BIO_printf(bio_c_out, "read X BLOCK\n");
1511dab3f910Sjsing 				break;
1512dab3f910Sjsing 			case SSL_ERROR_SYSCALL:
1513dab3f910Sjsing 				ret = errno;
1514dab3f910Sjsing 				BIO_printf(bio_err, "read:errno=%d\n", ret);
1515dab3f910Sjsing 				goto shut;
1516dab3f910Sjsing 			case SSL_ERROR_ZERO_RETURN:
1517dab3f910Sjsing 				BIO_printf(bio_c_out, "closed\n");
1518dab3f910Sjsing 				ret = 0;
1519dab3f910Sjsing 				goto shut;
1520dab3f910Sjsing 			case SSL_ERROR_SSL:
1521dab3f910Sjsing 				ERR_print_errors(bio_err);
1522dab3f910Sjsing 				goto shut;
1523dab3f910Sjsing 				/* break; */
1524dab3f910Sjsing 			}
15259c8ea7b6Sderaadt 		} else if (pfd[0].revents) {
15269c8ea7b6Sderaadt 			if (pfd[0].revents & (POLLERR|POLLNVAL)) {
15279c8ea7b6Sderaadt 				BIO_printf(bio_err, "poll error");
15289c8ea7b6Sderaadt 				goto shut;
15299c8ea7b6Sderaadt 			}
1530e7718adaStb 			if (cfg.crlf) {
1531dab3f910Sjsing 				int j, lf_num;
1532dab3f910Sjsing 
1533dab3f910Sjsing 				i = read(fileno(stdin), cbuf, BUFSIZZ / 2);
1534dab3f910Sjsing 				lf_num = 0;
1535dab3f910Sjsing 				/* both loops are skipped when i <= 0 */
1536dab3f910Sjsing 				for (j = 0; j < i; j++)
1537dab3f910Sjsing 					if (cbuf[j] == '\n')
1538dab3f910Sjsing 						lf_num++;
1539dab3f910Sjsing 				for (j = i - 1; j >= 0; j--) {
1540dab3f910Sjsing 					cbuf[j + lf_num] = cbuf[j];
1541dab3f910Sjsing 					if (cbuf[j] == '\n') {
1542dab3f910Sjsing 						lf_num--;
1543dab3f910Sjsing 						i++;
1544dab3f910Sjsing 						cbuf[j + lf_num] = '\r';
1545dab3f910Sjsing 					}
1546dab3f910Sjsing 				}
1547dab3f910Sjsing 				assert(lf_num == 0);
1548dab3f910Sjsing 			} else
1549dab3f910Sjsing 				i = read(fileno(stdin), cbuf, BUFSIZZ);
1550dab3f910Sjsing 
1551e7718adaStb 			if ((!cfg.ign_eof) &&
15526369f9f8Sinoguchi 			    ((i <= 0) || (cbuf[0] == 'Q'))) {
1553dab3f910Sjsing 				BIO_printf(bio_err, "DONE\n");
1554dab3f910Sjsing 				ret = 0;
1555dab3f910Sjsing 				goto shut;
1556dab3f910Sjsing 			}
1557e7718adaStb 			if ((!cfg.ign_eof) && (cbuf[0] == 'R')) {
1558dab3f910Sjsing 				BIO_printf(bio_err, "RENEGOTIATING\n");
1559dab3f910Sjsing 				SSL_renegotiate(con);
1560dab3f910Sjsing 				cbuf_len = 0;
1561dab3f910Sjsing 			} else {
1562dab3f910Sjsing 				cbuf_len = i;
1563dab3f910Sjsing 				cbuf_off = 0;
1564dab3f910Sjsing 			}
1565dab3f910Sjsing 
1566dab3f910Sjsing 			write_ssl = 1;
1567dab3f910Sjsing 			read_tty = 0;
1568dab3f910Sjsing 		}
1569dab3f910Sjsing 	}
1570dab3f910Sjsing 
1571dab3f910Sjsing 	ret = 0;
1572dab3f910Sjsing  shut:
1573dab3f910Sjsing 	if (in_init)
1574dab3f910Sjsing 		print_stuff(bio_c_out, con, full_log);
1575dab3f910Sjsing 	SSL_shutdown(con);
1576dab3f910Sjsing 	shutdown(SSL_get_fd(con), SHUT_RD);
1577dab3f910Sjsing 	close(SSL_get_fd(con));
1578dab3f910Sjsing  end:
1579dab3f910Sjsing 	if (con != NULL) {
1580e7718adaStb 		if (cfg.prexit != 0)
1581dab3f910Sjsing 			print_stuff(bio_c_out, con, 1);
1582dab3f910Sjsing 		SSL_free(con);
1583dab3f910Sjsing 	}
1584dab3f910Sjsing 	SSL_CTX_free(ctx);
1585dab3f910Sjsing 	X509_free(cert);
1586dab3f910Sjsing 	EVP_PKEY_free(key);
1587dab3f910Sjsing 	free(pass);
1588e7718adaStb 	X509_VERIFY_PARAM_free(cfg.vpm);
1589cf4db30dSderaadt 	freezero(cbuf, BUFSIZZ);
1590cf4db30dSderaadt 	freezero(sbuf, BUFSIZZ);
15911b9cd2daStb 	freezero(pbuf, BUFSIZZ);
1592cf4db30dSderaadt 	freezero(mbuf, BUFSIZZ);
1593dab3f910Sjsing 	BIO_free(bio_c_out);
1594dab3f910Sjsing 
1595dab3f910Sjsing 	return (ret);
1596dab3f910Sjsing }
1597dab3f910Sjsing 
1598dab3f910Sjsing static void
1599dab3f910Sjsing print_stuff(BIO *bio, SSL *s, int full)
1600dab3f910Sjsing {
1601dab3f910Sjsing 	X509 *peer = NULL;
1602dab3f910Sjsing 	char *p;
1603dab3f910Sjsing 	static const char *space = "                ";
1604dab3f910Sjsing 	char buf[BUFSIZ];
1605dab3f910Sjsing 	STACK_OF(X509) *sk;
1606dab3f910Sjsing 	STACK_OF(X509_NAME) *sk2;
1607dab3f910Sjsing 	const SSL_CIPHER *c;
1608dab3f910Sjsing 	X509_NAME *xn;
1609dab3f910Sjsing 	int j, i;
1610dab3f910Sjsing 	unsigned char *exportedkeymat;
1611dab3f910Sjsing 
1612dab3f910Sjsing 	if (full) {
1613dab3f910Sjsing 		int got_a_chain = 0;
1614dab3f910Sjsing 
1615dab3f910Sjsing 		sk = SSL_get_peer_cert_chain(s);
1616dab3f910Sjsing 		if (sk != NULL) {
1617dab3f910Sjsing 			got_a_chain = 1;	/* we don't have it for SSL2
1618dab3f910Sjsing 						 * (yet) */
1619dab3f910Sjsing 
1620dab3f910Sjsing 			BIO_printf(bio, "---\nCertificate chain\n");
1621dab3f910Sjsing 			for (i = 0; i < sk_X509_num(sk); i++) {
1622dab3f910Sjsing 				X509_NAME_oneline(X509_get_subject_name(
1623dab3f910Sjsing 					sk_X509_value(sk, i)), buf, sizeof buf);
1624dab3f910Sjsing 				BIO_printf(bio, "%2d s:%s\n", i, buf);
1625dab3f910Sjsing 				X509_NAME_oneline(X509_get_issuer_name(
1626dab3f910Sjsing 					sk_X509_value(sk, i)), buf, sizeof buf);
1627dab3f910Sjsing 				BIO_printf(bio, "   i:%s\n", buf);
1628e7718adaStb 				if (cfg.showcerts)
16296369f9f8Sinoguchi 					PEM_write_bio_X509(bio,
16306369f9f8Sinoguchi 					    sk_X509_value(sk, i));
1631dab3f910Sjsing 			}
1632dab3f910Sjsing 		}
1633dab3f910Sjsing 		BIO_printf(bio, "---\n");
1634dab3f910Sjsing 		peer = SSL_get_peer_certificate(s);
1635dab3f910Sjsing 		if (peer != NULL) {
1636dab3f910Sjsing 			BIO_printf(bio, "Server certificate\n");
1637e7718adaStb 			if (!(cfg.showcerts && got_a_chain)) {
16386369f9f8Sinoguchi 				/* Redundant if we showed the whole chain */
1639dab3f910Sjsing 				PEM_write_bio_X509(bio, peer);
16406369f9f8Sinoguchi 			}
1641dab3f910Sjsing 			X509_NAME_oneline(X509_get_subject_name(peer),
1642dab3f910Sjsing 			    buf, sizeof buf);
1643dab3f910Sjsing 			BIO_printf(bio, "subject=%s\n", buf);
1644dab3f910Sjsing 			X509_NAME_oneline(X509_get_issuer_name(peer),
1645dab3f910Sjsing 			    buf, sizeof buf);
1646dab3f910Sjsing 			BIO_printf(bio, "issuer=%s\n", buf);
1647dab3f910Sjsing 		} else
1648dab3f910Sjsing 			BIO_printf(bio, "no peer certificate available\n");
1649dab3f910Sjsing 
1650dab3f910Sjsing 		sk2 = SSL_get_client_CA_list(s);
1651dab3f910Sjsing 		if ((sk2 != NULL) && (sk_X509_NAME_num(sk2) > 0)) {
16526369f9f8Sinoguchi 			BIO_printf(bio,
16536369f9f8Sinoguchi 			    "---\nAcceptable client certificate CA names\n");
1654dab3f910Sjsing 			for (i = 0; i < sk_X509_NAME_num(sk2); i++) {
1655dab3f910Sjsing 				xn = sk_X509_NAME_value(sk2, i);
1656dab3f910Sjsing 				X509_NAME_oneline(xn, buf, sizeof(buf));
1657dab3f910Sjsing 				BIO_write(bio, buf, strlen(buf));
1658dab3f910Sjsing 				BIO_write(bio, "\n", 1);
1659dab3f910Sjsing 			}
1660dab3f910Sjsing 		} else {
16616369f9f8Sinoguchi 			BIO_printf(bio,
16626369f9f8Sinoguchi 			    "---\nNo client certificate CA names sent\n");
1663dab3f910Sjsing 		}
1664dab3f910Sjsing 		p = SSL_get_shared_ciphers(s, buf, sizeof buf);
1665dab3f910Sjsing 		if (p != NULL) {
1666dab3f910Sjsing 			/*
1667dab3f910Sjsing 			 * This works only for SSL 2.  In later protocol
1668dab3f910Sjsing 			 * versions, the client does not know what other
1669dab3f910Sjsing 			 * ciphers (in addition to the one to be used in the
1670dab3f910Sjsing 			 * current connection) the server supports.
1671dab3f910Sjsing 			 */
1672dab3f910Sjsing 
16736369f9f8Sinoguchi 			BIO_printf(bio,
16746369f9f8Sinoguchi 			    "---\nCiphers common between both SSL endpoints:\n");
1675dab3f910Sjsing 			j = i = 0;
1676dab3f910Sjsing 			while (*p) {
1677dab3f910Sjsing 				if (*p == ':') {
1678dab3f910Sjsing 					BIO_write(bio, space, 15 - j % 25);
1679dab3f910Sjsing 					i++;
1680dab3f910Sjsing 					j = 0;
16816369f9f8Sinoguchi 					BIO_write(bio,
16826369f9f8Sinoguchi 					    ((i % 3) ? " " : "\n"), 1);
1683dab3f910Sjsing 				} else {
1684dab3f910Sjsing 					BIO_write(bio, p, 1);
1685dab3f910Sjsing 					j++;
1686dab3f910Sjsing 				}
1687dab3f910Sjsing 				p++;
1688dab3f910Sjsing 			}
1689dab3f910Sjsing 			BIO_write(bio, "\n", 1);
1690dab3f910Sjsing 		}
169157a9ba28Sjsing 
169257a9ba28Sjsing 		ssl_print_tmp_key(bio, s);
169357a9ba28Sjsing 
16946369f9f8Sinoguchi 		BIO_printf(bio,
16956369f9f8Sinoguchi 		    "---\nSSL handshake has read %ld bytes and written %ld bytes\n",
1696dab3f910Sjsing 		    BIO_number_read(SSL_get_rbio(s)),
1697dab3f910Sjsing 		    BIO_number_written(SSL_get_wbio(s)));
1698dab3f910Sjsing 	}
1699dab3f910Sjsing 	BIO_printf(bio, (SSL_cache_hit(s) ? "---\nReused, " : "---\nNew, "));
1700dab3f910Sjsing 	c = SSL_get_current_cipher(s);
1701dab3f910Sjsing 	BIO_printf(bio, "%s, Cipher is %s\n",
1702dab3f910Sjsing 	    SSL_CIPHER_get_version(c),
1703dab3f910Sjsing 	    SSL_CIPHER_get_name(c));
1704dab3f910Sjsing 	if (peer != NULL) {
1705dab3f910Sjsing 		EVP_PKEY *pktmp;
170684dd6e9aStb 
170784dd6e9aStb 		pktmp = X509_get0_pubkey(peer);
1708dab3f910Sjsing 		BIO_printf(bio, "Server public key is %d bit\n",
1709dab3f910Sjsing 		    EVP_PKEY_bits(pktmp));
1710dab3f910Sjsing 	}
1711dab3f910Sjsing 	BIO_printf(bio, "Secure Renegotiation IS%s supported\n",
1712dab3f910Sjsing 	    SSL_get_secure_renegotiation_support(s) ? "" : " NOT");
1713dab3f910Sjsing 
1714dab3f910Sjsing 	/* Compression is not supported and will always be none. */
1715dab3f910Sjsing 	BIO_printf(bio, "Compression: NONE\n");
1716dab3f910Sjsing 	BIO_printf(bio, "Expansion: NONE\n");
1717dab3f910Sjsing 
1718dab3f910Sjsing #ifdef SSL_DEBUG
1719dab3f910Sjsing 	{
1720dab3f910Sjsing 		/* Print out local port of connection: useful for debugging */
1721dab3f910Sjsing 		int sock;
1722dab3f910Sjsing 		struct sockaddr_in ladd;
1723dab3f910Sjsing 		socklen_t ladd_size = sizeof(ladd);
1724dab3f910Sjsing 		sock = SSL_get_fd(s);
1725dab3f910Sjsing 		getsockname(sock, (struct sockaddr *) & ladd, &ladd_size);
17265042ef37Sinoguchi 		BIO_printf(bio, "LOCAL PORT is %u\n",
17276369f9f8Sinoguchi 		    ntohs(ladd.sin_port));
1728dab3f910Sjsing 	}
1729dab3f910Sjsing #endif
1730dab3f910Sjsing 
17311b4c9cadSjsing 	{
17321b4c9cadSjsing 		const unsigned char *proto;
17331b4c9cadSjsing 		unsigned int proto_len;
17341b4c9cadSjsing 		SSL_get0_alpn_selected(s, &proto, &proto_len);
17351b4c9cadSjsing 		if (proto_len > 0) {
17361b4c9cadSjsing 			BIO_printf(bio, "ALPN protocol: ");
17371b4c9cadSjsing 			BIO_write(bio, proto, proto_len);
17381b4c9cadSjsing 			BIO_write(bio, "\n", 1);
17391b4c9cadSjsing 		} else
17401b4c9cadSjsing 			BIO_printf(bio, "No ALPN negotiated\n");
17411b4c9cadSjsing 	}
1742dab3f910Sjsing 
1743dab3f910Sjsing #ifndef OPENSSL_NO_SRTP
1744dab3f910Sjsing 	{
17456369f9f8Sinoguchi 		SRTP_PROTECTION_PROFILE *srtp_profile;
1746dab3f910Sjsing 
17476369f9f8Sinoguchi 		srtp_profile = SSL_get_selected_srtp_profile(s);
1748dab3f910Sjsing 		if (srtp_profile)
17496369f9f8Sinoguchi 			BIO_printf(bio,
17506369f9f8Sinoguchi 			    "SRTP Extension negotiated, profile=%s\n",
1751dab3f910Sjsing 			    srtp_profile->name);
1752dab3f910Sjsing 	}
1753dab3f910Sjsing #endif
1754dab3f910Sjsing 
1755dab3f910Sjsing 	SSL_SESSION_print(bio, SSL_get_session(s));
1756e7718adaStb 	if (cfg.keymatexportlabel != NULL) {
1757dab3f910Sjsing 		BIO_printf(bio, "Keying material exporter:\n");
17586369f9f8Sinoguchi 		BIO_printf(bio, "    Label: '%s'\n",
1759e7718adaStb 		    cfg.keymatexportlabel);
17606369f9f8Sinoguchi 		BIO_printf(bio, "    Length: %i bytes\n",
1761e7718adaStb 		    cfg.keymatexportlen);
1762e7718adaStb 		exportedkeymat = malloc(cfg.keymatexportlen);
1763dab3f910Sjsing 		if (exportedkeymat != NULL) {
1764dab3f910Sjsing 			if (!SSL_export_keying_material(s, exportedkeymat,
1765e7718adaStb 				cfg.keymatexportlen,
1766e7718adaStb 				cfg.keymatexportlabel,
1767e7718adaStb 				strlen(cfg.keymatexportlabel),
1768dab3f910Sjsing 				NULL, 0, 0)) {
1769dab3f910Sjsing 				BIO_printf(bio, "    Error\n");
1770dab3f910Sjsing 			} else {
1771dab3f910Sjsing 				BIO_printf(bio, "    Keying material: ");
1772e7718adaStb 				for (i = 0; i < cfg.keymatexportlen; i++)
1773dab3f910Sjsing 					BIO_printf(bio, "%02X",
1774dab3f910Sjsing 					    exportedkeymat[i]);
1775dab3f910Sjsing 				BIO_printf(bio, "\n");
1776dab3f910Sjsing 			}
1777dab3f910Sjsing 			free(exportedkeymat);
1778dab3f910Sjsing 		}
1779dab3f910Sjsing 	}
1780dab3f910Sjsing 	BIO_printf(bio, "---\n");
1781dab3f910Sjsing 	X509_free(peer);
1782dab3f910Sjsing 	/* flush, or debugging output gets mixed with http response */
1783dab3f910Sjsing 	(void) BIO_flush(bio);
1784dab3f910Sjsing }
1785dab3f910Sjsing 
1786dab3f910Sjsing static int
1787dab3f910Sjsing ocsp_resp_cb(SSL *s, void *arg)
1788dab3f910Sjsing {
1789dab3f910Sjsing 	const unsigned char *p;
1790dab3f910Sjsing 	int len;
1791dab3f910Sjsing 	OCSP_RESPONSE *rsp;
1792dab3f910Sjsing 	len = SSL_get_tlsext_status_ocsp_resp(s, &p);
1793dab3f910Sjsing 	BIO_puts(arg, "OCSP response: ");
1794dab3f910Sjsing 	if (!p) {
1795dab3f910Sjsing 		BIO_puts(arg, "no response sent\n");
1796dab3f910Sjsing 		return 1;
1797dab3f910Sjsing 	}
1798dab3f910Sjsing 	rsp = d2i_OCSP_RESPONSE(NULL, &p, len);
1799dab3f910Sjsing 	if (!rsp) {
1800dab3f910Sjsing 		BIO_puts(arg, "response parse error\n");
1801dab3f910Sjsing 		BIO_dump_indent(arg, (char *) p, len, 4);
1802dab3f910Sjsing 		return 0;
1803dab3f910Sjsing 	}
1804dab3f910Sjsing 	BIO_puts(arg, "\n======================================\n");
1805dab3f910Sjsing 	OCSP_RESPONSE_print(arg, rsp, 0);
1806dab3f910Sjsing 	BIO_puts(arg, "======================================\n");
1807dab3f910Sjsing 	OCSP_RESPONSE_free(rsp);
1808dab3f910Sjsing 	return 1;
1809dab3f910Sjsing }
1810dab3f910Sjsing 
1811a2111520Sinoguchi static int
1812a2111520Sinoguchi ssl_servername_cb(SSL *s, int *ad, void *arg)
1813a2111520Sinoguchi {
1814a2111520Sinoguchi 	tlsextctx *p = (tlsextctx *) arg;
1815a2111520Sinoguchi 	const char *hn = SSL_get_servername(s, TLSEXT_NAMETYPE_host_name);
1816a2111520Sinoguchi 	if (SSL_get_servername_type(s) != -1)
1817a2111520Sinoguchi 		p->ack = !SSL_session_reused(s) && hn != NULL;
1818a2111520Sinoguchi 	else
1819a2111520Sinoguchi 		BIO_printf(bio_err, "Can't use SSL_get_servername\n");
1820a2111520Sinoguchi 
1821a2111520Sinoguchi 	return SSL_TLSEXT_ERR_OK;
1822a2111520Sinoguchi }
1823a2111520Sinoguchi 
1824