/*
- * Copyright 1995-2019 The OpenSSL Project Authors. All Rights Reserved.
+ * Copyright 1995-2020 The OpenSSL Project Authors. All Rights Reserved.
* Copyright 2005 Nokia. All rights reserved.
*
* Licensed under the Apache License 2.0 (the "License"). You may not use
# endif
#endif
+DEFINE_STACK_OF(X509)
+DEFINE_STACK_OF(X509_CRL)
+DEFINE_STACK_OF(X509_NAME)
+DEFINE_STACK_OF(SCT)
+DEFINE_STACK_OF_STRING()
+
#undef BUFSIZZ
#define BUFSIZZ 1024*8
#define S_CLIENT_IRC_READ_TIMEOUT 8
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;
return ret;
}
-static void do_ssl_shutdown(SSL *ssl)
-{
- int ret;
-
- do {
- /* We only do unidirectional shutdown */
- ret = SSL_shutdown(ssl);
- if (ret < 0) {
- switch (SSL_get_error(ssl, ret)) {
- case SSL_ERROR_WANT_READ:
- case SSL_ERROR_WANT_WRITE:
- case SSL_ERROR_WANT_ASYNC:
- case SSL_ERROR_WANT_ASYNC_JOB:
- /* We just do busy waiting. Nothing clever */
- continue;
- }
- ret = 0;
- }
- } while (ret < 0);
-}
-
/* Default PSK identity and key */
static char *psk_identity = "Client_identity";
OPT_READ_BUF, OPT_KEYLOG_FILE, OPT_EARLY_DATA, OPT_REQCAFILE,
OPT_V_ENUM,
OPT_X_ENUM,
- OPT_S_ENUM,
+ OPT_S_ENUM, OPT_IGNORE_UNEXPECTED_EOF,
OPT_FALLBACKSCSV, OPT_NOCMDS, OPT_PROXY, OPT_PROXY_USER, OPT_PROXY_PASS,
OPT_DANE_TLSA_DOMAIN,
#ifndef OPENSSL_NO_CT
OPT_DANE_TLSA_RRDATA, OPT_DANE_EE_NO_NAME,
OPT_ENABLE_PHA,
OPT_SCTP_LABEL_BUG,
- OPT_R_ENUM
+ OPT_R_ENUM, OPT_PROV_ENUM
} OPTION_CHOICE;
const OPTIONS s_client_options[] = {
{"ssl_client_engine", OPT_SSL_CLIENT_ENGINE, 's',
"Specify engine to be used for client certificate operations"},
#endif
- {"ssl_config", OPT_SSL_CONFIG, 's', "Use specified configuration file"},
+ {"ssl_config", OPT_SSL_CONFIG, 's', "Use specified section for SSL_CTX configuration"},
#ifndef OPENSSL_NO_CT
{"ct", OPT_CT, '-', "Request and parse SCTs (also enables OCSP stapling)"},
{"noct", OPT_NOCT, '-', "Do not request or parse SCTs (default)"},
{"fallback_scsv", OPT_FALLBACKSCSV, '-', "Send the fallback SCSV"},
OPT_SECTION("Identity"),
- {"verify", OPT_VERIFY, 'p', "Turn on peer certificate verification"},
- {"cert", OPT_CERT, '<', "Certificate file to use, PEM format assumed"},
+ {"cert", OPT_CERT, '<', "Client certificate file to use"},
{"certform", OPT_CERTFORM, 'F',
- "Certificate format (PEM or DER) PEM default"},
- {"nameopt", OPT_NAMEOPT, 's', "Various certificate name options"},
- {"key", OPT_KEY, 's', "Private key file to use, if not in -cert file"},
- {"keyform", OPT_KEYFORM, 'E', "Key format (PEM, DER or engine) PEM default"},
+ "Client certificate file format (PEM/DER/P12); has no effect"},
+ {"cert_chain", OPT_CERT_CHAIN, '<',
+ "Client certificate chain file (in PEM format)"},
+ {"build_chain", OPT_BUILD_CHAIN, '-', "Build client certificate chain"},
+ {"key", OPT_KEY, 's', "Private key file to use; default is: -cert file"},
+ {"keyform", OPT_KEYFORM, 'E', "Key format (ENGINE, other values ignored)"},
{"pass", OPT_PASS, 's', "Private key file pass phrase source"},
+ {"verify", OPT_VERIFY, 'p', "Turn on peer certificate verification"},
+ {"nameopt", OPT_NAMEOPT, 's', "Certificate subject/issuer name printing options"},
{"CApath", OPT_CAPATH, '/', "PEM format directory of CA's"},
{"CAfile", OPT_CAFILE, '<', "PEM format file of CA's"},
- {"CAstore", OPT_CAFILE, ':', "URI to store of CA's"},
+ {"CAstore", OPT_CASTORE, ':', "URI to store of CA's"},
{"no-CAfile", OPT_NOCAFILE, '-',
"Do not load the default certificates file"},
{"no-CApath", OPT_NOCAPATH, '-',
"Do not load certificates from the default certificates directory"},
- {"no-CAstore", OPT_NOCAPATH, '-',
+ {"no-CAstore", OPT_NOCASTORE, '-',
"Do not load certificates from the default certificates store"},
{"requestCAfile", OPT_REQCAFILE, '<',
"PEM format file of CA names to send to the server"},
"Do not send the server name (SNI) extension in the ClientHello"},
{"tlsextdebug", OPT_TLSEXTDEBUG, '-',
"Hex dump of all TLS extensions received"},
+ {"ignore_unexpected_eof", OPT_IGNORE_UNEXPECTED_EOF, '-',
+ "Do not treat lack of close_notify from a peer as an error"},
#ifndef OPENSSL_NO_OCSP
{"status", OPT_STATUS, '-', "Request certificate status from server"},
#endif
{"verify_return_error", OPT_VERIFY_RET_ERROR, '-',
"Close connection on verification error"},
{"verify_quiet", OPT_VERIFY_QUIET, '-', "Restrict verify output to errors"},
- {"cert_chain", OPT_CERT_CHAIN, '<',
- "Certificate chain file (in PEM format)"},
+ {"chainCAfile", OPT_CHAINCAFILE, '<',
+ "CA file for certificate chain (PEM format)"},
{"chainCApath", OPT_CHAINCAPATH, '/',
"Use dir as certificate store path to build CA certificate chain"},
{"chainCAstore", OPT_CHAINCASTORE, ':',
"Use dir as certificate store path to verify CA certificate"},
{"verifyCAstore", OPT_VERIFYCASTORE, ':',
"CA store URI for certificate verification"},
- {"build_chain", OPT_BUILD_CHAIN, '-', "Build certificate chain"},
- {"chainCAfile", OPT_CHAINCAFILE, '<',
- "CA file for certificate chain (PEM format)"},
OPT_X_OPTIONS,
+ OPT_PROV_OPTIONS,
OPT_PARAMETERS(),
{"host:port", 0, 0, "Where to connect; same as -connect option"},
int prexit = 0;
int sdebug = 0;
int reconnect = 0, verify = SSL_VERIFY_NONE, vpmtouched = 0;
- int ret = 1, in_init = 1, i, nbio_test = 0, s = -1, k, width, state = 0;
+ int ret = 1, in_init = 1, i, nbio_test = 0, sock = -1, k, width, state = 0;
int sbuf_len, sbuf_off, cmdletters = 1;
int socket_family = AF_UNSPEC, socket_type = SOCK_STREAM, protocol = 0;
int starttls_proto = PROTO_OFF, crl_format = FORMAT_PEM, crl_download = 0;
#ifndef OPENSSL_NO_SCTP
int sctp_label_bug = 0;
#endif
+ int ignore_unexpected_eof = 0;
FD_ZERO(&readfds);
FD_ZERO(&writefds);
sess_in = opt_arg();
break;
case OPT_CERTFORM:
- if (!opt_format(opt_arg(), OPT_FMT_PEMDER, &cert_format))
+ if (!opt_format(opt_arg(), OPT_FMT_ANY, &cert_format))
goto opthelp;
break;
case OPT_CRLFORM:
if (!args_excert(o, &exc))
goto end;
break;
+ case OPT_IGNORE_UNEXPECTED_EOF:
+ ignore_unexpected_eof = 1;
+ break;
case OPT_PREXIT:
prexit = 1;
break;
if (!opt_rand(o))
goto end;
break;
+ case OPT_PROV_CASES:
+ if (!opt_provider(o))
+ goto end;
+ break;
case OPT_IGN_EOF:
c_ign_eof = 1;
break;
fallback_scsv = 1;
break;
case OPT_KEYFORM:
- if (!opt_format(opt_arg(), OPT_FMT_PDE, &key_format))
+ if (!opt_format(opt_arg(), OPT_FMT_ANY, &key_format))
goto opthelp;
break;
case OPT_PASS:
if (key_file != NULL) {
key = load_key(key_file, key_format, 0, pass, e,
"client certificate private key file");
- if (key == NULL) {
- ERR_print_errors(bio_err);
+ if (key == NULL)
goto end;
- }
}
if (cert_file != NULL) {
cert = load_cert(cert_file, cert_format, "client certificate file");
- if (cert == NULL) {
- ERR_print_errors(bio_err);
+ if (cert == NULL)
goto end;
- }
}
if (chain_file != NULL) {
if (crl_file != NULL) {
X509_CRL *crl;
- crl = load_crl(crl_file, crl_format);
- if (crl == NULL) {
- BIO_puts(bio_err, "Error loading CRL\n");
- ERR_print_errors(bio_err);
+ crl = load_crl(crl_file, crl_format, "CRL");
+ if (crl == NULL)
goto end;
- }
crls = sk_X509_CRL_new_null();
if (crls == NULL || !sk_X509_CRL_push(crls, crl)) {
BIO_puts(bio_err, "Error adding CRL\n");
&& SSL_CTX_set_max_proto_version(ctx, max_version) == 0)
goto end;
+ if (ignore_unexpected_eof)
+ SSL_CTX_set_options(ctx, SSL_OP_IGNORE_UNEXPECTED_EOF);
+
if (vpmtouched && !SSL_CTX_set1_param(ctx, vpm)) {
BIO_printf(bio_err, "Error setting verify params\n");
ERR_print_errors(bio_err);
}
re_start:
- if (init_client(&s, host, port, bindhost, bindport, socket_family,
+ if (init_client(&sock, 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);
+ BIO_closesocket(sock);
goto end;
}
- BIO_printf(bio_c_out, "CONNECTED(%08X)\n", s);
+ BIO_printf(bio_c_out, "CONNECTED(%08X)\n", sock);
if (c_nbio) {
- if (!BIO_socket_nbio(s, 1)) {
+ if (!BIO_socket_nbio(sock, 1)) {
ERR_print_errors(bio_err);
goto end;
}
#ifndef OPENSSL_NO_SCTP
if (protocol == IPPROTO_SCTP)
- sbio = BIO_new_dgram_sctp(s, BIO_NOCLOSE);
+ sbio = BIO_new_dgram_sctp(sock, BIO_NOCLOSE);
else
#endif
- sbio = BIO_new_dgram(s, BIO_NOCLOSE);
+ sbio = BIO_new_dgram(sock, BIO_NOCLOSE);
if ((peer_info.addr = BIO_ADDR_new()) == NULL) {
BIO_printf(bio_err, "memory allocation failure\n");
- BIO_closesocket(s);
+ BIO_closesocket(sock);
goto end;
}
- if (!BIO_sock_info(s, BIO_SOCK_INFO_ADDRESS, &peer_info)) {
+ if (!BIO_sock_info(sock, BIO_SOCK_INFO_ADDRESS, &peer_info)) {
BIO_printf(bio_err, "getsockname:errno=%d\n",
get_last_socket_error());
BIO_ADDR_free(peer_info.addr);
- BIO_closesocket(s);
+ BIO_closesocket(sock);
goto end;
}
}
} else
#endif /* OPENSSL_NO_DTLS */
- sbio = BIO_new_socket(s, BIO_NOCLOSE);
+ sbio = BIO_new_socket(sock, BIO_NOCLOSE);
if (nbio_test) {
BIO *test;
}
break;
case PROTO_CONNECT:
- {
- enum {
- error_proto, /* Wrong protocol, not even HTTP */
- error_connect, /* CONNECT failed */
- success
- } foundit = error_connect;
- BIO *fbio = BIO_new(BIO_f_buffer());
-
- BIO_push(fbio, sbio);
- 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,
- * it's formatted exactly like this:
- *
- * 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 "
- "from proxy\n", prog);
- foundit = error_proto;
- } else if (mbuf[9] != '2') {
- BIO_printf(bio_err, "%s: HTTP CONNECT failed: %s ", prog,
- &mbuf[9]);
- } else {
- foundit = success;
- }
- if (foundit != error_proto) {
- /* Read past all following headers */
- do {
- mbuf_len = BIO_gets(fbio, mbuf, BUFSIZZ);
- } while (mbuf_len > 2);
- }
- (void)BIO_flush(fbio);
- BIO_pop(fbio);
- BIO_free(fbio);
- if (foundit != success) {
- goto shut;
- }
- }
+ if (!OSSL_HTTP_proxy_connect(sbio, host, port, proxyuser, proxypass,
+ 0 /* no timeout */, bio_err, prog))
+ goto shut;
break;
case PROTO_IRC:
{
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
+ openssl_fdset(sock, &readfds);
+ } while (select(sock + 1, &readfds, NULL, NULL, &timeout) > 0
&& BIO_read(sbio, sbuf, BUFSIZZ) > 0);
BIO_closesocket(SSL_get_fd(con));
OPENSSL_clear_free(cbuf, BUFSIZZ);
OPENSSL_clear_free(sbuf, BUFSIZZ);
OPENSSL_clear_free(mbuf, BUFSIZZ);
- if (proxypass != NULL)
- OPENSSL_clear_free(proxypass, strlen(proxypass));
+ clear_free(proxypass);
release_engine(e);
BIO_free(bio_c_out);
bio_c_out = NULL;
X509 *peer = NULL;
STACK_OF(X509) *sk;
const SSL_CIPHER *c;
+ EVP_PKEY *public_key;
int i, istls13 = (SSL_version(s) == TLS1_3_VERSION);
long verify_result;
#ifndef OPENSSL_NO_COMP
BIO_printf(bio, " i:");
X509_NAME_print_ex(bio, X509_get_issuer_name(sk_X509_value(sk, i)), 0, get_nameopt());
BIO_puts(bio, "\n");
+ public_key = X509_get_pubkey(sk_X509_value(sk, i));
+ if (public_key != NULL) {
+ BIO_printf(bio, " a:PKEY: %s, %d (bit); sigalg: %s\n",
+ OBJ_nid2sn(EVP_PKEY_base_id(public_key)),
+ EVP_PKEY_bits(public_key),
+ OBJ_nid2sn(X509_get_signature_nid(sk_X509_value(sk, i))));
+ EVP_PKEY_free(public_key);
+ }
+ BIO_printf(bio, " v:NotBefore: ");
+ ASN1_TIME_print(bio, X509_get0_notBefore(sk_X509_value(sk, i)));
+ BIO_printf(bio, "; NotAfter: ");
+ ASN1_TIME_print(bio, X509_get0_notAfter(sk_X509_value(sk, i)));
+ BIO_puts(bio, "\n");
if (c_showcerts)
PEM_write_bio_X509(bio, sk_X509_value(sk, i));
}
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