X-Git-Url: https://git.openssl.org/?p=openssl.git;a=blobdiff_plain;f=apps%2Fs_client.c;h=f93ae35f56651a39315a363f51836bcd2f340861;hp=08749830ba9249d4b028907b94106acdada7118f;hb=a5ecdc6af8f36d034ede991c8524b70d9ee72be6;hpb=ca3a82c3b364e1e584546f0f3bbb938b0b472580 diff --git a/apps/s_client.c b/apps/s_client.c index 08749830ba..f93ae35f56 100644 --- a/apps/s_client.c +++ b/apps/s_client.c @@ -1,4 +1,3 @@ -/* apps/s_client.c */ /* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com) * All rights reserved. * @@ -135,12 +134,12 @@ * OTHERWISE. */ -#include #include #include #include #include #include + /* * With IPv6, it looks like Digital has mixed up the proper order of * recursive header file inclusion, resulting in the compiler complaining @@ -161,6 +160,7 @@ typedef unsigned int u_int; #include #include #include +#include #ifndef OPENSSL_NO_SRP # include #endif @@ -172,56 +172,36 @@ typedef unsigned int u_int; # undef FIONBIO #endif -#undef PROG -#define PROG s_client_main - -/* - * #define SSL_HOST_NAME "www.netscape.com" - */ -/* - * #define SSL_HOST_NAME "193.118.187.102" - */ #define SSL_HOST_NAME "localhost" -/* no default cert. */ -/* - * #define TEST_CERT "client.pem" - */ - #undef BUFSIZZ #define BUFSIZZ 1024*8 +#define S_CLIENT_IRC_READ_TIMEOUT 8 extern int verify_depth; extern int verify_error; extern int verify_return_error; extern int verify_quiet; -#ifdef FIONBIO +static int async = 0; static int c_nbio = 0; -#endif -static int c_Pause = 0; -static int c_debug = 0; -#ifndef OPENSSL_NO_TLSEXT static int c_tlsextdebug = 0; static int c_status_req = 0; -#endif +static int c_Pause = 0; +static int c_debug = 0; static int c_msg = 0; static int c_showcerts = 0; - static char *keymatexportlabel = NULL; static int keymatexportlen = 20; - -static void sc_usage(void); -static void print_stuff(BIO *berr, SSL *con, int full); -#ifndef OPENSSL_NO_TLSEXT -static int ocsp_resp_cb(SSL *s, void *arg); -#endif static BIO *bio_c_out = NULL; static BIO *bio_c_msg = NULL; static int c_quiet = 0; static int c_ign_eof = 0; static int c_brief = 0; +static void print_stuff(BIO *berr, SSL *con, int full); +static int ocsp_resp_cb(SSL *s, void *arg); + #ifndef OPENSSL_NO_PSK /* Default PSK identity and key */ static char *psk_identity = "Client_identity"; @@ -261,8 +241,7 @@ static unsigned int psk_client_cb(SSL *ssl, const char *hint, char *identity, if (!ret) { BIO_printf(bio_err, "Could not convert PSK key '%s' to BIGNUM\n", psk_key); - if (bn) - BN_free(bn); + BN_free(bn); return 0; } @@ -290,149 +269,6 @@ static unsigned int psk_client_cb(SSL *ssl, const char *hint, char *identity, } #endif -static void sc_usage(void) -{ - BIO_printf(bio_err, "usage: s_client args\n"); - BIO_printf(bio_err, "\n"); - BIO_printf(bio_err, " -host host - use -connect instead\n"); - BIO_printf(bio_err, " -port port - use -connect instead\n"); - BIO_printf(bio_err, - " -connect host:port - connect over TCP/IP (default is %s:%s)\n", - SSL_HOST_NAME, PORT_STR); - BIO_printf(bio_err, - " -unix path - connect over unix domain sockets\n"); - BIO_printf(bio_err, - " -verify arg - turn on peer certificate verification\n"); - BIO_printf(bio_err, - " -verify_return_error - return verification errors\n"); - BIO_printf(bio_err, - " -cert arg - certificate file to use, PEM format assumed\n"); - BIO_printf(bio_err, - " -certform arg - certificate format (PEM or DER) PEM default\n"); - BIO_printf(bio_err, - " -key arg - Private key file to use, in cert file if\n"); - BIO_printf(bio_err, " not specified but cert file is.\n"); - BIO_printf(bio_err, - " -keyform arg - key format (PEM or DER) PEM default\n"); - BIO_printf(bio_err, - " -pass arg - private key file pass phrase source\n"); - BIO_printf(bio_err, " -CApath arg - PEM format directory of CA's\n"); - BIO_printf(bio_err, " -CAfile arg - PEM format file of CA's\n"); - BIO_printf(bio_err, - " -trusted_first - Use local CA's first when building trust chain\n"); - BIO_printf(bio_err, - " -no_alt_chains - only ever use the first certificate chain found\n"); - BIO_printf(bio_err, - " -reconnect - Drop and re-make the connection with the same Session-ID\n"); - BIO_printf(bio_err, - " -pause - sleep(1) after each read(2) and write(2) system call\n"); - BIO_printf(bio_err, - " -prexit - print session information even on connection failure\n"); - BIO_printf(bio_err, - " -showcerts - show all certificates in the chain\n"); - BIO_printf(bio_err, " -debug - extra output\n"); -#ifdef WATT32 - BIO_printf(bio_err, " -wdebug - WATT-32 tcp debugging\n"); -#endif - BIO_printf(bio_err, " -msg - Show protocol messages\n"); - BIO_printf(bio_err, " -nbio_test - more ssl protocol testing\n"); - BIO_printf(bio_err, " -state - print the 'ssl' states\n"); -#ifdef FIONBIO - BIO_printf(bio_err, " -nbio - Run with non-blocking IO\n"); -#endif - BIO_printf(bio_err, - " -crlf - convert LF from terminal into CRLF\n"); - BIO_printf(bio_err, " -quiet - no s_client output\n"); - BIO_printf(bio_err, - " -ign_eof - ignore input eof (default when -quiet)\n"); - BIO_printf(bio_err, " -no_ign_eof - don't ignore input eof\n"); -#ifndef OPENSSL_NO_PSK - BIO_printf(bio_err, " -psk_identity arg - PSK identity\n"); - BIO_printf(bio_err, " -psk arg - PSK in hex (without 0x)\n"); -# ifndef OPENSSL_NO_JPAKE - BIO_printf(bio_err, " -jpake arg - JPAKE secret to use\n"); -# endif -#endif -#ifndef OPENSSL_NO_SRP - BIO_printf(bio_err, - " -srpuser user - SRP authentification for 'user'\n"); - BIO_printf(bio_err, " -srppass arg - password for 'user'\n"); - BIO_printf(bio_err, - " -srp_lateuser - SRP username into second ClientHello message\n"); - BIO_printf(bio_err, - " -srp_moregroups - Tolerate other than the known g N values.\n"); - BIO_printf(bio_err, - " -srp_strength int - minimal length in bits for N (default %d).\n", - SRP_MINIMAL_N); -#endif -#ifndef OPENSSL_NO_SSL3_METHOD - BIO_printf(bio_err, " -ssl3 - just use SSLv3\n"); -#endif - BIO_printf(bio_err, " -tls1_2 - just use TLSv1.2\n"); - BIO_printf(bio_err, " -tls1_1 - just use TLSv1.1\n"); - BIO_printf(bio_err, " -tls1 - just use TLSv1\n"); - BIO_printf(bio_err, " -dtls1 - just use DTLSv1\n"); - BIO_printf(bio_err, " -fallback_scsv - send TLS_FALLBACK_SCSV\n"); - BIO_printf(bio_err, " -mtu - set the link layer MTU\n"); - BIO_printf(bio_err, - " -no_tls1_2/-no_tls1_1/-no_tls1/-no_ssl3 - turn off that protocol\n"); - BIO_printf(bio_err, - " -bugs - Switch on all SSL implementation bug workarounds\n"); - BIO_printf(bio_err, - " -cipher - preferred cipher to use, use the 'openssl ciphers'\n"); - BIO_printf(bio_err, - " command to see what is available\n"); - BIO_printf(bio_err, - " -starttls prot - use the STARTTLS command before starting TLS\n"); - BIO_printf(bio_err, - " for those protocols that support it, where\n"); - BIO_printf(bio_err, - " 'prot' defines which one to assume. Currently,\n"); - BIO_printf(bio_err, - " only \"smtp\", \"pop3\", \"imap\", \"ftp\" and \"xmpp\"\n"); - BIO_printf(bio_err, " are supported.\n"); - BIO_printf(bio_err, - " -xmpphost host - When used with \"-starttls xmpp\" specifies the virtual host.\n"); -#ifndef OPENSSL_NO_ENGINE - BIO_printf(bio_err, - " -engine id - Initialise and use the specified engine\n"); -#endif - BIO_printf(bio_err, " -rand file%cfile%c...\n", LIST_SEPARATOR_CHAR, - LIST_SEPARATOR_CHAR); - BIO_printf(bio_err, " -sess_out arg - file to write SSL session to\n"); - BIO_printf(bio_err, " -sess_in arg - file to read SSL session from\n"); -#ifndef OPENSSL_NO_TLSEXT - BIO_printf(bio_err, - " -servername host - Set TLS extension servername in ClientHello\n"); - BIO_printf(bio_err, - " -tlsextdebug - hex dump of all TLS extensions received\n"); - BIO_printf(bio_err, - " -status - request certificate status from server\n"); - BIO_printf(bio_err, - " -no_ticket - disable use of RFC4507bis session tickets\n"); - BIO_printf(bio_err, - " -serverinfo types - send empty ClientHello extensions (comma-separated numbers)\n"); -# ifndef OPENSSL_NO_NEXTPROTONEG - BIO_printf(bio_err, - " -nextprotoneg arg - enable NPN extension, considering named protocols supported (comma-separated list)\n"); -# endif - BIO_printf(bio_err, - " -alpn arg - enable ALPN extension, considering named protocols supported (comma-separated list)\n"); -#endif - BIO_printf(bio_err, - " -legacy_renegotiation - enable use of legacy renegotiation (dangerous)\n"); -#ifndef OPENSSL_NO_SRTP - BIO_printf(bio_err, - " -use_srtp profiles - Offer SRTP key management with a colon-separated profile list\n"); -#endif - BIO_printf(bio_err, - " -keymatexport label - Export keying material using label\n"); - BIO_printf(bio_err, - " -keymatexportlen len - Export len bytes of keying material (default 20)\n"); -} - -#ifndef OPENSSL_NO_TLSEXT - /* This is a context that we pass to callbacks */ typedef struct tlsextctx_st { BIO *biodebug; @@ -451,7 +287,7 @@ static int ssl_servername_cb(SSL *s, int *ad, void *arg) return SSL_TLSEXT_ERR_OK; } -# ifndef OPENSSL_NO_SRP +#ifndef OPENSSL_NO_SRP /* This is a context that we pass to all callbacks */ typedef struct srp_arg_st { @@ -463,7 +299,7 @@ typedef struct srp_arg_st { int strength /* minimal size for N */ ; } SRP_ARG; -# define SRP_NUMBER_ITERATIONS_FOR_PRIME 64 +# define SRP_NUMBER_ITERATIONS_FOR_PRIME 64 static int srp_Verify_N_and_g(const BIGNUM *N, const BIGNUM *g) { @@ -481,12 +317,9 @@ static int srp_Verify_N_and_g(const BIGNUM *N, const BIGNUM *g) BN_mod_exp(r, g, p, N, bn_ctx) && BN_add_word(r, 1) && BN_cmp(r, N) == 0; - if (r) - BN_free(r); - if (p) - BN_free(p); - if (bn_ctx) - BN_CTX_free(bn_ctx); + BN_free(r); + BN_free(p); + BN_CTX_free(bn_ctx); return ret; } @@ -510,7 +343,8 @@ static int ssl_srp_verify_param_cb(SSL *s, void *arg) { SRP_ARG *srp_arg = (SRP_ARG *)arg; BIGNUM *N = NULL, *g = NULL; - if (!(N = SSL_get_srp_N(s)) || !(g = SSL_get_srp_g(s))) + + if (((N = SSL_get_srp_N(s)) == NULL) || ((g = SSL_get_srp_g(s)) == NULL)) return 0; if (srp_arg->debug || srp_arg->msg || srp_arg->amp == 1) { BIO_printf(bio_err, "SRP parameters:\n"); @@ -541,20 +375,15 @@ static int ssl_srp_verify_param_cb(SSL *s, void *arg) return 0; } -# define PWD_STRLEN 1024 +# define PWD_STRLEN 1024 static char *ssl_give_srp_client_pwd_cb(SSL *s, void *arg) { SRP_ARG *srp_arg = (SRP_ARG *)arg; - char *pass = (char *)OPENSSL_malloc(PWD_STRLEN + 1); + char *pass = app_malloc(PWD_STRLEN + 1, "SRP password buffer"); PW_CB_DATA cb_tmp; int l; - if(!pass) { - BIO_printf(bio_err, "Malloc failure\n"); - return NULL; - } - cb_tmp.password = (char *)srp_arg->srppassin; cb_tmp.prompt_info = "SRP user"; if ((l = password_callback(pass, PWD_STRLEN, 0, &cb_tmp)) < 0) { @@ -567,12 +396,11 @@ static char *ssl_give_srp_client_pwd_cb(SSL *s, void *arg) return pass; } -# endif -# ifndef OPENSSL_NO_SRTP -char *srtp_profiles = NULL; -# endif +#endif -# ifndef OPENSSL_NO_NEXTPROTONEG +static char *srtp_profiles = NULL; + +#ifndef OPENSSL_NO_NEXTPROTONEG /* This the context that we pass to next_proto_cb */ typedef struct tlsextnextprotoctx_st { unsigned char *data; @@ -605,7 +433,7 @@ static int next_proto_cb(SSL *s, unsigned char **out, unsigned char *outlen, SSL_select_next_proto(out, outlen, in, inlen, ctx->data, ctx->len); return SSL_TLSEXT_ERR_OK; } -# endif /* ndef OPENSSL_NO_NEXTPROTONEG */ +#endif /* ndef OPENSSL_NO_NEXTPROTONEG */ static int serverinfo_cli_parse_cb(SSL *s, unsigned int ext_type, const unsigned char *in, size_t inlen, @@ -627,505 +455,635 @@ static int serverinfo_cli_parse_cb(SSL *s, unsigned int ext_type, return 1; } +typedef enum OPTION_choice { + OPT_ERR = -1, OPT_EOF = 0, OPT_HELP, + OPT_HOST, OPT_PORT, OPT_CONNECT, OPT_UNIX, OPT_XMPPHOST, OPT_VERIFY, + OPT_CERT, OPT_CRL, OPT_CRL_DOWNLOAD, OPT_SESS_OUT, OPT_SESS_IN, + OPT_CERTFORM, OPT_CRLFORM, OPT_VERIFY_RET_ERROR, OPT_VERIFY_QUIET, + OPT_BRIEF, OPT_PREXIT, OPT_CRLF, OPT_QUIET, OPT_NBIO, + OPT_SSL_CLIENT_ENGINE, OPT_RAND, OPT_IGN_EOF, OPT_NO_IGN_EOF, + OPT_PAUSE, OPT_DEBUG, OPT_TLSEXTDEBUG, OPT_STATUS, OPT_WDEBUG, + OPT_MSG, OPT_MSGFILE, OPT_ENGINE, OPT_TRACE, OPT_SECURITY_DEBUG, + OPT_SECURITY_DEBUG_VERBOSE, OPT_SHOWCERTS, OPT_NBIO_TEST, OPT_STATE, + OPT_PSK_IDENTITY, OPT_PSK, OPT_SRPUSER, OPT_SRPPASS, OPT_SRP_STRENGTH, + OPT_SRP_LATEUSER, OPT_SRP_MOREGROUPS, OPT_SSL3, + OPT_TLS1_2, OPT_TLS1_1, OPT_TLS1, OPT_DTLS, OPT_DTLS1, + OPT_DTLS1_2, OPT_TIMEOUT, OPT_MTU, OPT_KEYFORM, OPT_PASS, + OPT_CERT_CHAIN, OPT_CAPATH, OPT_NOCAPATH, OPT_CHAINCAPATH, OPT_VERIFYCAPATH, + OPT_KEY, OPT_RECONNECT, OPT_BUILD_CHAIN, OPT_CAFILE, OPT_NOCAFILE, + OPT_CHAINCAFILE, OPT_VERIFYCAFILE, OPT_NEXTPROTONEG, OPT_ALPN, + OPT_SERVERINFO, OPT_STARTTLS, OPT_SERVERNAME, OPT_JPAKE, + OPT_USE_SRTP, OPT_KEYMATEXPORT, OPT_KEYMATEXPORTLEN, OPT_SMTPHOST, + OPT_ASYNC, + OPT_V_ENUM, + OPT_X_ENUM, + OPT_S_ENUM, + OPT_FALLBACKSCSV, OPT_NOCMDS, OPT_PROXY +} OPTION_CHOICE; + +OPTIONS s_client_options[] = { + {"help", OPT_HELP, '-', "Display this summary"}, + {"host", OPT_HOST, 's', "Use -connect instead"}, + {"port", OPT_PORT, 'p', "Use -connect instead"}, + {"connect", OPT_CONNECT, 's', + "TCP/IP where to connect (default is " SSL_HOST_NAME ":" PORT_STR ")"}, + {"proxy", OPT_PROXY, 's', + "Connect to via specified proxy to the real server"}, + {"unix", OPT_UNIX, 's', "Connect over unix domain sockets"}, + {"verify", OPT_VERIFY, 'p', "Turn on peer certificate verification"}, + {"cert", OPT_CERT, '<', "Certificate file to use, PEM format assumed"}, + {"certform", OPT_CERTFORM, 'F', + "Certificate format (PEM or DER) PEM default"}, + {"key", OPT_KEY, '<', "Private key file to use, if not in -cert file"}, + {"keyform", OPT_KEYFORM, 'F', "Key format (PEM or DER) PEM default"}, + {"pass", OPT_PASS, 's', "Private key file pass phrase source"}, + {"CApath", OPT_CAPATH, '/', "PEM format directory of CA's"}, + {"CAfile", OPT_CAFILE, '<', "PEM format file of CA's"}, + {"no-CAfile", OPT_NOCAFILE, '-', + "Do not load the default certificates file"}, + {"no-CApath", OPT_NOCAPATH, '-', + "Do not load certificates from the default certificates directory"}, + {"reconnect", OPT_RECONNECT, '-', + "Drop and re-make the connection with the same Session-ID"}, + {"pause", OPT_PAUSE, '-', "Sleep after each read and write system call"}, + {"showcerts", OPT_SHOWCERTS, '-', "Show all certificates in the chain"}, + {"debug", OPT_DEBUG, '-', "Extra output"}, + {"msg", OPT_MSG, '-', "Show protocol messages"}, + {"msgfile", OPT_MSGFILE, '>'}, + {"nbio_test", OPT_NBIO_TEST, '-', "More ssl protocol testing"}, + {"state", OPT_STATE, '-', "Print the ssl states"}, + {"crlf", OPT_CRLF, '-', "Convert LF from terminal into CRLF"}, + {"quiet", OPT_QUIET, '-', "No s_client output"}, + {"ign_eof", OPT_IGN_EOF, '-', "Ignore input eof (default when -quiet)"}, + {"no_ign_eof", OPT_NO_IGN_EOF, '-', "Don't ignore input eof"}, + {"tls1_2", OPT_TLS1_2, '-', "Just use TLSv1.2"}, + {"tls1_1", OPT_TLS1_1, '-', "Just use TLSv1.1"}, + {"tls1", OPT_TLS1, '-', "Just use TLSv1"}, + {"starttls", OPT_STARTTLS, 's', + "Use the appropriate STARTTLS command before starting TLS"}, + {"xmpphost", OPT_XMPPHOST, 's', + "Host to use with \"-starttls xmpp[-server]\""}, + {"rand", OPT_RAND, 's', + "Load the file(s) into the random number generator"}, + {"sess_out", OPT_SESS_OUT, '>', "File to write SSL session to"}, + {"sess_in", OPT_SESS_IN, '<', "File to read SSL session from"}, + {"use_srtp", OPT_USE_SRTP, 's', + "Offer SRTP key management with a colon-separated profile list"}, + {"keymatexport", OPT_KEYMATEXPORT, 's', + "Export keying material using label"}, + {"keymatexportlen", OPT_KEYMATEXPORTLEN, 'p', + "Export len bytes of keying material (default 20)"}, + {"fallback_scsv", OPT_FALLBACKSCSV, '-', "Send the fallback SCSV"}, + {"name", OPT_SMTPHOST, 's', "Hostname to use for \"-starttls smtp\""}, + {"CRL", OPT_CRL, '<'}, + {"crl_download", OPT_CRL_DOWNLOAD, '-'}, + {"CRLform", OPT_CRLFORM, 'F'}, + {"verify_return_error", OPT_VERIFY_RET_ERROR, '-'}, + {"verify_quiet", OPT_VERIFY_QUIET, '-'}, + {"brief", OPT_BRIEF, '-'}, + {"prexit", OPT_PREXIT, '-'}, + {"security_debug", OPT_SECURITY_DEBUG, '-'}, + {"security_debug_verbose", OPT_SECURITY_DEBUG_VERBOSE, '-'}, + {"cert_chain", OPT_CERT_CHAIN, '<'}, + {"chainCApath", OPT_CHAINCAPATH, '/'}, + {"verifyCApath", OPT_VERIFYCAPATH, '/'}, + {"build_chain", OPT_BUILD_CHAIN, '-'}, + {"chainCAfile", OPT_CHAINCAFILE, '<'}, + {"verifyCAfile", OPT_VERIFYCAFILE, '<'}, + {"nocommands", OPT_NOCMDS, '-', "Do not use interactive command letters"}, + {"servername", OPT_SERVERNAME, 's', + "Set TLS extension servername in ClientHello"}, + {"tlsextdebug", OPT_TLSEXTDEBUG, '-', + "Hex dump of all TLS extensions received"}, + {"status", OPT_STATUS, '-', "Request certificate status from server"}, + {"serverinfo", OPT_SERVERINFO, 's', + "types Send empty ClientHello extensions (comma-separated numbers)"}, + {"alpn", OPT_ALPN, 's', + "Enable ALPN extension, considering named protocols supported (comma-separated list)"}, + {"async", OPT_ASYNC, '-', "Support asynchronous operation"}, + OPT_S_OPTIONS, + OPT_V_OPTIONS, + OPT_X_OPTIONS, +#ifndef OPENSSL_NO_SSL3 + {"ssl3", OPT_SSL3, '-', "Just use SSLv3"}, +#endif +#ifndef OPENSSL_NO_DTLS + {"dtls", OPT_DTLS, '-'}, + {"dtls1", OPT_DTLS1, '-', "Just use DTLSv1"}, + {"dtls1_2", OPT_DTLS1_2, '-'}, + {"timeout", OPT_TIMEOUT, '-'}, + {"mtu", OPT_MTU, 'p', "Set the link layer MTU"}, +#endif +#ifndef OPENSSL_NO_SSL_TRACE + {"trace", OPT_TRACE, '-'}, #endif +#ifdef WATT32 + {"wdebug", OPT_WDEBUG, '-', "WATT-32 tcp debugging"}, +#endif +#ifdef FIONBIO + {"nbio", OPT_NBIO, '-', "Use non-blocking IO"}, +#endif +#ifndef OPENSSL_NO_PSK + {"psk_identity", OPT_PSK_IDENTITY, 's', "PSK identity"}, + {"psk", OPT_PSK, 's', "PSK in hex (without 0x)"}, +# ifndef OPENSSL_NO_JPAKE + {"jpake", OPT_JPAKE, 's', "JPAKE secret to use"}, +# endif +#endif +#ifndef OPENSSL_NO_SRP + {"srpuser", OPT_SRPUSER, 's', "SRP authentification for 'user'"}, + {"srppass", OPT_SRPPASS, 's', "Password for 'user'"}, + {"srp_lateuser", OPT_SRP_LATEUSER, '-', + "SRP username into second ClientHello message"}, + {"srp_moregroups", OPT_SRP_MOREGROUPS, '-', + "Tolerate other than the known g N values."}, + {"srp_strength", OPT_SRP_STRENGTH, 'p', "Minimal length in bits for N"}, +#endif +#ifndef OPENSSL_NO_NEXTPROTONEG + {"nextprotoneg", OPT_NEXTPROTONEG, 's', + "Enable NPN extension, considering named protocols supported (comma-separated list)"}, +#endif +#ifndef OPENSSL_NO_ENGINE + {"engine", OPT_ENGINE, 's', "Use engine, possibly a hardware device"}, + {"ssl_client_engine", OPT_SSL_CLIENT_ENGINE, 's'}, +#endif + {NULL} +}; -enum { - PROTO_OFF = 0, +typedef enum PROTOCOL_choice { + PROTO_OFF, PROTO_SMTP, PROTO_POP3, PROTO_IMAP, PROTO_FTP, - PROTO_XMPP + PROTO_TELNET, + PROTO_XMPP, + PROTO_XMPP_SERVER, + PROTO_CONNECT, + PROTO_IRC +} PROTOCOL_CHOICE; + +static OPT_PAIR services[] = { + {"smtp", PROTO_SMTP}, + {"pop3", PROTO_POP3}, + {"imap", PROTO_IMAP}, + {"ftp", PROTO_FTP}, + {"xmpp", PROTO_XMPP}, + {"xmpp-server", PROTO_XMPP_SERVER}, + {"telnet", PROTO_TELNET}, + {"irc", PROTO_IRC}, + {NULL} }; -int MAIN(int, char **); - -int MAIN(int argc, char **argv) +int s_client_main(int argc, char **argv) { - int build_chain = 0; - SSL *con = NULL; -#ifndef OPENSSL_NO_KRB5 - KSSL_CTX *kctx; -#endif - int s, k, width, state = 0; - char *cbuf = NULL, *sbuf = NULL, *mbuf = NULL; - int cbuf_len, cbuf_off; - int sbuf_len, sbuf_off; - fd_set readfds, writefds; - short port = PORT; - int full_log = 1; - char *host = SSL_HOST_NAME; - const char *unix_path = NULL; - char *xmpphost = NULL; - char *cert_file = NULL, *key_file = NULL, *chain_file = NULL; - int cert_format = FORMAT_PEM, key_format = FORMAT_PEM; - char *passarg = NULL, *pass = NULL; - X509 *cert = NULL; + BIO *sbio; EVP_PKEY *key = NULL; - STACK_OF(X509) *chain = NULL; - char *CApath = NULL, *CAfile = NULL; - char *chCApath = NULL, *chCAfile = NULL; - char *vfyCApath = NULL, *vfyCAfile = NULL; - int reconnect = 0, badop = 0, verify = SSL_VERIFY_NONE; - int crlf = 0; - int write_tty, read_tty, write_ssl, read_ssl, tty_on, ssl_pending; + SSL *con = NULL; SSL_CTX *ctx = NULL; - int ret = 1, in_init = 1, i, nbio_test = 0; - int starttls_proto = PROTO_OFF; - int prexit = 0; + STACK_OF(X509) *chain = NULL; + X509 *cert = NULL; X509_VERIFY_PARAM *vpm = NULL; - int badarg = 0; - const SSL_METHOD *meth = NULL; - int socket_type = SOCK_STREAM; - BIO *sbio; + SSL_EXCERT *exc = NULL; + SSL_CONF_CTX *cctx = NULL; + STACK_OF(OPENSSL_STRING) *ssl_args = NULL; + STACK_OF(X509_CRL) *crls = NULL; + const SSL_METHOD *meth = TLS_client_method(); + char *CApath = NULL, *CAfile = NULL, *cbuf = NULL, *sbuf = NULL; + char *mbuf = NULL, *proxystr = NULL, *connectstr = NULL; + char *cert_file = NULL, *key_file = NULL, *chain_file = NULL, *prog; + char *chCApath = NULL, *chCAfile = NULL, *host = SSL_HOST_NAME; char *inrand = NULL; - int mbuf_len = 0; + char *passarg = NULL, *pass = NULL, *vfyCApath = NULL, *vfyCAfile = NULL; + char *sess_in = NULL, *sess_out = NULL, *crl_file = NULL, *p; + char *jpake_secret = NULL, *xmpphost = NULL; + const char *unix_path = NULL; + const char *ehlo = "mail.example.com"; + struct sockaddr peer; struct timeval timeout, *timeoutp; + fd_set readfds, writefds; + int noCApath = 0, noCAfile = 0; + int build_chain = 0, cbuf_len, cbuf_off, cert_format = FORMAT_PEM; + int key_format = FORMAT_PEM, crlf = 0, full_log = 1, mbuf_len = 0; + int prexit = 0; + int enable_timeouts = 0, sdebug = 0, peerlen = sizeof peer; + int reconnect = 0, verify = SSL_VERIFY_NONE, vpmtouched = 0; + int ret = 1, in_init = 1, i, nbio_test = 0, s = -1, k, width, state = 0; + int sbuf_len, sbuf_off, socket_type = SOCK_STREAM, cmdletters = 1; + int starttls_proto = PROTO_OFF, crl_format = FORMAT_PEM, crl_download = 0; + int write_tty, read_tty, write_ssl, read_ssl, tty_on, ssl_pending; + int fallback_scsv = 0; + long socket_mtu = 0, randamt = 0; + unsigned short port = PORT; + OPTION_CHOICE o; #ifndef OPENSSL_NO_ENGINE - char *engine_id = NULL; - char *ssl_client_engine_id = NULL; ENGINE *ssl_client_engine = NULL; #endif ENGINE *e = NULL; #if defined(OPENSSL_SYS_WINDOWS) || defined(OPENSSL_SYS_MSDOS) || defined(OPENSSL_SYS_NETWARE) struct timeval tv; #endif -#ifndef OPENSSL_NO_TLSEXT char *servername = NULL; - tlsextctx tlsextcbp = { NULL, 0 }; -# ifndef OPENSSL_NO_NEXTPROTONEG - const char *next_proto_neg_in = NULL; -# endif const char *alpn_in = NULL; -# define MAX_SI_TYPES 100 + tlsextctx tlsextcbp = { NULL, 0 }; +#define MAX_SI_TYPES 100 unsigned short serverinfo_types[MAX_SI_TYPES]; - int serverinfo_types_count = 0; -#endif - char *sess_in = NULL; - char *sess_out = NULL; - struct sockaddr peer; - int peerlen = sizeof(peer); - int fallback_scsv = 0; - int enable_timeouts = 0; - long socket_mtu = 0; -#ifndef OPENSSL_NO_JPAKE - static char *jpake_secret = NULL; -# define no_jpake !jpake_secret -#else -# define no_jpake 1 + int serverinfo_count = 0, start = 0, len; +#ifndef OPENSSL_NO_NEXTPROTONEG + const char *next_proto_neg_in = NULL; #endif #ifndef OPENSSL_NO_SRP char *srppass = NULL; int srp_lateuser = 0; SRP_ARG srp_arg = { NULL, NULL, 0, 0, 0, 1024 }; #endif - SSL_EXCERT *exc = NULL; - - SSL_CONF_CTX *cctx = NULL; - STACK_OF(OPENSSL_STRING) *ssl_args = NULL; - char *crl_file = NULL; - int crl_format = FORMAT_PEM; - int crl_download = 0; - STACK_OF(X509_CRL) *crls = NULL; - int sdebug = 0; - - meth = SSLv23_client_method(); - - apps_startup(); + prog = opt_progname(argv[0]); c_Pause = 0; c_quiet = 0; c_ign_eof = 0; c_debug = 0; c_msg = 0; c_showcerts = 0; - - if (bio_err == NULL) - bio_err = BIO_new_fp(stderr, BIO_NOCLOSE); - - if (!load_config(bio_err, NULL)) - goto end; + c_nbio = 0; + verify_depth = 0; + verify_error = X509_V_OK; + vpm = X509_VERIFY_PARAM_new(); + cbuf = app_malloc(BUFSIZZ, "cbuf"); + sbuf = app_malloc(BUFSIZZ, "sbuf"); + mbuf = app_malloc(BUFSIZZ, "mbuf"); cctx = SSL_CONF_CTX_new(); - if (!cctx) - goto end; - SSL_CONF_CTX_set_flags(cctx, SSL_CONF_FLAG_CLIENT); - SSL_CONF_CTX_set_flags(cctx, SSL_CONF_FLAG_CMDLINE); - if (((cbuf = OPENSSL_malloc(BUFSIZZ)) == NULL) || - ((sbuf = OPENSSL_malloc(BUFSIZZ)) == NULL) || - ((mbuf = OPENSSL_malloc(BUFSIZZ)) == NULL)) { - BIO_printf(bio_err, "out of memory\n"); + if (vpm == NULL || cctx == NULL) { + BIO_printf(bio_err, "%s: out of memory\n", prog); goto end; } - verify_depth = 0; - verify_error = X509_V_OK; -#ifdef FIONBIO - c_nbio = 0; -#endif + SSL_CONF_CTX_set_flags(cctx, SSL_CONF_FLAG_CLIENT | SSL_CONF_FLAG_CMDLINE); - argc--; - argv++; - while (argc >= 1) { - if (strcmp(*argv, "-host") == 0) { - if (--argc < 1) - goto bad; - host = *(++argv); - } else if (strcmp(*argv, "-port") == 0) { - if (--argc < 1) - goto bad; - port = atoi(*(++argv)); - if (port == 0) - goto bad; - } else if (strcmp(*argv, "-connect") == 0) { - if (--argc < 1) - goto bad; - if (!extract_host_port(*(++argv), &host, NULL, &port)) - goto bad; - } else if (strcmp(*argv, "-unix") == 0) { - if (--argc < 1) - goto bad; - unix_path = *(++argv); - } else if (strcmp(*argv, "-xmpphost") == 0) { - if (--argc < 1) - goto bad; - xmpphost = *(++argv); - } else if (strcmp(*argv, "-verify") == 0) { + prog = opt_init(argc, argv, s_client_options); + while ((o = opt_next()) != OPT_EOF) { + switch (o) { + case OPT_EOF: + case OPT_ERR: + opthelp: + BIO_printf(bio_err, "%s: Use -help for summary.\n", prog); + goto end; + case OPT_HELP: + opt_help(s_client_options); + ret = 0; + goto end; + case OPT_HOST: + host = opt_arg(); + break; + case OPT_PORT: + port = atoi(opt_arg()); + break; + case OPT_CONNECT: + connectstr = opt_arg(); + break; + case OPT_PROXY: + proxystr = opt_arg(); + starttls_proto = PROTO_CONNECT; + break; + case OPT_UNIX: + unix_path = opt_arg(); + break; + case OPT_XMPPHOST: + xmpphost = opt_arg(); + break; + case OPT_SMTPHOST: + ehlo = opt_arg(); + break; + case OPT_VERIFY: verify = SSL_VERIFY_PEER; - if (--argc < 1) - goto bad; - verify_depth = atoi(*(++argv)); + verify_depth = atoi(opt_arg()); if (!c_quiet) BIO_printf(bio_err, "verify depth is %d\n", verify_depth); - } else if (strcmp(*argv, "-cert") == 0) { - if (--argc < 1) - goto bad; - cert_file = *(++argv); - } else if (strcmp(*argv, "-CRL") == 0) { - if (--argc < 1) - goto bad; - crl_file = *(++argv); - } else if (strcmp(*argv, "-crl_download") == 0) + break; + case OPT_CERT: + cert_file = opt_arg(); + break; + case OPT_CRL: + crl_file = opt_arg(); + break; + case OPT_CRL_DOWNLOAD: crl_download = 1; - else if (strcmp(*argv, "-sess_out") == 0) { - if (--argc < 1) - goto bad; - sess_out = *(++argv); - } else if (strcmp(*argv, "-sess_in") == 0) { - if (--argc < 1) - goto bad; - sess_in = *(++argv); - } else if (strcmp(*argv, "-certform") == 0) { - if (--argc < 1) - goto bad; - cert_format = str2fmt(*(++argv)); - } else if (strcmp(*argv, "-CRLform") == 0) { - if (--argc < 1) - goto bad; - crl_format = str2fmt(*(++argv)); - } else if (args_verify(&argv, &argc, &badarg, bio_err, &vpm)) { - if (badarg) - goto bad; - continue; - } else if (strcmp(*argv, "-verify_return_error") == 0) + break; + case OPT_SESS_OUT: + sess_out = opt_arg(); + break; + case OPT_SESS_IN: + sess_in = opt_arg(); + break; + case OPT_CERTFORM: + if (!opt_format(opt_arg(), OPT_FMT_PEMDER, &cert_format)) + goto opthelp; + break; + case OPT_CRLFORM: + if (!opt_format(opt_arg(), OPT_FMT_PEMDER, &crl_format)) + goto opthelp; + break; + case OPT_VERIFY_RET_ERROR: verify_return_error = 1; - else if (strcmp(*argv, "-verify_quiet") == 0) - verify_quiet = 1; - else if (strcmp(*argv, "-brief") == 0) { - c_brief = 1; + break; + case OPT_VERIFY_QUIET: verify_quiet = 1; - c_quiet = 1; - } else if (args_excert(&argv, &argc, &badarg, bio_err, &exc)) { - if (badarg) - goto bad; - continue; - } else if (args_ssl(&argv, &argc, cctx, &badarg, bio_err, &ssl_args)) { - if (badarg) - goto bad; - continue; - } else if (strcmp(*argv, "-prexit") == 0) + break; + case OPT_BRIEF: + c_brief = verify_quiet = c_quiet = 1; + break; + case OPT_S_CASES: + if (ssl_args == NULL) + ssl_args = sk_OPENSSL_STRING_new_null(); + if (ssl_args == NULL + || !sk_OPENSSL_STRING_push(ssl_args, opt_flag()) + || !sk_OPENSSL_STRING_push(ssl_args, opt_arg())) { + BIO_printf(bio_err, "%s: Memory allocation failure\n", prog); + goto end; + } + break; + case OPT_V_CASES: + if (!opt_verify(o, vpm)) + goto end; + vpmtouched++; + break; + case OPT_X_CASES: + if (!args_excert(o, &exc)) + goto end; + break; + case OPT_PREXIT: prexit = 1; - else if (strcmp(*argv, "-crlf") == 0) + break; + case OPT_CRLF: crlf = 1; - else if (strcmp(*argv, "-quiet") == 0) { - c_quiet = 1; - c_ign_eof = 1; - } else if (strcmp(*argv, "-ign_eof") == 0) + break; + case OPT_QUIET: + c_quiet = c_ign_eof = 1; + break; + case OPT_NBIO: + c_nbio = 1; + break; + case OPT_NOCMDS: + cmdletters = 0; + break; + case OPT_ENGINE: + e = setup_engine(opt_arg(), 1); + break; + case OPT_SSL_CLIENT_ENGINE: +#ifndef OPENSSL_NO_ENGINE + ssl_client_engine = ENGINE_by_id(opt_arg()); + if (ssl_client_engine == NULL) { + BIO_printf(bio_err, "Error getting client auth engine\n"); + goto opthelp; + } + break; +#endif + break; + case OPT_RAND: + inrand = opt_arg(); + break; + case OPT_IGN_EOF: c_ign_eof = 1; - else if (strcmp(*argv, "-no_ign_eof") == 0) + break; + case OPT_NO_IGN_EOF: c_ign_eof = 0; - else if (strcmp(*argv, "-pause") == 0) + break; + case OPT_PAUSE: c_Pause = 1; - else if (strcmp(*argv, "-debug") == 0) + break; + case OPT_DEBUG: c_debug = 1; -#ifndef OPENSSL_NO_TLSEXT - else if (strcmp(*argv, "-tlsextdebug") == 0) + break; + case OPT_TLSEXTDEBUG: c_tlsextdebug = 1; - else if (strcmp(*argv, "-status") == 0) + break; + case OPT_STATUS: c_status_req = 1; -#endif + break; + case OPT_WDEBUG: #ifdef WATT32 - else if (strcmp(*argv, "-wdebug") == 0) dbug_init(); #endif - else if (strcmp(*argv, "-msg") == 0) + break; + case OPT_MSG: c_msg = 1; - else if (strcmp(*argv, "-msgfile") == 0) { - if (--argc < 1) - goto bad; - bio_c_msg = BIO_new_file(*(++argv), "w"); - } + break; + case OPT_MSGFILE: + bio_c_msg = BIO_new_file(opt_arg(), "w"); + break; + case OPT_TRACE: #ifndef OPENSSL_NO_SSL_TRACE - else if (strcmp(*argv, "-trace") == 0) c_msg = 2; #endif - else if (strcmp(*argv, "-security_debug") == 0) { + break; + case OPT_SECURITY_DEBUG: sdebug = 1; - } else if (strcmp(*argv, "-security_debug_verbose") == 0) { + break; + case OPT_SECURITY_DEBUG_VERBOSE: sdebug = 2; - } else if (strcmp(*argv, "-showcerts") == 0) + break; + case OPT_SHOWCERTS: c_showcerts = 1; - else if (strcmp(*argv, "-nbio_test") == 0) + break; + case OPT_NBIO_TEST: nbio_test = 1; - else if (strcmp(*argv, "-state") == 0) + break; + case OPT_STATE: state = 1; + break; #ifndef OPENSSL_NO_PSK - else if (strcmp(*argv, "-psk_identity") == 0) { - if (--argc < 1) - goto bad; - psk_identity = *(++argv); - } else if (strcmp(*argv, "-psk") == 0) { - size_t j; - - if (--argc < 1) - goto bad; - psk_key = *(++argv); - for (j = 0; j < strlen(psk_key); j++) { - if (isxdigit((unsigned char)psk_key[j])) + case OPT_PSK_IDENTITY: + psk_identity = opt_arg(); + break; + case OPT_PSK: + for (p = psk_key = opt_arg(); *p; p++) { + if (isxdigit(*p)) continue; - BIO_printf(bio_err, "Not a hex number '%s'\n", *argv); - goto bad; + BIO_printf(bio_err, "Not a hex number '%s'\n", psk_key); + goto end; } - } + break; +#else + case OPT_PSK_IDENTITY: + case OPT_PSK: + break; #endif #ifndef OPENSSL_NO_SRP - else if (strcmp(*argv, "-srpuser") == 0) { - if (--argc < 1) - goto bad; - srp_arg.srplogin = *(++argv); + case OPT_SRPUSER: + srp_arg.srplogin = opt_arg(); meth = TLSv1_client_method(); - } else if (strcmp(*argv, "-srppass") == 0) { - if (--argc < 1) - goto bad; - srppass = *(++argv); + break; + case OPT_SRPPASS: + srppass = opt_arg(); meth = TLSv1_client_method(); - } else if (strcmp(*argv, "-srp_strength") == 0) { - if (--argc < 1) - goto bad; - srp_arg.strength = atoi(*(++argv)); + break; + case OPT_SRP_STRENGTH: + srp_arg.strength = atoi(opt_arg()); BIO_printf(bio_err, "SRP minimal length for N is %d\n", srp_arg.strength); meth = TLSv1_client_method(); - } else if (strcmp(*argv, "-srp_lateuser") == 0) { + break; + case OPT_SRP_LATEUSER: srp_lateuser = 1; meth = TLSv1_client_method(); - } else if (strcmp(*argv, "-srp_moregroups") == 0) { + break; + case OPT_SRP_MOREGROUPS: srp_arg.amp = 1; meth = TLSv1_client_method(); - } + break; +#else + case OPT_SRPUSER: + case OPT_SRPPASS: + case OPT_SRP_STRENGTH: + case OPT_SRP_LATEUSER: + case OPT_SRP_MOREGROUPS: + break; #endif -#ifndef OPENSSL_NO_SSL3_METHOD - else if (strcmp(*argv, "-ssl3") == 0) + case OPT_SSL3: +#ifndef OPENSSL_NO_SSL3 meth = SSLv3_client_method(); #endif - else if (strcmp(*argv, "-tls1_2") == 0) + break; + case OPT_TLS1_2: meth = TLSv1_2_client_method(); - else if (strcmp(*argv, "-tls1_1") == 0) + break; + case OPT_TLS1_1: meth = TLSv1_1_client_method(); - else if (strcmp(*argv, "-tls1") == 0) + break; + case OPT_TLS1: meth = TLSv1_client_method(); -#ifndef OPENSSL_NO_DTLS1 - else if (strcmp(*argv, "-dtls") == 0) { + break; +#ifndef OPENSSL_NO_DTLS + case OPT_DTLS: meth = DTLS_client_method(); socket_type = SOCK_DGRAM; - } else if (strcmp(*argv, "-dtls1") == 0) { + break; + case OPT_DTLS1: meth = DTLSv1_client_method(); socket_type = SOCK_DGRAM; - } else if (strcmp(*argv, "-dtls1_2") == 0) { + break; + case OPT_DTLS1_2: meth = DTLSv1_2_client_method(); socket_type = SOCK_DGRAM; - } else if (strcmp(*argv, "-timeout") == 0) + break; + case OPT_TIMEOUT: enable_timeouts = 1; - else if (strcmp(*argv, "-mtu") == 0) { - if (--argc < 1) - goto bad; - socket_mtu = atol(*(++argv)); - } + break; + case OPT_MTU: + socket_mtu = atol(opt_arg()); + break; +#else + case OPT_DTLS: + case OPT_DTLS1: + case OPT_DTLS1_2: + case OPT_TIMEOUT: + case OPT_MTU: + break; #endif - else if (strcmp(*argv, "-fallback_scsv") == 0) { + case OPT_FALLBACKSCSV: fallback_scsv = 1; - } else if (strcmp(*argv, "-keyform") == 0) { - if (--argc < 1) - goto bad; - key_format = str2fmt(*(++argv)); - } else if (strcmp(*argv, "-pass") == 0) { - if (--argc < 1) - goto bad; - passarg = *(++argv); - } else if (strcmp(*argv, "-cert_chain") == 0) { - if (--argc < 1) - goto bad; - chain_file = *(++argv); - } else if (strcmp(*argv, "-key") == 0) { - if (--argc < 1) - goto bad; - key_file = *(++argv); - } else if (strcmp(*argv, "-reconnect") == 0) { + break; + case OPT_KEYFORM: + if (!opt_format(opt_arg(), OPT_FMT_PEMDER, &key_format)) + goto opthelp; + break; + case OPT_PASS: + passarg = opt_arg(); + break; + case OPT_CERT_CHAIN: + chain_file = opt_arg(); + break; + case OPT_KEY: + key_file = opt_arg(); + break; + case OPT_RECONNECT: reconnect = 5; - } else if (strcmp(*argv, "-CApath") == 0) { - if (--argc < 1) - goto bad; - CApath = *(++argv); - } else if (strcmp(*argv, "-chainCApath") == 0) { - if (--argc < 1) - goto bad; - chCApath = *(++argv); - } else if (strcmp(*argv, "-verifyCApath") == 0) { - if (--argc < 1) - goto bad; - vfyCApath = *(++argv); - } else if (strcmp(*argv, "-build_chain") == 0) + break; + case OPT_CAPATH: + CApath = opt_arg(); + break; + case OPT_NOCAPATH: + noCApath = 1; + break; + case OPT_CHAINCAPATH: + chCApath = opt_arg(); + break; + case OPT_VERIFYCAPATH: + vfyCApath = opt_arg(); + break; + case OPT_BUILD_CHAIN: build_chain = 1; - else if (strcmp(*argv, "-CAfile") == 0) { - if (--argc < 1) - goto bad; - CAfile = *(++argv); - } else if (strcmp(*argv, "-chainCAfile") == 0) { - if (--argc < 1) - goto bad; - chCAfile = *(++argv); - } else if (strcmp(*argv, "-verifyCAfile") == 0) { - if (--argc < 1) - goto bad; - vfyCAfile = *(++argv); - } -#ifndef OPENSSL_NO_TLSEXT -# ifndef OPENSSL_NO_NEXTPROTONEG - else if (strcmp(*argv, "-nextprotoneg") == 0) { - if (--argc < 1) - goto bad; - next_proto_neg_in = *(++argv); - } -# endif - 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++; + break; + case OPT_CAFILE: + CAfile = opt_arg(); + break; + case OPT_NOCAFILE: + noCAfile = 1; + break; + case OPT_CHAINCAFILE: + chCAfile = opt_arg(); + break; + case OPT_VERIFYCAFILE: + vfyCAfile = opt_arg(); + break; + case OPT_NEXTPROTONEG: + next_proto_neg_in = opt_arg(); + break; + case OPT_ALPN: + alpn_in = opt_arg(); + break; + case OPT_SERVERINFO: + p = opt_arg(); + len = strlen(p); + for (start = 0, i = 0; i <= len; ++i) { + if (i == len || p[i] == ',') { + serverinfo_types[serverinfo_count] = atoi(p + start); + if (++serverinfo_count == MAX_SI_TYPES) + break; start = i + 1; } - if (serverinfo_types_count == MAX_SI_TYPES) - break; } - } -#endif -#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; - else if (strcmp(*argv, "pop3") == 0) - starttls_proto = PROTO_POP3; - else if (strcmp(*argv, "imap") == 0) - starttls_proto = PROTO_IMAP; - else if (strcmp(*argv, "ftp") == 0) - starttls_proto = PROTO_FTP; - else if (strcmp(*argv, "xmpp") == 0) - starttls_proto = PROTO_XMPP; - else - goto bad; - } -#ifndef OPENSSL_NO_ENGINE - 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); - } -#endif - 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 + break; + case OPT_STARTTLS: + if (!opt_pair(opt_arg(), services, &starttls_proto)) + goto end; + case OPT_SERVERNAME: + servername = opt_arg(); + break; + case OPT_JPAKE: #ifndef OPENSSL_NO_JPAKE - else if (strcmp(*argv, "-jpake") == 0) { - if (--argc < 1) - goto bad; - jpake_secret = *++argv; - } -#endif -#ifndef OPENSSL_NO_SRTP - else if (strcmp(*argv, "-use_srtp") == 0) { - if (--argc < 1) - goto bad; - srtp_profiles = *(++argv); - } + jpake_secret = opt_arg(); #endif - 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; - } else { - BIO_printf(bio_err, "unknown option %s\n", *argv); - badop = 1; + break; + case OPT_USE_SRTP: + srtp_profiles = opt_arg(); + break; + case OPT_KEYMATEXPORT: + keymatexportlabel = opt_arg(); + break; + case OPT_KEYMATEXPORTLEN: + keymatexportlen = atoi(opt_arg()); + break; + case OPT_ASYNC: + async = 1; break; } - argc--; - argv++; } - if (badop) { - bad: - sc_usage(); - goto end; + argc = opt_num_rest(); + argv = opt_rest(); + + if (proxystr) { + if (connectstr == NULL) { + BIO_printf(bio_err, "%s: -proxy requires use of -connect\n", prog); + goto opthelp; + } + if (!extract_host_port(proxystr, &host, NULL, &port)) + goto end; } + else if (connectstr != NULL + && !extract_host_port(connectstr, &host, NULL, &port)) + goto end; if (unix_path && (socket_type != SOCK_STREAM)) { BIO_printf(bio_err, @@ -1142,10 +1100,7 @@ int MAIN(int argc, char **argv) } #endif - OpenSSL_add_ssl_algorithms(); - SSL_load_error_strings(); - -#if !defined(OPENSSL_NO_TLSEXT) && !defined(OPENSSL_NO_NEXTPROTONEG) +#if !defined(OPENSSL_NO_NEXTPROTONEG) next_proto.status = -1; if (next_proto_neg_in) { next_proto.data = @@ -1158,17 +1113,7 @@ int MAIN(int argc, char **argv) next_proto.data = NULL; #endif -#ifndef OPENSSL_NO_ENGINE - e = setup_engine(bio_err, engine_id, 1); - 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; - } - } -#endif - if (!app_passwd(bio_err, passarg, NULL, &pass, NULL)) { + if (!app_passwd(passarg, NULL, &pass, NULL)) { BIO_printf(bio_err, "Error getting password\n"); goto end; } @@ -1177,28 +1122,25 @@ int MAIN(int argc, char **argv) key_file = cert_file; if (key_file) { - - key = load_key(bio_err, key_file, key_format, 0, pass, e, + key = load_key(key_file, key_format, 0, pass, e, "client certificate private key file"); - if (!key) { + if (key == NULL) { ERR_print_errors(bio_err); goto end; } - } if (cert_file) { - cert = load_cert(bio_err, cert_file, cert_format, + cert = load_cert(cert_file, cert_format, NULL, e, "client certificate file"); - - if (!cert) { + if (cert == NULL) { ERR_print_errors(bio_err); goto end; } } if (chain_file) { - chain = load_certs(bio_err, chain_file, FORMAT_PEM, + chain = load_certs(chain_file, FORMAT_PEM, NULL, e, "client certificate chain"); if (!chain) goto end; @@ -1207,13 +1149,13 @@ int MAIN(int argc, char **argv) if (crl_file) { X509_CRL *crl; crl = load_crl(crl_file, crl_format); - if (!crl) { + if (crl == NULL) { 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)) { + if (crls == NULL || !sk_X509_CRL_push(crls, crl)) { BIO_puts(bio_err, "Error adding CRL\n"); ERR_print_errors(bio_err); X509_CRL_free(crl); @@ -1221,30 +1163,29 @@ int MAIN(int argc, char **argv) } } - if (!load_excert(&exc, bio_err)) + if (!load_excert(&exc)) goto end; - if (!app_RAND_load_file(NULL, bio_err, 1) && inrand == NULL + if (!app_RAND_load_file(NULL, 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 (inrand != NULL) { + randamt = app_RAND_load_files(inrand); + BIO_printf(bio_err, "%ld semi-random bytes loaded\n", randamt); + } if (bio_c_out == NULL) { 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); - } + bio_c_msg = dup_bio_out(FORMAT_TEXT); + } else if (bio_c_out == NULL) + bio_c_out = dup_bio_out(FORMAT_TEXT); } #ifndef OPENSSL_NO_SRP - if (!app_passwd(bio_err, srppass, NULL, &srp_arg.srppassin, NULL)) { + if (!app_passwd(srppass, NULL, &srp_arg.srppassin, NULL)) { BIO_printf(bio_err, "Error getting password\n"); goto end; } @@ -1257,19 +1198,22 @@ int MAIN(int argc, char **argv) } if (sdebug) - ssl_ctx_security_debug(ctx, bio_err, sdebug); + ssl_ctx_security_debug(ctx, sdebug); - if (vpm && !SSL_CTX_set1_param(ctx, vpm)) { + if (vpmtouched && !SSL_CTX_set1_param(ctx, vpm)) { BIO_printf(bio_err, "Error setting verify params\n"); ERR_print_errors(bio_err); goto end; } - if (!args_ssl_call(ctx, bio_err, cctx, ssl_args, 1, no_jpake)) { - ERR_print_errors(bio_err); - goto end; + if (async) { + SSL_CTX_set_mode(ctx, SSL_MODE_ASYNC); + ASYNC_init(1, 0, 0); } + if (!config_ctx(cctx, ssl_args, ctx, 1, jpake_secret == NULL)) + goto end; + if (!ssl_load_stores(ctx, vfyCApath, vfyCAfile, chCApath, chCAfile, crls, crl_download)) { BIO_printf(bio_err, "Error loading store locations\n"); @@ -1289,12 +1233,7 @@ int MAIN(int argc, char **argv) #endif #ifndef OPENSSL_NO_PSK -# ifdef OPENSSL_NO_JPAKE - if (psk_key != NULL) -# else - if (psk_key != NULL || jpake_secret) -# endif - { + if (psk_key != NULL || jpake_secret) { if (c_debug) BIO_printf(bio_c_out, "PSK key given or JPAKE in use, setting client callback\n"); @@ -1303,22 +1242,22 @@ int MAIN(int argc, char **argv) #endif #ifndef OPENSSL_NO_SRTP if (srtp_profiles != NULL) { - /* Returns 0 on success!! */ - if(SSL_CTX_set_tlsext_use_srtp(ctx, srtp_profiles)) { + /* Returns 0 on success! */ + if (SSL_CTX_set_tlsext_use_srtp(ctx, srtp_profiles) != 0) { BIO_printf(bio_err, "Error setting SRTP profile\n"); ERR_print_errors(bio_err); goto end; } } #endif + if (exc) ssl_ctx_set_excert(ctx, exc); -#if !defined(OPENSSL_NO_TLSEXT) -# if !defined(OPENSSL_NO_NEXTPROTONEG) +#if !defined(OPENSSL_NO_NEXTPROTONEG) if (next_proto.data) SSL_CTX_set_next_proto_select_cb(ctx, next_proto_cb, &next_proto); -# endif +#endif if (alpn_in) { unsigned short alpn_len; unsigned char *alpn = next_protos_parse(&alpn_len, alpn_in); @@ -1327,37 +1266,33 @@ int MAIN(int argc, char **argv) BIO_printf(bio_err, "Error parsing -alpn argument\n"); goto end; } - /* Returns 0 on success!! */ - if(SSL_CTX_set_alpn_protos(ctx, alpn, alpn_len)) { - BIO_printf(bio_err, "Error setting ALPN\n"); + /* Returns 0 on success! */ + if (SSL_CTX_set_alpn_protos(ctx, alpn, alpn_len) != 0) { + BIO_printf(bio_err, "Error setting ALPN\n"); goto end; } OPENSSL_free(alpn); } -#endif -#ifndef OPENSSL_NO_TLSEXT - for (i = 0; i < serverinfo_types_count; i++) { - if(!SSL_CTX_add_client_custom_ext(ctx, - serverinfo_types[i], - NULL, NULL, NULL, - serverinfo_cli_parse_cb, NULL)) { - BIO_printf(bio_err, "Warning: Unable to add custom extension %u. " - "Skipping\n", serverinfo_types[i]); + + for (i = 0; i < serverinfo_count; i++) { + if (!SSL_CTX_add_client_custom_ext(ctx, + serverinfo_types[i], + NULL, NULL, NULL, + serverinfo_cli_parse_cb, NULL)) { + BIO_printf(bio_err, + "Warning: Unable to add custom extension %u, skipping\n", + serverinfo_types[i]); } } -#endif if (state) SSL_CTX_set_info_callback(ctx, apps_ssl_info_callback); SSL_CTX_set_verify(ctx, verify, verify_callback); - if ((CAfile || CApath) - && !SSL_CTX_load_verify_locations(ctx, CAfile, CApath)) { - ERR_print_errors(bio_err); - } - if (!SSL_CTX_set_default_verify_paths(ctx)) { + if (!ctx_set_verify_locations(ctx, CAfile, CApath, noCAfile, noCApath)) { ERR_print_errors(bio_err); + goto end; } ssl_ctx_add_crls(ctx, crls, crl_download); @@ -1365,7 +1300,6 @@ int MAIN(int argc, char **argv) if (!set_cert_key_stuff(ctx, cert, key, chain, build_chain)) goto end; -#ifndef OPENSSL_NO_TLSEXT if (servername != NULL) { tlsextcbp.biodebug = bio_err; SSL_CTX_set_tlsext_servername_callback(ctx, ssl_servername_cb); @@ -1387,7 +1321,6 @@ int MAIN(int argc, char **argv) ssl_srp_verify_param_cb); } # endif -#endif con = SSL_new(ctx); if (sess_in) { @@ -1405,7 +1338,7 @@ int MAIN(int argc, char **argv) ERR_print_errors(bio_err); goto end; } - if(!SSL_set_session(con, sess)) { + if (!SSL_set_session(con, sess)) { BIO_printf(bio_err, "Can't set session\n"); ERR_print_errors(bio_err); goto end; @@ -1416,7 +1349,6 @@ int MAIN(int argc, char **argv) if (fallback_scsv) SSL_set_mode(con, SSL_MODE_SEND_FALLBACK_SCSV); -#ifndef OPENSSL_NO_TLSEXT if (servername != NULL) { if (!SSL_set_tlsext_host_name(con, servername)) { BIO_printf(bio_err, "Unable to set TLS servername extension.\n"); @@ -1424,13 +1356,6 @@ int MAIN(int argc, char **argv) goto end; } } -#endif -#ifndef OPENSSL_NO_KRB5 - if (con && (kctx = kssl_ctx_new()) != NULL) { - SSL_set0_kssl_ctx(con, kctx); - kssl_ctx_setstring(kctx, KSSL_SERVER, host); - } -#endif /* OPENSSL_NO_KRB5 */ re_start: #ifdef NO_SYS_UN_H @@ -1469,7 +1394,7 @@ int MAIN(int argc, char **argv) goto end; } - (void)BIO_ctrl_set_connected(sbio, 1, &peer); + (void)BIO_ctrl_set_connected(sbio, &peer); if (enable_timeouts) { timeout.tv_sec = 0; @@ -1521,7 +1446,7 @@ int MAIN(int argc, char **argv) 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); @@ -1531,7 +1456,6 @@ int MAIN(int argc, char **argv) SSL_CTX_set_tlsext_status_cb(ctx, ocsp_resp_cb); SSL_CTX_set_tlsext_status_arg(ctx, bio_c_out); } -#endif #ifndef OPENSSL_NO_JPAKE if (jpake_secret) jpake_client_auth(bio_c_out, sbio, jpake_secret); @@ -1554,111 +1478,248 @@ int MAIN(int argc, char **argv) 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) { - int foundit = 0; - 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); + switch ((PROTOCOL_CHOICE) starttls_proto) { + case PROTO_OFF: + break; + case PROTO_SMTP: + { + /* + * 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. + */ + int foundit = 0; + 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] == '-'); + BIO_printf(fbio, "EHLO %s\r\n", ehlo); + (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] == '-'); + (void)BIO_flush(fbio); + BIO_pop(fbio); + BIO_free(fbio); + if (!foundit) + BIO_printf(bio_err, + "didn't find starttls in server response," + " trying anyway...\n"); + BIO_printf(sbio, "STARTTLS\r\n"); + BIO_read(sbio, sbuf, BUFSIZZ); } - while (mbuf_len > 3 && mbuf[3] == '-'); - /* STARTTLS command requires EHLO... */ - BIO_printf(fbio, "EHLO openssl.client.net\r\n"); - (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; + break; + case PROTO_POP3: + { + BIO_read(sbio, mbuf, BUFSIZZ); + BIO_printf(sbio, "STLS\r\n"); + mbuf_len = BIO_read(sbio, sbuf, BUFSIZZ); + if (mbuf_len < 0) { + BIO_printf(bio_err, "BIO_read failed\n"); + goto end; + } } - while (mbuf_len > 3 && mbuf[3] == '-'); - (void)BIO_flush(fbio); - BIO_pop(fbio); - BIO_free(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) { - int foundit = 0; - 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"); - (void)BIO_flush(fbio); - /* wait for multi-line CAPABILITY response */ - do { - mbuf_len = BIO_gets(fbio, mbuf, BUFSIZZ); - if (strstr(mbuf, "STARTTLS")) - foundit = 1; + break; + case PROTO_IMAP: + { + int foundit = 0; + 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"); + (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] != '.'); + (void)BIO_flush(fbio); + BIO_pop(fbio); + BIO_free(fbio); + if (!foundit) + BIO_printf(bio_err, + "didn't find STARTTLS in server response," + " trying anyway...\n"); + BIO_printf(sbio, ". STARTTLS\r\n"); + BIO_read(sbio, sbuf, BUFSIZZ); } - while (mbuf_len > 3 && mbuf[0] != '.'); - (void)BIO_flush(fbio); - BIO_pop(fbio); - BIO_free(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); + break; + case 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] == '-'); + (void)BIO_flush(fbio); + BIO_pop(fbio); + BIO_free(fbio); + BIO_printf(sbio, "AUTH TLS\r\n"); + BIO_read(sbio, sbuf, BUFSIZZ); } - while (mbuf_len > 3 && mbuf[3] == '-'); - (void)BIO_flush(fbio); - BIO_pop(fbio); - BIO_free(fbio); - BIO_printf(sbio, "AUTH TLS\r\n"); - BIO_read(sbio, sbuf, BUFSIZZ); - } - if (starttls_proto == PROTO_XMPP) { - int seen = 0; - BIO_printf(sbio, "", xmpphost ? - xmpphost : host); - seen = BIO_read(sbio, mbuf, BUFSIZZ); - mbuf[seen] = 0; - while (!strstr - (mbuf, "", + starttls_proto == PROTO_XMPP ? "client" : "server", + xmpphost ? xmpphost : host); seen = BIO_read(sbio, mbuf, BUFSIZZ); + mbuf[seen] = 0; + while (!strstr + (mbuf, ""); + seen = BIO_read(sbio, sbuf, BUFSIZZ); + sbuf[seen] = 0; + if (!strstr(sbuf, " 3 && foundit == 0); + (void)BIO_flush(fbio); + BIO_pop(fbio); + BIO_free(fbio); + if (!foundit) { + BIO_printf(bio_err, "%s: HTTP CONNECT failed\n", prog); + goto shut; + } + } + break; + case PROTO_IRC: + { + int numeric; + BIO *fbio = BIO_new(BIO_f_buffer()); - mbuf[seen] = 0; + BIO_push(fbio, sbio); + BIO_printf(fbio, "STARTTLS\r\n"); + (void)BIO_flush(fbio); + width = SSL_get_fd(con) + 1; + + do { + numeric = 0; + + FD_ZERO(&readfds); + openssl_fdset(SSL_get_fd(con), &readfds); + timeout.tv_sec = S_CLIENT_IRC_READ_TIMEOUT; + timeout.tv_usec = 0; + /* + * If the IRCd doesn't respond within + * S_CLIENT_IRC_READ_TIMEOUT seconds, assume + * it doesn't support STARTTLS. Many IRCds + * will not give _any_ sort of response to a + * STARTTLS command when it's not supported. + */ + if (!BIO_get_buffer_num_lines(fbio) + && !BIO_pending(fbio) + && !BIO_pending(sbio) + && select(width, (void *)&readfds, NULL, NULL, + &timeout) < 1) { + BIO_printf(bio_err, + "Timeout waiting for response (%d seconds).\n", + S_CLIENT_IRC_READ_TIMEOUT); + break; + } + + mbuf_len = BIO_gets(fbio, mbuf, BUFSIZZ); + if (mbuf_len < 1 || sscanf(mbuf, "%*s %d", &numeric) != 1) + break; + /* :example.net 451 STARTTLS :You have not registered */ + /* :example.net 421 STARTTLS :Unknown command */ + if ((numeric == 451 || numeric == 421) + && strstr(mbuf, "STARTTLS") != NULL) { + BIO_printf(bio_err, "STARTTLS not supported: %s", mbuf); + break; + } + if (numeric == 691) { + BIO_printf(bio_err, "STARTTLS negotiation failed: "); + ERR_print_errors(bio_err); + break; + } + } while (numeric != 670); + + (void)BIO_flush(fbio); + BIO_pop(fbio); + BIO_free(fbio); + if (numeric != 670) { + BIO_printf(bio_err, "Server does not support STARTTLS.\n"); + ret = 1; + goto shut; + } } - BIO_printf(sbio, - ""); - seen = BIO_read(sbio, sbuf, BUFSIZZ); - sbuf[seen] = 0; - if (!strstr(sbuf, "