summaryrefslogtreecommitdiffstats
path: root/apps/s_client.c
diff options
context:
space:
mode:
authorMarc <34656315+MarcT512@users.noreply.github.com>2019-01-03 00:32:00 +0000
committerMatt Caswell <matt@openssl.org>2019-01-18 10:50:33 +0000
commit69738dadcda1b242a0b5e41d5d2fe4be3f55a448 (patch)
treec5ee6bca6ce3b5fc39f602a9535df1d1e1889a37 /apps/s_client.c
parent3afd537a3c2319f68280804004e9bf2e798a43f7 (diff)
s_client: Add basic proxy authentication support
1) Add two new flags (-proxy_user & -proxy_pass) to s_client to add support for basic (base64) proxy authentication. 2) Add a "Proxy-Connection: Keep-Alive" HTTP header which is a workaround for some broken proxies which otherwise close the connection when entering tunnel mode (eg Squid 2.6). Reviewed-by: Paul Dale <paul.dale@oracle.com> Reviewed-by: Matt Caswell <matt@openssl.org> (Merged from https://github.com/openssl/openssl/pull/7975)
Diffstat (limited to 'apps/s_client.c')
-rw-r--r--apps/s_client.c81
1 files changed, 76 insertions, 5 deletions
diff --git a/apps/s_client.c b/apps/s_client.c
index 51001d5766..d788b89dee 100644
--- a/apps/s_client.c
+++ b/apps/s_client.c
@@ -74,6 +74,7 @@ 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 saved_errno;
@@ -590,7 +591,8 @@ 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
@@ -608,6 +610,8 @@ const OPTIONS s_client_options[] = {
{"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
@@ -894,8 +898,10 @@ 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, *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);
@@ -1075,6 +1081,12 @@ int s_client_main(int argc, char **argv)
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;
@@ -1619,7 +1631,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;
}
@@ -2322,7 +2344,31 @@ 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");
+ 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,
@@ -3128,6 +3174,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;
@@ -3467,4 +3515,27 @@ 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;
+}
+
#endif /* OPENSSL_NO_SOCK */