* 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
+ * 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
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 saved_errno;
cipher = SSL_CIPHER_find(s, tls13_aes128gcmsha256_id);
if (cipher == NULL) {
BIO_printf(bio_err, "Error finding suitable ciphersuite\n");
+ OPENSSL_free(key);
return 0;
}
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_FORCE_PHA,
+ OPT_ENABLE_PHA,
OPT_R_ENUM
} OPTION_CHOICE;
{"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
#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"},
+ {"enable_pha", OPT_ENABLE_PHA, '-', "Enable post-handshake-authentication"},
{NULL, OPT_EOF, 0x00, NULL}
};
*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");
}
/*
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, *bindstr = 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);
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;
int isdtls = 0;
#endif
char *psksessf = NULL;
- int force_pha = 0;
+ int enable_pha = 0;
FD_ZERO(&readfds);
FD_ZERO(&writefds);
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;
noservername = 1;
break;
case OPT_USE_SRTP:
+#ifndef OPENSSL_NO_SRTP
srtp_profiles = opt_arg();
+#endif
break;
case OPT_KEYMATEXPORT:
keymatexportlabel = opt_arg();
case OPT_EARLY_DATA:
early_data_file = opt_arg();
break;
- case OPT_FORCE_PHA:
- force_pha = 1;
+ case OPT_ENABLE_PHA:
+ enable_pha = 1;
break;
}
}
#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;
}
goto end;
}
+ SSL_CTX_clear_mode(ctx, SSL_MODE_AUTO_RETRY);
+
if (sdebug)
ssl_ctx_security_debug(ctx, sdebug);
* 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;
if (con == NULL)
goto end;
- if (force_pha)
- SSL_force_post_handshake_auth(con);
+ if (enable_pha)
+ SSL_set_post_handshake_auth(con, 1);
if (sess_in != NULL) {
SSL_SESSION *sess;
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");
+ 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,
/* 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);
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;
}
}
- 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);
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;
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
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
{
}
#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");
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);
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;
+}
+
#endif /* OPENSSL_NO_SOCK */