X-Git-Url: https://git.openssl.org/?p=openssl.git;a=blobdiff_plain;f=apps%2Fs_client.c;h=114071c0a34561813af02a047ff4b26f43ff8380;hp=efdc8e3ef30de513e2d7bbaca0d96b08aecc5d2a;hb=222417eb71a91f28381f5b3f93d7db690e8d92bf;hpb=b5c4209be9162d4ceafb9aef833ca94ffa1cc5c9 diff --git a/apps/s_client.c b/apps/s_client.c index efdc8e3ef3..114071c0a3 100644 --- a/apps/s_client.c +++ b/apps/s_client.c @@ -1,5 +1,6 @@ /* - * Copyright 1995-2016 The OpenSSL Project Authors. All Rights Reserved. + * Copyright 1995-2017 The OpenSSL Project Authors. All Rights Reserved. + * Copyright 2005 Nokia. All rights reserved. * * Licensed under the OpenSSL license (the "License"). You may not use * this file except in compliance with the License. You can obtain a copy @@ -7,33 +8,6 @@ * https://www.openssl.org/source/license.html */ -/* ==================================================================== - * Copyright 2005 Nokia. All rights reserved. - * - * The portions of the attached software ("Contribution") is developed by - * Nokia Corporation and is licensed pursuant to the OpenSSL open source - * license. - * - * The Contribution, originally written by Mika Kousa and Pasi Eronen of - * Nokia Corporation, consists of the "PSK" (Pre-Shared Key) ciphersuites - * support (see RFC 4279) to OpenSSL. - * - * No patent licenses or other rights except those expressly stated in - * the OpenSSL open source license shall be deemed granted or received - * expressly, by implication, estoppel, or otherwise. - * - * No assurances are provided by Nokia that the Contribution does not - * infringe the patent or other intellectual property rights of any third - * party or that the license provides you with all the necessary rights - * to make use of the Contribution. - * - * THE SOFTWARE IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY KIND. IN - * ADDITION TO THE DISCLAIMERS INCLUDED IN THE LICENSE, NOKIA - * SPECIFICALLY DISCLAIMS ANY LIABILITY FOR CLAIMS BROUGHT BY YOU OR ANY - * OTHER ENTITY BASED ON INFRINGEMENT OF INTELLECTUAL PROPERTY RIGHTS OR - * OTHERWISE. - */ - #include #include #include @@ -91,6 +65,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 @@ -134,10 +109,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, @@ -154,8 +129,9 @@ static unsigned int psk_client_cb(SSL *ssl, const char *hint, char *identity, if (c_debug) BIO_printf(bio_c_out, "NULL received PSK identity hint, continuing anyway\n"); - } else if (c_debug) + } else if (c_debug) { BIO_printf(bio_c_out, "Received PSK identity hint '%s'\n", hint); + } /* * lookup PSK identity and PSK key based on the given identity hint here @@ -196,6 +172,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 0; + } + 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; @@ -530,9 +576,7 @@ typedef enum OPTION_choice { 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, @@ -540,13 +584,12 @@ typedef enum OPTION_choice { OPT_SSL3, OPT_SSL_CONFIG, OPT_TLS1_3, OPT_TLS1_2, OPT_TLS1_1, OPT_TLS1, OPT_DTLS, OPT_DTLS1, OPT_DTLS1_2, OPT_SCTP, OPT_TIMEOUT, OPT_MTU, OPT_KEYFORM, OPT_PASS, - OPT_CERT_CHAIN, OPT_CAPATH, OPT_NOCAPATH, OPT_CHAINCAPATH, - OPT_VERIFYCAPATH, + 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_SERVERINFO, OPT_STARTTLS, OPT_SERVERNAME, OPT_NOSERVERNAME, OPT_ASYNC, OPT_USE_SRTP, OPT_KEYMATEXPORT, OPT_KEYMATEXPORTLEN, OPT_SMTPHOST, - OPT_ASYNC, OPT_SPLIT_SEND_FRAG, OPT_MAX_PIPELINES, OPT_READ_BUF, + 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, @@ -651,7 +694,9 @@ const OPTIONS s_client_options[] = { "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"}, + "Set TLS extension servername (SNI) in ClientHello (default)"}, + {"noservername", OPT_NOSERVERNAME, '-', + "Do not send the server name (SNI) extension in the ClientHello"}, {"tlsextdebug", OPT_TLSEXTDEBUG, '-', "Hex dump of all TLS extensions received"}, #ifndef OPENSSL_NO_OCSP @@ -663,11 +708,12 @@ const OPTIONS s_client_options[] = { "Enable ALPN extension, considering named protocols supported (comma-separated list)"}, {"async", OPT_ASYNC, '-', "Support asynchronous operation"}, {"ssl_config", OPT_SSL_CONFIG, 's', "Use specified configuration file"}, - {"split_send_frag", OPT_SPLIT_SEND_FRAG, 'n', + {"max_send_frag", OPT_MAX_SEND_FRAG, 'p', "Maximum Size of send frames "}, + {"split_send_frag", OPT_SPLIT_SEND_FRAG, 'p', "Size used to split data for encrypt pipelines"}, - {"max_pipelines", OPT_MAX_PIPELINES, 'n', + {"max_pipelines", OPT_MAX_PIPELINES, 'p', "Maximum number of encrypt/decrypt pipelines to be used"}, - {"read_buf", OPT_READ_BUF, 'n', + {"read_buf", OPT_READ_BUF, 'p', "Default read buffer size to be used for connections"}, OPT_S_OPTIONS, OPT_V_OPTIONS, @@ -709,10 +755,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'"}, @@ -752,6 +797,7 @@ typedef enum PROTOCOL_choice { PROTO_XMPP_SERVER, PROTO_CONNECT, PROTO_IRC, + PROTO_MYSQL, PROTO_POSTGRES, PROTO_LMTP, PROTO_NNTP, @@ -768,6 +814,7 @@ static const OPT_PAIR services[] = { {"xmpp-server", PROTO_XMPP_SERVER}, {"telnet", PROTO_TELNET}, {"irc", PROTO_IRC}, + {"mysql", PROTO_MYSQL}, {"postgres", PROTO_POSTGRES}, {"lmtp", PROTO_LMTP}, {"nntp", PROTO_NNTP}, @@ -872,6 +919,7 @@ int s_client_main(int argc, char **argv) struct timeval tv; #endif char *servername = NULL; + int noservername = 0; const char *alpn_in = NULL; tlsextctx tlsextcbp = { NULL, 0 }; const char *ssl_config = NULL; @@ -892,8 +940,8 @@ int s_client_main(int argc, char **argv) #endif int min_version = 0, max_version = 0, prot_opt = 0, no_prot_opt = 0; int async = 0; - unsigned int split_send_fragment = 0; - unsigned int max_pipelines = 0; + unsigned int max_send_fragment = 0; + unsigned int split_send_fragment = 0, max_pipelines = 0; enum { use_inet, use_unix, use_unknown } connect_type = use_unknown; int count4or6 = 0; int c_nbio = 0, c_msg = 0, c_ign_eof = 0, c_brief = 0; @@ -903,7 +951,10 @@ int s_client_main(int argc, char **argv) #endif BIO *bio_c_msg = NULL; const char *keylog_file = NULL, *early_data_file = NULL; +#ifndef OPENSSL_NO_DTLS int isdtls = 0; +#endif + char *psksessf = NULL; FD_ZERO(&readfds); FD_ZERO(&writefds); @@ -1152,7 +1203,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; @@ -1164,7 +1214,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(); @@ -1359,6 +1411,9 @@ int s_client_main(int argc, char **argv) case OPT_SERVERNAME: servername = opt_arg(); break; + case OPT_NOSERVERNAME: + noservername = 1; + break; case OPT_USE_SRTP: srtp_profiles = opt_arg(); break; @@ -1371,15 +1426,11 @@ int s_client_main(int argc, char **argv) case OPT_ASYNC: async = 1; break; + case OPT_MAX_SEND_FRAG: + max_send_fragment = atoi(opt_arg()); + 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()); @@ -1399,15 +1450,49 @@ int s_client_main(int argc, char **argv) BIO_printf(bio_err, "%s: Can't use both -4 and -6\n", prog); goto opthelp; } + if (noservername) { + if (servername != NULL) { + BIO_printf(bio_err, + "%s: Can't use -servername and -noservername together\n", + prog); + goto opthelp; + } + if (dane_tlsa_domain != NULL) { + BIO_printf(bio_err, + "%s: Can't use -dane_tlsa_domain and -noservername together\n", + prog); + goto opthelp; + } + } argc = opt_num_rest(); - if (argc != 0) + if (argc == 1) { + /* If there's a positional argument, it's the equivalent of + * OPT_CONNECT. + * Don't allow -connect and a separate argument. + */ + if (connectstr != NULL) { + BIO_printf(bio_err, + "%s: must not provide both -connect option and target parameter\n", + prog); + goto opthelp; + } + connect_type = use_inet; + freeandcopy(&connectstr, *opt_rest()); + } else if (argc != 0) { goto opthelp; + } - if (proxystr) { +#ifndef OPENSSL_NO_NEXTPROTONEG + if (min_version == TLS1_3_VERSION && next_proto_neg_in != NULL) { + BIO_printf(bio_err, "Cannot supply -nextprotoneg with TLSv1.3\n"); + goto opthelp; + } +#endif + if (proxystr != NULL) { int res; char *tmp_host = host, *tmp_port = port; if (connectstr == NULL) { - BIO_printf(bio_err, "%s: -proxy requires use of -connect\n", prog); + BIO_printf(bio_err, "%s: -proxy requires use of -connect or target parameter\n", prog); goto opthelp; } res = BIO_parse_hostserv(proxystr, &host, &port, BIO_PARSE_PRIO_HOST); @@ -1432,7 +1517,7 @@ int s_client_main(int argc, char **argv) OPENSSL_free(tmp_port); if (!res) { BIO_printf(bio_err, - "%s: -connect argument malformed or ambiguous\n", + "%s: -connect argument or target parameter malformed or ambiguous\n", prog); goto end; } @@ -1455,16 +1540,6 @@ int s_client_main(int argc, char **argv) } #endif - 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; - } - #if !defined(OPENSSL_NO_NEXTPROTONEG) next_proto.status = -1; if (next_proto_neg_in) { @@ -1486,7 +1561,7 @@ int s_client_main(int argc, char **argv) if (key_file == NULL) key_file = cert_file; - if (key_file) { + if (key_file != NULL) { key = load_key(key_file, key_format, 0, pass, e, "client certificate private key file"); if (key == NULL) { @@ -1495,7 +1570,7 @@ int s_client_main(int argc, char **argv) } } - if (cert_file) { + if (cert_file != NULL) { cert = load_cert(cert_file, cert_format, "client certificate file"); if (cert == NULL) { ERR_print_errors(bio_err); @@ -1503,13 +1578,13 @@ int s_client_main(int argc, char **argv) } } - if (chain_file) { + if (chain_file != NULL) { if (!load_certs(chain_file, &chain, FORMAT_PEM, NULL, "client certificate chain")) goto end; } - if (crl_file) { + if (crl_file != NULL) { X509_CRL *crl; crl = load_crl(crl_file, crl_format); if (crl == NULL) { @@ -1542,7 +1617,7 @@ int s_client_main(int argc, char **argv) if (bio_c_out == NULL) { if (c_quiet && !c_debug) { bio_c_out = BIO_new(BIO_s_null()); - if (c_msg && !bio_c_msg) + if (c_msg && bio_c_msg == NULL) bio_c_msg = dup_bio_out(FORMAT_TEXT); } else if (bio_c_out == NULL) bio_c_out = dup_bio_out(FORMAT_TEXT); @@ -1563,7 +1638,7 @@ int s_client_main(int argc, char **argv) if (sdebug) ssl_ctx_security_debug(ctx, sdebug); - if (ssl_config) { + if (ssl_config != NULL) { if (SSL_CTX_config(ctx, ssl_config) == 0) { BIO_printf(bio_err, "Error using configuration \"%s\"\n", ssl_config); @@ -1586,11 +1661,26 @@ 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_send_fragment > 0 + && !SSL_CTX_set_max_send_fragment(ctx, max_send_fragment)) { + BIO_printf(bio_err, "%s: Max send fragment size %u is out of permitted range\n", + prog, max_send_fragment); + goto end; + } + + if (split_send_fragment > 0 + && !SSL_CTX_set_split_send_fragment(ctx, split_send_fragment)) { + BIO_printf(bio_err, "%s: Split send fragment size %u is out of permitted range\n", + prog, split_send_fragment); + goto end; } - if (max_pipelines > 0) { - SSL_CTX_set_max_pipelines(ctx, max_pipelines); + + if (max_pipelines > 0 + && !SSL_CTX_set_max_pipelines(ctx, max_pipelines)) { + BIO_printf(bio_err, "%s: Max pipelines %u is out of permitted range\n", + prog, max_pipelines); + goto end; } if (read_buf_len > 0) { @@ -1636,6 +1726,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! */ @@ -1647,11 +1756,11 @@ int s_client_main(int argc, char **argv) } #endif - if (exc) + if (exc != NULL) ssl_ctx_set_excert(ctx, exc); #if !defined(OPENSSL_NO_NEXTPROTONEG) - if (next_proto.data) + if (next_proto.data != NULL) SSL_CTX_set_next_proto_select_cb(ctx, next_proto_cb, &next_proto); #endif if (alpn_in) { @@ -1720,7 +1829,7 @@ int s_client_main(int argc, char **argv) if (!set_cert_key_stuff(ctx, cert, key, chain, build_chain)) goto end; - if (servername != NULL) { + if (!noservername) { tlsextcbp.biodebug = bio_err; SSL_CTX_set_tlsext_servername_callback(ctx, ssl_servername_cb); SSL_CTX_set_tlsext_servername_arg(ctx, &tlsextcbp); @@ -1757,7 +1866,7 @@ int s_client_main(int argc, char **argv) * come at any time. Therefore we use a callback to write out the session * when we know about it. This approach works for < TLSv1.3 as well. */ - if (sess_out) { + if (sess_out != NULL) { SSL_CTX_set_session_cache_mode(ctx, SSL_SESS_CACHE_CLIENT | SSL_SESS_CACHE_NO_INTERNAL_STORE); SSL_CTX_sess_set_new_cb(ctx, new_session_cb); @@ -1767,17 +1876,17 @@ int s_client_main(int argc, char **argv) goto end; con = SSL_new(ctx); - if (sess_in) { + if (sess_in != NULL) { SSL_SESSION *sess; BIO *stmp = BIO_new_file(sess_in, "r"); - if (!stmp) { + if (stmp == NULL) { BIO_printf(bio_err, "Can't open session file %s\n", sess_in); ERR_print_errors(bio_err); goto end; } sess = PEM_read_bio_SSL_SESSION(stmp, NULL, 0, NULL); BIO_free(stmp); - if (!sess) { + if (sess == NULL) { BIO_printf(bio_err, "Can't open session file %s\n", sess_in); ERR_print_errors(bio_err); goto end; @@ -1793,7 +1902,9 @@ int s_client_main(int argc, char **argv) if (fallback_scsv) SSL_set_mode(con, SSL_MODE_SEND_FALLBACK_SCSV); - if (servername != NULL) { + if (!noservername && (servername != NULL || dane_tlsa_domain == NULL)) { + if (servername == NULL) + servername = (host == NULL) ? "localhost" : host; if (!SSL_set_tlsext_host_name(con, servername)) { BIO_printf(bio_err, "Unable to set TLS servername extension.\n"); ERR_print_errors(bio_err); @@ -1893,9 +2004,10 @@ int s_client_main(int argc, char **argv) BIO_free(sbio); goto shut; } - } else + } else { /* want to do MTU discovery */ BIO_ctrl(sbio, BIO_CTRL_DGRAM_MTU_DISCOVER, 0, NULL); + } } else #endif /* OPENSSL_NO_DTLS */ sbio = BIO_new_socket(s, BIO_NOCLOSE); @@ -2145,6 +2257,15 @@ int s_client_main(int argc, char **argv) * HTTP/d.d ddd Reason text\r\n */ mbuf_len = BIO_gets(fbio, mbuf, BUFSIZZ); + if (mbuf_len < (int)strlen("HTTP/1.0 200")) { + BIO_printf(bio_err, + "%s: HTTP CONNECT failed, insufficient response " + "from proxy (got %d octets)\n", prog, mbuf_len); + (void)BIO_flush(fbio); + BIO_pop(fbio); + BIO_free(fbio); + goto shut; + } if (mbuf[8] != ' ') { BIO_printf(bio_err, "%s: HTTP CONNECT failed, incorrect response " @@ -2232,6 +2353,86 @@ int s_client_main(int argc, char **argv) } } break; + case PROTO_MYSQL: + { + /* SSL request packet */ + static const unsigned char ssl_req[] = { + /* payload_length, sequence_id */ + 0x20, 0x00, 0x00, 0x01, + /* payload */ + /* capability flags, CLIENT_SSL always set */ + 0x85, 0xae, 0x7f, 0x00, + /* max-packet size */ + 0x00, 0x00, 0x00, 0x01, + /* character set */ + 0x21, + /* string[23] reserved (all [0]) */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 + }; + int bytes = 0; + int ssl_flg = 0x800; + int pos; + const unsigned char *packet = (const unsigned char *)sbuf; + + /* Receiving Initial Handshake packet. */ + bytes = BIO_read(sbio, (void *)packet, BUFSIZZ); + if (bytes < 0) { + BIO_printf(bio_err, "BIO_read failed\n"); + goto shut; + /* Packet length[3], Packet number[1] + minimum payload[17] */ + } else if (bytes < 21) { + BIO_printf(bio_err, "MySQL packet too short.\n"); + goto shut; + } else if (bytes != (4 + packet[0] + + (packet[1] << 8) + + (packet[2] << 16))) { + BIO_printf(bio_err, "MySQL packet length does not match.\n"); + goto shut; + /* protocol version[1] */ + } else if (packet[4] != 0xA) { + BIO_printf(bio_err, + "Only MySQL protocol version 10 is supported.\n"); + goto shut; + } + + pos = 5; + /* server version[string+NULL] */ + for (;;) { + if (pos >= bytes) { + BIO_printf(bio_err, "Cannot confirm server version. "); + goto shut; + } else if (packet[pos++] == '\0') { + break; + } + } + + /* 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"); + goto shut; + } + + pos += 12; /* skip over conn id[4] + SALT[8] */ + if (packet[pos++] != '\0') { /* verify filler */ + BIO_printf(bio_err, + "MySQL packet is broken.\n"); + goto shut; + } + + /* capability flags[2] */ + if (!((packet[pos] + (packet[pos + 1] << 8)) & ssl_flg)) { + BIO_printf(bio_err, "MySQL server does not support SSL.\n"); + goto shut; + } + + /* Sending SSL Handshake packet. */ + BIO_write(sbio, ssl_req, sizeof(ssl_req)); + (void)BIO_flush(sbio); + } + break; case PROTO_POSTGRES: { static const unsigned char ssl_request[] = { @@ -2459,12 +2660,6 @@ int s_client_main(int argc, char **argv) if (in_init) { in_init = 0; - if (servername != NULL && !SSL_session_reused(con)) { - BIO_printf(bio_c_out, - "Server did %sacknowledge servername extension.\n", - tlsextcbp.ack ? "" : "not "); - } - if (c_brief) { BIO_puts(bio_err, "CONNECTION ESTABLISHED\n"); print_ssl_summary(con); @@ -2814,6 +3009,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 @@ -3059,12 +3255,12 @@ static int ocsp_resp_cb(SSL *s, void *arg) OCSP_RESPONSE *rsp; len = SSL_get_tlsext_status_ocsp_resp(s, &p); BIO_puts(arg, "OCSP response: "); - if (!p) { + if (p == NULL) { BIO_puts(arg, "no response sent\n"); return 1; } rsp = d2i_OCSP_RESPONSE(NULL, &p, len); - if (!rsp) { + if (rsp == NULL) { BIO_puts(arg, "response parse error\n"); BIO_dump_indent(arg, (char *)p, len, 4); return 0;