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

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