|
|
cfec1a |
diff -up openssl-1.0.2k/apps/apps.c.starttls openssl-1.0.2k/apps/apps.c
|
|
|
cfec1a |
--- openssl-1.0.2k/apps/apps.c.starttls 2017-01-26 14:22:03.000000000 +0100
|
|
|
cfec1a |
+++ openssl-1.0.2k/apps/apps.c 2017-03-09 17:35:35.519765927 +0100
|
|
|
cfec1a |
@@ -3277,3 +3277,11 @@ int raw_write_stdout(const void *buf, in
|
|
|
cfec1a |
return write(fileno_stdout(), buf, siz);
|
|
|
cfec1a |
}
|
|
|
cfec1a |
#endif
|
|
|
cfec1a |
+
|
|
|
cfec1a |
+void make_uppercase(char *string)
|
|
|
cfec1a |
+{
|
|
|
cfec1a |
+ int i;
|
|
|
cfec1a |
+
|
|
|
cfec1a |
+ for (i = 0; string[i] != '\0'; i++)
|
|
|
cfec1a |
+ string[i] = toupper((unsigned char)string[i]);
|
|
|
cfec1a |
+}
|
|
|
cfec1a |
diff -up openssl-1.0.2k/apps/apps.h.starttls openssl-1.0.2k/apps/apps.h
|
|
|
cfec1a |
--- openssl-1.0.2k/apps/apps.h.starttls 2017-03-09 17:35:28.632604234 +0100
|
|
|
cfec1a |
+++ openssl-1.0.2k/apps/apps.h 2017-03-09 17:35:35.520765950 +0100
|
|
|
cfec1a |
@@ -384,6 +384,8 @@ int raw_write_stdout(const void *, int);
|
|
|
cfec1a |
# define TM_STOP 1
|
|
|
cfec1a |
double app_tminterval(int stop, int usertime);
|
|
|
cfec1a |
|
|
|
cfec1a |
+void make_uppercase(char *string);
|
|
|
cfec1a |
+
|
|
|
cfec1a |
# define OPENSSL_NO_SSL_INTERN
|
|
|
cfec1a |
|
|
|
cfec1a |
#endif
|
|
|
cfec1a |
diff -up openssl-1.0.2k/apps/s_client.c.starttls openssl-1.0.2k/apps/s_client.c
|
|
|
cfec1a |
--- openssl-1.0.2k/apps/s_client.c.starttls 2017-03-09 17:35:28.684605455 +0100
|
|
|
cfec1a |
+++ openssl-1.0.2k/apps/s_client.c 2017-03-09 17:52:59.153207946 +0100
|
|
|
cfec1a |
@@ -134,7 +134,8 @@
|
|
|
cfec1a |
* OTHER ENTITY BASED ON INFRINGEMENT OF INTELLECTUAL PROPERTY RIGHTS OR
|
|
|
cfec1a |
* OTHERWISE.
|
|
|
cfec1a |
*/
|
|
|
cfec1a |
-
|
|
|
cfec1a |
+/* for strcasestr */
|
|
|
cfec1a |
+#define _GNU_SOURCE
|
|
|
cfec1a |
#include <assert.h>
|
|
|
cfec1a |
#include <ctype.h>
|
|
|
cfec1a |
#include <stdio.h>
|
|
|
cfec1a |
@@ -202,6 +203,7 @@ static char *krb5svc = NULL;
|
|
|
cfec1a |
|
|
|
cfec1a |
#undef BUFSIZZ
|
|
|
cfec1a |
#define BUFSIZZ 1024*8
|
|
|
cfec1a |
+#define S_CLIENT_IRC_READ_TIMEOUT 8
|
|
|
cfec1a |
|
|
|
cfec1a |
extern int verify_depth;
|
|
|
cfec1a |
extern int verify_error;
|
|
|
cfec1a |
@@ -228,6 +230,7 @@ static void print_stuff(BIO *berr, SSL *
|
|
|
cfec1a |
#ifndef OPENSSL_NO_TLSEXT
|
|
|
cfec1a |
static int ocsp_resp_cb(SSL *s, void *arg);
|
|
|
cfec1a |
#endif
|
|
|
cfec1a |
+static int ldap_ExtendedResponse_parse(const char *buf, long rem);
|
|
|
cfec1a |
static BIO *bio_c_out = NULL;
|
|
|
cfec1a |
static BIO *bio_c_msg = NULL;
|
|
|
cfec1a |
static int c_quiet = 0;
|
|
|
cfec1a |
@@ -402,8 +405,14 @@ static void sc_usage(void)
|
|
|
cfec1a |
BIO_printf(bio_err,
|
|
|
cfec1a |
" 'prot' defines which one to assume. Currently,\n");
|
|
|
cfec1a |
BIO_printf(bio_err,
|
|
|
cfec1a |
- " only \"smtp\", \"pop3\", \"imap\", \"ftp\" and \"xmpp\"\n");
|
|
|
cfec1a |
- BIO_printf(bio_err, " are supported.\n");
|
|
|
cfec1a |
+ " only \"smtp\", \"pop3\", \"imap\", \"ftp\", \"xmpp\",\n");
|
|
|
cfec1a |
+ BIO_printf(bio_err,
|
|
|
cfec1a |
+ " \"xmpp-server\", \"irc\", \"postgres\", \"lmtp\", \"nntp\",\n");
|
|
|
cfec1a |
+ BIO_printf(bio_err, " \"sieve\" and \"ldap\" are supported.\n");
|
|
|
cfec1a |
+ BIO_printf(bio_err,
|
|
|
cfec1a |
+ " -xmpphost host - Host to use with \"-starttls xmpp[-server]\"\n");
|
|
|
cfec1a |
+ BIO_printf(bio_err,
|
|
|
cfec1a |
+ " -name host - Hostname to use for \"-starttls lmtp\" or \"-starttls smtp\"\n");
|
|
|
cfec1a |
#ifndef OPENSSL_NO_KRB5
|
|
|
cfec1a |
BIO_printf(bio_err, " -krb5svc arg - Kerberos service name\n");
|
|
|
cfec1a |
#endif
|
|
|
cfec1a |
@@ -657,7 +666,15 @@ enum {
|
|
|
cfec1a |
PROTO_POP3,
|
|
|
cfec1a |
PROTO_IMAP,
|
|
|
cfec1a |
PROTO_FTP,
|
|
|
cfec1a |
- PROTO_XMPP
|
|
|
cfec1a |
+ PROTO_TELNET,
|
|
|
cfec1a |
+ PROTO_XMPP,
|
|
|
cfec1a |
+ PROTO_XMPP_SERVER,
|
|
|
cfec1a |
+ PROTO_IRC,
|
|
|
cfec1a |
+ PROTO_POSTGRES,
|
|
|
cfec1a |
+ PROTO_LMTP,
|
|
|
cfec1a |
+ PROTO_NNTP,
|
|
|
cfec1a |
+ PROTO_SIEVE,
|
|
|
cfec1a |
+ PROTO_LDAP
|
|
|
cfec1a |
};
|
|
|
cfec1a |
|
|
|
cfec1a |
int MAIN(int, char **);
|
|
|
cfec1a |
@@ -726,6 +743,8 @@ int MAIN(int argc, char **argv)
|
|
|
cfec1a |
#endif
|
|
|
cfec1a |
char *sess_in = NULL;
|
|
|
cfec1a |
char *sess_out = NULL;
|
|
|
cfec1a |
+ char *xmpphost = NULL;
|
|
|
cfec1a |
+ const char *ehlo = "openssl.client.net";
|
|
|
cfec1a |
struct sockaddr peer;
|
|
|
cfec1a |
int peerlen = sizeof(peer);
|
|
|
cfec1a |
int fallback_scsv = 0;
|
|
|
cfec1a |
@@ -1097,8 +1116,32 @@ int MAIN(int argc, char **argv)
|
|
|
cfec1a |
starttls_proto = PROTO_FTP;
|
|
|
cfec1a |
else if (strcmp(*argv, "xmpp") == 0)
|
|
|
cfec1a |
starttls_proto = PROTO_XMPP;
|
|
|
cfec1a |
+ else if (strcmp(*argv, "xmpp-server") == 0)
|
|
|
cfec1a |
+ starttls_proto = PROTO_XMPP_SERVER;
|
|
|
cfec1a |
+ else if (strcmp(*argv, "telnet") == 0)
|
|
|
cfec1a |
+ starttls_proto = PROTO_TELNET;
|
|
|
cfec1a |
+ else if (strcmp(*argv, "irc") == 0)
|
|
|
cfec1a |
+ starttls_proto = PROTO_IRC;
|
|
|
cfec1a |
+ else if (strcmp(*argv, "postgres") == 0)
|
|
|
cfec1a |
+ starttls_proto = PROTO_POSTGRES;
|
|
|
cfec1a |
+ else if (strcmp(*argv, "lmtp") == 0)
|
|
|
cfec1a |
+ starttls_proto = PROTO_LMTP;
|
|
|
cfec1a |
+ else if (strcmp(*argv, "nntp") == 0)
|
|
|
cfec1a |
+ starttls_proto = PROTO_NNTP;
|
|
|
cfec1a |
+ else if (strcmp(*argv, "sieve") == 0)
|
|
|
cfec1a |
+ starttls_proto = PROTO_SIEVE;
|
|
|
cfec1a |
+ else if (strcmp(*argv, "ldap") == 0)
|
|
|
cfec1a |
+ starttls_proto = PROTO_LDAP;
|
|
|
cfec1a |
else
|
|
|
cfec1a |
goto bad;
|
|
|
cfec1a |
+ } else if (strcmp(*argv, "-xmpphost") == 0) {
|
|
|
cfec1a |
+ if (--argc < 1)
|
|
|
cfec1a |
+ goto bad;
|
|
|
cfec1a |
+ xmpphost = *(++argv);
|
|
|
cfec1a |
+ } else if (strcmp(*argv, "-name") == 0) {
|
|
|
cfec1a |
+ if (--argc < 1)
|
|
|
cfec1a |
+ goto bad;
|
|
|
cfec1a |
+ ehlo = *(++argv);
|
|
|
cfec1a |
}
|
|
|
cfec1a |
#ifndef OPENSSL_NO_ENGINE
|
|
|
cfec1a |
else if (strcmp(*argv, "-engine") == 0) {
|
|
|
cfec1a |
@@ -1599,19 +1642,24 @@ int MAIN(int argc, char **argv)
|
|
|
cfec1a |
* BIO into the chain that is removed again later on to not disturb the
|
|
|
cfec1a |
* rest of the s_client operation.
|
|
|
cfec1a |
*/
|
|
|
cfec1a |
- if (starttls_proto == PROTO_SMTP) {
|
|
|
cfec1a |
+ if (starttls_proto == PROTO_SMTP || starttls_proto == PROTO_LMTP) {
|
|
|
cfec1a |
int foundit = 0;
|
|
|
cfec1a |
BIO *fbio = BIO_new(BIO_f_buffer());
|
|
|
cfec1a |
BIO_push(fbio, sbio);
|
|
|
cfec1a |
- /* wait for multi-line response to end from SMTP */
|
|
|
cfec1a |
+ /* Wait for multi-line response to end from LMTP or SMTP */
|
|
|
cfec1a |
do {
|
|
|
cfec1a |
mbuf_len = BIO_gets(fbio, mbuf, BUFSIZZ);
|
|
|
cfec1a |
}
|
|
|
cfec1a |
while (mbuf_len > 3 && mbuf[3] == '-');
|
|
|
cfec1a |
- /* STARTTLS command requires EHLO... */
|
|
|
cfec1a |
- BIO_printf(fbio, "EHLO openssl.client.net\r\n");
|
|
|
cfec1a |
+ if (starttls_proto == PROTO_LMTP)
|
|
|
cfec1a |
+ BIO_printf(fbio, "LHLO %s\r\n", ehlo);
|
|
|
cfec1a |
+ else
|
|
|
cfec1a |
+ BIO_printf(fbio, "EHLO %s\r\n", ehlo);
|
|
|
cfec1a |
(void)BIO_flush(fbio);
|
|
|
cfec1a |
- /* wait for multi-line response to end EHLO SMTP response */
|
|
|
cfec1a |
+ /*
|
|
|
cfec1a |
+ * Wait for multi-line response to end LHLO LMTP or EHLO SMTP
|
|
|
cfec1a |
+ * response.
|
|
|
cfec1a |
+ */
|
|
|
cfec1a |
do {
|
|
|
cfec1a |
mbuf_len = BIO_gets(fbio, mbuf, BUFSIZZ);
|
|
|
cfec1a |
if (strstr(mbuf, "STARTTLS"))
|
|
|
cfec1a |
@@ -1630,10 +1678,15 @@ int MAIN(int argc, char **argv)
|
|
|
cfec1a |
} else if (starttls_proto == PROTO_POP3) {
|
|
|
cfec1a |
BIO_read(sbio, mbuf, BUFSIZZ);
|
|
|
cfec1a |
BIO_printf(sbio, "STLS\r\n");
|
|
|
cfec1a |
- BIO_read(sbio, sbuf, BUFSIZZ);
|
|
|
cfec1a |
+ mbuf_len = BIO_read(sbio, sbuf, BUFSIZZ);
|
|
|
cfec1a |
+ if (mbuf_len < 0) {
|
|
|
cfec1a |
+ BIO_printf(bio_err, "BIO_read failed\n");
|
|
|
cfec1a |
+ goto end;
|
|
|
cfec1a |
+ }
|
|
|
cfec1a |
} else if (starttls_proto == PROTO_IMAP) {
|
|
|
cfec1a |
int foundit = 0;
|
|
|
cfec1a |
BIO *fbio = BIO_new(BIO_f_buffer());
|
|
|
cfec1a |
+
|
|
|
cfec1a |
BIO_push(fbio, sbio);
|
|
|
cfec1a |
BIO_gets(fbio, mbuf, BUFSIZZ);
|
|
|
cfec1a |
/* STARTTLS command requires CAPABILITY... */
|
|
|
cfec1a |
@@ -1669,27 +1722,287 @@ int MAIN(int argc, char **argv)
|
|
|
cfec1a |
BIO_printf(sbio, "AUTH TLS\r\n");
|
|
|
cfec1a |
BIO_read(sbio, sbuf, BUFSIZZ);
|
|
|
cfec1a |
}
|
|
|
cfec1a |
- if (starttls_proto == PROTO_XMPP) {
|
|
|
cfec1a |
+ else if (starttls_proto == PROTO_XMPP || starttls_proto == PROTO_XMPP_SERVER) {
|
|
|
cfec1a |
int seen = 0;
|
|
|
cfec1a |
BIO_printf(sbio, "
|
|
|
cfec1a |
"xmlns:stream='http://etherx.jabber.org/streams' "
|
|
|
cfec1a |
- "xmlns='jabber:client' to='%s' version='1.0'>", host);
|
|
|
cfec1a |
+ "xmlns='jabber:%s' to='%s' version='1.0'>",
|
|
|
cfec1a |
+ starttls_proto == PROTO_XMPP ? "client" : "server",
|
|
|
cfec1a |
+ xmpphost ? xmpphost : host);
|
|
|
cfec1a |
seen = BIO_read(sbio, mbuf, BUFSIZZ);
|
|
|
cfec1a |
+ if (seen < 0) {
|
|
|
cfec1a |
+ BIO_printf(bio_err, "BIO_read failed\n");
|
|
|
cfec1a |
+ goto end;
|
|
|
cfec1a |
+ }
|
|
|
cfec1a |
mbuf[seen] = 0;
|
|
|
cfec1a |
- while (!strstr
|
|
|
cfec1a |
- (mbuf, "
|
|
|
cfec1a |
- if (strstr(mbuf, "/stream:features>"))
|
|
|
cfec1a |
- goto shut;
|
|
|
cfec1a |
+ while (!strcasestr
|
|
|
cfec1a |
+ (mbuf, "
|
|
|
cfec1a |
+ && !strcasestr(mbuf,
|
|
|
cfec1a |
+ "
|
|
|
cfec1a |
+ {
|
|
|
cfec1a |
seen = BIO_read(sbio, mbuf, BUFSIZZ);
|
|
|
cfec1a |
+
|
|
|
cfec1a |
+ if (seen <= 0)
|
|
|
cfec1a |
+ goto shut;
|
|
|
cfec1a |
+
|
|
|
cfec1a |
mbuf[seen] = 0;
|
|
|
cfec1a |
}
|
|
|
cfec1a |
BIO_printf(sbio,
|
|
|
cfec1a |
"<starttls xmlns='urn:ietf:params:xml:ns:xmpp-tls'/>");
|
|
|
cfec1a |
seen = BIO_read(sbio, sbuf, BUFSIZZ);
|
|
|
cfec1a |
+ if (seen < 0) {
|
|
|
cfec1a |
+ BIO_printf(bio_err, "BIO_read failed\n");
|
|
|
cfec1a |
+ goto shut;
|
|
|
cfec1a |
+ }
|
|
|
cfec1a |
sbuf[seen] = 0;
|
|
|
cfec1a |
if (!strstr(sbuf, "
|
|
|
cfec1a |
goto shut;
|
|
|
cfec1a |
mbuf[0] = 0;
|
|
|
cfec1a |
+ } else if (starttls_proto == PROTO_TELNET) {
|
|
|
cfec1a |
+ static const unsigned char tls_do[] = {
|
|
|
cfec1a |
+ /* IAC DO START_TLS */
|
|
|
cfec1a |
+ 255, 253, 46
|
|
|
cfec1a |
+ };
|
|
|
cfec1a |
+ static const unsigned char tls_will[] = {
|
|
|
cfec1a |
+ /* IAC WILL START_TLS */
|
|
|
cfec1a |
+ 255, 251, 46
|
|
|
cfec1a |
+ };
|
|
|
cfec1a |
+ static const unsigned char tls_follows[] = {
|
|
|
cfec1a |
+ /* IAC SB START_TLS FOLLOWS IAC SE */
|
|
|
cfec1a |
+ 255, 250, 46, 1, 255, 240
|
|
|
cfec1a |
+ };
|
|
|
cfec1a |
+ int bytes;
|
|
|
cfec1a |
+
|
|
|
cfec1a |
+ /* Telnet server should demand we issue START_TLS */
|
|
|
cfec1a |
+ bytes = BIO_read(sbio, mbuf, BUFSIZZ);
|
|
|
cfec1a |
+ if (bytes != 3 || memcmp(mbuf, tls_do, 3) != 0)
|
|
|
cfec1a |
+ goto shut;
|
|
|
cfec1a |
+ /* Agree to issue START_TLS and send the FOLLOWS sub-command */
|
|
|
cfec1a |
+ BIO_write(sbio, tls_will, 3);
|
|
|
cfec1a |
+ BIO_write(sbio, tls_follows, 6);
|
|
|
cfec1a |
+ (void)BIO_flush(sbio);
|
|
|
cfec1a |
+ /* Telnet server also sent the FOLLOWS sub-command */
|
|
|
cfec1a |
+ bytes = BIO_read(sbio, mbuf, BUFSIZZ);
|
|
|
cfec1a |
+ if (bytes != 6 || memcmp(mbuf, tls_follows, 6) != 0)
|
|
|
cfec1a |
+ goto shut;
|
|
|
cfec1a |
+ } else if (starttls_proto == PROTO_IRC) {
|
|
|
cfec1a |
+ int numeric;
|
|
|
cfec1a |
+ BIO *fbio = BIO_new(BIO_f_buffer());
|
|
|
cfec1a |
+
|
|
|
cfec1a |
+ BIO_push(fbio, sbio);
|
|
|
cfec1a |
+ BIO_printf(fbio, "STARTTLS\r\n");
|
|
|
cfec1a |
+ (void)BIO_flush(fbio);
|
|
|
cfec1a |
+ width = SSL_get_fd(con) + 1;
|
|
|
cfec1a |
+
|
|
|
cfec1a |
+ do {
|
|
|
cfec1a |
+ numeric = 0;
|
|
|
cfec1a |
+
|
|
|
cfec1a |
+ FD_ZERO(&readfds);
|
|
|
cfec1a |
+ openssl_fdset(SSL_get_fd(con), &readfds);
|
|
|
cfec1a |
+ timeout.tv_sec = S_CLIENT_IRC_READ_TIMEOUT;
|
|
|
cfec1a |
+ timeout.tv_usec = 0;
|
|
|
cfec1a |
+ /*
|
|
|
cfec1a |
+ * If the IRCd doesn't respond within
|
|
|
cfec1a |
+ * S_CLIENT_IRC_READ_TIMEOUT seconds, assume
|
|
|
cfec1a |
+ * it doesn't support STARTTLS. Many IRCds
|
|
|
cfec1a |
+ * will not give _any_ sort of response to a
|
|
|
cfec1a |
+ * STARTTLS command when it's not supported.
|
|
|
cfec1a |
+ */
|
|
|
cfec1a |
+ if (!BIO_get_buffer_num_lines(fbio)
|
|
|
cfec1a |
+ && !BIO_pending(fbio)
|
|
|
cfec1a |
+ && !BIO_pending(sbio)
|
|
|
cfec1a |
+ && select(width, (void *)&readfds, NULL, NULL,
|
|
|
cfec1a |
+ &timeout) < 1) {
|
|
|
cfec1a |
+ BIO_printf(bio_err,
|
|
|
cfec1a |
+ "Timeout waiting for response (%d seconds).\n",
|
|
|
cfec1a |
+ S_CLIENT_IRC_READ_TIMEOUT);
|
|
|
cfec1a |
+ break;
|
|
|
cfec1a |
+ }
|
|
|
cfec1a |
+
|
|
|
cfec1a |
+ mbuf_len = BIO_gets(fbio, mbuf, BUFSIZZ);
|
|
|
cfec1a |
+ if (mbuf_len < 1 || sscanf(mbuf, "%*s %d", &numeric) != 1)
|
|
|
cfec1a |
+ break;
|
|
|
cfec1a |
+ /* :example.net 451 STARTTLS :You have not registered */
|
|
|
cfec1a |
+ /* :example.net 421 STARTTLS :Unknown command */
|
|
|
cfec1a |
+ if ((numeric == 451 || numeric == 421)
|
|
|
cfec1a |
+ && strstr(mbuf, "STARTTLS") != NULL) {
|
|
|
cfec1a |
+ BIO_printf(bio_err, "STARTTLS not supported: %s", mbuf);
|
|
|
cfec1a |
+ break;
|
|
|
cfec1a |
+ }
|
|
|
cfec1a |
+ if (numeric == 691) {
|
|
|
cfec1a |
+ BIO_printf(bio_err, "STARTTLS negotiation failed: ");
|
|
|
cfec1a |
+ ERR_print_errors(bio_err);
|
|
|
cfec1a |
+ break;
|
|
|
cfec1a |
+ }
|
|
|
cfec1a |
+ } while (numeric != 670);
|
|
|
cfec1a |
+
|
|
|
cfec1a |
+ (void)BIO_flush(fbio);
|
|
|
cfec1a |
+ BIO_pop(fbio);
|
|
|
cfec1a |
+ BIO_free(fbio);
|
|
|
cfec1a |
+ if (numeric != 670) {
|
|
|
cfec1a |
+ BIO_printf(bio_err, "Server does not support STARTTLS.\n");
|
|
|
cfec1a |
+ ret = 1;
|
|
|
cfec1a |
+ goto shut;
|
|
|
cfec1a |
+ }
|
|
|
cfec1a |
+ } else if (starttls_proto == PROTO_POSTGRES) {
|
|
|
cfec1a |
+ static const unsigned char ssl_request[] = {
|
|
|
cfec1a |
+ /* Length SSLRequest */
|
|
|
cfec1a |
+ 0, 0, 0, 8, 4, 210, 22, 47
|
|
|
cfec1a |
+ };
|
|
|
cfec1a |
+ int bytes;
|
|
|
cfec1a |
+
|
|
|
cfec1a |
+ /* Send SSLRequest packet */
|
|
|
cfec1a |
+ BIO_write(sbio, ssl_request, 8);
|
|
|
cfec1a |
+ (void)BIO_flush(sbio);
|
|
|
cfec1a |
+
|
|
|
cfec1a |
+ /* Reply will be a single S if SSL is enabled */
|
|
|
cfec1a |
+ bytes = BIO_read(sbio, sbuf, BUFSIZZ);
|
|
|
cfec1a |
+ if (bytes != 1 || sbuf[0] != 'S')
|
|
|
cfec1a |
+ goto shut;
|
|
|
cfec1a |
+ } else if (starttls_proto == PROTO_NNTP) {
|
|
|
cfec1a |
+ int foundit = 0;
|
|
|
cfec1a |
+ BIO *fbio = BIO_new(BIO_f_buffer());
|
|
|
cfec1a |
+
|
|
|
cfec1a |
+ BIO_push(fbio, sbio);
|
|
|
cfec1a |
+ BIO_gets(fbio, mbuf, BUFSIZZ);
|
|
|
cfec1a |
+ /* STARTTLS command requires CAPABILITIES... */
|
|
|
cfec1a |
+ BIO_printf(fbio, "CAPABILITIES\r\n");
|
|
|
cfec1a |
+ (void)BIO_flush(fbio);
|
|
|
cfec1a |
+ /* wait for multi-line CAPABILITIES response */
|
|
|
cfec1a |
+ do {
|
|
|
cfec1a |
+ mbuf_len = BIO_gets(fbio, mbuf, BUFSIZZ);
|
|
|
cfec1a |
+ if (strstr(mbuf, "STARTTLS"))
|
|
|
cfec1a |
+ foundit = 1;
|
|
|
cfec1a |
+ } while (mbuf_len > 1 && mbuf[0] != '.');
|
|
|
cfec1a |
+ (void)BIO_flush(fbio);
|
|
|
cfec1a |
+ BIO_pop(fbio);
|
|
|
cfec1a |
+ BIO_free(fbio);
|
|
|
cfec1a |
+ if (!foundit)
|
|
|
cfec1a |
+ BIO_printf(bio_err,
|
|
|
cfec1a |
+ "Didn't find STARTTLS in server response,"
|
|
|
cfec1a |
+ " trying anyway...\n");
|
|
|
cfec1a |
+ BIO_printf(sbio, "STARTTLS\r\n");
|
|
|
cfec1a |
+ mbuf_len = BIO_read(sbio, mbuf, BUFSIZZ);
|
|
|
cfec1a |
+ if (mbuf_len < 0) {
|
|
|
cfec1a |
+ BIO_printf(bio_err, "BIO_read failed\n");
|
|
|
cfec1a |
+ goto end;
|
|
|
cfec1a |
+ }
|
|
|
cfec1a |
+ mbuf[mbuf_len] = '\0';
|
|
|
cfec1a |
+ if (strstr(mbuf, "382") == NULL) {
|
|
|
cfec1a |
+ BIO_printf(bio_err, "STARTTLS failed: %s", mbuf);
|
|
|
cfec1a |
+ goto shut;
|
|
|
cfec1a |
+ }
|
|
|
cfec1a |
+ } else if (starttls_proto == PROTO_SIEVE) {
|
|
|
cfec1a |
+ int foundit = 0;
|
|
|
cfec1a |
+ BIO *fbio = BIO_new(BIO_f_buffer());
|
|
|
cfec1a |
+
|
|
|
cfec1a |
+ BIO_push(fbio, sbio);
|
|
|
cfec1a |
+ /* wait for multi-line response to end from Sieve */
|
|
|
cfec1a |
+ do {
|
|
|
cfec1a |
+ mbuf_len = BIO_gets(fbio, mbuf, BUFSIZZ);
|
|
|
cfec1a |
+ /*
|
|
|
cfec1a |
+ * According to RFC 5804 ยง 1.7, capability
|
|
|
cfec1a |
+ * is case-insensitive, make it uppercase
|
|
|
cfec1a |
+ */
|
|
|
cfec1a |
+ if (mbuf_len > 1 && mbuf[0] == '"') {
|
|
|
cfec1a |
+ make_uppercase(mbuf);
|
|
|
cfec1a |
+ if (strncmp(mbuf, "\"STARTTLS\"", 10) == 0)
|
|
|
cfec1a |
+ foundit = 1;
|
|
|
cfec1a |
+ }
|
|
|
cfec1a |
+ } while (mbuf_len > 1 && mbuf[0] == '"');
|
|
|
cfec1a |
+ (void)BIO_flush(fbio);
|
|
|
cfec1a |
+ BIO_pop(fbio);
|
|
|
cfec1a |
+ BIO_free(fbio);
|
|
|
cfec1a |
+ if (!foundit)
|
|
|
cfec1a |
+ BIO_printf(bio_err,
|
|
|
cfec1a |
+ "Didn't find STARTTLS in server response,"
|
|
|
cfec1a |
+ " trying anyway...\n");
|
|
|
cfec1a |
+ BIO_printf(sbio, "STARTTLS\r\n");
|
|
|
cfec1a |
+ mbuf_len = BIO_read(sbio, mbuf, BUFSIZZ);
|
|
|
cfec1a |
+ if (mbuf_len < 0) {
|
|
|
cfec1a |
+ BIO_printf(bio_err, "BIO_read failed\n");
|
|
|
cfec1a |
+ goto end;
|
|
|
cfec1a |
+ }
|
|
|
cfec1a |
+ mbuf[mbuf_len] = '\0';
|
|
|
cfec1a |
+ if (mbuf_len < 2) {
|
|
|
cfec1a |
+ BIO_printf(bio_err, "STARTTLS failed: %s", mbuf);
|
|
|
cfec1a |
+ goto shut;
|
|
|
cfec1a |
+ }
|
|
|
cfec1a |
+ /*
|
|
|
cfec1a |
+ * According to RFC 5804 ยง 2.2, response codes are case-
|
|
|
cfec1a |
+ * insensitive, make it uppercase but preserve the response.
|
|
|
cfec1a |
+ */
|
|
|
cfec1a |
+ strncpy(sbuf, mbuf, 2);
|
|
|
cfec1a |
+ make_uppercase(sbuf);
|
|
|
cfec1a |
+ if (strncmp(sbuf, "OK", 2) != 0) {
|
|
|
cfec1a |
+ BIO_printf(bio_err, "STARTTLS not supported: %s", mbuf);
|
|
|
cfec1a |
+ goto shut;
|
|
|
cfec1a |
+ }
|
|
|
cfec1a |
+ } else if (starttls_proto == PROTO_LDAP) {
|
|
|
cfec1a |
+ /* StartTLS Operation according to RFC 4511 */
|
|
|
cfec1a |
+ static char ldap_tls_genconf[] = "asn1=SEQUENCE:LDAPMessage\n"
|
|
|
cfec1a |
+ "[LDAPMessage]\n"
|
|
|
cfec1a |
+ "messageID=INTEGER:1\n"
|
|
|
cfec1a |
+ "extendedReq=EXPLICIT:23A,IMPLICIT:0C,"
|
|
|
cfec1a |
+ "FORMAT:ASCII,OCT:1.3.6.1.4.1.1466.20037\n";
|
|
|
cfec1a |
+ long errline = -1;
|
|
|
cfec1a |
+ char *genstr = NULL;
|
|
|
cfec1a |
+ int result = -1;
|
|
|
cfec1a |
+ ASN1_TYPE *atyp = NULL;
|
|
|
cfec1a |
+ BIO *ldapbio = BIO_new(BIO_s_mem());
|
|
|
cfec1a |
+ CONF *cnf = NCONF_new(NULL);
|
|
|
cfec1a |
+
|
|
|
cfec1a |
+ if (cnf == NULL) {
|
|
|
cfec1a |
+ BIO_free(ldapbio);
|
|
|
cfec1a |
+ goto end;
|
|
|
cfec1a |
+ }
|
|
|
cfec1a |
+ BIO_puts(ldapbio, ldap_tls_genconf);
|
|
|
cfec1a |
+ if (NCONF_load_bio(cnf, ldapbio, &errline) <= 0) {
|
|
|
cfec1a |
+ BIO_free(ldapbio);
|
|
|
cfec1a |
+ NCONF_free(cnf);
|
|
|
cfec1a |
+ if (errline <= 0) {
|
|
|
cfec1a |
+ BIO_printf(bio_err, "NCONF_load_bio failed\n");
|
|
|
cfec1a |
+ goto end;
|
|
|
cfec1a |
+ } else {
|
|
|
cfec1a |
+ BIO_printf(bio_err, "Error on line %ld\n", errline);
|
|
|
cfec1a |
+ goto end;
|
|
|
cfec1a |
+ }
|
|
|
cfec1a |
+ }
|
|
|
cfec1a |
+ BIO_free(ldapbio);
|
|
|
cfec1a |
+ genstr = NCONF_get_string(cnf, "default", "asn1");
|
|
|
cfec1a |
+ if (genstr == NULL) {
|
|
|
cfec1a |
+ NCONF_free(cnf);
|
|
|
cfec1a |
+ BIO_printf(bio_err, "NCONF_get_string failed\n");
|
|
|
cfec1a |
+ goto end;
|
|
|
cfec1a |
+ }
|
|
|
cfec1a |
+ atyp = ASN1_generate_nconf(genstr, cnf);
|
|
|
cfec1a |
+ if (atyp == NULL) {
|
|
|
cfec1a |
+ NCONF_free(cnf);
|
|
|
cfec1a |
+ BIO_printf(bio_err, "ASN1_generate_nconf failed\n");
|
|
|
cfec1a |
+ goto end;
|
|
|
cfec1a |
+ }
|
|
|
cfec1a |
+ NCONF_free(cnf);
|
|
|
cfec1a |
+ /* Send SSLRequest packet */
|
|
|
cfec1a |
+ BIO_write(sbio, atyp->value.sequence->data,
|
|
|
cfec1a |
+ atyp->value.sequence->length);
|
|
|
cfec1a |
+ (void)BIO_flush(sbio);
|
|
|
cfec1a |
+ ASN1_TYPE_free(atyp);
|
|
|
cfec1a |
+
|
|
|
cfec1a |
+ mbuf_len = BIO_read(sbio, mbuf, BUFSIZZ);
|
|
|
cfec1a |
+ if (mbuf_len < 0) {
|
|
|
cfec1a |
+ BIO_printf(bio_err, "BIO_read failed\n");
|
|
|
cfec1a |
+ goto end;
|
|
|
cfec1a |
+ }
|
|
|
cfec1a |
+ result = ldap_ExtendedResponse_parse(mbuf, mbuf_len);
|
|
|
cfec1a |
+ if (result < 0) {
|
|
|
cfec1a |
+ BIO_printf(bio_err, "ldap_ExtendedResponse_parse failed\n");
|
|
|
cfec1a |
+ goto shut;
|
|
|
cfec1a |
+ } else if (result > 0) {
|
|
|
cfec1a |
+ BIO_printf(bio_err, "STARTTLS failed, LDAP Result Code: %i\n",
|
|
|
cfec1a |
+ result);
|
|
|
cfec1a |
+ goto shut;
|
|
|
cfec1a |
+ }
|
|
|
cfec1a |
+ mbuf_len = 0;
|
|
|
cfec1a |
}
|
|
|
cfec1a |
|
|
|
cfec1a |
for (;;) {
|
|
|
cfec1a |
@@ -1738,7 +2051,7 @@ int MAIN(int argc, char **argv)
|
|
|
cfec1a |
full_log--;
|
|
|
cfec1a |
|
|
|
cfec1a |
if (starttls_proto) {
|
|
|
cfec1a |
- BIO_printf(bio_err, "%s", mbuf);
|
|
|
cfec1a |
+ BIO_write(bio_err, mbuf, mbuf_len);
|
|
|
cfec1a |
/* We don't need to know any more */
|
|
|
cfec1a |
starttls_proto = PROTO_OFF;
|
|
|
cfec1a |
}
|
|
|
cfec1a |
@@ -2372,3 +2685,87 @@ static int ocsp_resp_cb(SSL *s, void *ar
|
|
|
cfec1a |
}
|
|
|
cfec1a |
|
|
|
cfec1a |
#endif
|
|
|
cfec1a |
+
|
|
|
cfec1a |
+static int ldap_ExtendedResponse_parse(const char *buf, long rem)
|
|
|
cfec1a |
+{
|
|
|
cfec1a |
+ const unsigned char *cur, *end;
|
|
|
cfec1a |
+ long len;
|
|
|
cfec1a |
+ int tag, xclass, inf, ret = -1;
|
|
|
cfec1a |
+
|
|
|
cfec1a |
+ cur = (const unsigned char *)buf;
|
|
|
cfec1a |
+ end = cur + rem;
|
|
|
cfec1a |
+
|
|
|
cfec1a |
+ /*
|
|
|
cfec1a |
+ * From RFC 4511:
|
|
|
cfec1a |
+ *
|
|
|
cfec1a |
+ * LDAPMessage ::= SEQUENCE {
|
|
|
cfec1a |
+ * messageID MessageID,
|
|
|
cfec1a |
+ * protocolOp CHOICE {
|
|
|
cfec1a |
+ * ...
|
|
|
cfec1a |
+ * extendedResp ExtendedResponse,
|
|
|
cfec1a |
+ * ... },
|
|
|
cfec1a |
+ * controls [0] Controls OPTIONAL }
|
|
|
cfec1a |
+ *
|
|
|
cfec1a |
+ * ExtendedResponse ::= [APPLICATION 24] SEQUENCE {
|
|
|
cfec1a |
+ * COMPONENTS OF LDAPResult,
|
|
|
cfec1a |
+ * responseName [10] LDAPOID OPTIONAL,
|
|
|
cfec1a |
+ * responseValue [11] OCTET STRING OPTIONAL }
|
|
|
cfec1a |
+ *
|
|
|
cfec1a |
+ * LDAPResult ::= SEQUENCE {
|
|
|
cfec1a |
+ * resultCode ENUMERATED {
|
|
|
cfec1a |
+ * success (0),
|
|
|
cfec1a |
+ * ...
|
|
|
cfec1a |
+ * other (80),
|
|
|
cfec1a |
+ * ... },
|
|
|
cfec1a |
+ * matchedDN LDAPDN,
|
|
|
cfec1a |
+ * diagnosticMessage LDAPString,
|
|
|
cfec1a |
+ * referral [3] Referral OPTIONAL }
|
|
|
cfec1a |
+ */
|
|
|
cfec1a |
+
|
|
|
cfec1a |
+ /* pull SEQUENCE */
|
|
|
cfec1a |
+ inf = ASN1_get_object(&cur, &len, &tag, &xclass, rem);
|
|
|
cfec1a |
+ if (inf != V_ASN1_CONSTRUCTED || tag != V_ASN1_SEQUENCE ||
|
|
|
cfec1a |
+ (rem = end - cur, len > rem)) {
|
|
|
cfec1a |
+ BIO_printf(bio_err, "Unexpected LDAP response\n");
|
|
|
cfec1a |
+ goto end;
|
|
|
cfec1a |
+ }
|
|
|
cfec1a |
+
|
|
|
cfec1a |
+ rem = len; /* ensure that we don't overstep the SEQUENCE */
|
|
|
cfec1a |
+
|
|
|
cfec1a |
+ /* pull MessageID */
|
|
|
cfec1a |
+ inf = ASN1_get_object(&cur, &len, &tag, &xclass, rem);
|
|
|
cfec1a |
+ if (inf != V_ASN1_UNIVERSAL || tag != V_ASN1_INTEGER ||
|
|
|
cfec1a |
+ (rem = end - cur, len > rem)) {
|
|
|
cfec1a |
+ BIO_printf(bio_err, "No MessageID\n");
|
|
|
cfec1a |
+ goto end;
|
|
|
cfec1a |
+ }
|
|
|
cfec1a |
+
|
|
|
cfec1a |
+ cur += len; /* shall we check for MessageId match or just skip? */
|
|
|
cfec1a |
+
|
|
|
cfec1a |
+ /* pull [APPLICATION 24] */
|
|
|
cfec1a |
+ rem = end - cur;
|
|
|
cfec1a |
+ inf = ASN1_get_object(&cur, &len, &tag, &xclass, rem);
|
|
|
cfec1a |
+ if (inf != V_ASN1_CONSTRUCTED || xclass != V_ASN1_APPLICATION ||
|
|
|
cfec1a |
+ tag != 24) {
|
|
|
cfec1a |
+ BIO_printf(bio_err, "Not ExtendedResponse\n");
|
|
|
cfec1a |
+ goto end;
|
|
|
cfec1a |
+ }
|
|
|
cfec1a |
+
|
|
|
cfec1a |
+ /* pull resultCode */
|
|
|
cfec1a |
+ rem = end - cur;
|
|
|
cfec1a |
+ inf = ASN1_get_object(&cur, &len, &tag, &xclass, rem);
|
|
|
cfec1a |
+ if (inf != V_ASN1_UNIVERSAL || tag != V_ASN1_ENUMERATED || len == 0 ||
|
|
|
cfec1a |
+ (rem = end - cur, len > rem)) {
|
|
|
cfec1a |
+ BIO_printf(bio_err, "Not LDAPResult\n");
|
|
|
cfec1a |
+ goto end;
|
|
|
cfec1a |
+ }
|
|
|
cfec1a |
+
|
|
|
cfec1a |
+ /* len should always be one, but just in case... */
|
|
|
cfec1a |
+ for (ret = 0, inf = 0; inf < len; inf++) {
|
|
|
cfec1a |
+ ret <<= 8;
|
|
|
cfec1a |
+ ret |= cur[inf];
|
|
|
cfec1a |
+ }
|
|
|
cfec1a |
+ /* There is more data, but we don't care... */
|
|
|
cfec1a |
+ end:
|
|
|
cfec1a |
+ return ret;
|
|
|
cfec1a |
+}
|
|
|
cfec1a |
diff -up openssl-1.0.2k/doc/apps/s_client.pod.starttls openssl-1.0.2k/doc/apps/s_client.pod
|
|
|
cfec1a |
--- openssl-1.0.2k/doc/apps/s_client.pod.starttls 2017-03-09 17:35:28.684605455 +0100
|
|
|
cfec1a |
+++ openssl-1.0.2k/doc/apps/s_client.pod 2017-03-09 17:42:54.455070967 +0100
|
|
|
cfec1a |
@@ -46,6 +46,8 @@ B<openssl> B<s_client>
|
|
|
cfec1a |
[B<-krb5svc service>]
|
|
|
cfec1a |
[B<-serverpref>]
|
|
|
cfec1a |
[B<-starttls protocol>]
|
|
|
cfec1a |
+[B<-xmpphost hostname>]
|
|
|
cfec1a |
+[B<-name hostname>]
|
|
|
cfec1a |
[B<-engine id>]
|
|
|
cfec1a |
[B<-tlsextdebug>]
|
|
|
cfec1a |
[B<-no_ticket>]
|
|
|
cfec1a |
@@ -239,7 +241,20 @@ need keys for that principal in its keyt
|
|
|
cfec1a |
|
|
|
cfec1a |
send the protocol-specific message(s) to switch to TLS for communication.
|
|
|
cfec1a |
B<protocol> is a keyword for the intended protocol. Currently, the only
|
|
|
cfec1a |
-supported keywords are "smtp", "pop3", "imap", and "ftp".
|
|
|
cfec1a |
+supported keywords are "smtp", "pop3", "imap", "ftp", "xmpp", "xmpp-server",
|
|
|
cfec1a |
+"irc", "postgres", "lmtp", "nntp", "sieve" and "ldap".
|
|
|
cfec1a |
+
|
|
|
cfec1a |
+=item B<-xmpphost hostname>
|
|
|
cfec1a |
+
|
|
|
cfec1a |
+This option, when used with "-starttls xmpp" or "-starttls xmpp-server",
|
|
|
cfec1a |
+specifies the host for the "to" attribute of the stream element.
|
|
|
cfec1a |
+If this option is not specified, then the host specified with "-connect"
|
|
|
cfec1a |
+will be used.
|
|
|
cfec1a |
+
|
|
|
cfec1a |
+=item B<-name hostname>
|
|
|
cfec1a |
+
|
|
|
cfec1a |
+the host name to use with "-starttls smtp".
|
|
|
cfec1a |
+If this option is not specified, the default "openssl.client.net" will be used.
|
|
|
cfec1a |
|
|
|
cfec1a |
=item B<-tlsextdebug>
|
|
|
cfec1a |
|