]> git.ipfire.org Git - thirdparty/openldap.git/commitdiff
ITS#10014: Add TLS handle using MbedTLS
authorjohan pascal <johan.pascal@linphone.org>
Thu, 2 Mar 2023 09:51:19 +0000 (10:51 +0100)
committerQuanah Gibson-Mount <quanah@openldap.org>
Fri, 31 Mar 2023 05:19:30 +0000 (05:19 +0000)
.gitlab-ci.yml
configure.ac
doc/man/man3/ldap_get_option.3
doc/man/man5/lloadd.conf.5
doc/man/man5/slapd-config.5
doc/man/man5/slapd.conf.5
libraries/libldap/Makefile.in
libraries/libldap/tls_mt.c [new file with mode: 0644]
servers/slapd/overlays/otp.c
tests/scripts/test067-tls
tests/scripts/test077-sasl-gssapi

index 773d82df2ee907a7f51a0c3a79755ba895070852..1ff44c76b9b741572b8e1a157b940cc617263cc9 100644 (file)
@@ -73,3 +73,29 @@ build-gnutls-mit-standalone-lloadd:
       - obj/tests/testrun/
       - obj/servers/
       - obj/libraries/
+
+build-mbedtls-mit-standalone-lloadd:
+  image: "debian:testing"
+  stage: build
+  script:
+    - export STARTTIME=$(date +%s)
+    - apt update
+    - DEBIAN_FRONTEND=noninteractive apt install -y build-essential python3 gdb procps pkg-config automake libsasl2-dev libltdl-dev groff-base unixodbc-dev libwiredtiger-dev libperl-dev krb5-user krb5-kdc krb5-admin-server libsasl2-modules-gssapi-mit sasl2-bin libmbedtls-dev libevent-dev libargon2-dev libsystemd-dev
+    - autoreconf
+    - mkdir obj
+    - cd obj
+    - echo "$(date -u -d "now - $STARTTIME sec" +%T) Configuring"
+    - ../configure --with-tls=mbedtls --enable-backends=mod --enable-overlays=mod --disable-autoca --enable-modules --enable-dynamic --enable-balancer=mod --enable-argon2 --with-systemd
+    - make depend
+    - echo "$(date -u -d "now - $STARTTIME sec" +%T) Building"
+    - make
+    - ulimit -n 4096 # back-monitor takes a while scanning a long connections array
+    - SLAPD_COMMON_WRAPPER=gdb make test
+  artifacts:
+    name: testdir
+    when: on_failure
+    expire_in: '1 week'
+    paths:
+      - obj/tests/testrun/
+      - obj/servers/
+      - obj/libraries/
index 7d291e863fc45c02b6ff195c031dfbaf1d3a06bb..95cdbea4512bb5de4fc33bb0619d7381e181da38 100644 (file)
@@ -247,8 +247,8 @@ OL_ARG_WITH(threads,
        [AS_HELP_STRING([--with-threads], [with threads library auto|nt|posix|pth|lwp|manual])],
        auto, [auto nt posix pth lwp yes no manual] )
 OL_ARG_WITH(tls,
-       [AS_HELP_STRING([--with-tls], [with TLS/SSL support auto|openssl|gnutls])],
-       auto, [auto openssl gnutls yes no] )
+       [AS_HELP_STRING([--with-tls], [with TLS/SSL support auto|openssl|gnutls|mbedtls])],
+       auto, [auto openssl gnutls mbedtls yes no] )
 OL_ARG_WITH(yielding_select,
        [AS_HELP_STRING([--with-yielding-select], [with implicitly yielding select])],
        auto, [auto yes no manual] )
@@ -1290,6 +1290,35 @@ if test $ol_link_tls = no ; then
        fi
 fi
 
+if test $ol_link_tls = no ; then
+       if test $ol_with_tls = mbedtls || test $ol_with_tls = auto ; then
+               AC_CHECK_HEADERS(mbedtls/ssl.h)
+
+               if test $ac_cv_header_mbedtls_ssl_h = yes ; then
+                       AC_PREPROC_IFELSE([AC_LANG_SOURCE(
+                               [[#include <mbedtls/version.h>]
+[#if MBEDTLS_VERSION_NUMBER < 0x02120000]
+[#error "mbedtls is too old"]
+[#endif]])],
+                                       , [AC_MSG_FAILURE([mbedtls 2.18.0 or newer required])])
+
+                       AC_CHECK_LIB(mbedtls, mbedtls_ssl_init,
+                               [have_mbedtls=yes], [have_mbedtls=no], -lmbedx509 -lmbedcrypto)
+
+                       if test $have_mbedtls = yes ; then
+                               ol_with_tls=mbedtls
+                               ol_link_tls=yes
+                               WITH_TLS_TYPE=mbedtls
+
+                               TLS_LIBS="-lmbedtls -lmbedx509 -lmbedcrypto"
+
+                               AC_DEFINE(HAVE_MBEDTLS, 1,
+                                       [define if you have mbedtls])
+                       fi
+               fi
+       fi
+fi
+
 WITH_TLS=no
 if test $ol_link_tls = yes ; then
        AC_DEFINE(HAVE_TLS, 1, [define if you have TLS])
index b7ed9762e3e72f0621591217cb4594f28e42851d..7a8008e051b3df3c4dec198c5b454353f642fbb3 100644 (file)
@@ -692,6 +692,7 @@ and its contents need to be freed by the caller using
 .TP
 .B LDAP_OPT_X_TLS_CIPHER_SUITE
 Sets/gets the allowed cipher suite.
+This directive is not supported when using MbedTLS.
 .BR invalue
 must be
 .BR "const char *" ;
@@ -762,6 +763,7 @@ manipulate this structure.
 .B LDAP_OPT_X_TLS_DHFILE
 Gets/sets the full-path of the file containing the parameters
 for Diffie-Hellman ephemeral key exchange.
+This directive is not supported when using MbedTLS.
 .BR invalue
 must be
 .BR "const char *" ;
index 3d137d0e1ceacecba5b89f50f695a1ced509458b..6010cc32d19c94d4d04252260b6713a8b1bf6a63 100644 (file)
@@ -462,6 +462,7 @@ option.
 Permits configuring what ciphers will be accepted and the preference order.
 <cipher-suite-spec> should be a cipher specification for the TLS library
 in use (OpenSSL, GnuTLS, or Mozilla NSS).
+This directive is not supported when using MbedTLS.
 Example:
 .RS
 .RS
@@ -577,6 +578,7 @@ You should append "!ADH" to your cipher suites to ensure that these suites
 are not used.
 When using Mozilla NSS these parameters are always generated randomly
 so this directive is ignored.
+This directive is not supported when using MbedTLS.
 .TP
 .B TLSECName <name>
 Specify the name of a curve to use for Elliptic curve Diffie-Hellman
index a61ed67d570eba3bc273120a3fc16d3a46f770df..a16a223edc4ed6459bd8a147fa50305fd4150404 100644 (file)
@@ -903,6 +903,7 @@ you can specify.
 Permits configuring what ciphers will be accepted and the preference order.
 <cipher-suite-spec> should be a cipher specification for the TLS library
 in use (OpenSSL or GnuTLS).
+This directive is not supported when using MbedTLS.
 Example:
 .RS
 .RS
@@ -982,6 +983,7 @@ actual client or server authentication and provide no protection against
 man-in-the-middle attacks.
 You should append "!ADH" to your cipher suites to ensure that these suites
 are not used.
+This directive is not supported when using MbedTLS.
 .TP
 .B olcTLSECName: <name>
 Specify the name of the curve(s) to use for Elliptic curve Diffie-Hellman
index fdebcbdd55b3c8f7e6bc336f2b688c652086af85..3325b92d03b5f67174d11e2f837ccdee5a1ac5a7 100644 (file)
@@ -1133,6 +1133,7 @@ you can specify.
 Permits configuring what ciphers will be accepted and the preference order.
 <cipher-suite-spec> should be a cipher specification for the TLS library
 in use (OpenSSL or GnuTLS).
+This directive is not supported when using MbedTLS.
 Example:
 .RS
 .RS
@@ -1209,6 +1210,7 @@ actual client or server authentication and provide no protection against
 man-in-the-middle attacks.
 You should append "!ADH" to your cipher suites to ensure that these suites
 are not used.
+This directive is not supported when using MbedTLS.
 .TP
 .B TLSECName <name>
 Specify the name of the curve(s) to use for Elliptic curve Diffie-Hellman
index 5d5c4c65141a5d5c4ec6e3306986d196f8bb92ff..4d314ae8e421f02bd80fff8bd83d66c1abdff0f3 100644 (file)
@@ -26,7 +26,7 @@ SRCS  = bind.c open.c result.c error.c compare.c search.c \
        request.c os-ip.c url.c pagectrl.c sortctrl.c vlvctrl.c \
        init.c options.c print.c string.c util-int.c schema.c \
        charray.c os-local.c dnssrv.c utf-8.c utf-8-conv.c \
-       tls2.c tls_o.c tls_g.c \
+       tls2.c tls_o.c tls_g.c tls_mt.c\
        turn.c ppolicy.c dds.c txn.c ldap_sync.c stctrl.c \
        assertion.c deref.c ldifutil.c ldif.c fetch.c lbase64.c \
        msctrl.c psearchctrl.c threads.c rdwr.c tpool.c rq.c \
@@ -42,7 +42,7 @@ OBJS  = bind.lo open.lo result.lo error.lo compare.lo search.lo \
        request.lo os-ip.lo url.lo pagectrl.lo sortctrl.lo vlvctrl.lo \
        init.lo options.lo print.lo string.lo util-int.lo schema.lo \
        charray.lo os-local.lo dnssrv.lo utf-8.lo utf-8-conv.lo \
-       tls2.lo tls_o.lo tls_g.lo \
+       tls2.lo tls_o.lo tls_g.lo tls_mt.lo\
        turn.lo ppolicy.lo dds.lo txn.lo ldap_sync.lo stctrl.lo \
        assertion.lo deref.lo ldifutil.lo ldif.lo fetch.lo lbase64.lo \
        msctrl.lo psearchctrl.lo threads.lo rdwr.lo tpool.lo rq.lo \
diff --git a/libraries/libldap/tls_mt.c b/libraries/libldap/tls_mt.c
new file mode 100644 (file)
index 0000000..5ca0926
--- /dev/null
@@ -0,0 +1,1014 @@
+/* tls_mt.c - Handle tls/ssl using MbedTLS */
+/* $OpenLDAP$ */
+/* This work is part of OpenLDAP Software <http://www.openldap.org/>.
+ *
+ * Copyright 2010-2023 Belledonne Communications SARL.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted only as authorized by the OpenLDAP
+ * Public License.
+ *
+ * A copy of this license is available in the file LICENSE in the
+ * top-level directory of the distribution or, alternatively, at
+ * <http://www.OpenLDAP.org/license.html>.
+ */
+/* ACKNOWLEDGEMENTS:
+ */
+
+#include "portable.h"
+
+#ifdef HAVE_MBEDTLS
+
+#include "ldap_config.h"
+
+#include <stdio.h>
+
+#include <ac/stdlib.h>
+#include <ac/errno.h>
+#include <ac/socket.h>
+#include <ac/string.h>
+#include <ac/ctype.h>
+
+#include "ldap-int.h"
+#include "ldap-tls.h"
+
+#include <mbedtls/ssl.h>
+#include <mbedtls/oid.h>
+#include <mbedtls/x509.h>
+#include <mbedtls/version.h>
+#include <mbedtls/entropy.h>
+#include <mbedtls/ctr_drbg.h>
+#include <mbedtls/error.h>
+
+typedef struct tlsmt_ctx {
+       mbedtls_entropy_context entropy;
+       mbedtls_ctr_drbg_context ctr_drbg;
+       mbedtls_ssl_config ssl_config;
+       mbedtls_x509_crt own_cert;
+       mbedtls_pk_context own_cert_key;
+       mbedtls_x509_crt ca_chain;
+       unsigned long verify_depth;
+       int refcount;
+#ifdef LDAP_R_COMPILE
+       ldap_pvt_thread_mutex_t ref_mutex;
+#endif
+} tlsmt_ctx;
+
+typedef struct tlsmt_session {
+       mbedtls_ssl_context ssl_ctx;
+       tlsmt_ctx *config;
+} tlsmt_session;
+
+#ifdef LDAP_R_COMPILE
+static void tlsmt_thr_init( void )
+{
+}
+#endif /* LDAP_R_COMPILE */
+
+/*
+ * Initialize TLS subsystem. Should be called only once.
+ */
+static int
+tlsmt_init( void )
+{
+       return 0;
+}
+
+/*
+ * Tear down the TLS subsystem. Should only be called once.
+ */
+static void
+tlsmt_destroy( void )
+{
+
+}
+
+static tls_ctx *
+tlsmt_ctx_new( struct ldapoptions *lo )
+{
+       tlsmt_ctx *ctx;
+
+       ctx = ber_memcalloc ( 1, sizeof (*ctx) );
+       if ( ctx ) {
+               int ret = 0;
+               ctx->refcount = 1;
+               mbedtls_entropy_init( &ctx->entropy );
+               mbedtls_ctr_drbg_init( &ctx->ctr_drbg );
+               if( ( ret = mbedtls_ctr_drbg_seed( &ctx->ctr_drbg, mbedtls_entropy_func, &ctx->entropy, NULL, 0 ) )   != 0 )
+               {
+                       mbedtls_ctr_drbg_free( &ctx->ctr_drbg );
+                       mbedtls_entropy_free( &ctx->entropy );
+                       ber_memfree ( ctx );
+                       Debug1(LDAP_DEBUG_ANY, "Mbedtls can't init ctr_drbg: [-0x%x]. Unable to create tls context", -ret);
+                       return NULL;
+               }
+               mbedtls_ssl_config_init( &ctx->ssl_config );
+               mbedtls_ssl_conf_rng( &ctx->ssl_config, mbedtls_ctr_drbg_random, &ctx->ctr_drbg);
+               mbedtls_x509_crt_init( &ctx->own_cert );
+               mbedtls_pk_init( &ctx->own_cert_key );
+               mbedtls_x509_crt_init( &ctx->ca_chain );
+
+#ifdef LDAP_R_COMPILE
+               ldap_pvt_thread_mutex_init( &ctx->ref_mutex );
+#endif
+       }
+
+       return (tls_ctx *)ctx;
+}
+
+static void
+tlsmt_ctx_ref( tls_ctx *ctx )
+{
+
+       tlsmt_ctx *c = (tlsmt_ctx *)ctx;
+       LDAP_MUTEX_LOCK( &c->ref_mutex );
+       c->refcount++;
+       LDAP_MUTEX_UNLOCK( &c->ref_mutex );
+}
+
+static void
+tlsmt_ctx_free ( tls_ctx *ctx )
+{
+
+       tlsmt_ctx *c = (tlsmt_ctx *)ctx;
+       int refcount;
+
+       if ( !c ) return;
+
+       LDAP_MUTEX_LOCK( &c->ref_mutex );
+       refcount = --c->refcount;
+       LDAP_MUTEX_UNLOCK( &c->ref_mutex );
+       if ( refcount )
+               return;
+
+       mbedtls_ssl_config_free( &c->ssl_config );
+       mbedtls_ctr_drbg_free( &c->ctr_drbg );
+       mbedtls_entropy_free( &c->entropy );
+       mbedtls_x509_crt_free( &c->own_cert );
+       mbedtls_pk_free( &c->own_cert_key );
+       mbedtls_x509_crt_free( &c->ca_chain );
+       ber_memfree ( c );
+}
+
+/*
+ * initialize a new TLS context
+ */
+static int
+tlsmt_ctx_init( struct ldapoptions *lo, struct ldaptls *lt, int is_server, char *errmsg )
+{
+       tlsmt_ctx *ctx = (tlsmt_ctx *)lo->ldo_tls_ctx;
+       mbedtls_ssl_config *ssl_config = &ctx->ssl_config;
+
+       // Set all options for the connection
+       int ret = mbedtls_ssl_config_defaults(ssl_config, is_server?MBEDTLS_SSL_IS_SERVER:MBEDTLS_SSL_IS_CLIENT, MBEDTLS_SSL_TRANSPORT_STREAM, MBEDTLS_SSL_PRESET_DEFAULT);
+
+// MBedtls v3 deprecated SSLv3, TLS1.0, TLS1.1
+#if MBEDTLS_VERSION_NUMBER < 0x03000000
+       if ( lo->ldo_tls_protocol_min ) {
+               int minor = MBEDTLS_SSL_MINOR_VERSION_0; // SSLv3.0 shall be avoided
+               switch (lo->ldo_tls_protocol_min) {
+                       case LDAP_OPT_X_TLS_PROTOCOL_SSL2: // SSL2 not supported, set min to SSLv3
+                       case LDAP_OPT_X_TLS_PROTOCOL_SSL3:
+                               minor = MBEDTLS_SSL_MINOR_VERSION_0;
+                               break;
+                       case LDAP_OPT_X_TLS_PROTOCOL_TLS1_0:
+                               minor = MBEDTLS_SSL_MINOR_VERSION_1;
+                               break;
+                       case LDAP_OPT_X_TLS_PROTOCOL_TLS1_1:
+                               minor = MBEDTLS_SSL_MINOR_VERSION_2;
+                               break;
+                       case LDAP_OPT_X_TLS_PROTOCOL_TLS1_2:
+                       default:
+                               minor = MBEDTLS_SSL_MINOR_VERSION_3;
+                               break;
+                       case LDAP_OPT_X_TLS_PROTOCOL_TLS1_3:
+                               Debug0 ( LDAP_DEBUG_ANY, "MbedTLSv2 backend does not support TLSv1.3, keep minimum version to 1.2" );
+                               minor = MBEDTLS_SSL_MINOR_VERSION_3;
+                               break;
+               }
+               mbedtls_ssl_conf_min_version ( ssl_config, MBEDTLS_SSL_MAJOR_VERSION_3, minor );
+       }
+
+       if ( lo->ldo_tls_protocol_max ) {
+               int minor = MBEDTLS_SSL_MINOR_VERSION_3;
+               switch (lo->ldo_tls_protocol_max) {
+                       case LDAP_OPT_X_TLS_PROTOCOL_SSL2: // SSL2 not supported, set min to SSLv3
+                       case LDAP_OPT_X_TLS_PROTOCOL_SSL3:
+                               minor = MBEDTLS_SSL_MINOR_VERSION_0;
+                               break;
+                       case LDAP_OPT_X_TLS_PROTOCOL_TLS1_0:
+                               minor = MBEDTLS_SSL_MINOR_VERSION_1;
+                               break;
+                       case LDAP_OPT_X_TLS_PROTOCOL_TLS1_1:
+                               minor = MBEDTLS_SSL_MINOR_VERSION_2;
+                               break;
+                       case LDAP_OPT_X_TLS_PROTOCOL_TLS1_2:
+                       default:
+                               minor = MBEDTLS_SSL_MINOR_VERSION_3;
+                               break;
+                       case LDAP_OPT_X_TLS_PROTOCOL_TLS1_3:
+                               Debug0 ( LDAP_DEBUG_ANY, "MbedTLSv2 backend does not support TLSv1.3, keep maximum version to 1.2" );
+                               minor = MBEDTLS_SSL_MINOR_VERSION_3;
+                               break;
+               }
+               mbedtls_ssl_conf_max_version ( ssl_config, MBEDTLS_SSL_MAJOR_VERSION_3, minor );
+       }
+#else /* MBEDTLS_VERSION_NUMBER < 0x03000000 : MBEDTLS version 3 and above: No SSLv3, TLSv1.0, TLSv1.1 */
+       if ( lo->ldo_tls_protocol_min ) {
+               mbedtls_ssl_protocol_version version = MBEDTLS_SSL_VERSION_TLS1_2; // TLSv1.2 is the lowest version available
+               switch (lo->ldo_tls_protocol_max) {
+                       case LDAP_OPT_X_TLS_PROTOCOL_SSL2:
+                       case LDAP_OPT_X_TLS_PROTOCOL_SSL3:
+                       case LDAP_OPT_X_TLS_PROTOCOL_TLS1_0:
+                       case LDAP_OPT_X_TLS_PROTOCOL_TLS1_1:
+                               /* for all non supported version request, force TLSv1.2 */
+                               Debug0 ( LDAP_DEBUG_ANY, "MbedTLSv3 backend does not support TLS version under 1.2, switch the minimum version requested to it" );
+                       case LDAP_OPT_X_TLS_PROTOCOL_TLS1_2:
+                       default:
+                               version = MBEDTLS_SSL_VERSION_TLS1_2;
+                               break;
+                       case LDAP_OPT_X_TLS_PROTOCOL_TLS1_3:
+                               version = MBEDTLS_SSL_VERSION_TLS1_3;
+                               break;
+               }
+               mbedtls_ssl_conf_min_tls_version ( ssl_config, version );
+       }
+
+       if ( lo->ldo_tls_protocol_max ) {
+               mbedtls_ssl_protocol_version version = MBEDTLS_SSL_VERSION_TLS1_3;
+               switch (lo->ldo_tls_protocol_min) {
+                       case LDAP_OPT_X_TLS_PROTOCOL_SSL2:
+                       case LDAP_OPT_X_TLS_PROTOCOL_SSL3:
+                       case LDAP_OPT_X_TLS_PROTOCOL_TLS1_0:
+                       case LDAP_OPT_X_TLS_PROTOCOL_TLS1_1:
+                               /* for all non supported version request, force TLSv1.2 */
+                               Debug0 ( LDAP_DEBUG_ANY, "MbedTLSv3 backend does not support TLS version under 1.2, switch the maximum version requested to it" );
+                       case LDAP_OPT_X_TLS_PROTOCOL_TLS1_2:
+                       default:
+                               version = MBEDTLS_SSL_VERSION_TLS1_2;
+                               break;
+                       case LDAP_OPT_X_TLS_PROTOCOL_TLS1_3:
+                               version = MBEDTLS_SSL_VERSION_TLS1_3;
+                               break;
+               }
+               mbedtls_ssl_conf_max_tls_version ( ssl_config, version );
+       }
+
+#endif /* MBEDTLS_VERSION_NUMBER < 0x03000000 */
+
+       if ( lo->ldo_tls_ciphersuite ) {
+               Debug1 (LDAP_DEBUG_ANY, "tlsmt_ctx_init Cipher suite selection is not supported by MbedTLS backend, ignore setting %s\n", lt->lt_ciphersuite);
+       }
+
+       if (lo->ldo_tls_cacertdir != NULL) {
+               char **dirs = ldap_str2charray( lt->lt_cacertdir, CERTPATHSEP );
+               int i;
+               for ( i=0; dirs[i]; i++ ) {
+                       int ret = mbedtls_x509_crt_parse_path( &ctx->ca_chain, dirs[i] );
+                       if ( ret < 0 ) {
+                               Debug1( LDAP_DEBUG_ANY,
+                                       "TLS: warning: no certificate found in CA certificate directory `%s'.\n",
+                                       dirs[i] );
+                               /* only warn, no return */
+                               mbedtls_strerror( ret, errmsg, ERRBUFSIZE );
+                       }
+               }
+               ldap_charray_free( dirs );
+       }
+
+       if (lo->ldo_tls_cacertfile != NULL) {
+               int ret = mbedtls_x509_crt_parse_file( &ctx->ca_chain, lt->lt_cacertfile );
+               if ( ret < 0 ) {
+                       char errParseFile[ERRBUFSIZE];
+                       mbedtls_strerror( ret, errParseFile, ERRBUFSIZE );
+                       Debug3( LDAP_DEBUG_ANY,
+                               "TLS: could not use CA certificate file `%s': %s (%d)\n",
+                               lo->ldo_tls_cacertfile,
+                               errParseFile,
+                               ret );
+                       return -1;
+               }
+       }
+       mbedtls_ssl_conf_ca_chain(ssl_config, &ctx->ca_chain, NULL); // CRL not supported
+
+       if (( lo->ldo_tls_certfile && lo->ldo_tls_keyfile ) ||
+               ( lo->ldo_tls_cert.bv_val && lo->ldo_tls_key.bv_val )) {
+
+#if MBEDTLS_VERSION_NUMBER < 0x03000000
+               if ( lo->ldo_tls_key.bv_val ) {
+                       ret = mbedtls_pk_parse_key(&ctx->own_cert_key, (unsigned char *)lo->ldo_tls_key.bv_val, lo->ldo_tls_key.bv_len, NULL, 0);
+               } else {
+                       ret = mbedtls_pk_parse_keyfile(&ctx->own_cert_key, lt->lt_keyfile, NULL);
+               }
+#else /* MBEDTLS_VERSION_NUMBER < 0x03000000 */
+               if ( lo->ldo_tls_key.bv_val ) {
+                       ret = mbedtls_pk_parse_key(&ctx->own_cert_key, (unsigned char *)lo->ldo_tls_key.bv_val, lo->ldo_tls_key.bv_len, NULL, 0, mbedtls_ctr_drbg_random, &ctx->ctr_drbg);
+               } else {
+                       ret = mbedtls_pk_parse_keyfile(&ctx->own_cert_key, lt->lt_keyfile, NULL, mbedtls_ctr_drbg_random, &ctx->ctr_drbg);
+               }
+#endif /* MBEDTLS_VERSION_NUMBER < 0x03000000 */
+
+               if (ret != 0) {
+                       return -1;
+               }
+
+               if ( lo->ldo_tls_cert.bv_val ) {
+                       ret = mbedtls_x509_crt_parse( &ctx->own_cert, (unsigned char *)lo->ldo_tls_cert.bv_val, lo->ldo_tls_cert.bv_len);
+               } else {
+                       ret = mbedtls_x509_crt_parse_file( &ctx->own_cert, lt->lt_certfile);
+               }
+
+               if (ret != 0) {
+                       return -1;
+               }
+
+               if ( (ret = mbedtls_ssl_conf_own_cert(ssl_config, &ctx->own_cert, &ctx->own_cert_key ) ) != 0) {
+                       return -1;
+               }
+       }
+
+       switch ( lo->ldo_tls_require_cert ) {
+               case LDAP_OPT_X_TLS_NEVER :
+                       mbedtls_ssl_conf_authmode( ssl_config, MBEDTLS_SSL_VERIFY_NONE );
+                       break;
+               case LDAP_OPT_X_TLS_HARD:
+               case LDAP_OPT_X_TLS_DEMAND:
+               default:
+                       mbedtls_ssl_conf_authmode( ssl_config, MBEDTLS_SSL_VERIFY_REQUIRED );
+                       break;
+               case LDAP_OPT_X_TLS_ALLOW:
+               case LDAP_OPT_X_TLS_TRY:
+                       mbedtls_ssl_conf_authmode( ssl_config, MBEDTLS_SSL_VERIFY_OPTIONAL );
+                       break;
+       }
+
+       if ( is_server && lo->ldo_tls_dhfile ) {
+               Debug1 (LDAP_DEBUG_ANY, "tlsmt_ctx_init DH params from file is not supported by MbedTLS backend, ignore setting %s\n", lo->ldo_tls_dhfile);
+       }
+
+       return 0;
+}
+
+static tls_session *
+tlsmt_session_new( tls_ctx *ctx, int is_server )
+{
+       tlsmt_ctx *c = (tlsmt_ctx *)ctx;
+       tlsmt_session *session;
+
+       session = ber_memcalloc ( 1, sizeof (*session) );
+       if ( !session )
+               return NULL;
+
+       session->config = c;
+
+       mbedtls_ssl_init(&(session->ssl_ctx));
+       mbedtls_ssl_setup(&(session->ssl_ctx), &session->config->ssl_config);
+
+       return (tls_session *)session;
+}
+
+static int
+tlsmt_session_accept( tls_session *sess )
+{
+       tlsmt_session *s = (tlsmt_session *)sess;
+
+       int ret;
+       do {
+               ret = mbedtls_ssl_handshake( &(s->ssl_ctx) );
+       } while (ret!=0 && (ret== MBEDTLS_ERR_SSL_WANT_READ || ret==MBEDTLS_ERR_SSL_WANT_WRITE));
+
+       return ret;
+}
+
+static int
+tlsmt_session_connect( LDAP *ld, tls_session *sess, const char *name_in )
+{
+       tlsmt_session *s = (tlsmt_session *)sess;
+       if (name_in) {
+               int ret = mbedtls_ssl_set_hostname( &(s->ssl_ctx), name_in );
+               if ( ret != 0 ) {
+                       return ret;
+               }
+       }
+
+       return tlsmt_session_accept(sess);
+}
+
+static int
+tlsmt_session_upflags( Sockbuf *sb, tls_session *sess, int rc )
+{
+       if (rc == MBEDTLS_ERR_SSL_WANT_READ) {
+               sb->sb_trans_needs_read  = 1;
+               return 1;
+
+       } else if (rc == MBEDTLS_ERR_SSL_WANT_WRITE) {
+               sb->sb_trans_needs_write = 1;
+               return 1;
+       }
+       return 0;
+}
+
+static char *
+tlsmt_session_errmsg( tls_session *sess, int rc, char *buf, size_t len )
+{
+       if ( rc ) {
+               mbedtls_strerror(rc, buf, len);
+               return buf;
+       }
+       return NULL;
+}
+
+static int
+tlsmt_session_my_dn( tls_session *sess, struct berval *der_dn )
+{
+       // Session cannot give us our own certificate but it is stored in the config context
+       tlsmt_session *s = (tlsmt_session *)sess;
+
+       der_dn->bv_len = s->config->own_cert.subject_raw.len;
+       der_dn->bv_val = s->config->own_cert.subject_raw.p;
+
+       return 0;
+}
+
+static int
+tlsmt_session_peer_dn( tls_session *sess, struct berval *der_dn )
+{
+       tlsmt_session *s = (tlsmt_session *)sess;
+       const mbedtls_x509_crt* peer_cert = mbedtls_ssl_get_peer_cert( &s->ssl_ctx );
+
+       if ( peer_cert == NULL ) {
+
+               return LDAP_INVALID_CREDENTIALS;
+       }
+
+       der_dn->bv_len = peer_cert->subject_raw.len;
+       der_dn->bv_val = peer_cert->subject_raw.p;
+
+       return 0;
+}
+
+/* what kind of hostname were we given? */
+#define        IS_DNS  0
+#define        IS_IP4  1
+#define        IS_IP6  2
+
+static int
+tlsmt_session_chkhost( LDAP *ld, tls_session *sess, const char *name_in )
+{
+       tlsmt_session *s = (tlsmt_session *)sess;
+       int i, ret = LDAP_LOCAL_ERROR;
+       int chkSAN = ld->ld_options.ldo_tls_require_san, gotSAN = 0;
+       const char *name;
+       char *ptr;
+       char *domain = NULL;
+       int len1 = 0, len2 = 0;
+       int ntype = IS_DNS, nlen;
+#ifdef LDAP_PF_INET6
+       struct in6_addr addr;
+#else
+       struct in_addr addr;
+#endif
+
+       if( ldap_int_hostname &&
+               ( !name_in || !strcasecmp( name_in, "localhost" ) ) )
+       {
+               name = ldap_int_hostname;
+       } else {
+               name = name_in;
+       }
+       nlen = strlen(name);
+
+       const mbedtls_x509_crt* x = mbedtls_ssl_get_peer_cert( &s->ssl_ctx );
+       if (!x) {
+               Debug0( LDAP_DEBUG_ANY,
+                       "TLS: unable to get peer certificate.\n" );
+               /* If this was a fatal condition, things would have
+                * aborted long before now.
+                */
+               return LDAP_SUCCESS;
+       }
+
+#ifdef LDAP_PF_INET6
+       if (inet_pton(AF_INET6, name, &addr)) {
+               ntype = IS_IP6;
+       } else
+#endif
+       if ((ptr = strrchr(name, '.')) && isdigit((unsigned char)ptr[1])) {
+               if (inet_aton(name, (struct in_addr *)&addr)) ntype = IS_IP4;
+       }
+
+       if (ntype == IS_DNS) {
+               len1 = strlen(name);
+               domain = strchr(name, '.');
+               if (domain) {
+                       len2 = len1 - (domain-name);
+               }
+       }
+
+#if MBEDTLS_VERSION_NUMBER < 0x03000000
+       if ( chkSAN && ( ret != LDAP_SUCCESS ) && ( x->ext_types & MBEDTLS_X509_EXT_SUBJECT_ALT_NAME ) ) {
+#else
+       if ( chkSAN && ( ret != LDAP_SUCCESS ) && ( mbedtls_x509_crt_has_ext_type(x, MBEDTLS_X509_EXT_SUBJECT_ALT_NAME ) != 0 ) ) {
+#endif
+               mbedtls_x509_sequence *SANs = (mbedtls_x509_sequence *)&x->subject_alt_names;
+               while ( SANs != NULL && ret != LDAP_SUCCESS ) {
+                       gotSAN = 1;
+                       const mbedtls_x509_buf *san_buf = &SANs->buf;
+                       /* mbedtls does not support SAN ip address type, so parse it here instead of using x509_crt_check_san */
+                       switch ( san_buf->tag & ( MBEDTLS_ASN1_TAG_CLASS_MASK | MBEDTLS_ASN1_TAG_VALUE_MASK )) {
+                               /* DNS type */
+                               case (MBEDTLS_ASN1_CONTEXT_SPECIFIC | MBEDTLS_X509_SAN_DNS_NAME ) :
+                               {
+                                       /* Is this an exact match? */
+                                       if ((len1 == san_buf->len) && !strncasecmp(name, san_buf->p, len1)) {
+                                               ret = LDAP_SUCCESS;
+                                       }
+
+                                       /* Is this a wildcard match? */
+                                       if (domain && (san_buf->p[0] == '*') && (san_buf->p[1] == '.') &&
+                                               (len2 == san_buf->len-1) && !strncasecmp(domain, (san_buf->p)+1, len2))
+                                       {
+                                               ret = LDAP_SUCCESS;
+                                       }
+                               }
+                               break;
+                               /* IPADDRESS type */
+                               case (MBEDTLS_ASN1_CONTEXT_SPECIFIC | MBEDTLS_X509_SAN_IP_ADDRESS ) :
+                               {
+
+                                       if (
+                                               (ntype == IS_IP4 && san_buf->len == sizeof(struct in_addr))
+#ifdef LDAP_PF_INET6
+                                               || (ntype == IS_IP6 && san_buf->len == sizeof(struct in6_addr))
+#endif
+                                          ) {
+                                               if (!memcmp(san_buf->p, &addr, san_buf->len)) {
+                                                       ret = LDAP_SUCCESS;
+                                               }
+                                       }
+                               }
+                               break;
+                               default:
+                                       Debug0(LDAP_DEBUG_ANY, "Unsupported SAN type. Only DNS and IP ADDRESS are supported");
+                       }
+
+                       SANs = SANs->next;
+               }
+       }
+
+       if (ret != LDAP_SUCCESS && chkSAN) {
+               switch(chkSAN) {
+               case LDAP_OPT_X_TLS_DEMAND:
+               case LDAP_OPT_X_TLS_HARD:
+                       if (!gotSAN) {
+                               Debug0( LDAP_DEBUG_ANY,
+                                       "TLS: unable to get subjectAltName from peer certificate.\n" );
+                               ret = LDAP_CONNECT_ERROR;
+                               if ( ld->ld_error ) {
+                                       LDAP_FREE( ld->ld_error );
+                               }
+                               ld->ld_error = LDAP_STRDUP(
+                                       _("TLS: unable to get subjectAltName from peer certificate"));
+                               goto done;
+                       }
+                       /* FALLTHRU */
+               case LDAP_OPT_X_TLS_TRY:
+                       if (gotSAN) {
+                               Debug1( LDAP_DEBUG_ANY, "TLS: hostname (%s) does not match "
+                                       "subjectAltName in certificate.\n",
+                                       name );
+                               ret = LDAP_CONNECT_ERROR;
+                               if ( ld->ld_error ) {
+                                       LDAP_FREE( ld->ld_error );
+                               }
+                               ld->ld_error = LDAP_STRDUP(
+                                       _("TLS: hostname does not match subjectAltName in peer certificate"));
+                               goto done;
+                       }
+                       break;
+               case LDAP_OPT_X_TLS_ALLOW:
+                       break;
+               }
+       }
+
+       if (ret != LDAP_SUCCESS) {
+               /* find the last CN */
+               const mbedtls_x509_name *subject;
+               for( subject = &x->subject; subject != NULL && ret != LDAP_SUCCESS; subject = subject->next ) {
+                       if( MBEDTLS_OID_CMP( MBEDTLS_OID_AT_CN, &subject->oid ) == 0 ) {
+                               const mbedtls_x509_buf *cn=&subject->val;
+                               /* Is this an exact match? */
+                               if ((len1 == cn->len) && !strncasecmp(name, cn->p, len1)) {
+                                       ret = LDAP_SUCCESS;
+                               }
+
+                               /* Is this a wildcard match? */
+                               if (domain && (cn->p[0] == '*') && (cn->p[1] == '.') &&
+                                       (len2 == cn->len-1) && !strncasecmp(domain, (cn->p)+1, len2))
+                               {
+                                       ret = LDAP_SUCCESS;
+                               }
+                       }
+               }
+       }
+done:
+       return ret;
+}
+
+static int
+tlsmt_session_strength( tls_session *sess )
+{
+       tlsmt_session *s = (tlsmt_session *)sess;
+#if MBEDTLS_VERSION_NUMBER < 0x03000000
+       const mbedtls_ssl_ciphersuite_t *currentCipherSuite = mbedtls_ssl_ciphersuite_from_string( mbedtls_ssl_get_ciphersuite( &s->ssl_ctx ) );
+       if (currentCipherSuite == NULL) return 0;
+
+       return ( ( mbedtls_cipher_info_from_type( currentCipherSuite->cipher )->key_bitlen ) );
+#else /* MBEDTLS_VERSION_NUMBER < 0x03000000 */
+       const mbedtls_ssl_ciphersuite_t *currentCipherSuite = mbedtls_ssl_ciphersuite_from_id( mbedtls_ssl_get_ciphersuite_id_from_ssl( &s->ssl_ctx ) );
+       if (currentCipherSuite == NULL) return 0;
+
+       return ( ( mbedtls_ssl_ciphersuite_get_cipher_key_bitlen( currentCipherSuite ) ) );
+#endif /* MBEDTLS_VERSION_NUMBER < 0x03000000 */
+}
+
+static int
+tlsmt_session_unique( tls_session *sess, struct berval *buf, int is_server)
+{
+       Debug0(LDAP_DEBUG_ANY, "tlsmt_session_unique channel binding using unique is not available with MbedTLS backend\n");
+
+       return 0;
+}
+
+static int
+tlsmt_session_endpoint( tls_session *sess, struct berval *buf, int is_server )
+{
+       tlsmt_session *s = (tlsmt_session *)sess;
+
+       const mbedtls_x509_crt* cert = NULL;
+
+       /* get server certificate */
+       if ( is_server ) {
+               cert = &s->config->own_cert;
+       } else {
+               cert = mbedtls_ssl_get_peer_cert( &s->ssl_ctx );
+       }
+#if MBEDTLS_VERSION_NUMBER < 0x03000000
+       mbedtls_md_type_t mdt = cert->sig_md;
+#else
+       mbedtls_md_type_t mdt;
+       mbedtls_pk_type_t pk;
+       mbedtls_oid_get_sig_alg(&(cert->sig_oid), &mdt, &pk);
+#endif
+
+       /* RFC 5929 */
+       switch (mdt) {
+               case MBEDTLS_MD_NONE:
+#if MBEDTLS_VERSION_NUMBER < 0x03000000
+               case MBEDTLS_MD_MD2:
+               case MBEDTLS_MD_MD4:
+#endif
+               case MBEDTLS_MD_MD5:
+               case MBEDTLS_MD_SHA1:
+                       mdt = MBEDTLS_MD_SHA256;
+       }
+
+       const mbedtls_md_info_t *md = mbedtls_md_info_from_type(mdt);
+
+       int md_len = mbedtls_md_get_size(md);
+       if ( md_len > buf->bv_len) {
+               return 0;
+       }
+
+       if ( mbedtls_md( md, cert->raw.p, cert->raw.len, buf->bv_val ) != 0 ) {
+               return 0;
+       }
+       buf->bv_len = md_len;
+
+       return md_len;
+}
+
+static const char *
+tlsmt_session_version( tls_session *sess )
+{
+       tlsmt_session *s = (tlsmt_session *)sess;
+       return mbedtls_ssl_get_version( &s->ssl_ctx );
+}
+
+static const char *
+tlsmt_session_cipher( tls_session *sess )
+{
+       tlsmt_session *s = (tlsmt_session *)sess;
+       return mbedtls_ssl_get_ciphersuite( &s->ssl_ctx );
+}
+
+static int
+tlsmt_session_peercert( tls_session *sess, struct berval *der )
+{
+       tlsmt_session *s = (tlsmt_session *)sess;
+       const mbedtls_x509_crt* peer_cert = mbedtls_ssl_get_peer_cert( &s->ssl_ctx );
+
+       if ( peer_cert == NULL ) {
+               return -1;
+       }
+
+       der->bv_len = peer_cert->raw.len;
+       der->bv_val = LDAP_MALLOC( der->bv_len );
+       if (!der->bv_val)
+               return -1;
+       memcpy(der->bv_val, peer_cert->raw.p, der->bv_len);
+       return 0;
+}
+
+static int
+tlsmt_session_pinning( LDAP *ld, tls_session *sess, char *hashalg, struct berval *hash )
+{
+       int ret;
+       tlsmt_session *s = (tlsmt_session *)sess;
+       const mbedtls_x509_crt* peer_cert = mbedtls_ssl_get_peer_cert(&s->ssl_ctx);
+
+       if (peer_cert == NULL) {
+               return -1;
+       }
+       const mbedtls_md_info_t *mbedtls_hash;
+       if ( hashalg ) {
+               // mbedtls hash algo parser requires all uppercase characters in algo name
+               size_t hashalg_len = strlen(hashalg);
+               char *hashalgUpper = ber_memcalloc ( 1, hashalg_len + 1 );
+               for (int i=0; i<hashalg_len; i++) {
+                       hashalgUpper[i] = toupper(hashalg[i]);
+               }
+               mbedtls_hash = mbedtls_md_info_from_string( hashalgUpper );
+               ber_memfree( hashalgUpper );
+
+               if ( mbedtls_hash == NULL ) {
+                       Debug1( LDAP_DEBUG_ANY, "tlsmt_session_pinning: "
+                                       "unknown hashing algorithm for MbedTLS: '%s'\n",
+                                       hashalg );
+                       return -1;
+               }
+       }
+
+       // Extract certificate pk in DER format
+       const mbedtls_pk_context *pk = &peer_cert->pk;
+       size_t pk_size = mbedtls_pk_get_len( pk );
+
+       unsigned char *der_pk = ber_memcalloc ( 1, 2*pk_size );
+#if MBEDTLS_VERSION_NUMBER < 0x03000000
+       int der_pk_len = mbedtls_pk_write_pubkey_der( (mbedtls_pk_context *)pk, der_pk, pk_size*2 );
+#else
+       int der_pk_len = mbedtls_pk_write_pubkey_der( pk, der_pk, pk_size*2 );
+#endif
+
+       unsigned char *digest[MBEDTLS_MD_MAX_SIZE];
+       struct berval keyhash;
+
+       if ( hashalg ) {
+               keyhash.bv_len = mbedtls_md_get_size(mbedtls_hash);
+               keyhash.bv_val = (char *)digest;
+               mbedtls_md(mbedtls_hash, der_pk+2*pk_size-der_pk_len, der_pk_len, keyhash.bv_val );
+       } else {
+               keyhash.bv_len = der_pk_len;
+               keyhash.bv_val = der_pk+2*pk_size-der_pk_len;
+       }
+       ber_memfree(der_pk);
+
+       if ( ber_bvcmp( hash, &keyhash ) ) {
+               ret = LDAP_CONNECT_ERROR;
+               Debug0( LDAP_DEBUG_ANY, "tlsmt_session_pinning: "
+                               "public key hash does not match provided pin.\n" );
+               if ( ld->ld_error ) {
+                       LDAP_FREE( ld->ld_error );
+               }
+               ld->ld_error = LDAP_STRDUP(
+                       _("TLS: public key hash does not match provided pin"));
+       } else {
+               ret = LDAP_SUCCESS;
+       }
+
+       return ret;
+}
+
+/*
+ * TLS support for LBER Sockbufs
+ */
+
+struct tls_data {
+       tlsmt_session           *session;
+       Sockbuf_IO_Desc         *sbiod;
+};
+
+static int
+tlsmt_read ( void *ptr, unsigned char *buf, size_t len )
+{
+       struct tls_data *p;
+
+       if ( buf == NULL || len <= 0 ) return 0;
+
+       p = (struct tls_data *)ptr;
+
+       if ( p == NULL || p->sbiod == NULL ) {
+               return 0;
+       }
+
+       int ret = LBER_SBIOD_READ_NEXT( p->sbiod, buf, len );
+
+       if ( ret < 0 ) {
+               int err = sock_errno();
+               if ( err == EAGAIN || err == EWOULDBLOCK ) {
+                       return MBEDTLS_ERR_SSL_WANT_READ;
+               }
+       }
+
+       return ret;
+}
+
+static int
+tlsmt_write( void *ptr, const unsigned char *buf, size_t len )
+{
+       struct tls_data *p;
+
+       if ( buf == NULL || len <= 0 ) return 0;
+
+       p = (struct tls_data *)ptr;
+
+       if ( p == NULL || p->sbiod == NULL ) {
+               return 0;
+       }
+
+       int ret =  LBER_SBIOD_WRITE_NEXT( p->sbiod, (char *)buf, len );
+
+       if ( ret < 0 ) {
+               int err = sock_errno();
+               if ( err == EAGAIN || err == EWOULDBLOCK ) {
+
+                       return MBEDTLS_ERR_SSL_WANT_WRITE;
+               }
+       }
+
+       return ret;
+}
+
+static int
+tlsmt_sb_setup( Sockbuf_IO_Desc *sbiod, void *arg )
+{
+       struct tls_data *p;
+       tlsmt_session   *session = (tlsmt_session *) arg;
+
+       assert( sbiod != NULL );
+
+       p = LBER_MALLOC( sizeof( *p ) );
+       if ( p == NULL ) {
+               return -1;
+       }
+       mbedtls_ssl_set_bio(&(session->ssl_ctx), p, tlsmt_write, tlsmt_read, NULL);
+
+       p->session = session;
+       p->sbiod = sbiod;
+       sbiod->sbiod_pvt = p;
+
+       return 0;
+}
+
+static int
+tlsmt_sb_remove( Sockbuf_IO_Desc *sbiod )
+{
+       struct tls_data         *p;
+       assert( sbiod != NULL );
+       assert( sbiod->sbiod_pvt != NULL );
+       p = (struct tls_data *)sbiod->sbiod_pvt;
+
+       mbedtls_ssl_free( &p->session->ssl_ctx );
+       LBER_FREE( p->session );
+       LBER_FREE( sbiod->sbiod_pvt );
+       sbiod->sbiod_pvt = NULL;
+       return 0;
+}
+
+static int
+tlsmt_sb_close( Sockbuf_IO_Desc *sbiod )
+{
+       struct tls_data         *p;
+       assert( sbiod != NULL );
+       assert( sbiod->sbiod_pvt != NULL );
+       p = (struct tls_data *)sbiod->sbiod_pvt;
+
+       int ret = MBEDTLS_ERR_SSL_WANT_WRITE;
+       do { ret = mbedtls_ssl_close_notify( &(p->session->ssl_ctx) ); }
+       while (ret == MBEDTLS_ERR_SSL_WANT_WRITE);
+
+       return 0;
+}
+
+static int
+tlsmt_sb_ctrl( Sockbuf_IO_Desc *sbiod, int opt, void *arg )
+{
+       struct tls_data         *p;
+       assert( sbiod != NULL );
+       assert( sbiod->sbiod_pvt != NULL );
+       p = (struct tls_data *)sbiod->sbiod_pvt;
+
+       if ( opt == LBER_SB_OPT_GET_SSL ) {
+               *((tlsmt_session **)arg) = p->session;
+               return 1;
+
+       } else if ( opt == LBER_SB_OPT_DATA_READY ) {
+               return mbedtls_ssl_check_pending( &(p->session->ssl_ctx) );
+       }
+
+       return LBER_SBIOD_CTRL_NEXT( sbiod, opt, arg );
+}
+
+static ber_slen_t
+tlsmt_sb_read( Sockbuf_IO_Desc *sbiod, void *buf, ber_len_t len)
+{
+       struct tls_data *p;
+       assert( sbiod != NULL );
+       assert( sbiod->sbiod_pvt != NULL );
+       p = (struct tls_data *)sbiod->sbiod_pvt;
+
+       int ret = mbedtls_ssl_read( &(p->session->ssl_ctx), buf, len);
+
+       if (ret == MBEDTLS_ERR_SSL_WANT_READ || ret == MBEDTLS_ERR_SSL_WANT_WRITE ) {
+               sbiod->sbiod_sb->sb_trans_needs_read = 1;
+               sock_errset(EWOULDBLOCK);
+               return 0;
+       }
+       else {
+               sbiod->sbiod_sb->sb_trans_needs_read = 0;
+       }
+
+       return ret;
+}
+
+static ber_slen_t
+tlsmt_sb_write( Sockbuf_IO_Desc *sbiod, void *buf, ber_len_t len)
+{
+       struct tls_data *p;
+       assert( sbiod != NULL );
+       assert( sbiod->sbiod_pvt != NULL );
+       p = (struct tls_data *)sbiod->sbiod_pvt;
+
+       int ret = mbedtls_ssl_write( &(p->session->ssl_ctx), buf, len);
+
+       if (ret == MBEDTLS_ERR_SSL_WANT_READ || ret == MBEDTLS_ERR_SSL_WANT_WRITE ) {
+               sbiod->sbiod_sb->sb_trans_needs_write = 1;
+               sock_errset(EWOULDBLOCK);
+               return 0;
+       }
+       else {
+               sbiod->sbiod_sb->sb_trans_needs_write = 0;
+       }
+       return ret;
+}
+
+static Sockbuf_IO tlsmt_sbio =
+{
+       tlsmt_sb_setup,         /* sbi_setup */
+       tlsmt_sb_remove,                /* sbi_remove */
+       tlsmt_sb_ctrl,          /* sbi_ctrl */
+       tlsmt_sb_read,          /* sbi_read */
+       tlsmt_sb_write,         /* sbi_write */
+       tlsmt_sb_close          /* sbi_close */
+};
+
+tls_impl ldap_int_tls_impl = {
+       "MbedTLS",
+
+       tlsmt_init,
+       tlsmt_destroy,
+
+       tlsmt_ctx_new,
+       tlsmt_ctx_ref,
+       tlsmt_ctx_free,
+       tlsmt_ctx_init,
+
+       tlsmt_session_new,
+       tlsmt_session_connect,
+       tlsmt_session_accept,
+       tlsmt_session_upflags,
+       tlsmt_session_errmsg,
+       tlsmt_session_my_dn,
+       tlsmt_session_peer_dn,
+       tlsmt_session_chkhost,
+       tlsmt_session_strength,
+       tlsmt_session_unique,
+       tlsmt_session_endpoint,
+       tlsmt_session_version,
+       tlsmt_session_cipher,
+       tlsmt_session_peercert,
+       tlsmt_session_pinning,
+
+       &tlsmt_sbio,
+
+#ifdef LDAP_R_COMPILE
+       tlsmt_thr_init,
+#else
+       NULL,
+#endif
+
+       0
+};
+
+#endif /* HAVE_MBEDTLS */
index 590ee5022d70864fec211857975b54d67fcd6bd8..b9d6e37a97381e3025ccde47e006a2ac97a7bf49 100644 (file)
@@ -37,6 +37,7 @@
 /* include socket.h to get sys/types.h and/or winsock2.h */
 #include <ac/socket.h>
 
+#include "slap.h"
 #if HAVE_OPENSSL
 #include <openssl/sha.h>
 #include <openssl/hmac.h>
@@ -124,11 +125,45 @@ static EVP_MAC *evp_mac;
        hmac_digest( &ctx.outer, &ctx.inner, &ctx.state, h, h->digest_size, dig ); \
        dlen = h->digest_size
 
+#elif HAVE_MBEDTLS
+
+#include "mbedtls/md.h"
+
+#define TOTP_SHA512_DIGEST_LENGTH MBEDTLS_MD_MAX_SIZE
+#define TOTP_SHA1 mbedtls_md_info_from_type(MBEDTLS_MD_SHA1)
+#define TOTP_SHA224 mbedtls_md_info_from_type(MBEDTLS_MD_SHA224)
+#define TOTP_SHA256 mbedtls_md_info_from_type(MBEDTLS_MD_SHA256)
+#define TOTP_SHA384 mbedtls_md_info_from_type(MBEDTLS_MD_SHA384)
+#define TOTP_SHA512 mbedtls_md_info_from_type(MBEDTLS_MD_SHA512)
+
+static mbedtls_md_context_t *
+HMAC_CTX_new( void )
+{
+       mbedtls_md_context_t *ctx = ch_malloc( sizeof(mbedtls_md_context_t) );
+       if ( ctx != NULL ) {
+               mbedtls_md_init( ctx );
+       }
+       return ctx;
+}
+
+#define TOTP_HMAC_CTX mbedtls_md_context_t*
+#define HMAC_setup( ctx, key, len, hash ) \
+       ctx = HMAC_CTX_new(); \
+       mbedtls_md_setup(ctx, (const mbedtls_md_info_t *)hash, 1); \
+       mbedtls_md_hmac_starts(ctx, key, len)
+
+#define HMAC_crunch( ctx, buf, len ) mbedtls_md_hmac_update( ctx, buf, len )
+
+#define HMAC_finish( ctx, dig, dlen ) \
+       mbedtls_md_hmac_finish(ctx, dig); \
+       dlen = mbedtls_md_get_size((const mbedtls_md_info_t *)hash); \
+       mbedtls_md_free(ctx); \
+       ch_free(ctx)
+
 #else
 #error Unsupported crypto backend.
 #endif
 
-#include "slap.h"
 #include "slap-config.h"
 
 /* Schema from OATH-LDAP project by Michael Ströder */
index cd99fcfa0624e4fce825101575601f257036d078..7d1e4c1fe2a732a5c35d1c87b5c7d927d246c00b 100755 (executable)
@@ -110,7 +110,7 @@ else
        echo "success"
 fi
 
-if test $WITH_TLS_TYPE = openssl ; then
+if [ $WITH_TLS_TYPE = openssl ] || [ $WITH_TLS_TYPE = mbedtls ]; then
        echo -n "Using ldapsearch with startTLS and specific protocol version...."
        $LDAPSEARCH -o tls_cacert=$TESTDIR/tls/ca/certs/testsuiteCA.crt -o tls_reqcert=hard -o tls_protocol_min=3.3 -ZZ -b "" -s base -H $URIP1 \
                '@extensibleObject' > $SEARCHOUT 2>&1
index 4d4e260c8fbda3e122b3ebfbad019b0f2dc30477..c7698c09e753bef3f05994635d550918cd9db9e2 100755 (executable)
@@ -194,10 +194,15 @@ EOF
                for icb in "none" "tls-unique" "tls-endpoint" ; do
 
                        # The gnutls implementation of "tls-unique" seems broken
+                       # mbedtls does not support "tls-unique"
                        if test $icb = "tls-unique" -o $acb = "tls-unique" ; then
                                if test $WITH_TLS_TYPE = gnutls ; then
                                        continue
                                fi
+                               if test $WITH_TLS_TYPE = mbedtls ; then
+                                       echo "mbedtls backend does not support TLS-unique binding, skip"
+                                       continue
+                               fi
                        fi
 
                        fail="no"