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)
This commit is contained in:
parent
3afd537a3c
commit
69738dadcd
2 changed files with 93 additions and 5 deletions
|
@ -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 */
|
||||
|
|
|
@ -12,6 +12,8 @@ B<openssl> B<s_client>
|
|||
[B<-connect host:port>]
|
||||
[B<-bind host:port>]
|
||||
[B<-proxy host:port>]
|
||||
[B<-proxy_user userid>]
|
||||
[B<-proxy_pass arg>]
|
||||
[B<-unix path>]
|
||||
[B<-4>]
|
||||
[B<-6>]
|
||||
|
@ -175,6 +177,21 @@ When used with the B<-connect> flag, the program uses the host and port
|
|||
specified with this flag and issues an HTTP CONNECT command to connect
|
||||
to the desired server.
|
||||
|
||||
=item B<-proxy_user userid>
|
||||
|
||||
When used with the B<-proxy> flag, the program will attempt to authenticate
|
||||
with the specified proxy using basic (base64) authentication.
|
||||
NB: Basic authentication is insecure; the credentials are sent to the proxy
|
||||
in easily reversible base64 encoding before any TLS/SSL session is established.
|
||||
Therefore these credentials are easily recovered by anyone able to sniff/trace
|
||||
the network. Use with caution.
|
||||
|
||||
=item B<-proxy_pass arg>
|
||||
|
||||
The proxy password source, used with the B<-proxy_user> flag.
|
||||
For more information about the format of B<arg> see the B<PASS PHRASE ARGUMENTS>
|
||||
section in L<openssl(1)>.
|
||||
|
||||
=item B<-unix path>
|
||||
|
||||
Connect over the specified Unix-domain socket.
|
||||
|
|
Loading…
Reference in a new issue