X-Git-Url: https://git.openssl.org/gitweb/?p=openssl.git;a=blobdiff_plain;f=apps%2Fs_client.c;h=a1ef64b13fe4da4f72472dfb7a8cad695c27259d;hp=c122c1a613f3fb9733eb6eb3f90cc3a2a411a258;hb=e2d5183d7cd5479d7c63ba524b3ddc4abd707dba;hpb=7b9f8f7f03eda2faa1cdd42ed29a0b70e60eaf59 diff --git a/apps/s_client.c b/apps/s_client.c index c122c1a613..a1ef64b13f 100644 --- a/apps/s_client.c +++ b/apps/s_client.c @@ -165,12 +165,16 @@ typedef unsigned int u_int; #ifndef OPENSSL_NO_SRP # include #endif +#ifndef OPENSSL_NO_CT +# include +#endif #include "s_apps.h" #include "timeouts.h" -#if (defined(OPENSSL_SYS_VMS) && __VMS_VER < 70000000) -/* FIONBIO used as a switch to enable ioctl, and that isn't in VMS < 7.0 */ -# undef FIONBIO +#if defined(__has_feature) +# if __has_feature(memory_sanitizer) +# include +# endif #endif #undef BUFSIZZ @@ -184,6 +188,8 @@ extern int verify_quiet; static char *prog; static int async = 0; +static unsigned int split_send_fragment = 0; +static unsigned int max_pipelines = 0; static int c_nbio = 0; static int c_tlsextdebug = 0; static int c_status_req = 0; @@ -509,9 +515,9 @@ static ossl_ssize_t hexdecode(const char **inptr, void *result) for (byte = 0; *in; ++in) { char c; - if (isspace(*in)) + if (isspace(_UC(*in))) continue; - c = tolower(*in); + c = tolower(_UC(*in)); if ('0' <= c && c <= '9') { byte |= c - '0'; } else if ('a' <= c && c <= 'f') { @@ -553,11 +559,11 @@ static ossl_ssize_t checked_uint8(const char **inptr, void *out) e = restore_errno(); if (((v == LONG_MIN || v == LONG_MAX) && e == ERANGE) || - endp == in || !isspace(*endp) || + endp == in || !isspace(_UC(*endp)) || v != (*result = (uint8_t) v)) { return -1; } - for (in = endp; isspace(*in); ++in) + for (in = endp; isspace(_UC(*in)); ++in) continue; *inptr = in; @@ -648,13 +654,16 @@ typedef enum OPTION_choice { 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_SERVERINFO, OPT_STARTTLS, OPT_SERVERNAME, OPT_USE_SRTP, OPT_KEYMATEXPORT, OPT_KEYMATEXPORTLEN, OPT_SMTPHOST, - OPT_ASYNC, + OPT_ASYNC, OPT_SPLIT_SEND_FRAG, OPT_MAX_PIPELINES, OPT_READ_BUF, OPT_V_ENUM, OPT_X_ENUM, OPT_S_ENUM, OPT_FALLBACKSCSV, OPT_NOCMDS, OPT_PROXY, OPT_DANE_TLSA_DOMAIN, +#ifndef OPENSSL_NO_CT + OPT_NOCT, OPT_REQUESTCT, OPT_REQUIRECT, OPT_CTLOG_FILE, +#endif OPT_DANE_TLSA_RRDATA } OPTION_CHOICE; @@ -692,7 +701,8 @@ OPTIONS s_client_options[] = { {"showcerts", OPT_SHOWCERTS, '-', "Show all certificates in the chain"}, {"debug", OPT_DEBUG, '-', "Extra output"}, {"msg", OPT_MSG, '-', "Show protocol messages"}, - {"msgfile", OPT_MSGFILE, '>'}, + {"msgfile", OPT_MSGFILE, '>', + "File to send output of -msg or -trace, instead of stdout"}, {"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"}, @@ -715,21 +725,31 @@ OPTIONS s_client_options[] = { "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, '<'}, + {"CRL", OPT_CRL, '<', "CRL file to use"}, + {"crl_download", OPT_CRL_DOWNLOAD, '-', "Download CRL from distribution points"}, + {"CRLform", OPT_CRLFORM, 'F', "CRL format (PEM or DER) PEM is default"}, + {"verify_return_error", OPT_VERIFY_RET_ERROR, '-', + "Close connection on verification error"}, + {"verify_quiet", OPT_VERIFY_QUIET, '-', "Restrict verify output to errors"}, + {"brief", OPT_BRIEF, '-', + "Restrict output to brief summary of connection parameters"}, + {"prexit", OPT_PREXIT, '-', + "Print session information when the program exits"}, + {"security_debug", OPT_SECURITY_DEBUG, '-', + "Enable security debug messages"}, + {"security_debug_verbose", OPT_SECURITY_DEBUG_VERBOSE, '-', + "Output more security debug output"}, + {"cert_chain", OPT_CERT_CHAIN, '<', + "Certificate chain file (in PEM format)"}, + {"chainCApath", OPT_CHAINCAPATH, '/', + "Use dir as certificate store path to build CA certificate chain"}, + {"verifyCApath", OPT_VERIFYCAPATH, '/', + "Use dir as certificate store path to verify CA certificate"}, + {"build_chain", OPT_BUILD_CHAIN, '-', "Build certificate chain"}, + {"chainCAfile", OPT_CHAINCAFILE, '<', + "CA file for certificate chain (PEM format)"}, + {"verifyCAfile", OPT_VERIFYCAFILE, '<', + "CA file for certificate verification (PEM format)"}, {"nocommands", OPT_NOCMDS, '-', "Do not use interactive command letters"}, {"servername", OPT_SERVERNAME, 's', "Set TLS extension servername in ClientHello"}, @@ -741,7 +761,13 @@ OPTIONS s_client_options[] = { {"alpn", OPT_ALPN, 's', "Enable ALPN extension, considering named protocols supported (comma-separated list)"}, {"async", OPT_ASYNC, '-', "Support asynchronous operation"}, - {"ssl_config", OPT_SSL_CONFIG, 's'}, + {"ssl_config", OPT_SSL_CONFIG, 's', "Use specified configuration file"}, + {"split_send_frag", OPT_SPLIT_SEND_FRAG, 'n', + "Size used to split data for encrypt pipelines"}, + {"max_pipelines", OPT_MAX_PIPELINES, 'n', + "Maximum number of encrypt/decrypt pipelines to be used"}, + {"read_buf", OPT_READ_BUF, 'n', + "Default read buffer size to be used for connections"}, OPT_S_OPTIONS, OPT_V_OPTIONS, OPT_X_OPTIONS, @@ -758,31 +784,27 @@ OPTIONS s_client_options[] = { {"tls1_2", OPT_TLS1_2, '-', "Just use TLSv1.2"}, #endif #ifndef OPENSSL_NO_DTLS - {"dtls", OPT_DTLS, '-'}, - {"timeout", OPT_TIMEOUT, '-'}, + {"dtls", OPT_DTLS, '-', "Use any version of DTLS"}, + {"timeout", OPT_TIMEOUT, '-', + "Enable send/receive timeout on DTLS connections"}, {"mtu", OPT_MTU, 'p', "Set the link layer MTU"}, #endif #ifndef OPENSSL_NO_DTLS1 {"dtls1", OPT_DTLS1, '-', "Just use DTLSv1"}, #endif #ifndef OPENSSL_NO_DTLS1_2 - {"dtls1_2", OPT_DTLS1_2, '-'}, + {"dtls1_2", OPT_DTLS1_2, '-', "Just use DTLSv1.2"}, #endif #ifndef OPENSSL_NO_SSL_TRACE - {"trace", OPT_TRACE, '-'}, + {"trace", OPT_TRACE, '-', "Show trace output of protocol messages"}, #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'"}, @@ -799,7 +821,14 @@ OPTIONS s_client_options[] = { #endif #ifndef OPENSSL_NO_ENGINE {"engine", OPT_ENGINE, 's', "Use engine, possibly a hardware device"}, - {"ssl_client_engine", OPT_SSL_CLIENT_ENGINE, 's'}, + {"ssl_client_engine", OPT_SSL_CLIENT_ENGINE, 's', + "Specify engine to be used for client certificate operations"}, +#endif +#ifndef OPENSSL_NO_CT + {"noct", OPT_NOCT, '-', "Do not request or parse SCTs (default)"}, + {"requestct", OPT_REQUESTCT, '-', "Request SCTs (enables OCSP stapling)"}, + {"requirect", OPT_REQUIRECT, '-', "Require at least 1 SCT (enables OCSP stapling)"}, + {"ctlogfile", OPT_CTLOG_FILE, '<', "CT log list CONF file"}, #endif {NULL} }; @@ -853,7 +882,7 @@ int s_client_main(int argc, char **argv) char *inrand = NULL; 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; + char *xmpphost = NULL; const char *ehlo = "mail.example.com"; struct sockaddr peer; struct timeval timeout, *timeoutp; @@ -869,6 +898,7 @@ int s_client_main(int argc, char **argv) int socket_family = AF_UNSPEC, socket_type = SOCK_STREAM; 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 read_buf_len = 0; int fallback_scsv = 0; long socket_mtu = 0, randamt = 0; OPTION_CHOICE o; @@ -893,6 +923,20 @@ int s_client_main(int argc, char **argv) char *srppass = NULL; int srp_lateuser = 0; SRP_ARG srp_arg = { NULL, NULL, 0, 0, 0, 1024 }; +#endif +#ifndef OPENSSL_NO_CT + char *ctlog_file = NULL; + ct_validation_cb ct_validation = NULL; +#endif + + FD_ZERO(&readfds); + FD_ZERO(&writefds); +/* Known false-positive of MemorySanitizer. */ +#if defined(__has_feature) +# if __has_feature(memory_sanitizer) + __msan_unpoison(&readfds, sizeof(readfds)); + __msan_unpoison(&writefds, sizeof(writefds)); +# endif #endif prog = opt_progname(argv[0]); @@ -1141,7 +1185,7 @@ int s_client_main(int argc, char **argv) break; case OPT_PSK: for (p = psk_key = opt_arg(); *p; p++) { - if (isxdigit(*p)) + if (isxdigit(_UC(*p))) continue; BIO_printf(bio_err, "Not a hex number '%s'\n", psk_key); goto end; @@ -1274,6 +1318,20 @@ int s_client_main(int argc, char **argv) case OPT_NOCAFILE: noCAfile = 1; break; +#ifndef OPENSSL_NO_CT + case OPT_NOCT: + ct_validation = NULL; + break; + case OPT_REQUESTCT: + ct_validation = CT_verify_no_bad_scts; + break; + case OPT_REQUIRECT: + ct_validation = CT_verify_at_least_one_good_sct; + break; + case OPT_CTLOG_FILE: + ctlog_file = opt_arg(); + break; +#endif case OPT_CHAINCAFILE: chCAfile = opt_arg(); break; @@ -1316,11 +1374,6 @@ int s_client_main(int argc, char **argv) case OPT_SERVERNAME: servername = opt_arg(); break; - case OPT_JPAKE: -#ifndef OPENSSL_NO_JPAKE - jpake_secret = opt_arg(); -#endif - break; case OPT_USE_SRTP: srtp_profiles = opt_arg(); break; @@ -1333,10 +1386,27 @@ int s_client_main(int argc, char **argv) case OPT_ASYNC: async = 1; break; + case OPT_SPLIT_SEND_FRAG: + split_send_fragment = atoi(opt_arg()); + if (split_send_fragment == 0) { + /* + * Not allowed - set to a deliberately bad value so we get an + * error message below + */ + split_send_fragment = SSL3_RT_MAX_PLAIN_LENGTH + 1; + } + break; + case OPT_MAX_PIPELINES: + max_pipelines = atoi(opt_arg()); + break; + case OPT_READ_BUF: + read_buf_len = atoi(opt_arg()); + break; } } argc = opt_num_rest(); - argv = opt_rest(); + if (argc != 0) + goto opthelp; if (proxystr) { int res; @@ -1378,15 +1448,16 @@ int s_client_main(int argc, char **argv) "Can't use unix sockets and datagrams together\n"); goto end; } -#if !defined(OPENSSL_NO_JPAKE) && !defined(OPENSSL_NO_PSK) - if (jpake_secret) { - if (psk_key) { - BIO_printf(bio_err, "Can't use JPAKE and PSK together\n"); - goto end; - } - psk_identity = "JPAKE"; + + if (split_send_fragment > SSL3_RT_MAX_PLAIN_LENGTH) { + BIO_printf(bio_err, "Bad split send fragment size\n"); + goto end; + } + + if (max_pipelines > SSL_MAX_PIPELINES) { + BIO_printf(bio_err, "Bad max pipelines value\n"); + goto end; } -#endif #if !defined(OPENSSL_NO_NEXTPROTONEG) next_proto.status = -1; @@ -1419,8 +1490,7 @@ int s_client_main(int argc, char **argv) } if (cert_file) { - cert = load_cert(cert_file, cert_format, - NULL, e, "client certificate file"); + cert = load_cert(cert_file, cert_format, "client certificate file"); if (cert == NULL) { ERR_print_errors(bio_err); goto end; @@ -1428,7 +1498,7 @@ int s_client_main(int argc, char **argv) } if (chain_file) { - if (!load_certs(chain_file, &chain, FORMAT_PEM, NULL, e, + if (!load_certs(chain_file, &chain, FORMAT_PEM, NULL, "client certificate chain")) goto end; } @@ -1505,8 +1575,18 @@ int s_client_main(int argc, char **argv) if (async) { SSL_CTX_set_mode(ctx, SSL_MODE_ASYNC); } + if (split_send_fragment > 0) { + SSL_CTX_set_split_send_fragment(ctx, split_send_fragment); + } + if (max_pipelines > 0) { + SSL_CTX_set_max_pipelines(ctx, max_pipelines); + } + + if (read_buf_len > 0) { + SSL_CTX_set_default_read_buffer_len(ctx, read_buf_len); + } - if (!config_ctx(cctx, ssl_args, ctx, jpake_secret == NULL)) + if (!config_ctx(cctx, ssl_args, ctx)) goto end; if (!ssl_load_stores(ctx, vfyCApath, vfyCAfile, chCApath, chCAfile, @@ -1528,10 +1608,10 @@ int s_client_main(int argc, char **argv) #endif #ifndef OPENSSL_NO_PSK - if (psk_key != NULL || jpake_secret) { + if (psk_key != NULL) { if (c_debug) BIO_printf(bio_c_out, - "PSK key given or JPAKE in use, setting client callback\n"); + "PSK key given, setting client callback\n"); SSL_CTX_set_psk_client_callback(ctx, psk_client_cb); } #endif @@ -1583,6 +1663,18 @@ int s_client_main(int argc, char **argv) if (state) SSL_CTX_set_info_callback(ctx, apps_ssl_info_callback); +#ifndef OPENSSL_NO_CT + if (!SSL_CTX_set_ct_validation_callback(ctx, ct_validation, NULL)) { + ERR_print_errors(bio_err); + goto end; + } + + if (ctx_set_ctlog_list_file(ctx, ctlog_file) <= 0) { + ERR_print_errors(bio_err); + goto end; + } +#endif + SSL_CTX_set_verify(ctx, verify, verify_callback); if (!ctx_set_verify_locations(ctx, CAfile, CApath, noCAfile, noCApath)) { @@ -1688,28 +1780,25 @@ int s_client_main(int argc, char **argv) if (init_client(&s, host, port, socket_family, socket_type) == 0) { BIO_printf(bio_err, "connect:errno=%d\n", get_last_socket_error()); - SHUTDOWN(s); + BIO_closesocket(s); goto end; } BIO_printf(bio_c_out, "CONNECTED(%08X)\n", s); -#ifdef FIONBIO if (c_nbio) { - unsigned long l = 1; - BIO_printf(bio_c_out, "turning on non blocking io\n"); - if (BIO_socket_ioctl(s, FIONBIO, &l) < 0) { + if (!BIO_socket_nbio(s, 1)) { ERR_print_errors(bio_err); goto end; } + BIO_printf(bio_c_out, "Turned on non blocking io\n"); } -#endif if (socket_type == SOCK_DGRAM) { sbio = BIO_new_dgram(s, BIO_NOCLOSE); if (getsockname(s, &peer, (void *)&peerlen) < 0) { BIO_printf(bio_err, "getsockname:errno=%d\n", get_last_socket_error()); - SHUTDOWN(s); + BIO_closesocket(s); goto end; } @@ -1774,10 +1863,6 @@ int s_client_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); } -#ifndef OPENSSL_NO_JPAKE - if (jpake_secret) - jpake_client_auth(bio_c_out, sbio, jpake_secret); -#endif SSL_set_bio(con, sbio, sbio); SSL_set_connect_state(con); @@ -2095,13 +2180,13 @@ int s_client_main(int argc, char **argv) "drop connection and then reconnect\n"); do_ssl_shutdown(con); SSL_set_connect_state(con); - SHUTDOWN(SSL_get_fd(con)); + BIO_closesocket(SSL_get_fd(con)); goto re_start; } } } - ssl_pending = read_ssl && SSL_pending(con); + ssl_pending = read_ssl && SSL_has_pending(con); if (!ssl_pending) { #if !defined(OPENSSL_SYS_WINDOWS) && !defined(OPENSSL_SYS_MSDOS) && !defined(OPENSSL_SYS_NETWARE) @@ -2412,7 +2497,7 @@ int s_client_main(int argc, char **argv) if (in_init) print_stuff(bio_c_out, con, full_log); do_ssl_shutdown(con); - SHUTDOWN(SSL_get_fd(con)); + BIO_closesocket(SSL_get_fd(con)); end: if (con != NULL) { if (prexit != 0) @@ -2461,6 +2546,9 @@ static void print_stuff(BIO *bio, SSL *s, int full) const COMP_METHOD *comp, *expansion; #endif unsigned char *exportedkeymat; +#ifndef OPENSSL_NO_CT + const STACK_OF(SCT) *scts; +#endif if (full) { int got_a_chain = 0; @@ -2513,6 +2601,18 @@ static void print_stuff(BIO *bio, SSL *s, int full) ssl_print_sigalgs(bio, s); ssl_print_tmp_key(bio, s); +#ifndef OPENSSL_NO_CT + scts = SSL_get0_peer_scts(s); + BIO_printf(bio, "---\nSCTs present (%i)\n---\n", + scts ? sk_SCT_num(scts) : 0); + SCT_LIST_print(scts, bio, 0, "\n---\n"); + BIO_printf(bio, "\n"); + if (SSL_get_ct_validation_callback(s) == NULL) { + BIO_printf(bio, "---\nWarning: CT validation is disabled, so not all " + "SCTs may be displayed. Re-run with \"-requestct\".\n"); + } +#endif + BIO_printf(bio, "---\nSSL handshake has read %"PRIu64" bytes and written %"PRIu64" bytes\n", BIO_number_read(SSL_get_rbio(s)),