Blame SOURCES/openldap-cbinding-ITS-9189_1-rework-sasl-cbinding-support.patch

4404fd
NOTE: The patch has been adjusted to match the base code before backporting.
4404fd
4404fd
From 3cd50fa8b32a21040a9892e2a8a7a9dfc7541ce6 Mon Sep 17 00:00:00 2001
4404fd
From: Isaac Boukris <iboukris@gmail.com>
4404fd
Date: Tue, 14 Apr 2020 16:10:48 +0300
4404fd
Subject: [PATCH] ITS#9189 rework sasl-cbinding support
4404fd
4404fd
Add LDAP_OPT_X_SASL_CBINDING option to define the binding type to use,
4404fd
defaults to "none".
4404fd
4404fd
Add "tls-endpoint" binding type implementing "tls-server-end-point" from
4404fd
RCF 5929, which is compatible with Windows.
4404fd
4404fd
Fix "tls-unique" to include the prefix in the bindings as per RFC 5056.
4404fd
---
4404fd
 doc/man/man3/ldap_get_option.3 |  16 +++++
4404fd
 doc/man/man5/ldap.conf.5       |   3 +
4404fd
 doc/man/man5/slapd-config.5    |   4 ++
4404fd
 doc/man/man5/slapd.conf.5      |   3 +
4404fd
 include/ldap.h                 |   5 ++
4404fd
 include/ldap_pvt.h             |   5 ++
4404fd
 libraries/libldap/cyrus.c      | 103 ++++++++++++++++++++++++++++-----
4404fd
 libraries/libldap/init.c       |   1 +
4404fd
 libraries/libldap/ldap-int.h   |   1 +
4404fd
 libraries/libldap/ldap-tls.h   |   2 +
4404fd
 libraries/libldap/tls2.c       |   7 +++
4404fd
 libraries/libldap/tls_g.c      |  59 +++++++++++++++++++
4404fd
 libraries/libldap/tls_o.c      |  45 ++++++++++++++
4404fd
 servers/slapd/bconfig.c        |  11 +++-
4404fd
 servers/slapd/config.c         |   1 +
4404fd
 servers/slapd/connection.c     |   9 +--
4404fd
 servers/slapd/proto-slap.h     |   4 +-
4404fd
 servers/slapd/sasl.c           |  27 ++++++---
4404fd
 18 files changed, 274 insertions(+), 32 deletions(-)
4404fd
4404fd
diff --git a/doc/man/man3/ldap_get_option.3 b/doc/man/man3/ldap_get_option.3
4404fd
index 4f03a01a3..fd1b3c91c 100644
4404fd
--- a/doc/man/man3/ldap_get_option.3
4404fd
+++ b/doc/man/man3/ldap_get_option.3
4404fd
@@ -563,6 +563,22 @@ must be a
4404fd
 .BR "char **" .
4404fd
 Its content needs to be freed by the caller using
4404fd
 .BR ldap_memfree (3).
4404fd
+.B LDAP_OPT_X_SASL_CBINDING
4404fd
+Sets/gets the channel-binding type to use in SASL,
4404fd
+one of
4404fd
+.BR LDAP_OPT_X_SASL_CBINDING_NONE
4404fd
+(the default),
4404fd
+.BR LDAP_OPT_X_SASL_CBINDING_TLS_UNIQUE
4404fd
+the "tls-unique" type from RCF 5929.
4404fd
+.BR LDAP_OPT_X_SASL_CBINDING_TLS_ENDPOINT
4404fd
+the "tls-server-end-point" from RCF 5929, compatible with Windows.
4404fd
+.BR invalue
4404fd
+must be
4404fd
+.BR "const int *" ;
4404fd
+.BR outvalue
4404fd
+must be
4404fd
+.BR "int *" .
4404fd
+.TP
4404fd
 .SH TCP OPTIONS
4404fd
 The TCP options are OpenLDAP specific.
4404fd
 Mainly intended for use with Linux, they may not be portable.
4404fd
diff --git a/doc/man/man5/ldap.conf.5 b/doc/man/man5/ldap.conf.5
4404fd
index 65ad40c1b..4974f8340 100644
4404fd
--- a/doc/man/man5/ldap.conf.5
4404fd
+++ b/doc/man/man5/ldap.conf.5
4404fd
@@ -286,6 +286,9 @@ size allowed.  0 disables security layers.  The default is 65536.
4404fd
 .TP
4404fd
 .B SASL_NOCANON <on/true/yes/off/false/no>
4404fd
 Do not perform reverse DNS lookups to canonicalize SASL host names. The default is off.
4404fd
+.TP
4404fd
+.B SASL_CBINDING <none/tls-unique/tls-endpoint>
4404fd
+The channel-binding type to use, see also LDAP_OPT_X_SASL_CBINDING. The default is none.
4404fd
 .SH GSSAPI OPTIONS
4404fd
 If OpenLDAP is built with Generic Security Services Application Programming Interface support,
4404fd
 there are more options you can specify.
4404fd
diff --git a/doc/man/man5/slapd-config.5 b/doc/man/man5/slapd-config.5
4404fd
index 18518a186..dc0ab769f 100644
4404fd
--- a/doc/man/man5/slapd-config.5
4404fd
+++ b/doc/man/man5/slapd-config.5
4404fd
@@ -720,6 +720,10 @@ Used to specify the fully qualified domain name used for SASL processing.
4404fd
 .B olcSaslRealm: <realm>
4404fd
 Specify SASL realm.  Default is empty.
4404fd
 .TP
4404fd
+.B olcSaslCbinding: none | tls-unique | tls-endpoint
4404fd
+Specify the channel-binding type, see also LDAP_OPT_X_SASL_CBINDING.
4404fd
+Default is none.
4404fd
+.TP
4404fd
 .B olcSaslSecProps: <properties>
4404fd
 Used to specify Cyrus SASL security properties.
4404fd
 The
4404fd
diff --git a/doc/man/man5/slapd.conf.5 b/doc/man/man5/slapd.conf.5
4404fd
index f2094b7fd..73a151a70 100644
4404fd
--- a/doc/man/man5/slapd.conf.5
4404fd
+++ b/doc/man/man5/slapd.conf.5
4404fd
@@ -914,6 +914,9 @@ The
4404fd
 property specifies the maximum security layer receive buffer
4404fd
 size allowed.  0 disables security layers.  The default is 65536.
4404fd
 .TP
4404fd
+.B sasl\-cbinding none | tls-unique | tls-endpoint
4404fd
+Specify the channel-binding type, see also LDAP_OPT_X_SASL_CBINDING.
4404fd
+.TP
4404fd
 .B schemadn <dn>
4404fd
 Specify the distinguished name for the subschema subentry that
4404fd
 controls the entries on this server.  The default is "cn=Subschema".
4404fd
diff --git a/include/ldap.h b/include/ldap.h
4404fd
index 7b4fc9d64..9d5679ae8 100644
4404fd
--- a/include/ldap.h
4404fd
+++ b/include/ldap.h
4404fd
@@ -186,6 +186,10 @@ LDAP_BEGIN_DECL
4404fd
 #define LDAP_OPT_X_TLS_PROTOCOL_TLS1_1		((3 << 8) + 2)
4404fd
 #define LDAP_OPT_X_TLS_PROTOCOL_TLS1_2		((3 << 8) + 3)
4404fd
 
4404fd
+#define LDAP_OPT_X_SASL_CBINDING_NONE		0
4404fd
+#define LDAP_OPT_X_SASL_CBINDING_TLS_UNIQUE	1
4404fd
+#define LDAP_OPT_X_SASL_CBINDING_TLS_ENDPOINT	2
4404fd
+
4404fd
 /* OpenLDAP SASL options */
4404fd
 #define LDAP_OPT_X_SASL_MECH			0x6100
4404fd
 #define LDAP_OPT_X_SASL_REALM			0x6101
4404fd
@@ -201,6 +205,7 @@ LDAP_BEGIN_DECL
4404fd
 #define LDAP_OPT_X_SASL_NOCANON			0x610b
4404fd
 #define LDAP_OPT_X_SASL_USERNAME		0x610c /* read-only */
4404fd
 #define LDAP_OPT_X_SASL_GSS_CREDS		0x610d
4404fd
+#define LDAP_OPT_X_SASL_CBINDING		0x610e
4404fd
 
4404fd
 /* OpenLDAP GSSAPI options */
4404fd
 #define LDAP_OPT_X_GSSAPI_DO_NOT_FREE_CONTEXT      0x6200
4404fd
diff --git a/include/ldap_pvt.h b/include/ldap_pvt.h
4404fd
index 783d280a5..01220d00a 100644
4404fd
--- a/include/ldap_pvt.h
4404fd
+++ b/include/ldap_pvt.h
4404fd
@@ -262,6 +262,10 @@ LDAP_F (void *) ldap_pvt_sasl_mutex_new LDAP_P((void));
4404fd
 LDAP_F (int) ldap_pvt_sasl_mutex_lock LDAP_P((void *mutex));
4404fd
 LDAP_F (int) ldap_pvt_sasl_mutex_unlock LDAP_P((void *mutex));
4404fd
 LDAP_F (void) ldap_pvt_sasl_mutex_dispose LDAP_P((void *mutex));
4404fd
+
4404fd
+LDAP_F (int) ldap_pvt_sasl_cbinding_parse LDAP_P(( const char *arg ));
4404fd
+LDAP_F (void *) ldap_pvt_sasl_cbinding LDAP_P(( void *ssl, int type,
4404fd
+					        int is_server ));
4404fd
 #endif /* HAVE_CYRUS_SASL */
4404fd
 
4404fd
 struct sockbuf; /* avoid pulling in <lber.h> */
4404fd
@@ -438,6 +442,7 @@ LDAP_F (int) ldap_pvt_tls_get_peer_dn LDAP_P(( void *ctx, struct berval *dn,
4404fd
 	LDAPDN_rewrite_dummy *func, unsigned flags ));
4404fd
 LDAP_F (int) ldap_pvt_tls_get_strength LDAP_P(( void *ctx ));
4404fd
 LDAP_F (int) ldap_pvt_tls_get_unique LDAP_P(( void *ctx, struct berval *buf, int is_server ));
4404fd
+LDAP_F (int) ldap_pvt_tls_get_endpoint LDAP_P(( void *ctx, struct berval *buf, int is_server ));
4404fd
 
4404fd
 LDAP_END_DECL
4404fd
 
4404fd
diff --git a/libraries/libldap/cyrus.c b/libraries/libldap/cyrus.c
4404fd
index beb1cf4a0..4d4d5b3e3 100644
4404fd
--- a/libraries/libldap/cyrus.c
4404fd
+++ b/libraries/libldap/cyrus.c
4404fd
@@ -372,6 +372,65 @@ int ldap_int_sasl_close( LDAP *ld, LDAPConn *lc )
4404fd
 	return LDAP_SUCCESS;
4404fd
 }
4404fd
 
4404fd
+int ldap_pvt_sasl_cbinding_parse( const char *arg )
4404fd
+{
4404fd
+	int i = -1;
4404fd
+
4404fd
+	if ( strcasecmp(arg, "none") == 0 )
4404fd
+		i = LDAP_OPT_X_SASL_CBINDING_NONE;
4404fd
+	else if ( strcasecmp(arg, "tls-unique") == 0 )
4404fd
+		i = LDAP_OPT_X_SASL_CBINDING_TLS_UNIQUE;
4404fd
+	else if ( strcasecmp(arg, "tls-endpoint") == 0 )
4404fd
+		i = LDAP_OPT_X_SASL_CBINDING_TLS_ENDPOINT;
4404fd
+
4404fd
+	return i;
4404fd
+}
4404fd
+
4404fd
+void *ldap_pvt_sasl_cbinding( void *ssl, int type, int is_server )
4404fd
+{
4404fd
+#if defined(SASL_CHANNEL_BINDING) && defined(HAVE_TLS)
4404fd
+	char unique_prefix[] = "tls-unique:";
4404fd
+	char endpoint_prefix[] = "tls-server-end-point:";
4404fd
+	char cbinding[ 64 ];
4404fd
+	struct berval cbv = { 64, cbinding };
4404fd
+	void *cb_data; /* used since cb->data is const* */
4404fd
+	sasl_channel_binding_t *cb;
4404fd
+	char *prefix;
4404fd
+	int plen;
4404fd
+
4404fd
+	switch (type) {
4404fd
+	case LDAP_OPT_X_SASL_CBINDING_NONE:
4404fd
+		return NULL;
4404fd
+	case LDAP_OPT_X_SASL_CBINDING_TLS_UNIQUE:
4404fd
+		if ( !ldap_pvt_tls_get_unique( ssl, &cbv, is_server ))
4404fd
+			return NULL;
4404fd
+		prefix = unique_prefix;
4404fd
+		plen = sizeof(unique_prefix) -1;
4404fd
+		break;
4404fd
+	case LDAP_OPT_X_SASL_CBINDING_TLS_ENDPOINT:
4404fd
+		if ( !ldap_pvt_tls_get_endpoint( ssl, &cbv, is_server ))
4404fd
+			return NULL;
4404fd
+		prefix = endpoint_prefix;
4404fd
+		plen = sizeof(endpoint_prefix) -1;
4404fd
+		break;
4404fd
+	default:
4404fd
+		return NULL;
4404fd
+	}
4404fd
+
4404fd
+	cb = ldap_memalloc( sizeof(*cb) + plen + cbv.bv_len );
4404fd
+	cb->len = plen + cbv.bv_len;
4404fd
+	cb->data = cb_data = cb+1;
4404fd
+	memcpy( cb_data, prefix, plen );
4404fd
+	memcpy( cb_data + plen, cbv.bv_val, cbv.bv_len );
4404fd
+	cb->name = "ldap";
4404fd
+	cb->critical = 0;
4404fd
+
4404fd
+	return cb;
4404fd
+#else
4404fd
+	return NULL;
4404fd
+#endif
4404fd
+}
4404fd
+
4404fd
 int
4404fd
 ldap_int_sasl_bind(
4404fd
 	LDAP			*ld,
4404fd
@@ -497,17 +556,12 @@ ldap_int_sasl_bind(
4404fd
 			(void) ldap_int_sasl_external( ld, ld->ld_defconn, authid.bv_val, fac );
4404fd
 			LDAP_FREE( authid.bv_val );
4404fd
 #ifdef SASL_CHANNEL_BINDING	/* 2.1.25+ */
4404fd
-			{
4404fd
-				char cbinding[64];
4404fd
-				struct berval cbv = { sizeof(cbinding), cbinding };
4404fd
-				if ( ldap_pvt_tls_get_unique( ssl, &cbv, 0 )) {
4404fd
-					sasl_channel_binding_t *cb = ldap_memalloc( sizeof(*cb) +
4404fd
-						cbv.bv_len);
4404fd
-					cb->name = "ldap";
4404fd
-					cb->critical = 0;
4404fd
-					cb->data = (char *)(cb+1);
4404fd
-					cb->len = cbv.bv_len;
4404fd
-					memcpy( cb->data, cbv.bv_val, cbv.bv_len );
4404fd
+			if ( ld->ld_defconn->lconn_sasl_cbind == NULL ) {
4404fd
+				void *cb;
4404fd
+				cb = ldap_pvt_sasl_cbinding( ssl,
4404fd
+							     ld->ld_options.ldo_sasl_cbinding,
4404fd
+							     0 );
4404fd
+				if ( cb != NULL ) {
4404fd
 					sasl_setprop( ld->ld_defconn->lconn_sasl_authctx,
4404fd
 						SASL_CHANNEL_BINDING, cb );
4404fd
 					ld->ld_defconn->lconn_sasl_cbind = cb;
4404fd
@@ -931,12 +983,20 @@ int ldap_pvt_sasl_secprops(
4404fd
 int
4404fd
 ldap_int_sasl_config( struct ldapoptions *lo, int option, const char *arg )
4404fd
 {
4404fd
-	int rc;
4404fd
+	int rc, i;
4404fd
 
4404fd
 	switch( option ) {
4404fd
 	case LDAP_OPT_X_SASL_SECPROPS:
4404fd
 		rc = ldap_pvt_sasl_secprops( arg, &lo->ldo_sasl_secprops );
4404fd
 		if( rc == LDAP_SUCCESS ) return 0;
4404fd
+		break;
4404fd
+	case LDAP_OPT_X_SASL_CBINDING:
4404fd
+		i = ldap_pvt_sasl_cbinding_parse( arg );
4404fd
+		if ( i >= 0 ) {
4404fd
+			lo->ldo_sasl_cbinding = i;
4404fd
+			return 0;
4404fd
+		}
4404fd
+		break;
4404fd
 	}
4404fd
 
4404fd
 	return -1;
4404fd
@@ -1042,6 +1102,10 @@ ldap_int_sasl_get_option( LDAP *ld, int option, void *arg )
4404fd
 			/* this option is write only */
4404fd
 			return -1;
4404fd
 
4404fd
+		case LDAP_OPT_X_SASL_CBINDING:
4404fd
+			*(int *)arg = ld->ld_options.ldo_sasl_cbinding;
4404fd
+			break;
4404fd
+
4404fd
 #ifdef SASL_GSS_CREDS
4404fd
 		case LDAP_OPT_X_SASL_GSS_CREDS: {
4404fd
 			sasl_conn_t *ctx;
4404fd
@@ -1143,6 +1207,17 @@ ldap_int_sasl_set_option( LDAP *ld, int option, void *arg )
4404fd
 		return sc == LDAP_SUCCESS ? 0 : -1;
4404fd
 		}
4404fd
 
4404fd
+	case LDAP_OPT_X_SASL_CBINDING:
4404fd
+		if ( !arg ) return -1;
4404fd
+		switch( *(int *) arg ) {
4404fd
+		case LDAP_OPT_X_SASL_CBINDING_NONE:
4404fd
+		case LDAP_OPT_X_SASL_CBINDING_TLS_UNIQUE:
4404fd
+		case LDAP_OPT_X_SASL_CBINDING_TLS_ENDPOINT:
4404fd
+			ld->ld_options.ldo_sasl_cbinding = *(int *) arg;
4404fd
+			return 0;
4404fd
+		}
4404fd
+		return -1;
4404fd
+
4404fd
 #ifdef SASL_GSS_CREDS
4404fd
 	case LDAP_OPT_X_SASL_GSS_CREDS: {
4404fd
 		sasl_conn_t *ctx;
4404fd
diff --git a/libraries/libldap/init.c b/libraries/libldap/init.c
4404fd
index 3468ee249..dfe1ea9da 100644
4404fd
--- a/libraries/libldap/init.c
4404fd
+++ b/libraries/libldap/init.c
4404fd
@@ -110,6 +110,7 @@ static const struct ol_attribute {
4404fd
 		offsetof(struct ldapoptions, ldo_def_sasl_authzid)},
4404fd
 	{0, ATTR_SASL,		"SASL_SECPROPS",	NULL,	LDAP_OPT_X_SASL_SECPROPS},
4404fd
 	{0, ATTR_BOOL,		"SASL_NOCANON",	NULL,	LDAP_BOOL_SASL_NOCANON},
4404fd
+	{0, ATTR_SASL,		"SASL_CBINDING",	NULL,	LDAP_OPT_X_SASL_CBINDING},
4404fd
 #endif
4404fd
 
4404fd
 #ifdef HAVE_GSSAPI
4404fd
diff --git a/libraries/libldap/ldap-int.h b/libraries/libldap/ldap-int.h
4404fd
index 67e8bd6da..c6c6891a9 100644
4404fd
--- a/libraries/libldap/ldap-int.h
4404fd
+++ b/libraries/libldap/ldap-int.h
4404fd
@@ -300,6 +300,7 @@ struct ldapoptions {
4404fd
 
4404fd
 	/* SASL Security Properties */
4404fd
 	struct sasl_security_properties	ldo_sasl_secprops;
4404fd
+	int ldo_sasl_cbinding;
4404fd
 #define LDAP_LDO_SASL_NULLARG ,0,0,0,0,{0}
4404fd
 #else
4404fd
 #define LDAP_LDO_SASL_NULLARG
4404fd
diff --git a/libraries/libldap/ldap-tls.h b/libraries/libldap/ldap-tls.h
4404fd
index efd51aaa2..9f01ddda1 100644
4404fd
--- a/libraries/libldap/ldap-tls.h
4404fd
+++ b/libraries/libldap/ldap-tls.h
4404fd
@@ -42,6 +42,7 @@ typedef int (TI_session_dn)(tls_session *sess, struct berval *dn);
4404fd
 typedef int (TI_session_chkhost)(LDAP *ld, tls_session *s, const char *name_in);
4404fd
 typedef int (TI_session_strength)(tls_session *sess);
4404fd
 typedef int (TI_session_unique)(tls_session *sess, struct berval *buf, int is_server);
4404fd
+typedef int (TI_session_endpoint)(tls_session *sess, struct berval *buf, int is_server);
4404fd
 typedef int (TI_session_peercert)(tls_session *s, struct berval *der);
4404fd
4404fd
 typedef void (TI_thr_init)(void);
4404fd
@@ -69,6 +70,7 @@ typedef struct tls_impl {
4404fd
 	TI_session_chkhost *ti_session_chkhost;
4404fd
 	TI_session_strength *ti_session_strength;
4404fd
 	TI_session_unique *ti_session_unique;
4404fd
+	TI_session_endpoint *ti_session_endpoint;
4404fd
 	TI_session_peercert *ti_session_peercert;
4404fd
 
4404fd
 	Sockbuf_IO *ti_sbio;
4404fd
diff --git a/libraries/libldap/tls2.c b/libraries/libldap/tls2.c
4404fd
index 79a651a38..72827a1a3 100644
4404fd
--- a/libraries/libldap/tls2.c
4404fd
+++ b/libraries/libldap/tls2.c
4404fd
@@ -1200,6 +1200,13 @@ ldap_pvt_tls_get_unique( void *s, struct berval *buf, int is_server )
4404fd
 	return tls_imp->ti_session_unique( session, buf, is_server );
4404fd
 }
4404fd
 
4404fd
+int
4404fd
+ldap_pvt_tls_get_endpoint( void *s, struct berval *buf, int is_server )
4404fd
+{
4404fd
+	tls_session *session = s;
4404fd
+	return tls_imp->ti_session_endpoint( session, buf, is_server );
4404fd
+}
4404fd
+
4404fd
 int
4404fd
 ldap_pvt_tls_get_peercert( void *s, struct berval *der )
4404fd
 {
4404fd
diff --git a/libraries/libldap/tls_g.c b/libraries/libldap/tls_g.c
4404fd
index 956a9ec90..ef0f44e20 100644
4404fd
--- a/libraries/libldap/tls_g.c
4404fd
+++ b/libraries/libldap/tls_g.c
4404fd
@@ -729,6 +729,64 @@ tlsg_session_unique( tls_session *sess, struct berval *buf, int is_server)
4404fd
 	return 0;
4404fd
 }
4404fd
 
4404fd
+static int
4404fd
+tlsg_session_endpoint( tls_session *sess, struct berval *buf, int is_server )
4404fd
+{
4404fd
+	tlsg_session *s = (tlsg_session *)sess;
4404fd
+	const gnutls_datum_t *cert_data;
4404fd
+	gnutls_x509_crt_t server_cert;
4404fd
+	gnutls_digest_algorithm_t md;
4404fd
+	int sign_algo, md_len, rc;
4404fd
+
4404fd
+	if ( is_server )
4404fd
+		cert_data = gnutls_certificate_get_ours( s->session );
4404fd
+	else
4404fd
+		cert_data = gnutls_certificate_get_peers( s->session, NULL );
4404fd
+
4404fd
+	if ( cert_data == NULL )
4404fd
+		return 0;
4404fd
+
4404fd
+	rc = gnutls_x509_crt_init( &server_cert );
4404fd
+	if ( rc != GNUTLS_E_SUCCESS )
4404fd
+		return 0;
4404fd
+
4404fd
+	rc = gnutls_x509_crt_import( server_cert, cert_data, GNUTLS_X509_FMT_DER );
4404fd
+	if ( rc != GNUTLS_E_SUCCESS ) {
4404fd
+		gnutls_x509_crt_deinit( server_cert );
4404fd
+		return 0;
4404fd
+	}
4404fd
+
4404fd
+	sign_algo = gnutls_x509_crt_get_signature_algorithm( server_cert );
4404fd
+	gnutls_x509_crt_deinit( server_cert );
4404fd
+	if ( sign_algo <= GNUTLS_SIGN_UNKNOWN )
4404fd
+		return 0;
4404fd
+
4404fd
+	md = gnutls_sign_get_hash_algorithm( sign_algo );
4404fd
+	if ( md == GNUTLS_DIG_UNKNOWN )
4404fd
+		return 0;
4404fd
+
4404fd
+	/* See RFC 5929 */
4404fd
+	switch (md) {
4404fd
+	case GNUTLS_DIG_NULL:
4404fd
+	case GNUTLS_DIG_MD2:
4404fd
+	case GNUTLS_DIG_MD5:
4404fd
+	case GNUTLS_DIG_SHA1:
4404fd
+		md = GNUTLS_DIG_SHA256;
4404fd
+	}
4404fd
+
4404fd
+	md_len = gnutls_hash_get_len( md );
4404fd
+	if ( md_len == 0 || md_len > buf->bv_len )
4404fd
+		return 0;
4404fd
+
4404fd
+	rc = gnutls_hash_fast( md, cert_data->data, cert_data->size, buf->bv_val );
4404fd
+	if ( rc != GNUTLS_E_SUCCESS )
4404fd
+		return 0;
4404fd
+
4404fd
+	buf->bv_len = md_len;
4404fd
+
4404fd
+	return md_len;
4404fd
+}
4404fd
+
4404fd
 static int
4404fd
 tlsg_session_peercert( tls_session *sess, struct berval *der )
4404fd
 {
4404fd
@@ -1117,6 +1175,7 @@ tls_impl ldap_int_tls_impl = {
4404fd
 	tlsg_session_chkhost,
4404fd
 	tlsg_session_strength,
4404fd
 	tlsg_session_unique,
4404fd
+	tlsg_session_endpoint,
4404fd
 	tlsg_session_peercert,
4404fd
 
4404fd
 	&tlsg_sbio,
4404fd
diff --git a/libraries/libldap/tls_o.c b/libraries/libldap/tls_o.c
4404fd
index cf97d7632..aa855d77a 100644
4404fd
--- a/libraries/libldap/tls_o.c
4404fd
+++ b/libraries/libldap/tls_o.c
4404fd
@@ -858,6 +858,50 @@ tlso_session_unique( tls_session *sess, struct berval *buf, int is_server)
4404fd
 	return buf->bv_len;
4404fd
 }
4404fd
 
4404fd
+static int
4404fd
+tlso_session_endpoint( tls_session *sess, struct berval *buf, int is_server )
4404fd
+{
4404fd
+	tlso_session *s = (tlso_session *)sess;
4404fd
+	const EVP_MD *md;
4404fd
+	unsigned int md_len;
4404fd
+	X509 *cert;
4404fd
+
4404fd
+	if ( buf->bv_len < EVP_MAX_MD_SIZE )
4404fd
+		return 0;
4404fd
+
4404fd
+	if ( is_server )
4404fd
+		cert = SSL_get_certificate( s );
4404fd
+	else
4404fd
+		cert = SSL_get_peer_certificate( s );
4404fd
+
4404fd
+	if ( cert == NULL )
4404fd
+		return 0;
4404fd
+
4404fd
+#if OPENSSL_VERSION_NUMBER >= 0x10100000
4404fd
+	md = EVP_get_digestbynid( X509_get_signature_nid( cert ));
4404fd
+#else
4404fd
+	md = EVP_get_digestbynid(OBJ_obj2nid( cert->sig_alg->algorithm ));
4404fd
+#endif
4404fd
+
4404fd
+	/* See RFC 5929 */
4404fd
+	if ( md == NULL ||
4404fd
+	     md == EVP_md_null() ||
4404fd
+#ifndef OPENSSL_NO_MD2
4404fd
+	     md == EVP_md2() ||
4404fd
+#endif
4404fd
+	     md == EVP_md4() ||
4404fd
+	     md == EVP_md5() ||
4404fd
+	     md == EVP_sha1() )
4404fd
+		md = EVP_sha256();
4404fd
+
4404fd
+	if ( !X509_digest( cert, md, buf->bv_val, &md_len ))
4404fd
+		return 0;
4404fd
+
4404fd
+	buf->bv_len = md_len;
4404fd
+
4404fd
+	return md_len;
4404fd
+}
4404fd
+
4404fd
 static int
4404fd
 tlso_session_peercert( tls_session *sess, struct berval *der )
4404fd
 {
4404fd
@@ -1474,6 +1518,7 @@ tls_impl ldap_int_tls_impl = {
4404fd
 	tlso_session_chkhost,
4404fd
 	tlso_session_strength,
4404fd
 	tlso_session_unique,
4404fd
+	tlso_session_endpoint,
4404fd
 	tlso_session_peercert,
4404fd
 
4404fd
 	&tlso_sbio,
4404fd
diff --git a/servers/slapd/bconfig.c b/servers/slapd/bconfig.c
4404fd
index 6069ee203..4c90715be 100644
4404fd
--- a/servers/slapd/bconfig.c
4404fd
+++ b/servers/slapd/bconfig.c
4404fd
@@ -630,6 +630,15 @@ static ConfigTable config_back_cf_table[] = {
4404fd
 #endif
4404fd
 		"( OLcfgGlAt:89 NAME 'olcSaslAuxprops' "
4404fd
 			"SYNTAX OMsDirectoryString SINGLE-VALUE )", NULL, NULL },
4404fd
+	{ "sasl-cbinding", NULL, 2, 2, 0,
4404fd
+#ifdef HAVE_CYRUS_SASL
4404fd
+		ARG_STRING, &sasl_cbinding,
4404fd
+#else
4404fd
+		ARG_IGNORED, NULL,
4404fd
+#endif
4404fd
+		"( OLcfgGlAt:100 NAME 'olcSaslCBinding' "
4404fd
+			"EQUALITY caseIgnoreMatch "
4404fd
+			"SYNTAX OMsDirectoryString SINGLE-VALUE )", NULL, NULL },
4404fd
 	{ "sasl-host", "host", 2, 2, 0,
4404fd
 #ifdef HAVE_CYRUS_SASL
4404fd
 		ARG_STRING|ARG_UNIQUE, &sasl_host,
4404fd
@@ -948,7 +957,7 @@ static ConfigOCs cf_ocs[] = {
4404fd
 		 "olcPluginLogFile $ olcReadOnly $ olcReferral $ "
4404fd
 		 "olcReplogFile $ olcRequires $ olcRestrict $ olcReverseLookup $ "
4404fd
 		 "olcRootDSE $ "
4404fd
-		 "olcSaslAuxprops $ olcSaslHost $ olcSaslRealm $ olcSaslSecProps $ "
4404fd
+		 "olcSaslAuxprops $ olcSaslCBinding $ olcSaslHost $ olcSaslRealm $ olcSaslSecProps $ "
4404fd
 		 "olcSecurity $ olcServerID $ olcSizeLimit $ "
4404fd
 		 "olcSockbufMaxIncoming $ olcSockbufMaxIncomingAuth $ "
4404fd
 		 "olcTCPBuffer $ "
4404fd
diff --git a/servers/slapd/config.c b/servers/slapd/config.c
4404fd
index 060d3410f..3d713d4fb 100644
4404fd
--- a/servers/slapd/config.c
4404fd
+++ b/servers/slapd/config.c
4404fd
@@ -73,6 +73,7 @@ char	*global_host = NULL;
4404fd
 struct berval global_host_bv = BER_BVNULL;
4404fd
 char	*global_realm = NULL;
4404fd
 char	*sasl_host = NULL;
4404fd
+char	*sasl_cbinding = NULL;
4404fd
 char		**default_passwd_hash = NULL;
4404fd
 struct berval default_search_base = BER_BVNULL;
4404fd
 struct berval default_search_nbase = BER_BVNULL;
4404fd
diff --git a/servers/slapd/connection.c b/servers/slapd/connection.c
4404fd
index 5f11a0cf1..6d9bb8e85 100644
4404fd
--- a/servers/slapd/connection.c
4404fd
+++ b/servers/slapd/connection.c
4404fd
@@ -1440,12 +1440,9 @@ connection_read( ber_socket_t s, conn_readinfo *cri )
4404fd
 			    c->c_connid, (int) s, c->c_tls_ssf, c->c_ssf, 0 );
4404fd
 			slap_sasl_external( c, c->c_tls_ssf, &authid );
4404fd
 			if ( authid.bv_val ) free( authid.bv_val );
4404fd
-			{
4404fd
-				char cbinding[64];
4404fd
-				struct berval cbv = { sizeof(cbinding), cbinding };
4404fd
-				if ( ldap_pvt_tls_get_unique( ssl, &cbv, 1 ))
4404fd
-					slap_sasl_cbinding( c, &cbv );
4404fd
-			}
4404fd
+
4404fd
+			slap_sasl_cbinding( c, ssl );
4404fd
+
4404fd
 		} else if ( rc == 1 && ber_sockbuf_ctrl( c->c_sb,
4404fd
 			LBER_SB_OPT_NEEDS_WRITE, NULL )) {	/* need to retry */
4404fd
 			slapd_set_write( s, 1 );
4404fd
diff --git a/servers/slapd/proto-slap.h b/servers/slapd/proto-slap.h
4404fd
index b89fa836a..0790a8004 100644
4404fd
--- a/servers/slapd/proto-slap.h
4404fd
+++ b/servers/slapd/proto-slap.h
4404fd
@@ -1681,8 +1681,7 @@ LDAP_SLAPD_F (int) slap_sasl_external( Connection *c,
4404fd
 	slap_ssf_t ssf,	/* relative strength of external security */
4404fd
 	struct berval *authid );	/* asserted authenication id */
4404fd
 
4404fd
-LDAP_SLAPD_F (int) slap_sasl_cbinding( Connection *c,
4404fd
-	struct berval *cbv );
4404fd
+LDAP_SLAPD_F (int) slap_sasl_cbinding( Connection *c, void *ssl );
4404fd
 
4404fd
 LDAP_SLAPD_F (int) slap_sasl_reset( Connection *c );
4404fd
 LDAP_SLAPD_F (int) slap_sasl_close( Connection *c );
4404fd
@@ -2072,6 +2071,7 @@ LDAP_SLAPD_V (char *)	global_host;
4404fd
 LDAP_SLAPD_V (struct berval)	global_host_bv;
4404fd
 LDAP_SLAPD_V (char *)	global_realm;
4404fd
 LDAP_SLAPD_V (char *)	sasl_host;
4404fd
+LDAP_SLAPD_V (char *)	sasl_cbinding;
4404fd
 LDAP_SLAPD_V (char *)	slap_sasl_auxprops;
4404fd
 LDAP_SLAPD_V (char **)	default_passwd_hash;
4404fd
 LDAP_SLAPD_V (int)		lber_debug;
4404fd
diff --git a/servers/slapd/sasl.c b/servers/slapd/sasl.c
4404fd
index fc023904a..5cced358c 100644
4404fd
--- a/servers/slapd/sasl.c
4404fd
+++ b/servers/slapd/sasl.c
4404fd
@@ -1320,6 +1320,8 @@ int slap_sasl_destroy( void )
4404fd
 #endif
4404fd
 	free( sasl_host );
4404fd
 	sasl_host = NULL;
4404fd
+	free( sasl_cbinding );
4404fd
+	sasl_cbinding = NULL;
4404fd
 
4404fd
 	return 0;
4404fd
 }
4404fd
@@ -1506,17 +1508,24 @@ int slap_sasl_external(
4404fd
 	return LDAP_SUCCESS;
4404fd
 }
4404fd
 
4404fd
-int slap_sasl_cbinding( Connection *conn, struct berval *cbv )
4404fd
+int slap_sasl_cbinding( Connection *conn, void *ssl )
4404fd
 {
4404fd
 #ifdef SASL_CHANNEL_BINDING
4404fd
-	sasl_channel_binding_t *cb = ch_malloc( sizeof(*cb) + cbv->bv_len );;
4404fd
-	cb->name = "ldap";
4404fd
-	cb->critical = 0;
4404fd
-	cb->data = (char *)(cb+1);
4404fd
-	cb->len = cbv->bv_len;
4404fd
-	memcpy( cb->data, cbv->bv_val, cbv->bv_len );
4404fd
-	sasl_setprop( conn->c_sasl_authctx, SASL_CHANNEL_BINDING, cb );
4404fd
-	conn->c_sasl_cbind = cb;
4404fd
+	void *cb;
4404fd
+	int i;
4404fd
+
4404fd
+	if ( sasl_cbinding == NULL )
4404fd
+		return LDAP_SUCCESS;
4404fd
+
4404fd
+	i = ldap_pvt_sasl_cbinding_parse( sasl_cbinding );
4404fd
+	if ( i < 0 )
4404fd
+		return LDAP_SUCCESS;
4404fd
+
4404fd
+	cb = ldap_pvt_sasl_cbinding( ssl, i, 1 );
4404fd
+	if ( cb != NULL ) {
4404fd
+		sasl_setprop( conn->c_sasl_authctx, SASL_CHANNEL_BINDING, cb );
4404fd
+		conn->c_sasl_cbind = cb;
4404fd
+	}
4404fd
 #endif
4404fd
 	return LDAP_SUCCESS;
4404fd
 }
4404fd
-- 
4404fd
2.26.2
4404fd