X-Git-Url: https://git.openssl.org/gitweb/?p=openssl.git;a=blobdiff_plain;f=apps%2Fs_client.c;h=7a41d831e98bc622acd1d9b362f9f827cf47dc4d;hp=a549304b346a5afb1a8664bf8ed35098c8ec9719;hb=f0e4a860d0b350e10a1ee3898445cac85af8ea16;hpb=26ec943e020c0db6a25e6d155ba318270eff0fd7 diff --git a/apps/s_client.c b/apps/s_client.c index a549304b34..7a41d831e9 100644 --- a/apps/s_client.c +++ b/apps/s_client.c @@ -1,8 +1,8 @@ /* - * Copyright 1995-2017 The OpenSSL Project Authors. All Rights Reserved. + * Copyright 1995-2019 The OpenSSL Project Authors. All Rights Reserved. * Copyright 2005 Nokia. All rights reserved. * - * Licensed under the OpenSSL license (the "License"). You may not use + * Licensed under the Apache License 2.0 (the "License"). You may not use * this file except in compliance with the License. You can obtain a copy * in the file LICENSE in the source distribution or at * https://www.openssl.org/source/license.html @@ -30,6 +30,7 @@ typedef unsigned int u_int; #endif #include "apps.h" +#include "progs.h" #include #include #include @@ -37,6 +38,7 @@ typedef unsigned int u_int; #include #include #include +#include #include #ifndef OPENSSL_NO_SRP # include @@ -73,6 +75,8 @@ static void print_stuff(BIO *berr, SSL *con, int full); static int ocsp_resp_cb(SSL *s, void *arg); #endif static int ldap_ExtendedResponse_parse(const char *buf, long rem); +static char *base64encode (const void *buf, size_t len); +static int is_dNS_name(const char *host); static int saved_errno; @@ -196,19 +200,14 @@ static int psk_use_session_cb(SSL *s, const EVP_MD *md, 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); - + /* We default to SHA-256 */ + cipher = SSL_CIPHER_find(s, tls13_aes128gcmsha256_id); if (cipher == NULL) { - /* Doesn't look like a suitable TLSv1.3 key. Ignore it */ + BIO_printf(bio_err, "Error finding suitable ciphersuite\n"); 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) @@ -372,8 +371,6 @@ static char *ssl_give_srp_client_pwd_cb(SSL *s, void *arg) #endif -static char *srtp_profiles = NULL; - #ifndef OPENSSL_NO_NEXTPROTONEG /* This the context that we pass to next_proto_cb */ typedef struct tlsextnextprotoctx_st { @@ -569,7 +566,7 @@ 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, @@ -596,11 +593,14 @@ typedef enum OPTION_choice { OPT_V_ENUM, OPT_X_ENUM, OPT_S_ENUM, - OPT_FALLBACKSCSV, OPT_NOCMDS, OPT_PROXY, OPT_DANE_TLSA_DOMAIN, + OPT_FALLBACKSCSV, OPT_NOCMDS, OPT_PROXY, OPT_PROXY_USER, OPT_PROXY_PASS, + OPT_DANE_TLSA_DOMAIN, #ifndef OPENSSL_NO_CT OPT_CT, OPT_NOCT, OPT_CTLOG_FILE, #endif OPT_DANE_TLSA_RRDATA, OPT_DANE_EE_NO_NAME, + OPT_ENABLE_PHA, + OPT_SCTP_LABEL_BUG, OPT_R_ENUM } OPTION_CHOICE; @@ -610,8 +610,11 @@ 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"}, + {"proxy_user", OPT_PROXY_USER, 's', "UserID for proxy authentication"}, + {"proxy_pass", OPT_PROXY_PASS, 's', "Proxy authentication password source"}, #ifdef AF_UNIX {"unix", OPT_UNIX, 's', "Connect over the specified Unix-domain socket"}, #endif @@ -642,7 +645,8 @@ const OPTIONS s_client_options[] = { "Disable name checks when matching DANE-EE(3) TLSA records"}, {"reconnect", OPT_RECONNECT, '-', "Drop and re-make the connection with the same Session-ID"}, - {"showcerts", OPT_SHOWCERTS, '-', "Show all certificates in the chain"}, + {"showcerts", OPT_SHOWCERTS, '-', + "Show all certificates sent by the server"}, {"debug", OPT_DEBUG, '-', "Extra output"}, {"msg", OPT_MSG, '-', "Show protocol messages"}, {"msgfile", OPT_MSGFILE, '>', @@ -660,8 +664,10 @@ const OPTIONS s_client_options[] = { 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"}, +#ifndef OPENSSL_NO_SRTP {"use_srtp", OPT_USE_SRTP, 's', "Offer SRTP key management with a colon-separated profile list"}, +#endif {"keymatexport", OPT_KEYMATEXPORT, 's', "Export keying material using label"}, {"keymatexportlen", OPT_KEYMATEXPORTLEN, 'p', @@ -751,6 +757,7 @@ const OPTIONS s_client_options[] = { #endif #ifndef OPENSSL_NO_SCTP {"sctp", OPT_SCTP, '-', "Use SCTP"}, + {"sctp_label_bug", OPT_SCTP_LABEL_BUG, '-', "Enable SCTP label length bug"}, #endif #ifndef OPENSSL_NO_SSL_TRACE {"trace", OPT_TRACE, '-', "Show trace output of protocol messages"}, @@ -787,6 +794,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"}, + {"enable_pha", OPT_ENABLE_PHA, '-', "Enable post-handshake-authentication"}, {NULL, OPT_EOF, 0x00, NULL} }; @@ -844,15 +852,29 @@ static void freeandcopy(char **dest, const char *source) *dest = OPENSSL_strdup(source); } -static int new_session_cb(SSL *S, SSL_SESSION *sess) +static int new_session_cb(SSL *s, SSL_SESSION *sess) { - BIO *stmp = BIO_new_file(sess_out, "w"); - if (stmp == NULL) { - BIO_printf(bio_err, "Error writing session file %s\n", sess_out); - } else { - PEM_write_bio_SSL_SESSION(stmp, sess); - BIO_free(stmp); + if (sess_out != NULL) { + BIO *stmp = BIO_new_file(sess_out, "w"); + + if (stmp == NULL) { + BIO_printf(bio_err, "Error writing session file %s\n", sess_out); + } else { + PEM_write_bio_SSL_SESSION(stmp, sess); + BIO_free(stmp); + } + } + + /* + * Session data gets dumped on connection for TLSv1.2 and below, and on + * arrival of the NewSessionTicket for TLSv1.3. + */ + if (SSL_version(s) == TLS1_3_VERSION) { + BIO_printf(bio_c_out, + "---\nPost-Handshake New Session Ticket arrived:\n"); + SSL_SESSION_print(bio_c_out, sess); + BIO_printf(bio_c_out, "---\n"); } /* @@ -880,11 +902,14 @@ int s_client_main(int argc, char **argv) STACK_OF(X509_CRL) *crls = NULL; 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 *cbuf = NULL, *sbuf = NULL, *mbuf = NULL; + char *proxystr = NULL, *proxyuser = NULL; + char *proxypassarg = NULL, *proxypass = NULL; + char *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 *bindhost = NULL, *bindport = NULL; char *passarg = NULL, *pass = NULL, *vfyCApath = NULL, *vfyCAfile = NULL; char *ReqCAfile = NULL; char *sess_in = NULL, *crl_file = NULL, *p; @@ -935,6 +960,9 @@ int s_client_main(int argc, char **argv) int srp_lateuser = 0; SRP_ARG srp_arg = { NULL, NULL, 0, 0, 0, 1024 }; #endif +#ifndef OPENSSL_NO_SRTP + char *srtp_profiles = NULL; +#endif #ifndef OPENSSL_NO_CT char *ctlog_file = NULL; int ct_validation = 0; @@ -957,6 +985,10 @@ int s_client_main(int argc, char **argv) int isdtls = 0; #endif char *psksessf = NULL; + int enable_pha = 0; +#ifndef OPENSSL_NO_SCTP + int sctp_label_bug = 0; +#endif FD_ZERO(&readfds); FD_ZERO(&writefds); @@ -1049,10 +1081,19 @@ 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; break; + case OPT_PROXY_USER: + proxyuser = opt_arg(); + break; + case OPT_PROXY_PASS: + proxypassarg = opt_arg(); + break; #ifdef AF_UNIX case OPT_UNIX: connect_type = use_unix; @@ -1099,6 +1140,7 @@ int s_client_main(int argc, char **argv) goto opthelp; break; case OPT_VERIFY_RET_ERROR: + verify = SSL_VERIFY_PEER; verify_args.return_error = 1; break; case OPT_VERIFY_QUIET: @@ -1299,6 +1341,11 @@ int s_client_main(int argc, char **argv) case OPT_SCTP: #ifndef OPENSSL_NO_SCTP protocol = IPPROTO_SCTP; +#endif + break; + case OPT_SCTP_LABEL_BUG: +#ifndef OPENSSL_NO_SCTP + sctp_label_bug = 1; #endif break; case OPT_TIMEOUT: @@ -1417,7 +1464,9 @@ int s_client_main(int argc, char **argv) noservername = 1; break; case OPT_USE_SRTP: +#ifndef OPENSSL_NO_SRTP srtp_profiles = opt_arg(); +#endif break; case OPT_KEYMATEXPORT: keymatexportlabel = opt_arg(); @@ -1468,8 +1517,12 @@ int s_client_main(int argc, char **argv) case OPT_EARLY_DATA: early_data_file = opt_arg(); break; + case OPT_ENABLE_PHA: + enable_pha = 1; + break; } } + if (count4or6 >= 2) { BIO_printf(bio_err, "%s: Can't use both -4 and -6\n", prog); goto opthelp; @@ -1547,6 +1600,18 @@ 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, @@ -1580,7 +1645,17 @@ int s_client_main(int argc, char **argv) #endif if (!app_passwd(passarg, NULL, &pass, NULL)) { - BIO_printf(bio_err, "Error getting password\n"); + BIO_printf(bio_err, "Error getting private key password\n"); + goto end; + } + + if (!app_passwd(proxypassarg, NULL, &proxypass, NULL)) { + BIO_printf(bio_err, "Error getting proxy password\n"); + goto end; + } + + if (proxypass != NULL && proxyuser == NULL) { + BIO_printf(bio_err, "Error: Must specify proxy_user with proxy_pass\n"); goto end; } @@ -1651,9 +1726,14 @@ int s_client_main(int argc, char **argv) goto end; } + SSL_CTX_clear_mode(ctx, SSL_MODE_AUTO_RETRY); + if (sdebug) ssl_ctx_security_debug(ctx, sdebug); + if (!config_ctx(cctx, ssl_args, ctx)) + goto end; + if (ssl_config != NULL) { if (SSL_CTX_config(ctx, ssl_config) == 0) { BIO_printf(bio_err, "Error using configuration \"%s\"\n", @@ -1663,9 +1743,16 @@ int s_client_main(int argc, char **argv) } } - if (SSL_CTX_set_min_proto_version(ctx, min_version) == 0) +#ifndef OPENSSL_NO_SCTP + if (protocol == IPPROTO_SCTP && sctp_label_bug == 1) + SSL_CTX_set_mode(ctx, SSL_MODE_DTLS_SCTP_LABEL_LENGTH_BUG); +#endif + + if (min_version != 0 + && SSL_CTX_set_min_proto_version(ctx, min_version) == 0) goto end; - if (SSL_CTX_set_max_proto_version(ctx, max_version) == 0) + if (max_version != 0 + && SSL_CTX_set_max_proto_version(ctx, max_version) == 0) goto end; if (vpmtouched && !SSL_CTX_set1_param(ctx, vpm)) { @@ -1711,9 +1798,6 @@ int s_client_main(int argc, char **argv) goto end; } - if (!config_ctx(cctx, ssl_args, ctx)) - goto end; - if (!ssl_load_stores(ctx, vfyCApath, vfyCAfile, chCApath, chCAfile, crls, crl_download)) { BIO_printf(bio_err, "Error loading store locations\n"); @@ -1890,11 +1974,9 @@ 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 != 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); - } + 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); if (set_keylog_file(ctx, keylog_file)) goto end; @@ -1903,6 +1985,9 @@ int s_client_main(int argc, char **argv) if (con == NULL) goto end; + if (enable_pha) + SSL_set_post_handshake_auth(con, 1); + if (sess_in != NULL) { SSL_SESSION *sess; BIO *stmp = BIO_new_file(sess_in, "r"); @@ -1931,9 +2016,11 @@ int s_client_main(int argc, char **argv) SSL_set_mode(con, SSL_MODE_SEND_FALLBACK_SCSV); if (!noservername && (servername != NULL || dane_tlsa_domain == NULL)) { - if (servername == NULL) - servername = (host == NULL) ? "localhost" : host; - if (!SSL_set_tlsext_host_name(con, servername)) { + if (servername == NULL) { + if(host == NULL || is_dNS_name(host)) + servername = (host == NULL) ? "localhost" : host; + } + if (servername != NULL && !SSL_set_tlsext_host_name(con, servername)) { BIO_printf(bio_err, "Unable to set TLS servername extension.\n"); ERR_print_errors(bio_err); goto end; @@ -1966,8 +2053,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; @@ -2278,7 +2365,33 @@ int s_client_main(int argc, char **argv) BIO *fbio = BIO_new(BIO_f_buffer()); BIO_push(fbio, sbio); - BIO_printf(fbio, "CONNECT %s HTTP/1.0\r\n\r\n", connectstr); + BIO_printf(fbio, "CONNECT %s HTTP/1.0\r\n", connectstr); + /* + * Workaround for broken proxies which would otherwise close + * the connection when entering tunnel mode (eg Squid 2.6) + */ + BIO_printf(fbio, "Proxy-Connection: Keep-Alive\r\n"); + + /* Support for basic (base64) proxy authentication */ + if (proxyuser != NULL) { + size_t l; + char *proxyauth, *proxyauthenc; + + l = strlen(proxyuser); + if (proxypass != NULL) + l += strlen(proxypass); + proxyauth = app_malloc(l + 2, "Proxy auth string"); + BIO_snprintf(proxyauth, l + 2, "%s:%s", proxyuser, + (proxypass != NULL) ? proxypass : ""); + proxyauthenc = base64encode(proxyauth, strlen(proxyauth)); + BIO_printf(fbio, "Proxy-Authorization: Basic %s\r\n", + proxyauthenc); + OPENSSL_clear_free(proxyauth, strlen(proxyauth)); + OPENSSL_clear_free(proxyauthenc, strlen(proxyauthenc)); + } + + /* Terminate the HTTP CONNECT request */ + BIO_printf(fbio, "\r\n"); (void)BIO_flush(fbio); /* * The first line is the HTTP response. According to RFC 7230, @@ -2491,12 +2604,16 @@ int s_client_main(int argc, char **argv) /* STARTTLS command requires CAPABILITIES... */ BIO_printf(fbio, "CAPABILITIES\r\n"); (void)BIO_flush(fbio); - /* wait for multi-line CAPABILITIES response */ - do { - mbuf_len = BIO_gets(fbio, mbuf, BUFSIZZ); - if (strstr(mbuf, "STARTTLS")) - foundit = 1; - } while (mbuf_len > 1 && mbuf[0] != '.'); + BIO_gets(fbio, mbuf, BUFSIZZ); + /* no point in trying to parse the CAPABILITIES response if there is none */ + if (strstr(mbuf, "101") != NULL) { + /* wait for multi-line CAPABILITIES response */ + do { + mbuf_len = BIO_gets(fbio, mbuf, BUFSIZZ); + if (strstr(mbuf, "STARTTLS")) + foundit = 1; + } while (mbuf_len > 1 && mbuf[0] != '.'); + } (void)BIO_flush(fbio); BIO_pop(fbio); BIO_free(fbio); @@ -2678,8 +2795,7 @@ int s_client_main(int argc, char **argv) FD_ZERO(&readfds); FD_ZERO(&writefds); - if ((SSL_version(con) == DTLS1_VERSION) && - DTLSv1_get_timeout(con, &timeout)) + if (SSL_is_dtls(con) && DTLSv1_get_timeout(con, &timeout)) timeoutp = &timeout; else timeoutp = NULL; @@ -2790,10 +2906,8 @@ int s_client_main(int argc, char **argv) } } - if ((SSL_version(con) == DTLS1_VERSION) - && DTLSv1_handle_timeout(con) > 0) { + if (SSL_is_dtls(con) && DTLSv1_handle_timeout(con) > 0) BIO_printf(bio_err, "TIMEOUT occurred\n"); - } if (!ssl_pending && FD_ISSET(SSL_get_fd(con), &writefds)) { k = SSL_write(con, &(cbuf[cbuf_off]), (unsigned int)cbuf_len); @@ -2990,9 +3104,7 @@ int s_client_main(int argc, char **argv) BIO_printf(bio_err, "RENEGOTIATING\n"); SSL_renegotiate(con); cbuf_len = 0; - } - - if (!c_ign_eof && (cbuf[0] == 'K' || cbuf[0] == 'k' ) + } else if (!c_ign_eof && (cbuf[0] == 'K' || cbuf[0] == 'k' ) && cmdletters) { BIO_printf(bio_err, "KEYUPDATE\n"); SSL_key_update(con, @@ -3025,16 +3137,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 - * Windows to send the data before closing the socket...but sleeping - * for a short time seems to do it (units in ms) - * TODO: Find a better way to do this - */ - Sleep(50); -#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 @@ -3046,6 +3149,19 @@ int s_client_main(int argc, char **argv) * TCP-RST. This seems to allow the peer to read the alert data. */ shutdown(SSL_get_fd(con), 1); /* SHUT_WR */ + /* + * We just said we have nothing else to say, but it doesn't mean that + * the other side has nothing. It's even recommended to consume incoming + * data. [In testing context this ensures that alerts are passed on...] + */ + timeout.tv_sec = 0; + timeout.tv_usec = 500000; /* some extreme round-trip */ + do { + FD_ZERO(&readfds); + openssl_fdset(s, &readfds); + } while (select(s + 1, &readfds, NULL, NULL, &timeout) > 0 + && BIO_read(sbio, sbuf, BUFSIZZ) > 0); + BIO_closesocket(SSL_get_fd(con)); end: if (con != NULL) { @@ -3068,6 +3184,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); @@ -3078,6 +3195,8 @@ int s_client_main(int argc, char **argv) OPENSSL_clear_free(cbuf, BUFSIZZ); OPENSSL_clear_free(sbuf, BUFSIZZ); OPENSSL_clear_free(mbuf, BUFSIZZ); + if (proxypass != NULL) + OPENSSL_clear_free(proxypass, strlen(proxypass)); release_engine(e); BIO_free(bio_c_out); bio_c_out = NULL; @@ -3091,7 +3210,8 @@ static void print_stuff(BIO *bio, SSL *s, int full) X509 *peer = NULL; STACK_OF(X509) *sk; const SSL_CIPHER *c; - int i; + int i, istls13 = (SSL_version(s) == TLS1_3_VERSION); + long verify_result; #ifndef OPENSSL_NO_COMP const COMP_METHOD *comp, *expansion; #endif @@ -3198,9 +3318,12 @@ static void print_stuff(BIO *bio, SSL *s, int full) BIO_printf(bio, "Expansion: %s\n", expansion ? SSL_COMP_get_name(expansion) : "NONE"); #endif +#ifndef OPENSSL_NO_KTLS + if (BIO_get_ktls_send(SSL_get_wbio(s))) + BIO_printf(bio_err, "Using Kernel TLS for sending\n"); +#endif -#ifdef SSL_DEBUG - { + if (OSSL_TRACE_ENABLED(TLS)) { /* Print out local port of connection: useful for debugging */ int sock; union BIO_sock_info_u info; @@ -3213,7 +3336,6 @@ static void print_stuff(BIO *bio, SSL *s, int full) } BIO_ADDR_free(info.addr); } -#endif #if !defined(OPENSSL_NO_NEXTPROTONEG) if (next_proto.status != -1) { @@ -3248,7 +3370,7 @@ static void print_stuff(BIO *bio, SSL *s, int full) } #endif - if (SSL_version(s) == TLS1_3_VERSION) { + if (istls13) { switch (SSL_get_early_data_status(s)) { case SSL_EARLY_DATA_NOT_SENT: BIO_printf(bio, "Early data was not sent\n"); @@ -3263,9 +3385,20 @@ static void print_stuff(BIO *bio, SSL *s, int full) break; } + + /* + * We also print the verify results when we dump session information, + * but in TLSv1.3 we may not get that right away (or at all) depending + * on when we get a NewSessionTicket. Therefore we print it now as well. + */ + verify_result = SSL_get_verify_result(s); + BIO_printf(bio, "Verify return code: %ld (%s)\n", verify_result, + X509_verify_cert_error_string(verify_result)); + } else { + /* In TLSv1.3 we do this on arrival of a NewSessionTicket */ + SSL_SESSION_print(bio, SSL_get_session(s)); } - SSL_SESSION_print(bio, SSL_get_session(s)); if (SSL_get_session(s) != NULL && keymatexportlabel != NULL) { BIO_printf(bio, "Keying material exporter:\n"); BIO_printf(bio, " Label: '%s'\n", keymatexportlabel); @@ -3401,4 +3534,92 @@ static int ldap_ExtendedResponse_parse(const char *buf, long rem) return ret; } +/* + * BASE64 encoder: used only for encoding basic proxy authentication credentials + */ +static char *base64encode (const void *buf, size_t len) +{ + int i; + size_t outl; + char *out; + + /* Calculate size of encoded data */ + outl = (len / 3); + if (len % 3 > 0) + outl++; + outl <<= 2; + out = app_malloc(outl + 1, "base64 encode buffer"); + + i = EVP_EncodeBlock((unsigned char *)out, buf, len); + assert(i <= (int)outl); + if (i < 0) + *out = '\0'; + return out; +} + +/* + * Host dNS Name verifier: used for checking that the hostname is in dNS format + * before setting it as SNI + */ +static int is_dNS_name(const char *host) +{ + const size_t MAX_LABEL_LENGTH = 63; + size_t i; + int isdnsname = 0; + size_t length = strlen(host); + size_t label_length = 0; + int all_numeric = 1; + + /* + * Deviation from strict DNS name syntax, also check names with '_' + * Check DNS name syntax, any '-' or '.' must be internal, + * and on either side of each '.' we can't have a '-' or '.'. + * + * If the name has just one label, we don't consider it a DNS name. + */ + for (i = 0; i < length && label_length < MAX_LABEL_LENGTH; ++i) { + char c = host[i]; + + if ((c >= 'a' && c <= 'z') + || (c >= 'A' && c <= 'Z') + || c == '_') { + label_length += 1; + all_numeric = 0; + continue; + } + + if (c >= '0' && c <= '9') { + label_length += 1; + continue; + } + + /* Dot and hyphen cannot be first or last. */ + if (i > 0 && i < length - 1) { + if (c == '-') { + label_length += 1; + continue; + } + /* + * Next to a dot the preceding and following characters must not be + * another dot or a hyphen. Otherwise, record that the name is + * plausible, since it has two or more labels. + */ + if (c == '.' + && host[i + 1] != '.' + && host[i - 1] != '-' + && host[i + 1] != '-') { + label_length = 0; + isdnsname = 1; + continue; + } + } + isdnsname = 0; + break; + } + + /* dNS name must not be all numeric and labels must be shorter than 64 characters. */ + isdnsname &= !all_numeric && !(label_length == MAX_LABEL_LENGTH); + + return isdnsname; +} #endif /* OPENSSL_NO_SOCK */