X-Git-Url: https://git.openssl.org/?p=openssl.git;a=blobdiff_plain;f=apps%2Fs_client.c;h=a319d217c1f25518e07cab266d4485257e70ad6d;hp=0a45636c15b72d164ec6e2b438b3c0851c7a7257;hb=ebc0168384e9bbc29c02b85adb01036609769761;hpb=c80149d9f09b3a5a5b1621fa705e900d455334d4 diff --git a/apps/s_client.c b/apps/s_client.c index 0a45636c15..a319d217c1 100644 --- a/apps/s_client.c +++ b/apps/s_client.c @@ -1,5 +1,5 @@ /* - * Copyright 1995-2017 The OpenSSL Project Authors. All Rights Reserved. + * Copyright 1995-2018 The OpenSSL Project Authors. All Rights Reserved. * Copyright 2005 Nokia. All rights reserved. * * Licensed under the OpenSSL license (the "License"). You may not use @@ -8,6 +8,7 @@ * https://www.openssl.org/source/license.html */ +#include "e_os.h" #include #include #include @@ -28,8 +29,8 @@ typedef unsigned int u_int; #endif -#define USE_SOCKETS #include "apps.h" +#include "progs.h" #include #include #include @@ -46,6 +47,7 @@ typedef unsigned int u_int; #endif #include "s_apps.h" #include "timeouts.h" +#include "internal/sockets.h" #if defined(__has_feature) # if __has_feature(memory_sanitizer) @@ -65,6 +67,7 @@ static int keymatexportlen = 20; static BIO *bio_c_out = NULL; static int c_quiet = 0; static char *sess_out = NULL; +static SSL_SESSION *psksess = NULL; static void print_stuff(BIO *berr, SSL *con, int full); #ifndef OPENSSL_NO_OCSP @@ -108,10 +111,10 @@ static void do_ssl_shutdown(SSL *ssl) } while (ret < 0); } -#ifndef OPENSSL_NO_PSK /* Default PSK identity and key */ static char *psk_identity = "Client_identity"; +#ifndef OPENSSL_NO_PSK static unsigned int psk_client_cb(SSL *ssl, const char *hint, char *identity, unsigned int max_identity_len, unsigned char *psk, @@ -171,6 +174,76 @@ static unsigned int psk_client_cb(SSL *ssl, const char *hint, char *identity, } #endif +const unsigned char tls13_aes128gcmsha256_id[] = { 0x13, 0x01 }; +const unsigned char tls13_aes256gcmsha384_id[] = { 0x13, 0x02 }; + +static int psk_use_session_cb(SSL *s, const EVP_MD *md, + const unsigned char **id, size_t *idlen, + SSL_SESSION **sess) +{ + SSL_SESSION *usesess = NULL; + const SSL_CIPHER *cipher = NULL; + + if (psksess != NULL) { + SSL_SESSION_up_ref(psksess); + usesess = psksess; + } else { + long key_len; + unsigned char *key = OPENSSL_hexstr2buf(psk_key, &key_len); + + if (key == NULL) { + BIO_printf(bio_err, "Could not convert PSK key '%s' to buffer\n", + psk_key); + return 0; + } + + if (key_len == EVP_MD_size(EVP_sha256())) + cipher = SSL_CIPHER_find(s, tls13_aes128gcmsha256_id); + else if (key_len == EVP_MD_size(EVP_sha384())) + cipher = SSL_CIPHER_find(s, tls13_aes256gcmsha384_id); + + if (cipher == NULL) { + /* Doesn't look like a suitable TLSv1.3 key. Ignore it */ + OPENSSL_free(key); + *id = NULL; + *idlen = 0; + *sess = NULL; + return 1; + } + usesess = SSL_SESSION_new(); + if (usesess == NULL + || !SSL_SESSION_set1_master_key(usesess, key, key_len) + || !SSL_SESSION_set_cipher(usesess, cipher) + || !SSL_SESSION_set_protocol_version(usesess, TLS1_3_VERSION)) { + OPENSSL_free(key); + goto err; + } + OPENSSL_free(key); + } + + cipher = SSL_SESSION_get0_cipher(usesess); + if (cipher == NULL) + goto err; + + if (md != NULL && SSL_CIPHER_get_handshake_digest(cipher) != md) { + /* PSK not usable, ignore it */ + *id = NULL; + *idlen = 0; + *sess = NULL; + SSL_SESSION_free(usesess); + } else { + *sess = usesess; + *id = (unsigned char *)psk_identity; + *idlen = strlen(psk_identity); + } + + return 1; + + err: + SSL_SESSION_free(usesess); + return 0; +} + /* This is a context that we pass to callbacks */ typedef struct tlsextctx_st { BIO *biodebug; @@ -345,10 +418,11 @@ static int serverinfo_cli_parse_cb(SSL *s, unsigned int ext_type, unsigned char ext_buf[4 + 65536]; /* Reconstruct the type/len fields prior to extension data */ - ext_buf[0] = ext_type >> 8; - ext_buf[1] = ext_type & 0xFF; - ext_buf[2] = inlen >> 8; - ext_buf[3] = inlen & 0xFF; + inlen &= 0xffff; /* for formal memcmpy correctness */ + ext_buf[0] = (unsigned char)(ext_type >> 8); + ext_buf[1] = (unsigned char)(ext_type); + ext_buf[2] = (unsigned char)(inlen >> 8); + ext_buf[3] = (unsigned char)(inlen); memcpy(ext_buf + 4, in, inlen); BIO_snprintf(pem_name, sizeof(pem_name), "SERVERINFO FOR EXTENSION %d", @@ -496,18 +570,16 @@ static int tlsa_import_rrset(SSL *con, STACK_OF(OPENSSL_STRING) *rrset) typedef enum OPTION_choice { OPT_ERR = -1, OPT_EOF = 0, OPT_HELP, - OPT_4, OPT_6, OPT_HOST, OPT_PORT, OPT_CONNECT, OPT_UNIX, + OPT_4, OPT_6, OPT_HOST, OPT_PORT, OPT_CONNECT, OPT_BIND, OPT_UNIX, OPT_XMPPHOST, OPT_VERIFY, OPT_NAMEOPT, 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_SSL_CLIENT_ENGINE, OPT_IGN_EOF, OPT_NO_IGN_EOF, 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, -#ifndef OPENSSL_NO_PSK - OPT_PSK_IDENTITY, OPT_PSK, -#endif + OPT_PSK_IDENTITY, OPT_PSK, OPT_PSK_SESS, #ifndef OPENSSL_NO_SRP OPT_SRPUSER, OPT_SRPPASS, OPT_SRP_STRENGTH, OPT_SRP_LATEUSER, OPT_SRP_MOREGROUPS, @@ -519,9 +591,9 @@ typedef enum OPTION_choice { 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_NOSERVERNAME, OPT_ASYNC, - OPT_USE_SRTP, OPT_KEYMATEXPORT, OPT_KEYMATEXPORTLEN, OPT_SMTPHOST, - OPT_MAX_SEND_FRAG, OPT_SPLIT_SEND_FRAG, OPT_MAX_PIPELINES, OPT_READ_BUF, - OPT_KEYLOG_FILE, OPT_EARLY_DATA, OPT_REQCAFILE, + OPT_USE_SRTP, OPT_KEYMATEXPORT, OPT_KEYMATEXPORTLEN, OPT_PROTOHOST, + OPT_MAXFRAGLEN, OPT_MAX_SEND_FRAG, OPT_SPLIT_SEND_FRAG, OPT_MAX_PIPELINES, + OPT_READ_BUF, OPT_KEYLOG_FILE, OPT_EARLY_DATA, OPT_REQCAFILE, OPT_V_ENUM, OPT_X_ENUM, OPT_S_ENUM, @@ -529,7 +601,9 @@ typedef enum OPTION_choice { #ifndef OPENSSL_NO_CT OPT_CT, OPT_NOCT, OPT_CTLOG_FILE, #endif - OPT_DANE_TLSA_RRDATA, OPT_DANE_EE_NO_NAME + OPT_DANE_TLSA_RRDATA, OPT_DANE_EE_NO_NAME, + OPT_FORCE_PHA, + OPT_R_ENUM } OPTION_CHOICE; const OPTIONS s_client_options[] = { @@ -538,6 +612,7 @@ const OPTIONS s_client_options[] = { {"port", OPT_PORT, 'p', "Use -connect instead"}, {"connect", OPT_CONNECT, 's', "TCP/IP where to connect (default is :" PORT ")"}, + {"bind", OPT_BIND, 's', "bind local address for connection"}, {"proxy", OPT_PROXY, 's', "Connect to via specified proxy to the real server"}, #ifdef AF_UNIX @@ -584,9 +659,8 @@ const OPTIONS s_client_options[] = { {"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"}, + "Alias of -name option for \"-starttls xmpp[-server]\""}, + OPT_R_OPTIONS, {"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', @@ -595,9 +669,11 @@ const OPTIONS s_client_options[] = { "Export keying material using label"}, {"keymatexportlen", OPT_KEYMATEXPORTLEN, 'p', "Export len bytes of keying material (default 20)"}, + {"maxfraglen", OPT_MAXFRAGLEN, 'p', + "Enable Maximum Fragment Length Negotiation (len values: 512, 1024, 2048 and 4096)"}, {"fallback_scsv", OPT_FALLBACKSCSV, '-', "Send the fallback SCSV"}, - {"name", OPT_SMTPHOST, 's', - "Hostname to use for \"-starttls lmtp\" or \"-starttls smtp\""}, + {"name", OPT_PROTOHOST, 's', + "Hostname to use for \"-starttls lmtp\", \"-starttls smtp\" or \"-starttls xmpp[-server]\""}, {"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"}, @@ -686,10 +762,9 @@ const OPTIONS s_client_options[] = { {"wdebug", OPT_WDEBUG, '-', "WATT-32 tcp debugging"}, #endif {"nbio", OPT_NBIO, '-', "Use non-blocking IO"}, -#ifndef OPENSSL_NO_PSK {"psk_identity", OPT_PSK_IDENTITY, 's', "PSK identity"}, {"psk", OPT_PSK, 's', "PSK in hex (without 0x)"}, -#endif + {"psk_session", OPT_PSK_SESS, '<', "File to read PSK SSL session from"}, #ifndef OPENSSL_NO_SRP {"srpuser", OPT_SRPUSER, 's', "SRP authentication for 'user'"}, {"srppass", OPT_SRPPASS, 's', "Password for 'user'"}, @@ -715,6 +790,7 @@ const OPTIONS s_client_options[] = { #endif {"keylogfile", OPT_KEYLOG_FILE, '>', "Write TLS secrets to file"}, {"early_data", OPT_EARLY_DATA, '<', "File to send as early data"}, + {"force_pha", OPT_FORCE_PHA, '-', "Force-enable post-handshake-authentication"}, {NULL, OPT_EOF, 0x00, NULL} }; @@ -809,16 +885,15 @@ int s_client_main(int argc, char **argv) const SSL_METHOD *meth = TLS_client_method(); const char *CApath = NULL, *CAfile = NULL; char *cbuf = NULL, *sbuf = NULL; - char *mbuf = NULL, *proxystr = NULL, *connectstr = NULL; + char *mbuf = NULL, *proxystr = NULL, *connectstr = NULL, *bindstr = NULL; char *cert_file = NULL, *key_file = NULL, *chain_file = NULL; char *chCApath = NULL, *chCAfile = NULL, *host = NULL; char *port = OPENSSL_strdup(PORT); - char *inrand = NULL; + char *bindhost = NULL, *bindport = NULL; char *passarg = NULL, *pass = NULL, *vfyCApath = NULL, *vfyCAfile = NULL; char *ReqCAfile = NULL; char *sess_in = NULL, *crl_file = NULL, *p; - char *xmpphost = NULL; - const char *ehlo = "mail.example.com"; + const char *protohost = NULL; struct timeval timeout, *timeoutp; fd_set readfds, writefds; int noCApath = 0, noCAfile = 0; @@ -837,7 +912,6 @@ int s_client_main(int argc, char **argv) #endif int read_buf_len = 0; int fallback_scsv = 0; - long randamt = 0; OPTION_CHOICE o; #ifndef OPENSSL_NO_DTLS int enable_timeouts = 0; @@ -850,7 +924,7 @@ int s_client_main(int argc, char **argv) #if defined(OPENSSL_SYS_WINDOWS) || defined(OPENSSL_SYS_MSDOS) struct timeval tv; #endif - char *servername = NULL; + const char *servername = NULL; int noservername = 0; const char *alpn_in = NULL; tlsextctx tlsextcbp = { NULL, 0 }; @@ -876,6 +950,7 @@ int s_client_main(int argc, char **argv) unsigned int split_send_fragment = 0, max_pipelines = 0; enum { use_inet, use_unix, use_unknown } connect_type = use_unknown; int count4or6 = 0; + uint8_t maxfraglen = 0; int c_nbio = 0, c_msg = 0, c_ign_eof = 0, c_brief = 0; int c_tlsextdebug = 0; #ifndef OPENSSL_NO_OCSP @@ -886,6 +961,8 @@ int s_client_main(int argc, char **argv) #ifndef OPENSSL_NO_DTLS int isdtls = 0; #endif + char *psksessf = NULL; + int force_pha = 0; FD_ZERO(&readfds); FD_ZERO(&writefds); @@ -978,6 +1055,9 @@ int s_client_main(int argc, char **argv) connect_type = use_inet; freeandcopy(&connectstr, opt_arg()); break; + case OPT_BIND: + freeandcopy(&bindstr, opt_arg()); + break; case OPT_PROXY: proxystr = opt_arg(); starttls_proto = PROTO_CONNECT; @@ -990,10 +1070,9 @@ int s_client_main(int argc, char **argv) break; #endif case OPT_XMPPHOST: - xmpphost = opt_arg(); - break; - case OPT_SMTPHOST: - ehlo = opt_arg(); + /* fall through, since this is an alias */ + case OPT_PROTOHOST: + protohost = opt_arg(); break; case OPT_VERIFY: verify = SSL_VERIFY_PEER; @@ -1083,8 +1162,9 @@ int s_client_main(int argc, char **argv) } #endif break; - case OPT_RAND: - inrand = opt_arg(); + case OPT_R_CASES: + if (!opt_rand(o)) + goto end; break; case OPT_IGN_EOF: c_ign_eof = 1; @@ -1134,7 +1214,6 @@ int s_client_main(int argc, char **argv) case OPT_STATE: state = 1; break; -#ifndef OPENSSL_NO_PSK case OPT_PSK_IDENTITY: psk_identity = opt_arg(); break; @@ -1146,7 +1225,9 @@ int s_client_main(int argc, char **argv) goto end; } break; -#endif + case OPT_PSK_SESS: + psksessf = opt_arg(); + break; #ifndef OPENSSL_NO_SRP case OPT_SRPUSER: srp_arg.srplogin = opt_arg(); @@ -1356,6 +1437,28 @@ int s_client_main(int argc, char **argv) case OPT_ASYNC: async = 1; break; + case OPT_MAXFRAGLEN: + len = atoi(opt_arg()); + switch (len) { + case 512: + maxfraglen = TLSEXT_max_fragment_length_512; + break; + case 1024: + maxfraglen = TLSEXT_max_fragment_length_1024; + break; + case 2048: + maxfraglen = TLSEXT_max_fragment_length_2048; + break; + case 4096: + maxfraglen = TLSEXT_max_fragment_length_4096; + break; + default: + BIO_printf(bio_err, + "%s: Max Fragment Len %u is out of permitted values", + prog, len); + goto opthelp; + } + break; case OPT_MAX_SEND_FRAG: max_send_fragment = atoi(opt_arg()); break; @@ -1374,6 +1477,9 @@ int s_client_main(int argc, char **argv) case OPT_EARLY_DATA: early_data_file = opt_arg(); break; + case OPT_FORCE_PHA: + force_pha = 1; + break; } } if (count4or6 >= 2) { @@ -1407,7 +1513,7 @@ int s_client_main(int argc, char **argv) goto opthelp; } connect_type = use_inet; - connectstr = *opt_rest(); + freeandcopy(&connectstr, *opt_rest()); } else if (argc != 0) { goto opthelp; } @@ -1453,11 +1559,25 @@ int s_client_main(int argc, char **argv) } } + if (bindstr != NULL) { + int res; + res = BIO_parse_hostserv(bindstr, &bindhost, &bindport, + BIO_PARSE_PRIO_HOST); + if (!res) { + BIO_printf(bio_err, + "%s: -bind argument parameter malformed or ambiguous\n", + prog); + goto end; + } + } + +#ifdef AF_UNIX if (socket_family == AF_UNIX && socket_type != SOCK_STREAM) { BIO_printf(bio_err, "Can't use unix sockets and datagrams together\n"); goto end; } +#endif #ifndef OPENSSL_NO_SCTP if (protocol == IPPROTO_SCTP) { @@ -1534,16 +1654,6 @@ int s_client_main(int argc, char **argv) if (!load_excert(&exc)) goto end; - 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) { - 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()); @@ -1617,6 +1727,14 @@ int s_client_main(int argc, char **argv) SSL_CTX_set_default_read_buffer_len(ctx, read_buf_len); } + if (maxfraglen > 0 + && !SSL_CTX_set_tlsext_max_fragment_length(ctx, maxfraglen)) { + BIO_printf(bio_err, + "%s: Max Fragment Length code %u is out of permitted values" + "\n", prog, maxfraglen); + goto end; + } + if (!config_ctx(cctx, ssl_args, ctx)) goto end; @@ -1656,6 +1774,25 @@ int s_client_main(int argc, char **argv) SSL_CTX_set_psk_client_callback(ctx, psk_client_cb); } #endif + if (psksessf != NULL) { + BIO *stmp = BIO_new_file(psksessf, "r"); + + if (stmp == NULL) { + BIO_printf(bio_err, "Can't open PSK session file %s\n", psksessf); + ERR_print_errors(bio_err); + goto end; + } + psksess = PEM_read_bio_SSL_SESSION(stmp, NULL, 0, NULL); + BIO_free(stmp); + if (psksess == NULL) { + BIO_printf(bio_err, "Can't read PSK session file %s\n", psksessf); + ERR_print_errors(bio_err); + goto end; + } + } + if (psk_key != NULL || psksess != NULL) + SSL_CTX_set_psk_use_session_callback(ctx, psk_use_session_cb); + #ifndef OPENSSL_NO_SRTP if (srtp_profiles != NULL) { /* Returns 0 on success! */ @@ -1787,6 +1924,12 @@ int s_client_main(int argc, char **argv) goto end; con = SSL_new(ctx); + if (con == NULL) + goto end; + + if (force_pha) + SSL_force_post_handshake_auth(con); + if (sess_in != NULL) { SSL_SESSION *sess; BIO *stmp = BIO_new_file(sess_in, "r"); @@ -1807,6 +1950,7 @@ int s_client_main(int argc, char **argv) ERR_print_errors(bio_err); goto end; } + SSL_SESSION_free(sess); } @@ -1849,8 +1993,8 @@ int s_client_main(int argc, char **argv) } re_start: - if (init_client(&s, host, port, socket_family, socket_type, protocol) - == 0) { + if (init_client(&s, host, port, bindhost, bindport, socket_family, + socket_type, protocol) == 0) { BIO_printf(bio_err, "connect:errno=%d\n", get_last_socket_error()); BIO_closesocket(s); goto end; @@ -1998,10 +2142,12 @@ int s_client_main(int argc, char **argv) do { mbuf_len = BIO_gets(fbio, mbuf, BUFSIZZ); } while (mbuf_len > 3 && mbuf[3] == '-'); + if (protohost == NULL) + protohost = "mail.example.com"; if (starttls_proto == (int)PROTO_LMTP) - BIO_printf(fbio, "LHLO %s\r\n", ehlo); + BIO_printf(fbio, "LHLO %s\r\n", protohost); else - BIO_printf(fbio, "EHLO %s\r\n", ehlo); + BIO_printf(fbio, "EHLO %s\r\n", protohost); (void)BIO_flush(fbio); /* * Wait for multi-line response to end LHLO LMTP or EHLO SMTP @@ -2087,7 +2233,7 @@ int s_client_main(int argc, char **argv) "xmlns:stream='http://etherx.jabber.org/streams' " "xmlns='jabber:%s' to='%s' version='1.0'>", starttls_proto == PROTO_XMPP ? "client" : "server", - xmpphost ? xmpphost : host); + protohost ? protohost : host); seen = BIO_read(sbio, mbuf, BUFSIZZ); if (seen < 0) { BIO_printf(bio_err, "BIO_read failed\n"); @@ -2317,10 +2463,9 @@ int s_client_main(int argc, char **argv) } else if (packet[pos++] == '\0') { break; } - pos++; } - /* make sure we have more 15 bytes left in the packet */ + /* make sure we have at least 15 bytes left in the packet */ if (pos + 15 > bytes) { BIO_printf(bio_err, "MySQL server handshake packet is broken.\n"); @@ -2520,8 +2665,10 @@ int s_client_main(int argc, char **argv) } if (early_data_file != NULL - && SSL_get0_session(con) != NULL - && SSL_SESSION_get_max_early_data(SSL_get0_session(con)) > 0) { + && ((SSL_get0_session(con) != NULL + && SSL_SESSION_get_max_early_data(SSL_get0_session(con)) > 0) + || (psksess != NULL + && SSL_SESSION_get_max_early_data(psksess) > 0))) { BIO *edfile = BIO_new_file(early_data_file, "r"); size_t readbytes, writtenbytes; int finish = 0; @@ -2545,6 +2692,7 @@ int s_client_main(int argc, char **argv) default: BIO_printf(bio_err, "Error writing early data\n"); BIO_free(edfile); + ERR_print_errors(bio_err); goto shut; } } @@ -2904,7 +3052,7 @@ int s_client_main(int argc, char **argv) if (in_init) print_stuff(bio_c_out, con, full_log); do_ssl_shutdown(con); -#if defined(OPENSSL_SYS_WINDOWS) + /* * Give the socket time to send its last data before we close it. * No amount of setting SO_LINGER etc on the socket seems to persuade @@ -2912,8 +3060,23 @@ int s_client_main(int argc, char **argv) * for a short time seems to do it (units in ms) * TODO: Find a better way to do this */ +#if defined(OPENSSL_SYS_WINDOWS) Sleep(50); +#elif defined(OPENSSL_SYS_CYGWIN) + usleep(50000); #endif + + /* + * If we ended with an alert being sent, but still with data in the + * network buffer to be read, then calling BIO_closesocket() will + * result in a TCP-RST being sent. On some platforms (notably + * Windows) then this will result in the peer immediately abandoning + * the connection including any buffered alert data before it has + * had a chance to be read. Shutting down the sending side first, + * and then closing the socket sends TCP-FIN first followed by + * TCP-RST. This seems to allow the peer to read the alert data. + */ + shutdown(SSL_get_fd(con), 1); /* SHUT_WR */ BIO_closesocket(SSL_get_fd(con)); end: if (con != NULL) { @@ -2921,6 +3084,7 @@ int s_client_main(int argc, char **argv) print_stuff(bio_c_out, con, 1); SSL_free(con); } + SSL_SESSION_free(psksess); #if !defined(OPENSSL_NO_NEXTPROTONEG) OPENSSL_free(next_proto.data); #endif @@ -2935,6 +3099,7 @@ int s_client_main(int argc, char **argv) OPENSSL_free(srp_arg.srppassin); #endif OPENSSL_free(connectstr); + OPENSSL_free(bindstr); OPENSSL_free(host); OPENSSL_free(port); X509_VERIFY_PARAM_free(vpm); @@ -2950,7 +3115,7 @@ int s_client_main(int argc, char **argv) bio_c_out = NULL; BIO_free(bio_c_msg); bio_c_msg = NULL; - return (ret); + return ret; } static void print_stuff(BIO *bio, SSL *s, int full)