NOTE: The patch has been adjusted to match the base code before backporting. From 16f8b0902c28b1eaab93ddf120ce40b89bcda8d1 Mon Sep 17 00:00:00 2001 From: Howard Chu Date: Tue, 10 Sep 2013 04:26:51 -0700 Subject: [PATCH] ITS#7398 add LDAP_OPT_X_TLS_PEERCERT retrieve peer cert for an active TLS session --- doc/man/man3/ldap_get_option.3 | 8 ++++++++ include/ldap.h | 1 + libraries/libldap/ldap-tls.h | 2 ++ libraries/libldap/tls2.c | 23 +++++++++++++++++++++++ libraries/libldap/tls_g.c | 19 +++++++++++++++++++ libraries/libldap/tls_m.c | 17 +++++++++++++++++ libraries/libldap/tls_o.c | 16 ++++++++++++++++ 7 files changed, 86 insertions(+) diff --git a/doc/man/man3/ldap_get_option.3 b/doc/man/man3/ldap_get_option.3 index e67de75e9..1bb55d357 100644 --- a/doc/man/man3/ldap_get_option.3 +++ b/doc/man/man3/ldap_get_option.3 @@ -732,6 +732,14 @@ A non-zero value pointed to by .BR invalue tells the library to create a context for a server. .TP +.B LDAP_OPT_X_TLS_PEERCERT +Gets the peer's certificate in DER format from an established TLS session. +.BR outvalue +must be +.BR "struct berval *" , +and the data it returns needs to be freed by the caller using +.BR ldap_memfree (3). +.TP .B LDAP_OPT_X_TLS_PROTOCOL_MIN Sets/gets the minimum protocol version. .BR invalue diff --git a/include/ldap.h b/include/ldap.h index 4de3f7f32..97ca524d7 100644 --- a/include/ldap.h +++ b/include/ldap.h @@ -161,6 +161,7 @@ LDAP_BEGIN_DECL #define LDAP_OPT_X_TLS_CRLFILE 0x6010 /* GNUtls only */ #define LDAP_OPT_X_TLS_PACKAGE 0x6011 #define LDAP_OPT_X_TLS_ECNAME 0x6012 +#define LDAP_OPT_X_TLS_PEERCERT 0x6015 /* read-only */ #define LDAP_OPT_X_TLS_NEVER 0 #define LDAP_OPT_X_TLS_HARD 1 diff --git a/libraries/libldap/ldap-tls.h b/libraries/libldap/ldap-tls.h index 548814d7f..890d20dc7 100644 --- a/libraries/libldap/ldap-tls.h +++ b/libraries/libldap/ldap-tls.h @@ -43,6 +43,7 @@ typedef int (TI_session_dn)(tls_session *sess, struct berval *dn); typedef int (TI_session_chkhost)(LDAP *ld, tls_session *s, const char *name_in); typedef int (TI_session_strength)(tls_session *sess); typedef int (TI_session_unique)(tls_session *sess, struct berval *buf, int is_server); +typedef int (TI_session_peercert)(tls_session *s, struct berval *der); typedef void (TI_thr_init)(void); @@ -69,6 +70,7 @@ typedef struct tls_impl { TI_session_chkhost *ti_session_chkhost; TI_session_strength *ti_session_strength; TI_session_unique *ti_session_unique; + TI_session_peercert *ti_session_peercert; Sockbuf_IO *ti_sbio; diff --git a/libraries/libldap/tls2.c b/libraries/libldap/tls2.c index 05fce3218..cbf73bdd5 100644 --- a/libraries/libldap/tls2.c +++ b/libraries/libldap/tls2.c @@ -718,6 +718,23 @@ ldap_pvt_tls_get_option( LDAP *ld, int option, void *arg ) case LDAP_OPT_X_TLS_CONNECT_ARG: *(void **)arg = lo->ldo_tls_connect_arg; break; + case LDAP_OPT_X_TLS_PEERCERT: { + void *sess = NULL; + struct berval *bv = arg; + bv->bv_len = 0; + bv->bv_val = NULL; + if ( ld != NULL ) { + LDAPConn *conn = ld->ld_defconn; + if ( conn != NULL ) { + Sockbuf *sb = conn->lconn_sb; + sess = ldap_pvt_tls_sb_ctx( sb ); + if ( sess != NULL ) + return ldap_pvt_tls_get_peercert( sess, bv ); + } + } + break; + } + default: return -1; } @@ -1050,6 +1066,13 @@ ldap_pvt_tls_get_unique( void *s, struct berval *buf, int is_server ) tls_session *session = s; return tls_imp->ti_session_unique( session, buf, is_server ); } + +int +ldap_pvt_tls_get_peercert( void *s, struct berval *der ) +{ + tls_session *session = s; + return tls_imp->ti_session_peercert( session, der ); +} #endif /* HAVE_TLS */ int diff --git a/libraries/libldap/tls_g.c b/libraries/libldap/tls_g.c index ce422387c..739680439 100644 --- a/libraries/libldap/tls_g.c +++ b/libraries/libldap/tls_g.c @@ -830,6 +830,24 @@ tlsg_session_unique( tls_session *sess, struct berval *buf, int is_server) return 0; } +static int +tlsg_session_peercert( tls_session *sess, struct berval *der ) +{ + tlsg_session *s = (tlsg_session *)sess; + const gnutls_datum_t *peer_cert_list; + unsigned int list_size; + + peer_cert_list = gnutls_certificate_get_peers( s->session, &list_size ); + if (!peer_cert_list) + return -1; + der->bv_len = peer_cert_list[0].size; + der->bv_val = LDAP_MALLOC( der->bv_len ); + if (!der->bv_val) + return -1; + memcpy(der->bv_val, peer_cert_list[0].data, der->bv_len); + return 0; +} + /* suites is a string of colon-separated cipher suite names. */ static int tlsg_parse_ciphers( tlsg_ctx *ctx, char *suites ) @@ -1166,6 +1184,7 @@ tls_impl ldap_int_tls_impl = { tlsg_session_chkhost, tlsg_session_strength, tlsg_session_unique, + tlsg_session_peercert, &tlsg_sbio, diff --git a/libraries/libldap/tls_m.c b/libraries/libldap/tls_m.c index 4bd9e63cb..36dc989ef 100644 --- a/libraries/libldap/tls_m.c +++ b/libraries/libldap/tls_m.c @@ -2891,6 +2891,22 @@ tlsm_session_unique( tls_session *sess, struct berval *buf, int is_server) return 0; } +static int +tlsm_session_peercert( tls_session *sess, struct berval *der ) +{ + tlsm_session *s = (tlsm_session *)sess; + CERTCertificate *cert; + cert = SSL_PeerCertificate( s ); + if (!cert) + return -1; + der->bv_len = cert->derCert.len; + der->bv_val = LDAP_MALLOC( der->bv_len ); + if (!der->bv_val) + return -1; + memcpy( der->bv_val, cert->derCert.data, der->bv_len ); + return 0; +} + /* * TLS support for LBER Sockbufs */ @@ -3322,6 +3338,7 @@ tls_impl ldap_int_tls_impl = { tlsm_session_chkhost, tlsm_session_strength, tlsm_session_unique, + tlsm_session_peercert, &tlsm_sbio, diff --git a/libraries/libldap/tls_o.c b/libraries/libldap/tls_o.c index 6288456d3..1fa50392f 100644 --- a/libraries/libldap/tls_o.c +++ b/libraries/libldap/tls_o.c @@ -721,6 +721,21 @@ tlso_session_unique( tls_session *sess, struct berval *buf, int is_server) return buf->bv_len; } +static int +tlso_session_peercert( tls_session *sess, struct berval *der ) +{ + tlso_session *s = (tlso_session *)sess; + unsigned char *ptr; + X509 *x = SSL_get_peer_certificate(s); + der->bv_len = i2d_X509(x, NULL); + der->bv_val = LDAP_MALLOC(der->bv_len); + if ( !der->bv_val ) + return -1; + ptr = der->bv_val; + i2d_X509(x, &ptr); + return 0; +} + /* * TLS support for LBER Sockbufs */ @@ -1229,6 +1244,7 @@ tls_impl ldap_int_tls_impl = { tlso_session_chkhost, tlso_session_strength, tlso_session_unique, + tlso_session_peercert, &tlso_sbio, -- 2.26.2