Add LDAP support (RFC 4511) to s_client ("-starttls ldap")
Based on initial patch by Alex Bergmann <alex@linlab.net> and new function ldap_ExtendedResponse_parse() by Andy Polyakov <appro@openssl.org>. Thanks very much to both. Reviewed-by: Rich Salz <rsalz@openssl.org> Reviewed-by: Andy Polyakov <appro@openssl.org> (Merged from https://github.com/openssl/openssl/pull/2293)
This commit is contained in:
parent
8cfc21f53a
commit
398b0bbdf7
2 changed files with 156 additions and 2 deletions
156
apps/s_client.c
156
apps/s_client.c
|
@ -96,6 +96,7 @@ static void print_stuff(BIO *berr, SSL *con, int full);
|
|||
#ifndef OPENSSL_NO_OCSP
|
||||
static int ocsp_resp_cb(SSL *s, void *arg);
|
||||
#endif
|
||||
static int ldap_ExtendedResponse_parse(const char *buf, long rem);
|
||||
|
||||
static int saved_errno;
|
||||
|
||||
|
@ -748,7 +749,8 @@ typedef enum PROTOCOL_choice {
|
|||
PROTO_POSTGRES,
|
||||
PROTO_LMTP,
|
||||
PROTO_NNTP,
|
||||
PROTO_SIEVE
|
||||
PROTO_SIEVE,
|
||||
PROTO_LDAP
|
||||
} PROTOCOL_CHOICE;
|
||||
|
||||
static const OPT_PAIR services[] = {
|
||||
|
@ -764,6 +766,7 @@ static const OPT_PAIR services[] = {
|
|||
{"lmtp", PROTO_LMTP},
|
||||
{"nntp", PROTO_NNTP},
|
||||
{"sieve", PROTO_SIEVE},
|
||||
{"ldap", PROTO_LDAP},
|
||||
{NULL, 0}
|
||||
};
|
||||
|
||||
|
@ -2281,6 +2284,75 @@ int s_client_main(int argc, char **argv)
|
|||
}
|
||||
}
|
||||
break;
|
||||
case 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;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
for (;;) {
|
||||
|
@ -2920,4 +2992,86 @@ static int ocsp_resp_cb(SSL *s, void *arg)
|
|||
}
|
||||
# endif
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
/* 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;
|
||||
}
|
||||
|
||||
#endif /* OPENSSL_NO_SOCK */
|
||||
|
|
|
@ -445,7 +445,7 @@ command for more information.
|
|||
send the protocol-specific message(s) to switch to TLS for communication.
|
||||
B<protocol> is a keyword for the intended protocol. Currently, the only
|
||||
supported keywords are "smtp", "pop3", "imap", "ftp", "xmpp", "xmpp-server",
|
||||
"irc", "postgres", "lmtp", "nntp" and "sieve".
|
||||
"irc", "postgres", "lmtp", "nntp", "sieve" and "ldap".
|
||||
|
||||
=item B<-xmpphost hostname>
|
||||
|
||||
|
|
Loading…
Reference in a new issue