aboutsummaryrefslogblamecommitdiffstats
path: root/main/libressl/starttls-ldap.patch
blob: 3ee44d87fdb7352d26b4384a06d526c483949f0a (plain) (tree)
1
2
3
4
5
6
7
8
9
10
11

                             








                                                                        
















                                                                                                                              
                   








                   
                   







                                                            
                    







































































                                                                                      
                      





















































































                                                                              
--- a/apps/openssl/s_client.c
+++ b/apps/openssl/s_client.c
@@ -56,7 +56,7 @@
  * [including the GNU Public Licence.]
  */
 /* ====================================================================
- * Copyright (c) 1998-2006 The OpenSSL Project.  All rights reserved.
+ * Copyright (c) 1998-2017 The OpenSSL Project.  All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions
@@ -184,6 +184,7 @@
 static void sc_usage(void);
 static void print_stuff(BIO * berr, SSL * con, int full);
 static int ocsp_resp_cb(SSL * s, void *arg);
+static int ldap_ExtendedResponse_parse(const char *buf, long rem);
 static BIO *bio_c_out = NULL;
 static int c_quiet = 0;
 static int c_ign_eof = 0;
@@ -234,7 +235,7 @@
 	BIO_printf(bio_err, " -starttls prot - use the STARTTLS command before starting TLS\n");
 	BIO_printf(bio_err, "                 for those protocols that support it, where\n");
 	BIO_printf(bio_err, "                 'prot' defines which one to assume.  Currently,\n");
-	BIO_printf(bio_err, "                 only \"smtp\", \"lmtp\", \"pop3\", \"imap\", \"ftp\" and \"xmpp\"\n");
+	BIO_printf(bio_err, "                 only \"smtp\", \"lmtp\", \"pop3\", \"imap\", \"ftp\", \"xmpp\" and \"ldap\"\n");
 	BIO_printf(bio_err, "                 are supported.\n");
 	BIO_printf(bio_err, " -xmpphost host - connect to this virtual host on the xmpp server\n");
 	BIO_printf(bio_err, " -sess_out arg - file to write SSL session to\n");
@@ -284,7 +285,8 @@
 	PROTO_POP3,
 	PROTO_IMAP,
 	PROTO_FTP,
-	PROTO_XMPP
+	PROTO_XMPP,
+	PROTO_LDAP
 };
 
 int
@@ -543,6 +545,8 @@
 				starttls_proto = PROTO_FTP;
 			else if (strcmp(*argv, "xmpp") == 0)
 				starttls_proto = PROTO_XMPP;
+			else if (strcmp(*argv, "ldap") == 0)
+				starttls_proto = PROTO_LDAP;
 			else
 				goto bad;
 		}
@@ -934,6 +938,72 @@
 		if (!strstr(sbuf, "<proceed"))
 			goto shut;
 		mbuf[0] = 0;
+	} else if (starttls_proto == PROTO_LDAP) {
+		/* StartTLS Operation according to RFC 4511 */
+		static char ldap_tls_genconf[] = "asn1=SEQUENCE:LDAPMessage\n"
+			"[LDAPMessage]\n"
+			"messageID=INTEGER:1\n"
+			"extendedReq=EXPLICIT:23A,IMPLICIT:0C,"
+			"FORMAT:ASCII,OCT:1.3.6.1.4.1.1466.20037\n";
+		long errline = -1;
+		char *genstr = NULL;
+		int result = -1;
+		ASN1_TYPE *atyp = NULL;
+		BIO *ldapbio = BIO_new(BIO_s_mem());
+		CONF *cnf = NCONF_new(NULL);
+
+		if (cnf == NULL) {
+			BIO_free(ldapbio);
+			goto end;
+		}
+		BIO_puts(ldapbio, ldap_tls_genconf);
+		if (NCONF_load_bio(cnf, ldapbio, &errline) <= 0) {
+			BIO_free(ldapbio);
+			NCONF_free(cnf);
+			if (errline <= 0) {
+				BIO_printf(bio_err, "NCONF_load_bio failed\n");
+				goto end;
+			} else {
+				BIO_printf(bio_err, "Error on line %ld\n", errline);
+				goto end;
+			}
+		}
+		BIO_free(ldapbio);
+		genstr = NCONF_get_string(cnf, "default", "asn1");
+		if (genstr == NULL) {
+			NCONF_free(cnf);
+			BIO_printf(bio_err, "NCONF_get_string failed\n");
+			goto end;
+		}
+		atyp = ASN1_generate_nconf(genstr, cnf);
+		if (atyp == NULL) {
+			NCONF_free(cnf);
+			BIO_printf(bio_err, "ASN1_generate_nconf failed\n");
+			goto end;
+		}
+		NCONF_free(cnf);
+
+		/* Send SSLRequest packet */
+		BIO_write(sbio, atyp->value.sequence->data,
+				  atyp->value.sequence->length);
+		(void)BIO_flush(sbio);
+		ASN1_TYPE_free(atyp);
+
+		mbuf_len = BIO_read(sbio, mbuf, BUFSIZZ);
+		if (mbuf_len < 0) {
+			BIO_printf(bio_err, "BIO_read failed\n");
+			goto end;
+		}
+		result = ldap_ExtendedResponse_parse(mbuf, mbuf_len);
+		if (result < 0) {
+			BIO_printf(bio_err, "ldap_ExtendedResponse_parse failed\n");
+			goto shut;
+		} else if (result > 0) {
+			BIO_printf(bio_err, "STARTTLS failed, LDAP Result Code: %i\n",
+			           result);
+			goto shut;
+		}
+		mbuf_len = 0;
 	} else if (proxy != NULL) {
 		BIO_printf(sbio, "CONNECT %s HTTP/1.0\r\n\r\n", connect);
 		mbuf_len = BIO_read(sbio, mbuf, BUFSIZZ);
@@ -1437,3 +1507,86 @@
 	return 1;
 }
 
+static int ldap_ExtendedResponse_parse(const char *buf, long rem)
+{
+	const unsigned char *cur, *end;
+	long len;
+	int tag, xclass, inf, ret = -1;
+
+	cur = (const unsigned char *)buf;
+	end = cur + rem;
+
+	/*
+	 * From RFC 4511:
+	 *
+	 *    LDAPMessage ::= SEQUENCE {
+	 *         messageID       MessageID,
+	 *         protocolOp      CHOICE {
+	 *              ...
+	 *              extendedResp          ExtendedResponse,
+	 *              ... },
+	 *         controls       [0] Controls OPTIONAL }
+	 *
+	 *    ExtendedResponse ::= [APPLICATION 24] SEQUENCE {
+	 *         COMPONENTS OF LDAPResult,
+	 *         responseName     [10] LDAPOID OPTIONAL,
+	 *         responseValue    [11] OCTET STRING OPTIONAL }
+	 *
+	 *    LDAPResult ::= SEQUENCE {
+	 *         resultCode         ENUMERATED {
+	 *              success                      (0),
+	 *              ...
+	 *              other                        (80),
+	 *              ...  },
+	 *         matchedDN          LDAPDN,
+	 *         diagnosticMessage  LDAPString,
+	 *         referral           [3] Referral OPTIONAL }
+	 */
+
+	/* pull SEQUENCE */
+	inf = ASN1_get_object(&cur, &len, &tag, &xclass, rem);
+	if (inf != V_ASN1_CONSTRUCTED || tag != V_ASN1_SEQUENCE ||
+		(rem = end - cur, len > rem)) {
+		BIO_printf(bio_err, "Unexpected LDAP response\n");
+		goto end;
+	}
+
+	rem = len;  /* ensure that we don't overstep the SEQUENCE */
+
+	/* pull MessageID */
+	inf = ASN1_get_object(&cur, &len, &tag, &xclass, rem);
+	if (inf != V_ASN1_UNIVERSAL || tag != V_ASN1_INTEGER ||
+		(rem = end - cur, len > rem)) {
+		BIO_printf(bio_err, "No MessageID\n");
+		goto end;
+	}
+
+	cur += len; /* shall we check for MessageId match or just skip? */
+
+	/* pull [APPLICATION 24] */
+	rem = end - cur;
+	inf = ASN1_get_object(&cur, &len, &tag, &xclass, rem);
+	if (inf != V_ASN1_CONSTRUCTED || xclass != V_ASN1_APPLICATION ||
+		tag != 24) {
+		BIO_printf(bio_err, "Not ExtendedResponse\n");
+		goto end;
+	}
+
+	/* pull resultCode */
+	rem = end - cur;
+	inf = ASN1_get_object(&cur, &len, &tag, &xclass, rem);
+	if (inf != V_ASN1_UNIVERSAL || tag != V_ASN1_ENUMERATED || len == 0 ||
+		(rem = end - cur, len > rem)) {
+		BIO_printf(bio_err, "Not LDAPResult\n");
+		goto end;
+	}
+
+	/* len should always be one, but just in case... */
+	for (ret = 0, inf = 0; inf < len; inf++) {
+		ret <<= 8;
+		ret |= cur[inf];
+	}
+	/* There is more data, but we don't care... */
+    end:
+	return ret;
+}