Blame SOURCES/openldap-cbinding-ITS-7398-add-LDAP_OPT_X_TLS_PEERCERT.patch

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