The patch looks huge, but it's just file renames, and required changes in
includes / Makefiles.  Use 'git diff -C' or a tool like gitk to easily
review this patch.

Signed-off-by: Steffan Karger <stef...@karger.me>
---
 src/openvpn/Makefile.am           |    8 +-
 src/openvpn/crypto_backend.h      |    2 +-
 src/openvpn/crypto_mbedtls.c      |  758 ++++++++++++++++++++++++
 src/openvpn/crypto_mbedtls.h      |  146 +++++
 src/openvpn/crypto_polarssl.c     |  758 ------------------------
 src/openvpn/crypto_polarssl.h     |  146 -----
 src/openvpn/pkcs11_mbedtls.c      |  129 ++++
 src/openvpn/pkcs11_polarssl.c     |  129 ----
 src/openvpn/plugin.h              |    2 +-
 src/openvpn/ssl_backend.h         |    4 +-
 src/openvpn/ssl_mbedtls.c         | 1184 +++++++++++++++++++++++++++++++++++++
 src/openvpn/ssl_mbedtls.h         |   92 +++
 src/openvpn/ssl_polarssl.c        | 1184 -------------------------------------
 src/openvpn/ssl_polarssl.h        |   92 ---
 src/openvpn/ssl_verify.h          |    2 +-
 src/openvpn/ssl_verify_mbedtls.c  |  508 ++++++++++++++++
 src/openvpn/ssl_verify_mbedtls.h  |   78 +++
 src/openvpn/ssl_verify_polarssl.c |  508 ----------------
 src/openvpn/ssl_verify_polarssl.h |   78 ---
 19 files changed, 2904 insertions(+), 2904 deletions(-)
 create mode 100644 src/openvpn/crypto_mbedtls.c
 create mode 100644 src/openvpn/crypto_mbedtls.h
 delete mode 100644 src/openvpn/crypto_polarssl.c
 delete mode 100644 src/openvpn/crypto_polarssl.h
 create mode 100644 src/openvpn/pkcs11_mbedtls.c
 delete mode 100644 src/openvpn/pkcs11_polarssl.c
 create mode 100644 src/openvpn/ssl_mbedtls.c
 create mode 100644 src/openvpn/ssl_mbedtls.h
 delete mode 100644 src/openvpn/ssl_polarssl.c
 delete mode 100644 src/openvpn/ssl_polarssl.h
 create mode 100644 src/openvpn/ssl_verify_mbedtls.c
 create mode 100644 src/openvpn/ssl_verify_mbedtls.h
 delete mode 100644 src/openvpn/ssl_verify_polarssl.c
 delete mode 100644 src/openvpn/ssl_verify_polarssl.h

diff --git a/src/openvpn/Makefile.am b/src/openvpn/Makefile.am
index bf1d749..9d4bf61 100644
--- a/src/openvpn/Makefile.am
+++ b/src/openvpn/Makefile.am
@@ -46,7 +46,7 @@ openvpn_SOURCES = \
        comp-lz4.c comp-lz4.h \
        crypto.c crypto.h crypto_backend.h \
        crypto_openssl.c crypto_openssl.h \
-       crypto_polarssl.c crypto_polarssl.h \
+       crypto_mbedtls.c crypto_mbedtls.h \
        dhcp.c dhcp.h \
        errlevel.h \
        error.c error.h \
@@ -80,7 +80,7 @@ openvpn_SOURCES = \
        occ.c occ.h occ-inline.h \
        pkcs11.c pkcs11.h pkcs11_backend.h \
        pkcs11_openssl.c \
-       pkcs11_polarssl.c \
+       pkcs11_mbedtls.c \
        openvpn.c openvpn.h \
        options.c options.h \
        otime.c otime.h \
@@ -105,11 +105,11 @@ openvpn_SOURCES = \
        socks.c socks.h \
        ssl.c ssl.h  ssl_backend.h \
        ssl_openssl.c ssl_openssl.h \
-       ssl_polarssl.c ssl_polarssl.h \
+       ssl_mbedtls.c ssl_mbedtls.h \
        ssl_common.h \
        ssl_verify.c ssl_verify.h ssl_verify_backend.h \
        ssl_verify_openssl.c ssl_verify_openssl.h \
-       ssl_verify_polarssl.c ssl_verify_polarssl.h \
+       ssl_verify_mbedtls.c ssl_verify_mbedtls.h \
        status.c status.h \
        syshead.h \
        tun.c tun.h \
diff --git a/src/openvpn/crypto_backend.h b/src/openvpn/crypto_backend.h
index c4986f5..3893f14 100644
--- a/src/openvpn/crypto_backend.h
+++ b/src/openvpn/crypto_backend.h
@@ -34,7 +34,7 @@
 #include "crypto_openssl.h"
 #endif
 #ifdef ENABLE_CRYPTO_MBEDTLS
-#include "crypto_polarssl.h"
+#include "crypto_mbedtls.h"
 #endif
 #include "basic.h"

diff --git a/src/openvpn/crypto_mbedtls.c b/src/openvpn/crypto_mbedtls.c
new file mode 100644
index 0000000..da1b417
--- /dev/null
+++ b/src/openvpn/crypto_mbedtls.c
@@ -0,0 +1,758 @@
+/*
+ *  OpenVPN -- An application to securely tunnel IP networks
+ *             over a single TCP/UDP port, with support for SSL/TLS-based
+ *             session authentication and key exchange,
+ *             packet encryption, packet authentication, and
+ *             packet compression.
+ *
+ *  Copyright (C) 2002-2010 OpenVPN Technologies, Inc. <sa...@openvpn.net>
+ *  Copyright (C) 2010 Fox Crypto B.V. <open...@fox-it.com>
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License version 2
+ *  as published by the Free Software Foundation.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program (see the file COPYING included with this
+ *  distribution); if not, write to the Free Software Foundation, Inc.,
+ *  59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+/**
+ * @file Data Channel Cryptography mbed TLS-specific backend interface
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#elif defined(_MSC_VER)
+#include "config-msvc.h"
+#endif
+
+#include "syshead.h"
+
+#if defined(ENABLE_CRYPTO) && defined(ENABLE_CRYPTO_MBEDTLS)
+
+#include "errlevel.h"
+#include "basic.h"
+#include "buffer.h"
+#include "integer.h"
+#include "crypto_backend.h"
+#include "otime.h"
+#include "misc.h"
+
+#include <mbedtls/des.h>
+#include <mbedtls/error.h>
+#include <mbedtls/md5.h>
+#include <mbedtls/cipher.h>
+#include <mbedtls/havege.h>
+
+#include <mbedtls/entropy.h>
+
+
+/*
+ *
+ * Hardware engine support. Allows loading/unloading of engines.
+ *
+ */
+
+void
+crypto_init_lib_engine (const char *engine_name)
+{
+  msg (M_WARN, "Note: mbed TLS hardware crypto engine functionality is not "
+      "available");
+}
+
+/*
+ *
+ * Functions related to the core crypto library
+ *
+ */
+
+void
+crypto_init_lib (void)
+{
+}
+
+void
+crypto_uninit_lib (void)
+{
+}
+
+void
+crypto_clear_error (void)
+{
+}
+
+bool mbed_log_err(unsigned int flags, int errval, const char *prefix)
+{
+  if (0 != errval)
+    {
+      char errstr[256];
+      mbedtls_strerror(errval, errstr, sizeof(errstr));
+
+      if (NULL == prefix) prefix = "mbed TLS error";
+      msg (flags, "%s: %s", prefix, errstr);
+    }
+
+  return 0 == errval;
+}
+
+bool mbed_log_func_line(unsigned int flags, int errval, const char *func,
+    int line)
+{
+  char prefix[256];
+
+  if (!openvpn_snprintf(prefix, sizeof(prefix), "%s:%d", func, line))
+    return mbed_log_err(flags, errval, func);
+
+  return mbed_log_err(flags, errval, prefix);
+}
+
+
+#ifdef DMALLOC
+void
+crypto_init_dmalloc (void)
+{
+  msg (M_ERR, "Error: dmalloc support is not available for mbed TLS.");
+}
+#endif /* DMALLOC */
+
+const cipher_name_pair cipher_name_translation_table[] = {
+    { "BF-CBC", "BLOWFISH-CBC" },
+    { "BF-CFB", "BLOWFISH-CFB64" },
+    { "CAMELLIA-128-CFB", "CAMELLIA-128-CFB128" },
+    { "CAMELLIA-192-CFB", "CAMELLIA-192-CFB128" },
+    { "CAMELLIA-256-CFB", "CAMELLIA-256-CFB128" }
+};
+const size_t cipher_name_translation_table_count =
+    sizeof (cipher_name_translation_table) / sizeof 
(*cipher_name_translation_table);
+
+void
+show_available_ciphers ()
+{
+  const int *ciphers = mbedtls_cipher_list();
+
+#ifndef ENABLE_SMALL
+  printf ("The following ciphers and cipher modes are available for use\n"
+         "with " PACKAGE_NAME ".  Each cipher shown below may be used as a\n"
+         "parameter to the --cipher option.  Using a CBC or GCM mode is\n"
+         "recommended.  In static key mode only CBC mode is allowed.\n\n");
+#endif
+
+  while (*ciphers != 0)
+    {
+      const cipher_kt_t *info = mbedtls_cipher_info_from_type(*ciphers);
+
+      if (info && (cipher_kt_mode_cbc(info)
+#ifdef HAVE_AEAD_CIPHER_MODES
+          || cipher_kt_mode_aead(info)
+#endif
+          ))
+       {
+         const char *ssl_only = cipher_kt_mode_cbc(info) ?
+             "" : " (TLS client/server mode)";
+
+         printf ("%s %d bit default key%s\n",
+             cipher_kt_name(info), cipher_kt_key_size(info) * 8, ssl_only);
+       }
+
+      ciphers++;
+    }
+  printf ("\n");
+}
+
+void
+show_available_digests ()
+{
+  const int *digests = mbedtls_md_list();
+
+#ifndef ENABLE_SMALL
+  printf ("The following message digests are available for use with\n"
+         PACKAGE_NAME ".  A message digest is used in conjunction with\n"
+         "the HMAC function, to authenticate received packets.\n"
+         "You can specify a message digest as parameter to\n"
+         "the --auth option.\n\n");
+#endif
+
+  while (*digests != 0)
+    {
+      const mbedtls_md_info_t *info = mbedtls_md_info_from_type(*digests);
+
+      if (info)
+       printf ("%s %d bit default key\n", mbedtls_md_get_name(info),
+           mbedtls_md_get_size(info) * 8);
+      digests++;
+    }
+  printf ("\n");
+}
+
+void
+show_available_engines ()
+{
+  printf ("Sorry, mbed TLS hardware crypto engine functionality is not "
+      "available\n");
+}
+
+/*
+ *
+ * Random number functions, used in cases where we want
+ * reasonably strong cryptographic random number generation
+ * without depleting our entropy pool.  Used for random
+ * IV values and a number of other miscellaneous tasks.
+ *
+ */
+
+/*
+ * Initialise the given ctr_drbg context, using a personalisation string and an
+ * entropy gathering function.
+ */
+mbedtls_ctr_drbg_context * rand_ctx_get()
+{
+  static mbedtls_entropy_context ec = {0};
+  static mbedtls_ctr_drbg_context cd_ctx = {0};
+  static bool rand_initialised = false;
+
+  if (!rand_initialised)
+    {
+      struct gc_arena gc = gc_new();
+      struct buffer pers_string = alloc_buf_gc(100, &gc);
+
+      /*
+       * Personalisation string, should be as unique as possible (see NIST
+       * 800-90 section 8.7.1). We have very little information at this stage.
+       * Include Program Name, memory address of the context and PID.
+       */
+      buf_printf(&pers_string, "OpenVPN %0u %p %s", platform_getpid(), 
&cd_ctx, time_string(0, 0, 0, &gc));
+
+      /* Initialise mbed TLS RNG, and built-in entropy sources */
+      mbedtls_entropy_init(&ec);
+
+      mbedtls_ctr_drbg_init(&cd_ctx);
+      if (!mbed_ok(mbedtls_ctr_drbg_seed(&cd_ctx, mbedtls_entropy_func, &ec,
+                   BPTR(&pers_string), BLEN(&pers_string))))
+        msg (M_FATAL, "Failed to initialize random generator");
+
+      gc_free(&gc);
+      rand_initialised = true;
+  }
+
+  return &cd_ctx;
+}
+
+#ifdef ENABLE_PREDICTION_RESISTANCE
+void rand_ctx_enable_prediction_resistance()
+{
+  mbedtls_ctr_drbg_context *cd_ctx = rand_ctx_get();
+
+  mbedtls_ctr_drbg_set_prediction_resistance(cd_ctx, 1);
+}
+#endif /* ENABLE_PREDICTION_RESISTANCE */
+
+int
+rand_bytes (uint8_t *output, int len)
+{
+  mbedtls_ctr_drbg_context *rng_ctx = rand_ctx_get();
+
+  while (len > 0)
+    {
+      const size_t blen = min_int (len, MBEDTLS_CTR_DRBG_MAX_REQUEST);
+      if (0 != mbedtls_ctr_drbg_random(rng_ctx, output, blen))
+       return 0;
+
+      output += blen;
+      len -= blen;
+    }
+
+  return 1;
+}
+
+/*
+ *
+ * Key functions, allow manipulation of keys.
+ *
+ */
+
+
+int
+key_des_num_cblocks (const mbedtls_cipher_info_t *kt)
+{
+  int ret = 0;
+  if (kt->type == MBEDTLS_CIPHER_DES_CBC)
+    ret = 1;
+  if (kt->type == MBEDTLS_CIPHER_DES_EDE_CBC)
+    ret = 2;
+  if (kt->type == MBEDTLS_CIPHER_DES_EDE3_CBC)
+    ret = 3;
+
+  dmsg (D_CRYPTO_DEBUG, "CRYPTO INFO: n_DES_cblocks=%d", ret);
+  return ret;
+}
+
+bool
+key_des_check (uint8_t *key, int key_len, int ndc)
+{
+  int i;
+  struct buffer b;
+
+  buf_set_read (&b, key, key_len);
+
+  for (i = 0; i < ndc; ++i)
+    {
+      unsigned char *key = buf_read_alloc(&b, MBEDTLS_DES_KEY_SIZE);
+      if (!key)
+       {
+         msg (D_CRYPT_ERRORS, "CRYPTO INFO: check_key_DES: insufficient key 
material");
+         goto err;
+       }
+      if (0 != mbedtls_des_key_check_weak(key))
+       {
+         msg (D_CRYPT_ERRORS, "CRYPTO INFO: check_key_DES: weak key detected");
+         goto err;
+       }
+      if (0 != mbedtls_des_key_check_key_parity(key))
+       {
+         msg (D_CRYPT_ERRORS, "CRYPTO INFO: check_key_DES: bad parity 
detected");
+         goto err;
+       }
+    }
+  return true;
+
+ err:
+  return false;
+}
+
+void
+key_des_fixup (uint8_t *key, int key_len, int ndc)
+{
+  int i;
+  struct buffer b;
+
+  buf_set_read (&b, key, key_len);
+  for (i = 0; i < ndc; ++i)
+    {
+      unsigned char *key = buf_read_alloc(&b, MBEDTLS_DES_KEY_SIZE);
+      if (!key)
+       {
+         msg (D_CRYPT_ERRORS, "CRYPTO INFO: fixup_key_DES: insufficient key 
material");
+         return;
+       }
+      mbedtls_des_key_set_parity(key);
+    }
+}
+
+/*
+ *
+ * Generic cipher key type functions
+ *
+ */
+
+
+const mbedtls_cipher_info_t *
+cipher_kt_get (const char *ciphername)
+{
+  const mbedtls_cipher_info_t *cipher = NULL;
+
+  ASSERT (ciphername);
+
+  cipher = mbedtls_cipher_info_from_string(ciphername);
+
+  if (NULL == cipher)
+    msg (M_FATAL, "Cipher algorithm '%s' not found", ciphername);
+
+  if (cipher->key_bitlen/8 > MAX_CIPHER_KEY_LENGTH)
+    msg (M_FATAL, "Cipher algorithm '%s' uses a default key size (%d bytes) 
which is larger than " PACKAGE_NAME "'s current maximum key size (%d bytes)",
+        ciphername,
+        cipher->key_bitlen/8,
+        MAX_CIPHER_KEY_LENGTH);
+
+  return cipher;
+}
+
+const char *
+cipher_kt_name (const mbedtls_cipher_info_t *cipher_kt)
+{
+  if (NULL == cipher_kt)
+    return "[null-cipher]";
+
+  return translate_cipher_name_to_openvpn(cipher_kt->name);
+}
+
+int
+cipher_kt_key_size (const mbedtls_cipher_info_t *cipher_kt)
+{
+  if (NULL == cipher_kt)
+    return 0;
+
+  return cipher_kt->key_bitlen/8;
+}
+
+int
+cipher_kt_iv_size (const mbedtls_cipher_info_t *cipher_kt)
+{
+  if (NULL == cipher_kt)
+    return 0;
+  return cipher_kt->iv_size;
+}
+
+int
+cipher_kt_block_size (const mbedtls_cipher_info_t *cipher_kt)
+{
+  if (NULL == cipher_kt)
+    return 0;
+  return cipher_kt->block_size;
+}
+
+int
+cipher_kt_tag_size (const mbedtls_cipher_info_t *cipher_kt)
+{
+#ifdef HAVE_AEAD_CIPHER_MODES
+  if (cipher_kt && cipher_kt_mode_aead(cipher_kt))
+    return OPENVPN_AEAD_TAG_LENGTH;
+#endif
+  return 0;
+}
+
+int
+cipher_kt_mode (const mbedtls_cipher_info_t *cipher_kt)
+{
+  ASSERT(NULL != cipher_kt);
+  return cipher_kt->mode;
+}
+
+bool
+cipher_kt_mode_cbc(const cipher_kt_t *cipher)
+{
+  return cipher && cipher_kt_mode(cipher) == OPENVPN_MODE_CBC;
+}
+
+bool
+cipher_kt_mode_ofb_cfb(const cipher_kt_t *cipher)
+{
+  return cipher && (cipher_kt_mode(cipher) == OPENVPN_MODE_OFB ||
+      cipher_kt_mode(cipher) == OPENVPN_MODE_CFB);
+}
+
+bool
+cipher_kt_mode_aead(const cipher_kt_t *cipher)
+{
+  return cipher && cipher_kt_mode(cipher) == OPENVPN_MODE_GCM;
+}
+
+
+/*
+ *
+ * Generic cipher context functions
+ *
+ */
+
+
+void
+cipher_ctx_init (mbedtls_cipher_context_t *ctx, uint8_t *key, int key_len,
+    const mbedtls_cipher_info_t *kt, const mbedtls_operation_t operation)
+{
+  ASSERT(NULL != kt && NULL != ctx);
+
+  CLEAR (*ctx);
+
+  if (!mbed_ok(mbedtls_cipher_setup(ctx, kt)))
+    msg (M_FATAL, "mbed TLS cipher context init #1");
+
+  if (!mbed_ok(mbedtls_cipher_setkey(ctx, key, key_len*8, operation)))
+    msg (M_FATAL, "mbed TLS cipher set key");
+
+  /* make sure we used a big enough key */
+  ASSERT (ctx->key_bitlen <= key_len*8);
+}
+
+void cipher_ctx_cleanup (mbedtls_cipher_context_t *ctx)
+{
+  mbedtls_cipher_free(ctx);
+}
+
+int cipher_ctx_iv_length (const mbedtls_cipher_context_t *ctx)
+{
+  return mbedtls_cipher_get_iv_size(ctx);
+}
+
+int cipher_ctx_get_tag (cipher_ctx_t *ctx, uint8_t* tag, int tag_len)
+{
+#ifdef HAVE_AEAD_CIPHER_MODES
+  if (tag_len > SIZE_MAX)
+    return 0;
+
+  if (!mbed_ok (mbedtls_cipher_write_tag (ctx, (unsigned char *) tag, 
tag_len)))
+    return 0;
+
+  return 1;
+#else
+  ASSERT(0);
+#endif /* HAVE_AEAD_CIPHER_MODES */
+}
+
+int cipher_ctx_block_size(const mbedtls_cipher_context_t *ctx)
+{
+  return mbedtls_cipher_get_block_size(ctx);
+}
+
+int cipher_ctx_mode (const mbedtls_cipher_context_t *ctx)
+{
+  ASSERT(NULL != ctx);
+
+  return cipher_kt_mode(ctx->cipher_info);
+}
+
+const cipher_kt_t *
+cipher_ctx_get_cipher_kt (const cipher_ctx_t *ctx)
+{
+  return ctx ? ctx->cipher_info : NULL;
+}
+
+int cipher_ctx_reset (mbedtls_cipher_context_t *ctx, uint8_t *iv_buf)
+{
+  if (!mbed_ok(mbedtls_cipher_reset(ctx)))
+    return 0;
+
+  if (!mbed_ok(mbedtls_cipher_set_iv(ctx, iv_buf, ctx->cipher_info->iv_size)))
+    return 0;
+
+  return 1;
+}
+
+int cipher_ctx_update_ad (cipher_ctx_t *ctx, const uint8_t *src, int src_len)
+{
+#ifdef HAVE_AEAD_CIPHER_MODES
+  if (src_len > SIZE_MAX)
+    return 0;
+
+  if (!mbed_ok (mbedtls_cipher_update_ad (ctx, src, src_len)))
+    return 0;
+
+  return 1;
+#else
+  ASSERT(0);
+#endif /* HAVE_AEAD_CIPHER_MODES */
+}
+
+int cipher_ctx_update (mbedtls_cipher_context_t *ctx, uint8_t *dst,
+    int *dst_len, uint8_t *src, int src_len)
+{
+  size_t s_dst_len = *dst_len;
+
+  if (!mbed_ok(mbedtls_cipher_update(ctx, src, (size_t) src_len, dst,
+      &s_dst_len)))
+    return 0;
+
+  *dst_len = s_dst_len;
+
+  return 1;
+}
+
+int cipher_ctx_final (mbedtls_cipher_context_t *ctx, uint8_t *dst, int 
*dst_len)
+{
+  size_t s_dst_len = *dst_len;
+
+  if (!mbed_ok(mbedtls_cipher_finish(ctx, dst, &s_dst_len)))
+    return 0;
+
+  *dst_len = s_dst_len;
+
+  return 1;
+}
+
+int cipher_ctx_final_check_tag (mbedtls_cipher_context_t *ctx, uint8_t *dst,
+    int *dst_len, uint8_t *tag, size_t tag_len)
+{
+#ifdef HAVE_AEAD_CIPHER_MODES
+  size_t olen = 0;
+
+  if (MBEDTLS_DECRYPT != ctx->operation)
+    return 0;
+
+  if (tag_len > SIZE_MAX)
+    return 0;
+
+  if (!mbed_ok (mbedtls_cipher_finish (ctx, dst, &olen)))
+    {
+      msg (D_CRYPT_ERRORS, "%s: cipher_ctx_final() failed", __func__);
+      return 0;
+    }
+
+  if (olen > INT_MAX)
+    return 0;
+  *dst_len = olen;
+
+  if (!mbed_ok (mbedtls_cipher_check_tag (ctx, (const unsigned char *) tag,
+      tag_len)))
+    return 0;
+
+  return 1;
+#else
+  ASSERT(0);
+#endif /* HAVE_AEAD_CIPHER_MODES */
+}
+
+void
+cipher_des_encrypt_ecb (const unsigned char key[DES_KEY_LENGTH],
+    unsigned char *src,
+    unsigned char *dst)
+{
+  mbedtls_des_context ctx;
+
+  ASSERT (mbed_ok(mbedtls_des_setkey_enc(&ctx, key)));
+  ASSERT (mbed_ok(mbedtls_des_crypt_ecb(&ctx, src, dst)));
+}
+
+
+
+/*
+ *
+ * Generic message digest information functions
+ *
+ */
+
+
+const mbedtls_md_info_t *
+md_kt_get (const char *digest)
+{
+  const mbedtls_md_info_t *md = NULL;
+  ASSERT (digest);
+
+  md = mbedtls_md_info_from_string(digest);
+  if (!md)
+    msg (M_FATAL, "Message hash algorithm '%s' not found", digest);
+  if (mbedtls_md_get_size(md) > MAX_HMAC_KEY_LENGTH)
+    msg (M_FATAL, "Message hash algorithm '%s' uses a default hash size (%d 
bytes) which is larger than " PACKAGE_NAME "'s current maximum hash size (%d 
bytes)",
+        digest,
+        mbedtls_md_get_size(md),
+        MAX_HMAC_KEY_LENGTH);
+  return md;
+}
+
+const char *
+md_kt_name (const mbedtls_md_info_t *kt)
+{
+  if (NULL == kt)
+    return "[null-digest]";
+  return mbedtls_md_get_name (kt);
+}
+
+int
+md_kt_size (const mbedtls_md_info_t *kt)
+{
+  if (NULL == kt)
+    return 0;
+  return mbedtls_md_get_size(kt);
+}
+
+/*
+ *
+ * Generic message digest functions
+ *
+ */
+
+int
+md_full (const md_kt_t *kt, const uint8_t *src, int src_len, uint8_t *dst)
+{
+  return 0 == mbedtls_md(kt, src, src_len, dst);
+}
+
+
+void
+md_ctx_init (mbedtls_md_context_t *ctx, const mbedtls_md_info_t *kt)
+{
+  ASSERT(NULL != ctx && NULL != kt);
+
+  mbedtls_md_init(ctx);
+  ASSERT(0 == mbedtls_md_setup(ctx, kt, 0));
+  ASSERT(0 == mbedtls_md_starts(ctx));
+}
+
+void
+md_ctx_cleanup(mbedtls_md_context_t *ctx)
+{
+}
+
+int
+md_ctx_size (const mbedtls_md_context_t *ctx)
+{
+  if (NULL == ctx)
+    return 0;
+  return mbedtls_md_get_size(ctx->md_info);
+}
+
+void
+md_ctx_update (mbedtls_md_context_t *ctx, const uint8_t *src, int src_len)
+{
+  ASSERT(0 == mbedtls_md_update(ctx, src, src_len));
+}
+
+void
+md_ctx_final (mbedtls_md_context_t *ctx, uint8_t *dst)
+{
+  ASSERT(0 == mbedtls_md_finish(ctx, dst));
+  mbedtls_md_free(ctx);
+}
+
+
+/*
+ *
+ * Generic HMAC functions
+ *
+ */
+
+
+/*
+ * TODO: re-enable dmsg for crypto debug
+ */
+void
+hmac_ctx_init (mbedtls_md_context_t *ctx, const uint8_t *key, int key_len,
+    const mbedtls_md_info_t *kt)
+{
+  ASSERT(NULL != kt && NULL != ctx);
+
+  mbedtls_md_init(ctx);
+  ASSERT(0 == mbedtls_md_setup(ctx, kt, 1));
+  ASSERT(0 == mbedtls_md_hmac_starts(ctx, key, key_len));
+
+  /* make sure we used a big enough key */
+  ASSERT (mbedtls_md_get_size(kt) <= key_len);
+}
+
+void
+hmac_ctx_cleanup(mbedtls_md_context_t *ctx)
+{
+  mbedtls_md_free(ctx);
+}
+
+int
+hmac_ctx_size (const mbedtls_md_context_t *ctx)
+{
+  if (NULL == ctx)
+    return 0;
+  return mbedtls_md_get_size(ctx->md_info);
+}
+
+void
+hmac_ctx_reset (mbedtls_md_context_t *ctx)
+{
+  ASSERT(0 == mbedtls_md_hmac_reset(ctx));
+}
+
+void
+hmac_ctx_update (mbedtls_md_context_t *ctx, const uint8_t *src, int src_len)
+{
+  ASSERT(0 == mbedtls_md_hmac_update(ctx, src, src_len));
+}
+
+void
+hmac_ctx_final (mbedtls_md_context_t *ctx, uint8_t *dst)
+{
+  ASSERT(0 == mbedtls_md_hmac_finish(ctx, dst));
+}
+
+#endif /* ENABLE_CRYPTO && ENABLE_CRYPTO_MBEDTLS */
diff --git a/src/openvpn/crypto_mbedtls.h b/src/openvpn/crypto_mbedtls.h
new file mode 100644
index 0000000..574a63f
--- /dev/null
+++ b/src/openvpn/crypto_mbedtls.h
@@ -0,0 +1,146 @@
+/*
+ *  OpenVPN -- An application to securely tunnel IP networks
+ *             over a single TCP/UDP port, with support for SSL/TLS-based
+ *             session authentication and key exchange,
+ *             packet encryption, packet authentication, and
+ *             packet compression.
+ *
+ *  Copyright (C) 2002-2010 OpenVPN Technologies, Inc. <sa...@openvpn.net>
+ *  Copyright (C) 2010 Fox Crypto B.V. <open...@fox-it.com>
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License version 2
+ *  as published by the Free Software Foundation.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program (see the file COPYING included with this
+ *  distribution); if not, write to the Free Software Foundation, Inc.,
+ *  59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+/**
+ * @file Data Channel Cryptography mbed TLS-specific backend interface
+ */
+
+#ifndef CRYPTO_MBEDTLS_H_
+#define CRYPTO_MBEDTLS_H_
+
+#include <mbedtls/cipher.h>
+#include <mbedtls/md.h>
+#include <mbedtls/ctr_drbg.h>
+
+/** Generic cipher key type %context. */
+typedef mbedtls_cipher_info_t cipher_kt_t;
+
+/** Generic message digest key type %context. */
+typedef mbedtls_md_info_t md_kt_t;
+
+/** Generic cipher %context. */
+typedef mbedtls_cipher_context_t cipher_ctx_t;
+
+/** Generic message digest %context. */
+typedef mbedtls_md_context_t md_ctx_t;
+
+/** Generic HMAC %context. */
+typedef mbedtls_md_context_t hmac_ctx_t;
+
+/** Maximum length of an IV */
+#define OPENVPN_MAX_IV_LENGTH  MBEDTLS_MAX_IV_LENGTH
+
+/** Cipher is in CBC mode */
+#define OPENVPN_MODE_CBC       MBEDTLS_MODE_CBC
+
+/** Cipher is in OFB mode */
+#define OPENVPN_MODE_OFB       MBEDTLS_MODE_OFB
+
+/** Cipher is in CFB mode */
+#define OPENVPN_MODE_CFB       MBEDTLS_MODE_CFB
+
+/** Cipher is in GCM mode */
+#define OPENVPN_MODE_GCM       MBEDTLS_MODE_GCM
+
+/** Cipher should encrypt */
+#define OPENVPN_OP_ENCRYPT     MBEDTLS_ENCRYPT
+
+/** Cipher should decrypt */
+#define OPENVPN_OP_DECRYPT     MBEDTLS_DECRYPT
+
+#define MD4_DIGEST_LENGTH      16
+#define MD5_DIGEST_LENGTH      16
+#define SHA_DIGEST_LENGTH      20
+#define DES_KEY_LENGTH 8
+
+/**
+ * Returns a singleton instance of the mbed TLS random number generator.
+ *
+ * For PolarSSL/mbed TLS 1.1+, this is the CTR_DRBG random number generator. 
If it
+ * hasn't been initialised yet, the RNG will be initialised using the default
+ * entropy sources. Aside from the default platform entropy sources, an
+ * additional entropy source, the HAVEGE random number generator will also be
+ * added. During initialisation, a personalisation string will be added based
+ * on the time, the PID, and a pointer to the random context.
+ */
+mbedtls_ctr_drbg_context *rand_ctx_get();
+
+#ifdef ENABLE_PREDICTION_RESISTANCE
+/**
+ * Enable prediction resistance on the random number generator.
+ */
+void rand_ctx_enable_prediction_resistance();
+#endif
+
+/**
+ * Log the supplied mbed TLS error, prefixed by supplied prefix.
+ *
+ * @param flags                Flags to indicate error type and priority.
+ * @param errval       mbed TLS error code to convert to error message.
+ * @param prefix       Prefix to mbed TLS error message.
+ *
+ * @returns true if no errors are detected, false otherwise.
+ */
+bool mbed_log_err(unsigned int flags, int errval, const char *prefix);
+
+/**
+ * Log the supplied mbed TLS error, prefixed by function name and line number.
+ *
+ * @param flags                Flags to indicate error type and priority.
+ * @param errval       mbed TLS error code to convert to error message.
+ * @param func         Function name where error was reported.
+ * @param line         Line number where error was reported.
+ *
+ * @returns true if no errors are detected, false otherwise.
+ */
+bool mbed_log_func_line(unsigned int flags, int errval, const char *func,
+    int line);
+
+/** Wraps mbed_log_func_line() to prevent function calls for non-errors */
+static inline bool mbed_log_func_line_lite(unsigned int flags, int errval,
+    const char *func, int line) {
+  if (errval) {
+    return mbed_log_func_line (flags, errval, func, line);
+  }
+  return true;
+}
+
+/**
+ * Check errval and log on error.
+ *
+ * Convenience wrapper to put around mbed TLS library calls, e.g.
+ *   if (!mbed_ok (mbedtls_ssl_func())) return 0;
+ * or
+ *   ASSERT (mbed_ok (mbedtls_ssl_func()));
+ *
+ * @param errval       mbed TLS error code to convert to error message.
+ *
+ * @returns true if no errors are detected, false otherwise.
+ */
+#define mbed_ok(errval) \
+  mbed_log_func_line_lite(D_CRYPT_ERRORS, errval, __func__, __LINE__)
+
+
+#endif /* CRYPTO_MBEDTLS_H_ */
diff --git a/src/openvpn/crypto_polarssl.c b/src/openvpn/crypto_polarssl.c
deleted file mode 100644
index da1b417..0000000
--- a/src/openvpn/crypto_polarssl.c
+++ /dev/null
@@ -1,758 +0,0 @@
-/*
- *  OpenVPN -- An application to securely tunnel IP networks
- *             over a single TCP/UDP port, with support for SSL/TLS-based
- *             session authentication and key exchange,
- *             packet encryption, packet authentication, and
- *             packet compression.
- *
- *  Copyright (C) 2002-2010 OpenVPN Technologies, Inc. <sa...@openvpn.net>
- *  Copyright (C) 2010 Fox Crypto B.V. <open...@fox-it.com>
- *
- *  This program is free software; you can redistribute it and/or modify
- *  it under the terms of the GNU General Public License version 2
- *  as published by the Free Software Foundation.
- *
- *  This program is distributed in the hope that it will be useful,
- *  but WITHOUT ANY WARRANTY; without even the implied warranty of
- *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- *  GNU General Public License for more details.
- *
- *  You should have received a copy of the GNU General Public License
- *  along with this program (see the file COPYING included with this
- *  distribution); if not, write to the Free Software Foundation, Inc.,
- *  59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
- */
-
-/**
- * @file Data Channel Cryptography mbed TLS-specific backend interface
- */
-
-#ifdef HAVE_CONFIG_H
-#include "config.h"
-#elif defined(_MSC_VER)
-#include "config-msvc.h"
-#endif
-
-#include "syshead.h"
-
-#if defined(ENABLE_CRYPTO) && defined(ENABLE_CRYPTO_MBEDTLS)
-
-#include "errlevel.h"
-#include "basic.h"
-#include "buffer.h"
-#include "integer.h"
-#include "crypto_backend.h"
-#include "otime.h"
-#include "misc.h"
-
-#include <mbedtls/des.h>
-#include <mbedtls/error.h>
-#include <mbedtls/md5.h>
-#include <mbedtls/cipher.h>
-#include <mbedtls/havege.h>
-
-#include <mbedtls/entropy.h>
-
-
-/*
- *
- * Hardware engine support. Allows loading/unloading of engines.
- *
- */
-
-void
-crypto_init_lib_engine (const char *engine_name)
-{
-  msg (M_WARN, "Note: mbed TLS hardware crypto engine functionality is not "
-      "available");
-}
-
-/*
- *
- * Functions related to the core crypto library
- *
- */
-
-void
-crypto_init_lib (void)
-{
-}
-
-void
-crypto_uninit_lib (void)
-{
-}
-
-void
-crypto_clear_error (void)
-{
-}
-
-bool mbed_log_err(unsigned int flags, int errval, const char *prefix)
-{
-  if (0 != errval)
-    {
-      char errstr[256];
-      mbedtls_strerror(errval, errstr, sizeof(errstr));
-
-      if (NULL == prefix) prefix = "mbed TLS error";
-      msg (flags, "%s: %s", prefix, errstr);
-    }
-
-  return 0 == errval;
-}
-
-bool mbed_log_func_line(unsigned int flags, int errval, const char *func,
-    int line)
-{
-  char prefix[256];
-
-  if (!openvpn_snprintf(prefix, sizeof(prefix), "%s:%d", func, line))
-    return mbed_log_err(flags, errval, func);
-
-  return mbed_log_err(flags, errval, prefix);
-}
-
-
-#ifdef DMALLOC
-void
-crypto_init_dmalloc (void)
-{
-  msg (M_ERR, "Error: dmalloc support is not available for mbed TLS.");
-}
-#endif /* DMALLOC */
-
-const cipher_name_pair cipher_name_translation_table[] = {
-    { "BF-CBC", "BLOWFISH-CBC" },
-    { "BF-CFB", "BLOWFISH-CFB64" },
-    { "CAMELLIA-128-CFB", "CAMELLIA-128-CFB128" },
-    { "CAMELLIA-192-CFB", "CAMELLIA-192-CFB128" },
-    { "CAMELLIA-256-CFB", "CAMELLIA-256-CFB128" }
-};
-const size_t cipher_name_translation_table_count =
-    sizeof (cipher_name_translation_table) / sizeof 
(*cipher_name_translation_table);
-
-void
-show_available_ciphers ()
-{
-  const int *ciphers = mbedtls_cipher_list();
-
-#ifndef ENABLE_SMALL
-  printf ("The following ciphers and cipher modes are available for use\n"
-         "with " PACKAGE_NAME ".  Each cipher shown below may be used as a\n"
-         "parameter to the --cipher option.  Using a CBC or GCM mode is\n"
-         "recommended.  In static key mode only CBC mode is allowed.\n\n");
-#endif
-
-  while (*ciphers != 0)
-    {
-      const cipher_kt_t *info = mbedtls_cipher_info_from_type(*ciphers);
-
-      if (info && (cipher_kt_mode_cbc(info)
-#ifdef HAVE_AEAD_CIPHER_MODES
-          || cipher_kt_mode_aead(info)
-#endif
-          ))
-       {
-         const char *ssl_only = cipher_kt_mode_cbc(info) ?
-             "" : " (TLS client/server mode)";
-
-         printf ("%s %d bit default key%s\n",
-             cipher_kt_name(info), cipher_kt_key_size(info) * 8, ssl_only);
-       }
-
-      ciphers++;
-    }
-  printf ("\n");
-}
-
-void
-show_available_digests ()
-{
-  const int *digests = mbedtls_md_list();
-
-#ifndef ENABLE_SMALL
-  printf ("The following message digests are available for use with\n"
-         PACKAGE_NAME ".  A message digest is used in conjunction with\n"
-         "the HMAC function, to authenticate received packets.\n"
-         "You can specify a message digest as parameter to\n"
-         "the --auth option.\n\n");
-#endif
-
-  while (*digests != 0)
-    {
-      const mbedtls_md_info_t *info = mbedtls_md_info_from_type(*digests);
-
-      if (info)
-       printf ("%s %d bit default key\n", mbedtls_md_get_name(info),
-           mbedtls_md_get_size(info) * 8);
-      digests++;
-    }
-  printf ("\n");
-}
-
-void
-show_available_engines ()
-{
-  printf ("Sorry, mbed TLS hardware crypto engine functionality is not "
-      "available\n");
-}
-
-/*
- *
- * Random number functions, used in cases where we want
- * reasonably strong cryptographic random number generation
- * without depleting our entropy pool.  Used for random
- * IV values and a number of other miscellaneous tasks.
- *
- */
-
-/*
- * Initialise the given ctr_drbg context, using a personalisation string and an
- * entropy gathering function.
- */
-mbedtls_ctr_drbg_context * rand_ctx_get()
-{
-  static mbedtls_entropy_context ec = {0};
-  static mbedtls_ctr_drbg_context cd_ctx = {0};
-  static bool rand_initialised = false;
-
-  if (!rand_initialised)
-    {
-      struct gc_arena gc = gc_new();
-      struct buffer pers_string = alloc_buf_gc(100, &gc);
-
-      /*
-       * Personalisation string, should be as unique as possible (see NIST
-       * 800-90 section 8.7.1). We have very little information at this stage.
-       * Include Program Name, memory address of the context and PID.
-       */
-      buf_printf(&pers_string, "OpenVPN %0u %p %s", platform_getpid(), 
&cd_ctx, time_string(0, 0, 0, &gc));
-
-      /* Initialise mbed TLS RNG, and built-in entropy sources */
-      mbedtls_entropy_init(&ec);
-
-      mbedtls_ctr_drbg_init(&cd_ctx);
-      if (!mbed_ok(mbedtls_ctr_drbg_seed(&cd_ctx, mbedtls_entropy_func, &ec,
-                   BPTR(&pers_string), BLEN(&pers_string))))
-        msg (M_FATAL, "Failed to initialize random generator");
-
-      gc_free(&gc);
-      rand_initialised = true;
-  }
-
-  return &cd_ctx;
-}
-
-#ifdef ENABLE_PREDICTION_RESISTANCE
-void rand_ctx_enable_prediction_resistance()
-{
-  mbedtls_ctr_drbg_context *cd_ctx = rand_ctx_get();
-
-  mbedtls_ctr_drbg_set_prediction_resistance(cd_ctx, 1);
-}
-#endif /* ENABLE_PREDICTION_RESISTANCE */
-
-int
-rand_bytes (uint8_t *output, int len)
-{
-  mbedtls_ctr_drbg_context *rng_ctx = rand_ctx_get();
-
-  while (len > 0)
-    {
-      const size_t blen = min_int (len, MBEDTLS_CTR_DRBG_MAX_REQUEST);
-      if (0 != mbedtls_ctr_drbg_random(rng_ctx, output, blen))
-       return 0;
-
-      output += blen;
-      len -= blen;
-    }
-
-  return 1;
-}
-
-/*
- *
- * Key functions, allow manipulation of keys.
- *
- */
-
-
-int
-key_des_num_cblocks (const mbedtls_cipher_info_t *kt)
-{
-  int ret = 0;
-  if (kt->type == MBEDTLS_CIPHER_DES_CBC)
-    ret = 1;
-  if (kt->type == MBEDTLS_CIPHER_DES_EDE_CBC)
-    ret = 2;
-  if (kt->type == MBEDTLS_CIPHER_DES_EDE3_CBC)
-    ret = 3;
-
-  dmsg (D_CRYPTO_DEBUG, "CRYPTO INFO: n_DES_cblocks=%d", ret);
-  return ret;
-}
-
-bool
-key_des_check (uint8_t *key, int key_len, int ndc)
-{
-  int i;
-  struct buffer b;
-
-  buf_set_read (&b, key, key_len);
-
-  for (i = 0; i < ndc; ++i)
-    {
-      unsigned char *key = buf_read_alloc(&b, MBEDTLS_DES_KEY_SIZE);
-      if (!key)
-       {
-         msg (D_CRYPT_ERRORS, "CRYPTO INFO: check_key_DES: insufficient key 
material");
-         goto err;
-       }
-      if (0 != mbedtls_des_key_check_weak(key))
-       {
-         msg (D_CRYPT_ERRORS, "CRYPTO INFO: check_key_DES: weak key detected");
-         goto err;
-       }
-      if (0 != mbedtls_des_key_check_key_parity(key))
-       {
-         msg (D_CRYPT_ERRORS, "CRYPTO INFO: check_key_DES: bad parity 
detected");
-         goto err;
-       }
-    }
-  return true;
-
- err:
-  return false;
-}
-
-void
-key_des_fixup (uint8_t *key, int key_len, int ndc)
-{
-  int i;
-  struct buffer b;
-
-  buf_set_read (&b, key, key_len);
-  for (i = 0; i < ndc; ++i)
-    {
-      unsigned char *key = buf_read_alloc(&b, MBEDTLS_DES_KEY_SIZE);
-      if (!key)
-       {
-         msg (D_CRYPT_ERRORS, "CRYPTO INFO: fixup_key_DES: insufficient key 
material");
-         return;
-       }
-      mbedtls_des_key_set_parity(key);
-    }
-}
-
-/*
- *
- * Generic cipher key type functions
- *
- */
-
-
-const mbedtls_cipher_info_t *
-cipher_kt_get (const char *ciphername)
-{
-  const mbedtls_cipher_info_t *cipher = NULL;
-
-  ASSERT (ciphername);
-
-  cipher = mbedtls_cipher_info_from_string(ciphername);
-
-  if (NULL == cipher)
-    msg (M_FATAL, "Cipher algorithm '%s' not found", ciphername);
-
-  if (cipher->key_bitlen/8 > MAX_CIPHER_KEY_LENGTH)
-    msg (M_FATAL, "Cipher algorithm '%s' uses a default key size (%d bytes) 
which is larger than " PACKAGE_NAME "'s current maximum key size (%d bytes)",
-        ciphername,
-        cipher->key_bitlen/8,
-        MAX_CIPHER_KEY_LENGTH);
-
-  return cipher;
-}
-
-const char *
-cipher_kt_name (const mbedtls_cipher_info_t *cipher_kt)
-{
-  if (NULL == cipher_kt)
-    return "[null-cipher]";
-
-  return translate_cipher_name_to_openvpn(cipher_kt->name);
-}
-
-int
-cipher_kt_key_size (const mbedtls_cipher_info_t *cipher_kt)
-{
-  if (NULL == cipher_kt)
-    return 0;
-
-  return cipher_kt->key_bitlen/8;
-}
-
-int
-cipher_kt_iv_size (const mbedtls_cipher_info_t *cipher_kt)
-{
-  if (NULL == cipher_kt)
-    return 0;
-  return cipher_kt->iv_size;
-}
-
-int
-cipher_kt_block_size (const mbedtls_cipher_info_t *cipher_kt)
-{
-  if (NULL == cipher_kt)
-    return 0;
-  return cipher_kt->block_size;
-}
-
-int
-cipher_kt_tag_size (const mbedtls_cipher_info_t *cipher_kt)
-{
-#ifdef HAVE_AEAD_CIPHER_MODES
-  if (cipher_kt && cipher_kt_mode_aead(cipher_kt))
-    return OPENVPN_AEAD_TAG_LENGTH;
-#endif
-  return 0;
-}
-
-int
-cipher_kt_mode (const mbedtls_cipher_info_t *cipher_kt)
-{
-  ASSERT(NULL != cipher_kt);
-  return cipher_kt->mode;
-}
-
-bool
-cipher_kt_mode_cbc(const cipher_kt_t *cipher)
-{
-  return cipher && cipher_kt_mode(cipher) == OPENVPN_MODE_CBC;
-}
-
-bool
-cipher_kt_mode_ofb_cfb(const cipher_kt_t *cipher)
-{
-  return cipher && (cipher_kt_mode(cipher) == OPENVPN_MODE_OFB ||
-      cipher_kt_mode(cipher) == OPENVPN_MODE_CFB);
-}
-
-bool
-cipher_kt_mode_aead(const cipher_kt_t *cipher)
-{
-  return cipher && cipher_kt_mode(cipher) == OPENVPN_MODE_GCM;
-}
-
-
-/*
- *
- * Generic cipher context functions
- *
- */
-
-
-void
-cipher_ctx_init (mbedtls_cipher_context_t *ctx, uint8_t *key, int key_len,
-    const mbedtls_cipher_info_t *kt, const mbedtls_operation_t operation)
-{
-  ASSERT(NULL != kt && NULL != ctx);
-
-  CLEAR (*ctx);
-
-  if (!mbed_ok(mbedtls_cipher_setup(ctx, kt)))
-    msg (M_FATAL, "mbed TLS cipher context init #1");
-
-  if (!mbed_ok(mbedtls_cipher_setkey(ctx, key, key_len*8, operation)))
-    msg (M_FATAL, "mbed TLS cipher set key");
-
-  /* make sure we used a big enough key */
-  ASSERT (ctx->key_bitlen <= key_len*8);
-}
-
-void cipher_ctx_cleanup (mbedtls_cipher_context_t *ctx)
-{
-  mbedtls_cipher_free(ctx);
-}
-
-int cipher_ctx_iv_length (const mbedtls_cipher_context_t *ctx)
-{
-  return mbedtls_cipher_get_iv_size(ctx);
-}
-
-int cipher_ctx_get_tag (cipher_ctx_t *ctx, uint8_t* tag, int tag_len)
-{
-#ifdef HAVE_AEAD_CIPHER_MODES
-  if (tag_len > SIZE_MAX)
-    return 0;
-
-  if (!mbed_ok (mbedtls_cipher_write_tag (ctx, (unsigned char *) tag, 
tag_len)))
-    return 0;
-
-  return 1;
-#else
-  ASSERT(0);
-#endif /* HAVE_AEAD_CIPHER_MODES */
-}
-
-int cipher_ctx_block_size(const mbedtls_cipher_context_t *ctx)
-{
-  return mbedtls_cipher_get_block_size(ctx);
-}
-
-int cipher_ctx_mode (const mbedtls_cipher_context_t *ctx)
-{
-  ASSERT(NULL != ctx);
-
-  return cipher_kt_mode(ctx->cipher_info);
-}
-
-const cipher_kt_t *
-cipher_ctx_get_cipher_kt (const cipher_ctx_t *ctx)
-{
-  return ctx ? ctx->cipher_info : NULL;
-}
-
-int cipher_ctx_reset (mbedtls_cipher_context_t *ctx, uint8_t *iv_buf)
-{
-  if (!mbed_ok(mbedtls_cipher_reset(ctx)))
-    return 0;
-
-  if (!mbed_ok(mbedtls_cipher_set_iv(ctx, iv_buf, ctx->cipher_info->iv_size)))
-    return 0;
-
-  return 1;
-}
-
-int cipher_ctx_update_ad (cipher_ctx_t *ctx, const uint8_t *src, int src_len)
-{
-#ifdef HAVE_AEAD_CIPHER_MODES
-  if (src_len > SIZE_MAX)
-    return 0;
-
-  if (!mbed_ok (mbedtls_cipher_update_ad (ctx, src, src_len)))
-    return 0;
-
-  return 1;
-#else
-  ASSERT(0);
-#endif /* HAVE_AEAD_CIPHER_MODES */
-}
-
-int cipher_ctx_update (mbedtls_cipher_context_t *ctx, uint8_t *dst,
-    int *dst_len, uint8_t *src, int src_len)
-{
-  size_t s_dst_len = *dst_len;
-
-  if (!mbed_ok(mbedtls_cipher_update(ctx, src, (size_t) src_len, dst,
-      &s_dst_len)))
-    return 0;
-
-  *dst_len = s_dst_len;
-
-  return 1;
-}
-
-int cipher_ctx_final (mbedtls_cipher_context_t *ctx, uint8_t *dst, int 
*dst_len)
-{
-  size_t s_dst_len = *dst_len;
-
-  if (!mbed_ok(mbedtls_cipher_finish(ctx, dst, &s_dst_len)))
-    return 0;
-
-  *dst_len = s_dst_len;
-
-  return 1;
-}
-
-int cipher_ctx_final_check_tag (mbedtls_cipher_context_t *ctx, uint8_t *dst,
-    int *dst_len, uint8_t *tag, size_t tag_len)
-{
-#ifdef HAVE_AEAD_CIPHER_MODES
-  size_t olen = 0;
-
-  if (MBEDTLS_DECRYPT != ctx->operation)
-    return 0;
-
-  if (tag_len > SIZE_MAX)
-    return 0;
-
-  if (!mbed_ok (mbedtls_cipher_finish (ctx, dst, &olen)))
-    {
-      msg (D_CRYPT_ERRORS, "%s: cipher_ctx_final() failed", __func__);
-      return 0;
-    }
-
-  if (olen > INT_MAX)
-    return 0;
-  *dst_len = olen;
-
-  if (!mbed_ok (mbedtls_cipher_check_tag (ctx, (const unsigned char *) tag,
-      tag_len)))
-    return 0;
-
-  return 1;
-#else
-  ASSERT(0);
-#endif /* HAVE_AEAD_CIPHER_MODES */
-}
-
-void
-cipher_des_encrypt_ecb (const unsigned char key[DES_KEY_LENGTH],
-    unsigned char *src,
-    unsigned char *dst)
-{
-  mbedtls_des_context ctx;
-
-  ASSERT (mbed_ok(mbedtls_des_setkey_enc(&ctx, key)));
-  ASSERT (mbed_ok(mbedtls_des_crypt_ecb(&ctx, src, dst)));
-}
-
-
-
-/*
- *
- * Generic message digest information functions
- *
- */
-
-
-const mbedtls_md_info_t *
-md_kt_get (const char *digest)
-{
-  const mbedtls_md_info_t *md = NULL;
-  ASSERT (digest);
-
-  md = mbedtls_md_info_from_string(digest);
-  if (!md)
-    msg (M_FATAL, "Message hash algorithm '%s' not found", digest);
-  if (mbedtls_md_get_size(md) > MAX_HMAC_KEY_LENGTH)
-    msg (M_FATAL, "Message hash algorithm '%s' uses a default hash size (%d 
bytes) which is larger than " PACKAGE_NAME "'s current maximum hash size (%d 
bytes)",
-        digest,
-        mbedtls_md_get_size(md),
-        MAX_HMAC_KEY_LENGTH);
-  return md;
-}
-
-const char *
-md_kt_name (const mbedtls_md_info_t *kt)
-{
-  if (NULL == kt)
-    return "[null-digest]";
-  return mbedtls_md_get_name (kt);
-}
-
-int
-md_kt_size (const mbedtls_md_info_t *kt)
-{
-  if (NULL == kt)
-    return 0;
-  return mbedtls_md_get_size(kt);
-}
-
-/*
- *
- * Generic message digest functions
- *
- */
-
-int
-md_full (const md_kt_t *kt, const uint8_t *src, int src_len, uint8_t *dst)
-{
-  return 0 == mbedtls_md(kt, src, src_len, dst);
-}
-
-
-void
-md_ctx_init (mbedtls_md_context_t *ctx, const mbedtls_md_info_t *kt)
-{
-  ASSERT(NULL != ctx && NULL != kt);
-
-  mbedtls_md_init(ctx);
-  ASSERT(0 == mbedtls_md_setup(ctx, kt, 0));
-  ASSERT(0 == mbedtls_md_starts(ctx));
-}
-
-void
-md_ctx_cleanup(mbedtls_md_context_t *ctx)
-{
-}
-
-int
-md_ctx_size (const mbedtls_md_context_t *ctx)
-{
-  if (NULL == ctx)
-    return 0;
-  return mbedtls_md_get_size(ctx->md_info);
-}
-
-void
-md_ctx_update (mbedtls_md_context_t *ctx, const uint8_t *src, int src_len)
-{
-  ASSERT(0 == mbedtls_md_update(ctx, src, src_len));
-}
-
-void
-md_ctx_final (mbedtls_md_context_t *ctx, uint8_t *dst)
-{
-  ASSERT(0 == mbedtls_md_finish(ctx, dst));
-  mbedtls_md_free(ctx);
-}
-
-
-/*
- *
- * Generic HMAC functions
- *
- */
-
-
-/*
- * TODO: re-enable dmsg for crypto debug
- */
-void
-hmac_ctx_init (mbedtls_md_context_t *ctx, const uint8_t *key, int key_len,
-    const mbedtls_md_info_t *kt)
-{
-  ASSERT(NULL != kt && NULL != ctx);
-
-  mbedtls_md_init(ctx);
-  ASSERT(0 == mbedtls_md_setup(ctx, kt, 1));
-  ASSERT(0 == mbedtls_md_hmac_starts(ctx, key, key_len));
-
-  /* make sure we used a big enough key */
-  ASSERT (mbedtls_md_get_size(kt) <= key_len);
-}
-
-void
-hmac_ctx_cleanup(mbedtls_md_context_t *ctx)
-{
-  mbedtls_md_free(ctx);
-}
-
-int
-hmac_ctx_size (const mbedtls_md_context_t *ctx)
-{
-  if (NULL == ctx)
-    return 0;
-  return mbedtls_md_get_size(ctx->md_info);
-}
-
-void
-hmac_ctx_reset (mbedtls_md_context_t *ctx)
-{
-  ASSERT(0 == mbedtls_md_hmac_reset(ctx));
-}
-
-void
-hmac_ctx_update (mbedtls_md_context_t *ctx, const uint8_t *src, int src_len)
-{
-  ASSERT(0 == mbedtls_md_hmac_update(ctx, src, src_len));
-}
-
-void
-hmac_ctx_final (mbedtls_md_context_t *ctx, uint8_t *dst)
-{
-  ASSERT(0 == mbedtls_md_hmac_finish(ctx, dst));
-}
-
-#endif /* ENABLE_CRYPTO && ENABLE_CRYPTO_MBEDTLS */
diff --git a/src/openvpn/crypto_polarssl.h b/src/openvpn/crypto_polarssl.h
deleted file mode 100644
index 574a63f..0000000
--- a/src/openvpn/crypto_polarssl.h
+++ /dev/null
@@ -1,146 +0,0 @@
-/*
- *  OpenVPN -- An application to securely tunnel IP networks
- *             over a single TCP/UDP port, with support for SSL/TLS-based
- *             session authentication and key exchange,
- *             packet encryption, packet authentication, and
- *             packet compression.
- *
- *  Copyright (C) 2002-2010 OpenVPN Technologies, Inc. <sa...@openvpn.net>
- *  Copyright (C) 2010 Fox Crypto B.V. <open...@fox-it.com>
- *
- *  This program is free software; you can redistribute it and/or modify
- *  it under the terms of the GNU General Public License version 2
- *  as published by the Free Software Foundation.
- *
- *  This program is distributed in the hope that it will be useful,
- *  but WITHOUT ANY WARRANTY; without even the implied warranty of
- *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- *  GNU General Public License for more details.
- *
- *  You should have received a copy of the GNU General Public License
- *  along with this program (see the file COPYING included with this
- *  distribution); if not, write to the Free Software Foundation, Inc.,
- *  59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
- */
-
-/**
- * @file Data Channel Cryptography mbed TLS-specific backend interface
- */
-
-#ifndef CRYPTO_MBEDTLS_H_
-#define CRYPTO_MBEDTLS_H_
-
-#include <mbedtls/cipher.h>
-#include <mbedtls/md.h>
-#include <mbedtls/ctr_drbg.h>
-
-/** Generic cipher key type %context. */
-typedef mbedtls_cipher_info_t cipher_kt_t;
-
-/** Generic message digest key type %context. */
-typedef mbedtls_md_info_t md_kt_t;
-
-/** Generic cipher %context. */
-typedef mbedtls_cipher_context_t cipher_ctx_t;
-
-/** Generic message digest %context. */
-typedef mbedtls_md_context_t md_ctx_t;
-
-/** Generic HMAC %context. */
-typedef mbedtls_md_context_t hmac_ctx_t;
-
-/** Maximum length of an IV */
-#define OPENVPN_MAX_IV_LENGTH  MBEDTLS_MAX_IV_LENGTH
-
-/** Cipher is in CBC mode */
-#define OPENVPN_MODE_CBC       MBEDTLS_MODE_CBC
-
-/** Cipher is in OFB mode */
-#define OPENVPN_MODE_OFB       MBEDTLS_MODE_OFB
-
-/** Cipher is in CFB mode */
-#define OPENVPN_MODE_CFB       MBEDTLS_MODE_CFB
-
-/** Cipher is in GCM mode */
-#define OPENVPN_MODE_GCM       MBEDTLS_MODE_GCM
-
-/** Cipher should encrypt */
-#define OPENVPN_OP_ENCRYPT     MBEDTLS_ENCRYPT
-
-/** Cipher should decrypt */
-#define OPENVPN_OP_DECRYPT     MBEDTLS_DECRYPT
-
-#define MD4_DIGEST_LENGTH      16
-#define MD5_DIGEST_LENGTH      16
-#define SHA_DIGEST_LENGTH      20
-#define DES_KEY_LENGTH 8
-
-/**
- * Returns a singleton instance of the mbed TLS random number generator.
- *
- * For PolarSSL/mbed TLS 1.1+, this is the CTR_DRBG random number generator. 
If it
- * hasn't been initialised yet, the RNG will be initialised using the default
- * entropy sources. Aside from the default platform entropy sources, an
- * additional entropy source, the HAVEGE random number generator will also be
- * added. During initialisation, a personalisation string will be added based
- * on the time, the PID, and a pointer to the random context.
- */
-mbedtls_ctr_drbg_context *rand_ctx_get();
-
-#ifdef ENABLE_PREDICTION_RESISTANCE
-/**
- * Enable prediction resistance on the random number generator.
- */
-void rand_ctx_enable_prediction_resistance();
-#endif
-
-/**
- * Log the supplied mbed TLS error, prefixed by supplied prefix.
- *
- * @param flags                Flags to indicate error type and priority.
- * @param errval       mbed TLS error code to convert to error message.
- * @param prefix       Prefix to mbed TLS error message.
- *
- * @returns true if no errors are detected, false otherwise.
- */
-bool mbed_log_err(unsigned int flags, int errval, const char *prefix);
-
-/**
- * Log the supplied mbed TLS error, prefixed by function name and line number.
- *
- * @param flags                Flags to indicate error type and priority.
- * @param errval       mbed TLS error code to convert to error message.
- * @param func         Function name where error was reported.
- * @param line         Line number where error was reported.
- *
- * @returns true if no errors are detected, false otherwise.
- */
-bool mbed_log_func_line(unsigned int flags, int errval, const char *func,
-    int line);
-
-/** Wraps mbed_log_func_line() to prevent function calls for non-errors */
-static inline bool mbed_log_func_line_lite(unsigned int flags, int errval,
-    const char *func, int line) {
-  if (errval) {
-    return mbed_log_func_line (flags, errval, func, line);
-  }
-  return true;
-}
-
-/**
- * Check errval and log on error.
- *
- * Convenience wrapper to put around mbed TLS library calls, e.g.
- *   if (!mbed_ok (mbedtls_ssl_func())) return 0;
- * or
- *   ASSERT (mbed_ok (mbedtls_ssl_func()));
- *
- * @param errval       mbed TLS error code to convert to error message.
- *
- * @returns true if no errors are detected, false otherwise.
- */
-#define mbed_ok(errval) \
-  mbed_log_func_line_lite(D_CRYPT_ERRORS, errval, __func__, __LINE__)
-
-
-#endif /* CRYPTO_MBEDTLS_H_ */
diff --git a/src/openvpn/pkcs11_mbedtls.c b/src/openvpn/pkcs11_mbedtls.c
new file mode 100644
index 0000000..e208b61
--- /dev/null
+++ b/src/openvpn/pkcs11_mbedtls.c
@@ -0,0 +1,129 @@
+/*
+ *  OpenVPN -- An application to securely tunnel IP networks
+ *             over a single TCP/UDP port, with support for SSL/TLS-based
+ *             session authentication and key exchange,
+ *             packet encryption, packet authentication, and
+ *             packet compression.
+ *
+ *  Copyright (C) 2002-2010 OpenVPN Technologies, Inc. <sa...@openvpn.net>
+ *  Copyright (C) 2010 Fox Crypto B.V. <open...@fox-it.com>
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License version 2
+ *  as published by the Free Software Foundation.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program (see the file COPYING included with this
+ *  distribution); if not, write to the Free Software Foundation, Inc.,
+ *  59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+/**
+ * @file PKCS #11 mbed TLS backend
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#elif defined(_MSC_VER)
+#include "config-msvc.h"
+#endif
+
+#include "syshead.h"
+
+#if defined(ENABLE_PKCS11) && defined(ENABLE_CRYPTO_MBEDTLS)
+
+#include "errlevel.h"
+#include "pkcs11_backend.h"
+#include <mbedtls/pkcs11.h>
+#include <mbedtls/x509.h>
+
+int
+pkcs11_init_tls_session(pkcs11h_certificate_t certificate,
+    struct tls_root_ctx * const ssl_ctx)
+{
+  int ret = 1;
+
+  ASSERT (NULL != ssl_ctx);
+
+  ALLOC_OBJ_CLEAR (ssl_ctx->crt_chain, mbedtls_x509_crt);
+  if (mbedtls_pkcs11_x509_cert_bind(ssl_ctx->crt_chain, certificate)) {
+      msg (M_FATAL, "PKCS#11: Cannot retrieve mbed TLS certificate object");
+      goto cleanup;
+  }
+
+  ALLOC_OBJ_CLEAR (ssl_ctx->priv_key_pkcs11, mbedtls_pkcs11_context);
+  if (mbedtls_pkcs11_priv_key_bind(ssl_ctx->priv_key_pkcs11, certificate)) {
+      msg (M_FATAL, "PKCS#11: Cannot initialize mbed TLS private key object");
+      goto cleanup;
+  }
+
+  ALLOC_OBJ_CLEAR (ssl_ctx->priv_key, mbedtls_pk_context);
+  if (!mbed_ok(mbedtls_pk_setup_rsa_alt(ssl_ctx->priv_key,
+      ssl_ctx->priv_key_pkcs11, mbedtls_ssl_pkcs11_decrypt,
+      mbedtls_ssl_pkcs11_sign, mbedtls_ssl_pkcs11_key_len))) {
+      goto cleanup;
+  }
+
+  ret = 0;
+
+cleanup:
+  return ret;
+}
+
+char *
+pkcs11_certificate_dn (pkcs11h_certificate_t cert, struct gc_arena *gc)
+{
+  char *ret = NULL;
+  char dn[1024] = {0};
+
+  mbedtls_x509_crt mbed_crt = {0};
+
+  if (mbedtls_pkcs11_x509_cert_bind(&mbed_crt, cert)) {
+      msg (M_FATAL, "PKCS#11: Cannot retrieve mbed TLS certificate object");
+      goto cleanup;
+  }
+
+  if (-1 == mbedtls_x509_dn_gets (dn, sizeof(dn), &mbed_crt.subject)) {
+      msg (M_FATAL, "PKCS#11: mbed TLS cannot parse subject");
+      goto cleanup;
+  }
+
+  ret = string_alloc(dn, gc);
+
+cleanup:
+  mbedtls_x509_crt_free(&mbed_crt);
+
+  return ret;
+}
+
+int
+pkcs11_certificate_serial (pkcs11h_certificate_t cert, char *serial,
+    size_t serial_len)
+{
+  int ret = 1;
+
+  mbedtls_x509_crt mbed_crt = {0};
+
+  if (mbedtls_pkcs11_x509_cert_bind(&mbed_crt, cert)) {
+      msg (M_FATAL, "PKCS#11: Cannot retrieve mbed TLS certificate object");
+      goto cleanup;
+  }
+
+  if (-1 == mbedtls_x509_serial_gets (serial, serial_len, &mbed_crt.serial)) {
+      msg (M_FATAL, "PKCS#11: mbed TLS cannot parse serial");
+      goto cleanup;
+  }
+
+  ret = 0;
+
+cleanup:
+  mbedtls_x509_crt_free(&mbed_crt);
+
+  return ret;
+}
+#endif /* defined(ENABLE_PKCS11) && defined(ENABLE_CRYPTO_MBEDTLS) */
diff --git a/src/openvpn/pkcs11_polarssl.c b/src/openvpn/pkcs11_polarssl.c
deleted file mode 100644
index e208b61..0000000
--- a/src/openvpn/pkcs11_polarssl.c
+++ /dev/null
@@ -1,129 +0,0 @@
-/*
- *  OpenVPN -- An application to securely tunnel IP networks
- *             over a single TCP/UDP port, with support for SSL/TLS-based
- *             session authentication and key exchange,
- *             packet encryption, packet authentication, and
- *             packet compression.
- *
- *  Copyright (C) 2002-2010 OpenVPN Technologies, Inc. <sa...@openvpn.net>
- *  Copyright (C) 2010 Fox Crypto B.V. <open...@fox-it.com>
- *
- *  This program is free software; you can redistribute it and/or modify
- *  it under the terms of the GNU General Public License version 2
- *  as published by the Free Software Foundation.
- *
- *  This program is distributed in the hope that it will be useful,
- *  but WITHOUT ANY WARRANTY; without even the implied warranty of
- *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- *  GNU General Public License for more details.
- *
- *  You should have received a copy of the GNU General Public License
- *  along with this program (see the file COPYING included with this
- *  distribution); if not, write to the Free Software Foundation, Inc.,
- *  59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
- */
-
-/**
- * @file PKCS #11 mbed TLS backend
- */
-
-#ifdef HAVE_CONFIG_H
-#include "config.h"
-#elif defined(_MSC_VER)
-#include "config-msvc.h"
-#endif
-
-#include "syshead.h"
-
-#if defined(ENABLE_PKCS11) && defined(ENABLE_CRYPTO_MBEDTLS)
-
-#include "errlevel.h"
-#include "pkcs11_backend.h"
-#include <mbedtls/pkcs11.h>
-#include <mbedtls/x509.h>
-
-int
-pkcs11_init_tls_session(pkcs11h_certificate_t certificate,
-    struct tls_root_ctx * const ssl_ctx)
-{
-  int ret = 1;
-
-  ASSERT (NULL != ssl_ctx);
-
-  ALLOC_OBJ_CLEAR (ssl_ctx->crt_chain, mbedtls_x509_crt);
-  if (mbedtls_pkcs11_x509_cert_bind(ssl_ctx->crt_chain, certificate)) {
-      msg (M_FATAL, "PKCS#11: Cannot retrieve mbed TLS certificate object");
-      goto cleanup;
-  }
-
-  ALLOC_OBJ_CLEAR (ssl_ctx->priv_key_pkcs11, mbedtls_pkcs11_context);
-  if (mbedtls_pkcs11_priv_key_bind(ssl_ctx->priv_key_pkcs11, certificate)) {
-      msg (M_FATAL, "PKCS#11: Cannot initialize mbed TLS private key object");
-      goto cleanup;
-  }
-
-  ALLOC_OBJ_CLEAR (ssl_ctx->priv_key, mbedtls_pk_context);
-  if (!mbed_ok(mbedtls_pk_setup_rsa_alt(ssl_ctx->priv_key,
-      ssl_ctx->priv_key_pkcs11, mbedtls_ssl_pkcs11_decrypt,
-      mbedtls_ssl_pkcs11_sign, mbedtls_ssl_pkcs11_key_len))) {
-      goto cleanup;
-  }
-
-  ret = 0;
-
-cleanup:
-  return ret;
-}
-
-char *
-pkcs11_certificate_dn (pkcs11h_certificate_t cert, struct gc_arena *gc)
-{
-  char *ret = NULL;
-  char dn[1024] = {0};
-
-  mbedtls_x509_crt mbed_crt = {0};
-
-  if (mbedtls_pkcs11_x509_cert_bind(&mbed_crt, cert)) {
-      msg (M_FATAL, "PKCS#11: Cannot retrieve mbed TLS certificate object");
-      goto cleanup;
-  }
-
-  if (-1 == mbedtls_x509_dn_gets (dn, sizeof(dn), &mbed_crt.subject)) {
-      msg (M_FATAL, "PKCS#11: mbed TLS cannot parse subject");
-      goto cleanup;
-  }
-
-  ret = string_alloc(dn, gc);
-
-cleanup:
-  mbedtls_x509_crt_free(&mbed_crt);
-
-  return ret;
-}
-
-int
-pkcs11_certificate_serial (pkcs11h_certificate_t cert, char *serial,
-    size_t serial_len)
-{
-  int ret = 1;
-
-  mbedtls_x509_crt mbed_crt = {0};
-
-  if (mbedtls_pkcs11_x509_cert_bind(&mbed_crt, cert)) {
-      msg (M_FATAL, "PKCS#11: Cannot retrieve mbed TLS certificate object");
-      goto cleanup;
-  }
-
-  if (-1 == mbedtls_x509_serial_gets (serial, serial_len, &mbed_crt.serial)) {
-      msg (M_FATAL, "PKCS#11: mbed TLS cannot parse serial");
-      goto cleanup;
-  }
-
-  ret = 0;
-
-cleanup:
-  mbedtls_x509_crt_free(&mbed_crt);
-
-  return ret;
-}
-#endif /* defined(ENABLE_PKCS11) && defined(ENABLE_CRYPTO_MBEDTLS) */
diff --git a/src/openvpn/plugin.h b/src/openvpn/plugin.h
index 74ac8b1..3c01047 100644
--- a/src/openvpn/plugin.h
+++ b/src/openvpn/plugin.h
@@ -33,7 +33,7 @@
 #include "ssl_verify_openssl.h"
 #endif
 #ifdef ENABLE_CRYPTO_MBEDTLS
-#include "ssl_verify_polarssl.h"
+#include "ssl_verify_mbedtls.h"
 #endif
 #include "openvpn-plugin.h"

diff --git a/src/openvpn/ssl_backend.h b/src/openvpn/ssl_backend.h
index dfccb44..542c373 100644
--- a/src/openvpn/ssl_backend.h
+++ b/src/openvpn/ssl_backend.h
@@ -39,8 +39,8 @@
 #define SSLAPI SSLAPI_OPENSSL
 #endif
 #ifdef ENABLE_CRYPTO_MBEDTLS
-#include "ssl_polarssl.h"
-#include "ssl_verify_polarssl.h"
+#include "ssl_mbedtls.h"
+#include "ssl_verify_mbedtls.h"
 #define SSLAPI SSLAPI_MBEDTLS
 #endif

diff --git a/src/openvpn/ssl_mbedtls.c b/src/openvpn/ssl_mbedtls.c
new file mode 100644
index 0000000..9da33ad
--- /dev/null
+++ b/src/openvpn/ssl_mbedtls.c
@@ -0,0 +1,1184 @@
+/*
+ *  OpenVPN -- An application to securely tunnel IP networks
+ *             over a single TCP/UDP port, with support for SSL/TLS-based
+ *             session authentication and key exchange,
+ *             packet encryption, packet authentication, and
+ *             packet compression.
+ *
+ *  Copyright (C) 2002-2010 OpenVPN Technologies, Inc. <sa...@openvpn.net>
+ *  Copyright (C) 2010 Fox Crypto B.V. <open...@fox-it.com>
+ *  Copyright (C) 2006-2010, Brainspark B.V.
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License version 2
+ *  as published by the Free Software Foundation.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program (see the file COPYING included with this
+ *  distribution); if not, write to the Free Software Foundation, Inc.,
+ *  59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+/**
+ * @file Control Channel mbed TLS Backend
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#elif defined(_MSC_VER)
+#include "config-msvc.h"
+#endif
+
+#include "syshead.h"
+
+#if defined(ENABLE_CRYPTO) && defined(ENABLE_CRYPTO_MBEDTLS)
+
+#include "errlevel.h"
+#include "ssl_backend.h"
+#include "base64.h"
+#include "buffer.h"
+#include "misc.h"
+#include "manage.h"
+#include "ssl_common.h"
+
+#include <mbedtls/havege.h>
+
+#include "ssl_verify_mbedtls.h"
+#include <mbedtls/debug.h>
+#include <mbedtls/error.h>
+#include <mbedtls/net.h>
+#include <mbedtls/oid.h>
+#include <mbedtls/pem.h>
+#include <mbedtls/sha256.h>
+#include <mbedtls/version.h>
+
+void
+tls_init_lib()
+{
+}
+
+void
+tls_free_lib()
+{
+}
+
+void
+tls_clear_error()
+{
+}
+
+void
+tls_ctx_server_new(struct tls_root_ctx *ctx)
+{
+  ASSERT(NULL != ctx);
+  CLEAR(*ctx);
+
+  ALLOC_OBJ_CLEAR(ctx->dhm_ctx, mbedtls_dhm_context);
+
+  ALLOC_OBJ_CLEAR(ctx->ca_chain, mbedtls_x509_crt);
+
+  ctx->endpoint = MBEDTLS_SSL_IS_SERVER;
+  ctx->initialised = true;
+}
+
+void
+tls_ctx_client_new(struct tls_root_ctx *ctx)
+{
+  ASSERT(NULL != ctx);
+  CLEAR(*ctx);
+
+  ALLOC_OBJ_CLEAR(ctx->dhm_ctx, mbedtls_dhm_context);
+  ALLOC_OBJ_CLEAR(ctx->ca_chain, mbedtls_x509_crt);
+
+  ctx->endpoint = MBEDTLS_SSL_IS_CLIENT;
+  ctx->initialised = true;
+}
+
+void
+tls_ctx_free(struct tls_root_ctx *ctx)
+{
+  if (ctx)
+    {
+      mbedtls_pk_free(ctx->priv_key);
+      if (ctx->priv_key)
+       free(ctx->priv_key);
+
+      mbedtls_x509_crt_free(ctx->ca_chain);
+      if (ctx->ca_chain)
+       free(ctx->ca_chain);
+
+      mbedtls_x509_crt_free(ctx->crt_chain);
+      if (ctx->crt_chain)
+       free(ctx->crt_chain);
+
+      mbedtls_dhm_free(ctx->dhm_ctx);
+      if (ctx->dhm_ctx)
+       free(ctx->dhm_ctx);
+
+#if defined(ENABLE_PKCS11)
+      if (ctx->priv_key_pkcs11 != NULL) {
+         mbedtls_pkcs11_priv_key_free(ctx->priv_key_pkcs11);
+         free(ctx->priv_key_pkcs11);
+      }
+#endif
+#if defined(MANAGMENT_EXTERNAL_KEY)
+      if (ctx->external_key != NULL)
+          free(ctx->external_key);
+#endif
+
+      if (ctx->allowed_ciphers)
+       free(ctx->allowed_ciphers);
+
+      CLEAR(*ctx);
+
+      ctx->initialised = false;
+
+    }
+}
+
+bool
+tls_ctx_initialised(struct tls_root_ctx *ctx)
+{
+  ASSERT(NULL != ctx);
+  return ctx->initialised;
+}
+
+void
+key_state_export_keying_material(struct key_state_ssl *ssl,
+                                 struct tls_session *session)
+{
+}
+
+void
+tls_ctx_set_options (struct tls_root_ctx *ctx, unsigned int ssl_flags)
+{
+}
+
+static const char *
+tls_translate_cipher_name (const char * cipher_name) {
+  const tls_cipher_name_pair * pair = tls_get_cipher_name_pair(cipher_name, 
strlen(cipher_name));
+
+  if (NULL == pair)
+    {
+      // No translation found, return original
+      return cipher_name;
+    }
+
+  if (0 != strcmp(cipher_name, pair->iana_name))
+    {
+      // Deprecated name found, notify user
+      msg(M_WARN, "Deprecated cipher suite name '%s', please use IANA name 
'%s'", pair->openssl_name, pair->iana_name);
+    }
+
+  return pair->iana_name;
+}
+
+void
+tls_ctx_restrict_ciphers(struct tls_root_ctx *ctx, const char *ciphers)
+{
+  char *tmp_ciphers, *tmp_ciphers_orig, *token;
+  int i, cipher_count;
+  int ciphers_len;
+
+  if (NULL == ciphers)
+    return; /* Nothing to do */
+
+  ciphers_len = strlen (ciphers);
+
+  ASSERT (NULL != ctx);
+  ASSERT (0 != ciphers_len);
+
+  /* Get number of ciphers */
+  for (i = 0, cipher_count = 1; i < ciphers_len; i++)
+    if (ciphers[i] == ':')
+      cipher_count++;
+
+  /* Allocate an array for them */
+  ALLOC_ARRAY_CLEAR(ctx->allowed_ciphers, int, cipher_count+1)
+
+  /* Parse allowed ciphers, getting IDs */
+  i = 0;
+  tmp_ciphers_orig = tmp_ciphers = string_alloc (ciphers, NULL);
+
+  token = strtok (tmp_ciphers, ":");
+  while(token)
+    {
+      ctx->allowed_ciphers[i] = mbedtls_ssl_get_ciphersuite_id (
+         tls_translate_cipher_name (token));
+      if (0 != ctx->allowed_ciphers[i])
+       i++;
+      token = strtok (NULL, ":");
+    }
+  free(tmp_ciphers_orig);
+}
+
+void
+tls_ctx_check_cert_time (const struct tls_root_ctx *ctx)
+{
+  ASSERT (ctx);
+  if (ctx->crt_chain == NULL)
+    {
+      return; /* Nothing to check if there is no certificate */
+    }
+
+  if (mbedtls_x509_time_is_future (&ctx->crt_chain->valid_from))
+    {
+      msg (M_WARN, "WARNING: Your certificate is not yet valid!");
+    }
+
+  if (mbedtls_x509_time_is_past (&ctx->crt_chain->valid_to))
+    {
+      msg (M_WARN, "WARNING: Your certificate has expired!");
+    }
+}
+
+void
+tls_ctx_load_dh_params (struct tls_root_ctx *ctx, const char *dh_file,
+    const char *dh_inline
+    )
+{
+  if (!strcmp (dh_file, INLINE_FILE_TAG) && dh_inline)
+    {
+      if (!mbed_ok(mbedtls_dhm_parse_dhm(ctx->dhm_ctx,
+         (const unsigned char *) dh_inline, strlen(dh_inline)+1)))
+       msg (M_FATAL, "Cannot read inline DH parameters");
+  }
+else
+  {
+    if (!mbed_ok(mbedtls_dhm_parse_dhmfile(ctx->dhm_ctx, dh_file)))
+      msg (M_FATAL, "Cannot read DH parameters from file %s", dh_file);
+  }
+
+  msg (D_TLS_DEBUG_LOW, "Diffie-Hellman initialized with " counter_format " 
bit key",
+      (counter_type) 8 * mbedtls_mpi_size(&ctx->dhm_ctx->P));
+}
+
+void
+tls_ctx_load_ecdh_params (struct tls_root_ctx *ctx, const char *curve_name
+    )
+{
+    if (NULL != curve_name)
+      msg(M_WARN, "WARNING: mbed TLS builds do not support specifying an ECDH "
+                  "curve, using default curves.");
+}
+
+int
+tls_ctx_load_pkcs12(struct tls_root_ctx *ctx, const char *pkcs12_file,
+    const char *pkcs12_file_inline,
+    bool load_ca_file
+    )
+{
+  msg(M_FATAL, "PKCS #12 files not yet supported for mbed TLS.");
+  return 0;
+}
+
+#ifdef ENABLE_CRYPTOAPI
+void
+tls_ctx_load_cryptoapi(struct tls_root_ctx *ctx, const char *cryptoapi_cert)
+{
+  msg(M_FATAL, "Windows CryptoAPI not yet supported for mbed TLS.");
+}
+#endif /* WIN32 */
+
+void
+tls_ctx_load_cert_file (struct tls_root_ctx *ctx, const char *cert_file,
+    const char *cert_inline
+    )
+{
+  ASSERT(NULL != ctx);
+
+  if (!ctx->crt_chain)
+    {
+      ALLOC_OBJ_CLEAR(ctx->crt_chain, mbedtls_x509_crt);
+    }
+
+  if (!strcmp (cert_file, INLINE_FILE_TAG) && cert_inline)
+    {
+      if (!mbed_ok(mbedtls_x509_crt_parse(ctx->crt_chain,
+         (const unsigned char *) cert_inline, strlen(cert_inline)+1)))
+        msg (M_FATAL, "Cannot load inline certificate file");
+    }
+  else
+    {
+      if (!mbed_ok(mbedtls_x509_crt_parse_file(ctx->crt_chain, cert_file)))
+       {
+         msg (M_FATAL, "Cannot load certificate file %s", cert_file);
+       }
+    }
+}
+
+int
+tls_ctx_load_priv_file (struct tls_root_ctx *ctx, const char *priv_key_file,
+    const char *priv_key_inline
+    )
+{
+  int status;
+  ASSERT(NULL != ctx);
+
+  if (!ctx->priv_key)
+    {
+      ALLOC_OBJ_CLEAR(ctx->priv_key, mbedtls_pk_context);
+    }
+
+  if (!strcmp (priv_key_file, INLINE_FILE_TAG) && priv_key_inline)
+    {
+      status = mbedtls_pk_parse_key(ctx->priv_key,
+         (const unsigned char *) priv_key_inline, strlen(priv_key_inline)+1,
+         NULL, 0);
+
+      if (MBEDTLS_ERR_PK_PASSWORD_REQUIRED == status)
+       {
+         char passbuf[512] = {0};
+         pem_password_callback(passbuf, 512, 0, NULL);
+         status = mbedtls_pk_parse_key(ctx->priv_key,
+             (const unsigned char *) priv_key_inline,
+             strlen(priv_key_inline)+1, (unsigned char *) passbuf,
+             strlen(passbuf));
+       }
+    }
+  else
+    {
+      status = mbedtls_pk_parse_keyfile(ctx->priv_key, priv_key_file, NULL);
+      if (MBEDTLS_ERR_PK_PASSWORD_REQUIRED == status)
+       {
+         char passbuf[512] = {0};
+         pem_password_callback(passbuf, 512, 0, NULL);
+         status = mbedtls_pk_parse_keyfile(ctx->priv_key, priv_key_file, 
passbuf);
+       }
+    }
+  if (!mbed_ok(status))
+    {
+#ifdef ENABLE_MANAGEMENT
+      if (management && (MBEDTLS_ERR_PK_PASSWORD_MISMATCH == status))
+         management_auth_failure (management, UP_TYPE_PRIVATE_KEY, NULL);
+#endif
+      msg (M_WARN, "Cannot load private key file %s", priv_key_file);
+      return 1;
+    }
+
+  warn_if_group_others_accessible (priv_key_file);
+
+  /* TODO: Check Private Key */
+#if 0
+  if (!SSL_CTX_check_private_key (ctx))
+    msg (M_SSLERR, "Private key does not match the certificate");
+#endif
+  return 0;
+}
+
+#ifdef MANAGMENT_EXTERNAL_KEY
+
+
+struct external_context {
+  size_t signature_length;
+};
+
+/**
+ * external_pkcs1_sign implements a mbed TLS rsa_sign_func callback, that uses
+ * the management interface to request an RSA signature for the supplied hash.
+ *
+ * @param ctx_voidptr   Management external key context.
+ * @param f_rng         (Unused)
+ * @param p_rng         (Unused)
+ * @param mode          RSA mode (should be RSA_PRIVATE).
+ * @param md_alg        Message digest ('hash') algorithm type.
+ * @param hashlen       Length of hash (overridden by length specified by 
md_alg
+ *                      if md_alg != MBEDTLS_MD_NONE).
+ * @param hash          The digest ('hash') to sign. Should have a size
+ *                      matching the length of md_alg (if != MBEDTLS_MD_NONE),
+ *                      or hashlen otherwise.
+ * @param sig           Buffer that returns the signature. Should be at least 
of
+ *                      size ctx->signature_length.
+ *
+ * @return 0 on success, non-zero mbed TLS error code on failure.
+ */
+static inline int external_pkcs1_sign( void *ctx_voidptr,
+    int (*f_rng)(void *, unsigned char *, size_t), void *p_rng, int mode,
+    mbedtls_md_type_t md_alg, unsigned int hashlen, const unsigned char *hash,
+    unsigned char *sig )
+{
+  struct external_context * const ctx = ctx_voidptr;
+  char *in_b64 = NULL;
+  char *out_b64 = NULL;
+  int rv;
+  unsigned char *p = sig;
+  size_t asn_len = 0, oid_size = 0, sig_len = 0;
+  const char *oid = NULL;
+
+  if( NULL == ctx )
+    return MBEDTLS_ERR_RSA_BAD_INPUT_DATA;
+
+  if( MBEDTLS_RSA_PRIVATE != mode )
+    return MBEDTLS_ERR_RSA_BAD_INPUT_DATA;
+
+  /*
+   * Support a wide range of hashes. TLSv1.1 and before only need SIG_RSA_RAW,
+   * but TLSv1.2 needs the full suite of hashes.
+   *
+   * This code has been taken from mbed TLS pkcs11_sign(), under the GPLv2.0+.
+   */
+  if( md_alg != MBEDTLS_MD_NONE )
+    {
+      const mbedtls_md_info_t *md_info = mbedtls_md_info_from_type( md_alg );
+      if( md_info == NULL )
+        return( MBEDTLS_ERR_RSA_BAD_INPUT_DATA );
+
+      if (!mbed_ok(mbedtls_oid_get_oid_by_md( md_alg, &oid, &oid_size )))
+        return( MBEDTLS_ERR_RSA_BAD_INPUT_DATA );
+
+      hashlen = mbedtls_md_get_size( md_info );
+      asn_len = 10 + oid_size;
+    }
+
+  sig_len = ctx->signature_length;
+  if ( (SIZE_MAX - hashlen) < asn_len || (hashlen + asn_len) > sig_len )
+    return MBEDTLS_ERR_RSA_BAD_INPUT_DATA;
+
+  if( md_alg != MBEDTLS_MD_NONE )
+    {
+      /*
+       * DigestInfo ::= SEQUENCE {
+       *   digestAlgorithm DigestAlgorithmIdentifier,
+       *   digest Digest }
+       *
+       * DigestAlgorithmIdentifier ::= AlgorithmIdentifier
+       *
+       * Digest ::= OCTET STRING
+       */
+      *p++ = MBEDTLS_ASN1_SEQUENCE | MBEDTLS_ASN1_CONSTRUCTED;
+      *p++ = (unsigned char) ( 0x08 + oid_size + hashlen );
+      *p++ = MBEDTLS_ASN1_SEQUENCE | MBEDTLS_ASN1_CONSTRUCTED;
+      *p++ = (unsigned char) ( 0x04 + oid_size );
+      *p++ = MBEDTLS_ASN1_OID;
+      *p++ = oid_size & 0xFF;
+      memcpy( p, oid, oid_size );
+      p += oid_size;
+      *p++ = MBEDTLS_ASN1_NULL;
+      *p++ = 0x00;
+      *p++ = MBEDTLS_ASN1_OCTET_STRING;
+      *p++ = hashlen;
+
+      /* Determine added ASN length */
+      asn_len = p - sig;
+  }
+
+  /* Copy the hash to be signed */
+  memcpy( p, hash, hashlen );
+
+  /* convert 'from' to base64 */
+  if (openvpn_base64_encode (sig, asn_len + hashlen, &in_b64) <= 0)
+    {
+      rv = MBEDTLS_ERR_RSA_BAD_INPUT_DATA;
+      goto done;
+    }
+
+  /* call MI for signature */
+  if (management)
+    out_b64 = management_query_rsa_sig (management, in_b64);
+  if (!out_b64)
+    {
+      rv = MBEDTLS_ERR_RSA_PRIVATE_FAILED;
+      goto done;
+    }
+
+  /* decode base64 signature to binary and verify length */
+  if ( openvpn_base64_decode (out_b64, sig, ctx->signature_length) !=
+       ctx->signature_length )
+    {
+      rv = MBEDTLS_ERR_RSA_PRIVATE_FAILED;
+      goto done;
+    }
+
+  rv = 0;
+
+done:
+  if (in_b64)
+    free (in_b64);
+  if (out_b64)
+    free (out_b64);
+  return rv;
+}
+
+static inline size_t external_key_len(void *vctx)
+{
+  struct external_context * const ctx = vctx;
+
+  return ctx->signature_length;
+}
+
+int
+tls_ctx_use_external_private_key (struct tls_root_ctx *ctx,
+    const char *cert_file, const char *cert_file_inline)
+{
+  ASSERT(NULL != ctx);
+
+  tls_ctx_load_cert_file(ctx, cert_file, cert_file_inline);
+
+  if (ctx->crt_chain == NULL)
+    return 0;
+
+  ALLOC_OBJ_CLEAR (ctx->external_key, struct external_context);
+  ctx->external_key->signature_length = mbedtls_pk_get_len 
(&ctx->crt_chain->pk);
+
+  ALLOC_OBJ_CLEAR (ctx->priv_key, mbedtls_pk_context);
+  if (!mbed_ok (mbedtls_pk_setup_rsa_alt (ctx->priv_key, ctx->external_key,
+           NULL, external_pkcs1_sign, external_key_len)))
+    return 0;
+
+  return 1;
+}
+#endif
+
+void tls_ctx_load_ca (struct tls_root_ctx *ctx, const char *ca_file,
+    const char *ca_inline, const char *ca_path, bool tls_server
+    )
+{
+  if (ca_path)
+      msg(M_FATAL, "ERROR: mbed TLS cannot handle the capath directive");
+
+  if (ca_file && !strcmp (ca_file, INLINE_FILE_TAG) && ca_inline)
+    {
+      if (!mbed_ok (mbedtls_x509_crt_parse (ctx->ca_chain,
+         (const unsigned char *) ca_inline, strlen(ca_inline)+1)))
+       msg (M_FATAL, "Cannot load inline CA certificates");
+    }
+  else
+    {
+      /* Load CA file for verifying peer supplied certificate */
+      if (!mbed_ok (mbedtls_x509_crt_parse_file (ctx->ca_chain, ca_file)))
+       msg (M_FATAL, "Cannot load CA certificate file %s", ca_file);
+    }
+}
+
+void
+tls_ctx_load_extra_certs (struct tls_root_ctx *ctx, const char 
*extra_certs_file,
+    const char *extra_certs_inline
+    )
+{
+  ASSERT(NULL != ctx);
+
+  if (!ctx->crt_chain)
+    {
+      ALLOC_OBJ_CLEAR (ctx->crt_chain, mbedtls_x509_crt);
+    }
+
+  if (!strcmp (extra_certs_file, INLINE_FILE_TAG) && extra_certs_inline)
+    {
+      if (!mbed_ok(mbedtls_x509_crt_parse(ctx->crt_chain,
+          (const unsigned char *) extra_certs_inline,
+         strlen(extra_certs_inline)+1)))
+        msg (M_FATAL, "Cannot load inline extra-certs file");
+    }
+  else
+    {
+      if (!mbed_ok(mbedtls_x509_crt_parse_file(ctx->crt_chain, 
extra_certs_file)))
+       msg (M_FATAL, "Cannot load extra-certs file: %s", extra_certs_file);
+    }
+}
+
+/* **************************************
+ *
+ * Key-state specific functions
+ *
+ ***************************************/
+
+/*
+ * "Endless buffer"
+ */
+
+static inline void buf_free_entry(buffer_entry *entry)
+{
+  if (NULL != entry)
+    {
+      free(entry->data);
+      free(entry);
+    }
+}
+
+static void buf_free_entries(endless_buffer *buf)
+{
+  while(buf->first_block)
+    {
+      buffer_entry *cur_block = buf->first_block;
+      buf->first_block = cur_block->next_block;
+      buf_free_entry(cur_block);
+    }
+  buf->last_block = NULL;
+}
+
+static int endless_buf_read( endless_buffer *in, unsigned char * out, size_t 
out_len )
+{
+  size_t read_len = 0;
+
+  if (in->first_block == NULL)
+    return MBEDTLS_ERR_SSL_WANT_READ;
+
+  while (in->first_block != NULL && read_len < out_len)
+    {
+      int block_len = in->first_block->length - in->data_start;
+      if (block_len <= out_len - read_len)
+       {
+         buffer_entry *cur_entry = in->first_block;
+         memcpy(out + read_len, cur_entry->data + in->data_start,
+             block_len);
+
+         read_len += block_len;
+
+         in->first_block = cur_entry->next_block;
+         in->data_start = 0;
+
+         if (in->first_block == NULL)
+           in->last_block = NULL;
+
+         buf_free_entry(cur_entry);
+       }
+      else
+       {
+         memcpy(out + read_len, in->first_block->data + in->data_start,
+             out_len - read_len);
+         in->data_start += out_len - read_len;
+         read_len = out_len;
+       }
+    }
+
+  return read_len;
+}
+
+static int endless_buf_write( endless_buffer *out, const unsigned char *in, 
size_t len )
+{
+  buffer_entry *new_block = malloc(sizeof(buffer_entry));
+  if (NULL == new_block)
+    return MBEDTLS_ERR_NET_SEND_FAILED;
+
+  new_block->data = malloc(len);
+  if (NULL == new_block->data)
+    {
+      free(new_block);
+      return MBEDTLS_ERR_NET_SEND_FAILED;
+    }
+
+  new_block->length = len;
+  new_block->next_block = NULL;
+
+  memcpy(new_block->data, in, len);
+
+  if (NULL == out->first_block)
+    out->first_block = new_block;
+
+  if (NULL != out->last_block)
+    out->last_block->next_block = new_block;
+
+  out->last_block = new_block;
+
+  return len;
+}
+
+static int ssl_bio_read( void *ctx, unsigned char *out, size_t out_len)
+{
+  bio_ctx *my_ctx = (bio_ctx *) ctx;
+  return endless_buf_read (&my_ctx->in, out, out_len);
+}
+
+static int ssl_bio_write( void *ctx, const unsigned char *in, size_t in_len)
+{
+  bio_ctx *my_ctx = (bio_ctx *) ctx;
+  return endless_buf_write (&my_ctx->out, in, in_len);
+}
+
+static void my_debug( void *ctx, int level, const char *file, int line,
+    const char *str )
+{
+  int my_loglevel = (level < 3) ? D_TLS_DEBUG_MED : D_TLS_DEBUG;
+  msg (my_loglevel, "mbed TLS msg (%s:%d): %s", file, line, str);
+}
+
+/*
+ * Further personalise the RNG using a hash of the public key
+ */
+void tls_ctx_personalise_random(struct tls_root_ctx *ctx)
+{
+  static char old_sha256_hash[32] = {0};
+  unsigned char sha256_hash[32] = {0};
+  mbedtls_ctr_drbg_context *cd_ctx = rand_ctx_get();
+
+  if (NULL != ctx->crt_chain)
+    {
+      mbedtls_x509_crt *cert = ctx->crt_chain;
+
+      mbedtls_sha256(cert->tbs.p, cert->tbs.len, sha256_hash, false);
+      if ( 0 != memcmp(old_sha256_hash, sha256_hash, sizeof(sha256_hash)))
+       {
+         mbedtls_ctr_drbg_update(cd_ctx, sha256_hash, 32);
+         memcpy(old_sha256_hash, sha256_hash, sizeof(old_sha256_hash));
+       }
+    }
+}
+
+int
+tls_version_max(void)
+{
+#if defined(SSL_MAJOR_VERSION_3) && defined(SSL_MINOR_VERSION_3)
+  return TLS_VER_1_2;
+#elif defined(SSL_MAJOR_VERSION_3) && defined(SSL_MINOR_VERSION_2)
+  return TLS_VER_1_1;
+#else
+  return TLS_VER_1_0;
+#endif
+}
+
+/**
+ * Convert an OpenVPN tls-version variable to mbed TLS format (i.e. a major and
+ * minor ssl version number).
+ *
+ * @param tls_ver      The tls-version variable to convert.
+ * @param major                Returns the TLS major version in mbed TLS 
format.
+ *                     Must be a valid pointer.
+ * @param minor                Returns the TLS minor version in mbed TLS 
format.
+ *                     Must be a valid pointer.
+ */
+static void tls_version_to_major_minor(int tls_ver, int *major, int *minor) {
+  ASSERT(major);
+  ASSERT(minor);
+
+  switch (tls_ver)
+  {
+    case TLS_VER_1_0:
+      *major = MBEDTLS_SSL_MAJOR_VERSION_3;
+      *minor = MBEDTLS_SSL_MINOR_VERSION_1;
+      break;
+    case TLS_VER_1_1:
+      *major = MBEDTLS_SSL_MAJOR_VERSION_3;
+      *minor = MBEDTLS_SSL_MINOR_VERSION_2;
+      break;
+    case TLS_VER_1_2:
+      *major = MBEDTLS_SSL_MAJOR_VERSION_3;
+      *minor = MBEDTLS_SSL_MINOR_VERSION_3;
+      break;
+    default:
+      msg(M_FATAL, "%s: invalid TLS version %d", __func__, tls_ver);
+      break;
+  }
+}
+
+void key_state_ssl_init(struct key_state_ssl *ks_ssl,
+    const struct tls_root_ctx *ssl_ctx, bool is_server, struct tls_session 
*session)
+{
+  ASSERT(NULL != ssl_ctx);
+  ASSERT(ks_ssl);
+  CLEAR(*ks_ssl);
+
+  /* Initialise SSL config */
+  mbedtls_ssl_config_init(&ks_ssl->ssl_config);
+  mbedtls_ssl_config_defaults(&ks_ssl->ssl_config, ssl_ctx->endpoint,
+      MBEDTLS_SSL_TRANSPORT_STREAM, MBEDTLS_SSL_PRESET_DEFAULT);
+  mbedtls_debug_set_threshold(3);
+  mbedtls_ssl_conf_dbg (&ks_ssl->ssl_config, my_debug, NULL);
+  mbedtls_ssl_conf_rng (&ks_ssl->ssl_config, mbedtls_ctr_drbg_random,
+      rand_ctx_get());
+
+  if (ssl_ctx->allowed_ciphers)
+    mbedtls_ssl_conf_ciphersuites (&ks_ssl->ssl_config, 
ssl_ctx->allowed_ciphers);
+
+  /* Disable record splitting (for now).  OpenVPN assumes records are sent
+   * unfragmented, and changing that will require thorough review and
+   * testing.  Since OpenVPN is not susceptible to BEAST, we can just
+   * disable record splitting as a quick fix. */
+#if defined(MBEDTLS_SSL_CBC_RECORD_SPLITTING)
+  mbedtls_ssl_conf_cbc_record_splitting (&ks_ssl->ssl_config,
+      MBEDTLS_SSL_CBC_RECORD_SPLITTING_DISABLED);
+#endif /* MBEDTLS_SSL_CBC_RECORD_SPLITTING */
+
+  /* Initialise authentication information */
+  if (is_server)
+    mbed_ok (mbedtls_ssl_conf_dh_param_ctx(&ks_ssl->ssl_config,
+       ssl_ctx->dhm_ctx));
+
+  mbed_ok (mbedtls_ssl_conf_own_cert(&ks_ssl->ssl_config, ssl_ctx->crt_chain,
+      ssl_ctx->priv_key));
+
+  /* Initialise SSL verification */
+#if P2MP_SERVER
+  if (session->opt->ssl_flags & SSLF_CLIENT_CERT_OPTIONAL)
+    {
+      mbedtls_ssl_conf_authmode(&ks_ssl->ssl_config, 
MBEDTLS_SSL_VERIFY_OPTIONAL);
+    }
+  else if (!(session->opt->ssl_flags & SSLF_CLIENT_CERT_NOT_REQUIRED))
+#endif
+  {
+    mbedtls_ssl_conf_authmode (&ks_ssl->ssl_config, 
MBEDTLS_SSL_VERIFY_REQUIRED);
+  }
+  mbedtls_ssl_conf_verify (&ks_ssl->ssl_config, verify_callback, session);
+
+  /* TODO: mbed TLS does not currently support sending the CA chain to the 
client */
+  mbedtls_ssl_conf_ca_chain (&ks_ssl->ssl_config, ssl_ctx->ca_chain, NULL );
+
+  /* Initialize minimum TLS version */
+  {
+    const int tls_version_min =
+       (session->opt->ssl_flags >> SSLF_TLS_VERSION_MIN_SHIFT) &
+       SSLF_TLS_VERSION_MIN_MASK;
+
+    /* default to TLS 1.0 */
+    int major = MBEDTLS_SSL_MAJOR_VERSION_3;
+    int minor = MBEDTLS_SSL_MINOR_VERSION_1;
+
+    if (tls_version_min > TLS_VER_UNSPEC)
+      tls_version_to_major_minor(tls_version_min, &major, &minor);
+
+    mbedtls_ssl_conf_min_version(&ks_ssl->ssl_config, major, minor);
+  }
+
+  /* Initialize maximum TLS version */
+  {
+    const int tls_version_max =
+       (session->opt->ssl_flags >> SSLF_TLS_VERSION_MAX_SHIFT) &
+       SSLF_TLS_VERSION_MAX_MASK;
+
+    if (tls_version_max > TLS_VER_UNSPEC)
+      {
+       int major, minor;
+       tls_version_to_major_minor(tls_version_max, &major, &minor);
+       mbedtls_ssl_conf_max_version(&ks_ssl->ssl_config, major, minor);
+      }
+  }
+
+  /* Initialise SSL context */
+  ALLOC_OBJ_CLEAR(ks_ssl->ctx, mbedtls_ssl_context);
+  mbedtls_ssl_init(ks_ssl->ctx);
+  mbedtls_ssl_setup(ks_ssl->ctx, &ks_ssl->ssl_config);
+
+  /* Initialise BIOs */
+  CLEAR (ks_ssl->bio_ctx);
+  mbedtls_ssl_set_bio (ks_ssl->ctx, &ks_ssl->bio_ctx, ssl_bio_write,
+      ssl_bio_read, NULL);
+}
+
+void
+key_state_ssl_free(struct key_state_ssl *ks_ssl)
+{
+  if (ks_ssl) {
+      if (ks_ssl->ctx)
+       {
+         mbedtls_ssl_free(ks_ssl->ctx);
+         free(ks_ssl->ctx);
+       }
+      mbedtls_ssl_config_free(&ks_ssl->ssl_config);
+      buf_free_entries(&ks_ssl->bio_ctx.in);
+      buf_free_entries(&ks_ssl->bio_ctx.out);
+      CLEAR(*ks_ssl);
+  }
+}
+
+int
+key_state_write_plaintext (struct key_state_ssl *ks, struct buffer *buf)
+{
+  int retval = 0;
+
+  ASSERT (buf);
+
+  retval = key_state_write_plaintext_const(ks, BPTR(buf), BLEN(buf));
+
+  if (1 == retval)
+    {
+      memset (BPTR (buf), 0, BLEN (buf)); /* erase data just written */
+      buf->len = 0;
+    }
+
+  return retval;
+}
+
+int
+key_state_write_plaintext_const (struct key_state_ssl *ks, const uint8_t 
*data, int len)
+{
+  int retval = 0;
+  perf_push (PERF_BIO_WRITE_PLAINTEXT);
+
+  ASSERT (NULL != ks);
+  ASSERT (len >= 0);
+
+  if (0 == len)
+    {
+      perf_pop ();
+      return 0;
+    }
+
+  ASSERT (data);
+
+  retval = mbedtls_ssl_write(ks->ctx, data, len);
+
+  if (retval < 0)
+    {
+      perf_pop ();
+      if (MBEDTLS_ERR_SSL_WANT_WRITE == retval || MBEDTLS_ERR_SSL_WANT_READ == 
retval)
+       return 0;
+      mbed_log_err (D_TLS_ERRORS, retval,
+         "TLS ERROR: write tls_write_plaintext_const error");
+      return -1;
+    }
+
+  if (retval != len)
+    {
+      msg (D_TLS_ERRORS,
+         "TLS ERROR: write tls_write_plaintext_const incomplete %d/%d",
+         retval, len);
+      perf_pop ();
+      return -1;
+    }
+
+  /* successful write */
+  dmsg (D_HANDSHAKE_VERBOSE, "write tls_write_plaintext_const %d bytes", 
retval);
+
+  perf_pop ();
+  return 1;
+}
+
+int
+key_state_read_ciphertext (struct key_state_ssl *ks, struct buffer *buf,
+    int maxlen)
+{
+  int retval = 0;
+  int len = 0;
+
+  perf_push (PERF_BIO_READ_CIPHERTEXT);
+
+  ASSERT (NULL != ks);
+  ASSERT (buf);
+  ASSERT (buf->len >= 0);
+
+  if (buf->len)
+    {
+      perf_pop ();
+      return 0;
+    }
+
+  len = buf_forward_capacity (buf);
+  if (maxlen < len)
+    len = maxlen;
+
+  retval = endless_buf_read(&ks->bio_ctx.out, BPTR(buf), len);
+
+  /* Error during read, check for retry error */
+  if (retval < 0)
+    {
+      perf_pop ();
+      if (MBEDTLS_ERR_SSL_WANT_WRITE == retval || MBEDTLS_ERR_SSL_WANT_READ == 
retval)
+       return 0;
+      mbed_log_err (D_TLS_ERRORS, retval, "TLS_ERROR: read tls_read_ciphertext 
error");
+      buf->len = 0;
+      return -1;
+    }
+  /* Nothing read, try again */
+  if (0 == retval)
+    {
+      buf->len = 0;
+      perf_pop ();
+      return 0;
+    }
+
+  /* successful read */
+  dmsg (D_HANDSHAKE_VERBOSE, "read tls_read_ciphertext %d bytes", retval);
+  buf->len = retval;
+  perf_pop ();
+  return 1;
+}
+
+int
+key_state_write_ciphertext (struct key_state_ssl *ks, struct buffer *buf)
+{
+  int retval = 0;
+  perf_push (PERF_BIO_WRITE_CIPHERTEXT);
+
+  ASSERT (NULL != ks);
+  ASSERT (buf);
+  ASSERT (buf->len >= 0);
+
+  if (0 == buf->len)
+    {
+      perf_pop ();
+      return 0;
+    }
+
+  retval = endless_buf_write(&ks->bio_ctx.in, BPTR(buf), buf->len);
+
+  if (retval < 0)
+    {
+      perf_pop ();
+
+      if (MBEDTLS_ERR_SSL_WANT_WRITE == retval || MBEDTLS_ERR_SSL_WANT_READ == 
retval)
+       return 0;
+      mbed_log_err (D_TLS_ERRORS, retval,
+         "TLS ERROR: write tls_write_ciphertext error");
+      return -1;
+    }
+
+  if (retval != buf->len)
+    {
+      msg (D_TLS_ERRORS, "TLS ERROR: write tls_write_ciphertext incomplete 
%d/%d",
+         retval, buf->len);
+      perf_pop ();
+      return -1;
+    }
+
+  /* successful write */
+  dmsg (D_HANDSHAKE_VERBOSE, "write tls_write_ciphertext %d bytes", retval);
+
+  memset (BPTR (buf), 0, BLEN (buf)); /* erase data just written */
+  buf->len = 0;
+
+  perf_pop ();
+  return 1;
+}
+
+int
+key_state_read_plaintext (struct key_state_ssl *ks, struct buffer *buf,
+    int maxlen)
+{
+  int retval = 0;
+  int len = 0;
+
+  perf_push (PERF_BIO_READ_PLAINTEXT);
+
+  ASSERT (NULL != ks);
+  ASSERT (buf);
+  ASSERT (buf->len >= 0);
+
+  if (buf->len)
+    {
+      perf_pop ();
+      return 0;
+    }
+
+  len = buf_forward_capacity (buf);
+  if (maxlen < len)
+    len = maxlen;
+
+  retval = mbedtls_ssl_read(ks->ctx, BPTR(buf), len);
+
+  /* Error during read, check for retry error */
+  if (retval < 0)
+    {
+      if (MBEDTLS_ERR_SSL_WANT_WRITE == retval || MBEDTLS_ERR_SSL_WANT_READ == 
retval)
+       return 0;
+      mbed_log_err (D_TLS_ERRORS, retval, "TLS_ERROR: read tls_read_plaintext 
error");
+      buf->len = 0;
+      perf_pop ();
+      return -1;
+    }
+  /* Nothing read, try again */
+  if (0 == retval)
+    {
+      buf->len = 0;
+      perf_pop ();
+      return 0;
+    }
+
+  /* successful read */
+  dmsg (D_HANDSHAKE_VERBOSE, "read tls_read_plaintext %d bytes", retval);
+  buf->len = retval;
+
+  perf_pop ();
+  return 1;
+}
+
+/* **************************************
+ *
+ * Information functions
+ *
+ * Print information for the end user.
+ *
+ ***************************************/
+void
+print_details (struct key_state_ssl * ks_ssl, const char *prefix)
+{
+  const mbedtls_x509_crt *cert;
+  char s1[256];
+  char s2[256];
+
+  s1[0] = s2[0] = 0;
+  openvpn_snprintf (s1, sizeof (s1), "%s %s, cipher %s",
+                   prefix,
+                   mbedtls_ssl_get_version (ks_ssl->ctx),
+                   mbedtls_ssl_get_ciphersuite (ks_ssl->ctx));
+
+  cert = mbedtls_ssl_get_peer_cert (ks_ssl->ctx);
+  if (cert != NULL)
+    {
+      openvpn_snprintf (s2, sizeof (s2), ", %zu bit key",
+         mbedtls_pk_get_bitlen (&cert->pk));
+    }
+
+  msg (D_HANDSHAKE, "%s%s", s1, s2);
+}
+
+void
+show_available_tls_ciphers (const char *cipher_list)
+{
+  struct tls_root_ctx tls_ctx;
+  const int *ciphers = mbedtls_ssl_list_ciphersuites ();
+
+  tls_ctx_server_new(&tls_ctx);
+  tls_ctx_restrict_ciphers(&tls_ctx, cipher_list);
+
+  if (tls_ctx.allowed_ciphers)
+    ciphers = tls_ctx.allowed_ciphers;
+
+#ifndef ENABLE_SMALL
+  printf ("Available TLS Ciphers,\n");
+  printf ("listed in order of preference:\n\n");
+#endif
+
+  while (*ciphers != 0)
+    {
+      printf ("%s\n", mbedtls_ssl_get_ciphersuite_name (*ciphers));
+      ciphers++;
+    }
+  printf ("\n" SHOW_TLS_CIPHER_LIST_WARNING);
+
+  tls_ctx_free(&tls_ctx);
+}
+
+void
+show_available_curves (void)
+{
+  const mbedtls_ecp_curve_info *pcurve = mbedtls_ecp_curve_list ();
+
+  if (NULL == pcurve)
+    msg (M_FATAL, "Cannot retrieve curve list from mbed TLS");
+
+  /* Print curve list */
+  printf ("Available Elliptic curves, listed in order of preference:\n\n");
+  while (MBEDTLS_ECP_DP_NONE != pcurve->grp_id)
+    {
+      printf("%s\n", pcurve->name);
+      pcurve++;
+    }
+}
+
+void
+get_highest_preference_tls_cipher (char *buf, int size)
+{
+  const char *cipher_name;
+  const int *ciphers = mbedtls_ssl_list_ciphersuites();
+  if (*ciphers == 0)
+    msg (M_FATAL, "Cannot retrieve list of supported SSL ciphers.");
+
+  cipher_name = mbedtls_ssl_get_ciphersuite_name(*ciphers);
+  strncpynt (buf, cipher_name, size);
+}
+
+const char *
+get_ssl_library_version(void)
+{
+    static char mbedtls_version[30];
+    unsigned int pv = mbedtls_version_get_number();
+    sprintf( mbedtls_version, "mbed TLS %d.%d.%d",
+               (pv>>24)&0xff, (pv>>16)&0xff, (pv>>8)&0xff );
+    return mbedtls_version;
+}
+
+#endif /* defined(ENABLE_CRYPTO) && defined(ENABLE_CRYPTO_MBEDTLS) */
diff --git a/src/openvpn/ssl_mbedtls.h b/src/openvpn/ssl_mbedtls.h
new file mode 100644
index 0000000..6f778ef
--- /dev/null
+++ b/src/openvpn/ssl_mbedtls.h
@@ -0,0 +1,92 @@
+/*
+ *  OpenVPN -- An application to securely tunnel IP networks
+ *             over a single TCP/UDP port, with support for SSL/TLS-based
+ *             session authentication and key exchange,
+ *             packet encryption, packet authentication, and
+ *             packet compression.
+ *
+ *  Copyright (C) 2002-2010 OpenVPN Technologies, Inc. <sa...@openvpn.net>
+ *  Copyright (C) 2010 Fox Crypto B.V. <open...@fox-it.com>
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License version 2
+ *  as published by the Free Software Foundation.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program (see the file COPYING included with this
+ *  distribution); if not, write to the Free Software Foundation, Inc.,
+ *  59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+/**
+ * @file Control Channel mbed TLS Backend
+ */
+
+#ifndef SSL_MBEDTLS_H_
+#define SSL_MBEDTLS_H_
+
+#include "syshead.h"
+
+#include <mbedtls/ssl.h>
+#include <mbedtls/x509_crt.h>
+
+#if defined(ENABLE_PKCS11)
+#include <mbedtls/pkcs11.h>
+#endif
+
+typedef struct _buffer_entry buffer_entry;
+
+struct _buffer_entry {
+    size_t length;
+    uint8_t *data;
+    buffer_entry *next_block;
+};
+
+typedef struct {
+    size_t data_start;
+    buffer_entry *first_block;
+    buffer_entry *last_block;
+} endless_buffer;
+
+typedef struct {
+    endless_buffer in;
+    endless_buffer out;
+} bio_ctx;
+
+/**
+ * Structure that wraps the TLS context. Contents differ depending on the
+ * SSL library used.
+ *
+ * Either \c priv_key_pkcs11 or \c priv_key must be filled in.
+ */
+struct tls_root_ctx {
+    bool initialised;          /**< True if the context has been initialised */
+
+    int endpoint;              /**< Whether or not this is a server or a 
client */
+
+    mbedtls_dhm_context *dhm_ctx;      /**< Diffie-Helmann-Merkle context */
+    mbedtls_x509_crt *crt_chain;       /**< Local Certificate chain */
+    mbedtls_x509_crt *ca_chain;                /**< CA chain for remote 
verification */
+    mbedtls_pk_context *priv_key;      /**< Local private key */
+#if defined(ENABLE_PKCS11)
+    mbedtls_pkcs11_context *priv_key_pkcs11;   /**< PKCS11 private key */
+#endif
+#ifdef MANAGMENT_EXTERNAL_KEY
+    struct external_context *external_key; /**< Management external key */
+#endif
+    int * allowed_ciphers;     /**< List of allowed ciphers for this 
connection */
+};
+
+struct key_state_ssl {
+    mbedtls_ssl_config ssl_config;     /**< mbedTLS global ssl config */
+    mbedtls_ssl_context *ctx;          /**< mbedTLS connection context */
+    bio_ctx bio_ctx;
+};
+
+
+#endif /* SSL_MBEDTLS_H_ */
diff --git a/src/openvpn/ssl_polarssl.c b/src/openvpn/ssl_polarssl.c
deleted file mode 100644
index 483ec1c..0000000
--- a/src/openvpn/ssl_polarssl.c
+++ /dev/null
@@ -1,1184 +0,0 @@
-/*
- *  OpenVPN -- An application to securely tunnel IP networks
- *             over a single TCP/UDP port, with support for SSL/TLS-based
- *             session authentication and key exchange,
- *             packet encryption, packet authentication, and
- *             packet compression.
- *
- *  Copyright (C) 2002-2010 OpenVPN Technologies, Inc. <sa...@openvpn.net>
- *  Copyright (C) 2010 Fox Crypto B.V. <open...@fox-it.com>
- *  Copyright (C) 2006-2010, Brainspark B.V.
- *
- *  This program is free software; you can redistribute it and/or modify
- *  it under the terms of the GNU General Public License version 2
- *  as published by the Free Software Foundation.
- *
- *  This program is distributed in the hope that it will be useful,
- *  but WITHOUT ANY WARRANTY; without even the implied warranty of
- *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- *  GNU General Public License for more details.
- *
- *  You should have received a copy of the GNU General Public License
- *  along with this program (see the file COPYING included with this
- *  distribution); if not, write to the Free Software Foundation, Inc.,
- *  59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
- */
-
-/**
- * @file Control Channel mbed TLS Backend
- */
-
-#ifdef HAVE_CONFIG_H
-#include "config.h"
-#elif defined(_MSC_VER)
-#include "config-msvc.h"
-#endif
-
-#include "syshead.h"
-
-#if defined(ENABLE_CRYPTO) && defined(ENABLE_CRYPTO_MBEDTLS)
-
-#include "errlevel.h"
-#include "ssl_backend.h"
-#include "base64.h"
-#include "buffer.h"
-#include "misc.h"
-#include "manage.h"
-#include "ssl_common.h"
-
-#include <mbedtls/havege.h>
-
-#include "ssl_verify_polarssl.h"
-#include <mbedtls/debug.h>
-#include <mbedtls/error.h>
-#include <mbedtls/net.h>
-#include <mbedtls/oid.h>
-#include <mbedtls/pem.h>
-#include <mbedtls/sha256.h>
-#include <mbedtls/version.h>
-
-void
-tls_init_lib()
-{
-}
-
-void
-tls_free_lib()
-{
-}
-
-void
-tls_clear_error()
-{
-}
-
-void
-tls_ctx_server_new(struct tls_root_ctx *ctx)
-{
-  ASSERT(NULL != ctx);
-  CLEAR(*ctx);
-
-  ALLOC_OBJ_CLEAR(ctx->dhm_ctx, mbedtls_dhm_context);
-
-  ALLOC_OBJ_CLEAR(ctx->ca_chain, mbedtls_x509_crt);
-
-  ctx->endpoint = MBEDTLS_SSL_IS_SERVER;
-  ctx->initialised = true;
-}
-
-void
-tls_ctx_client_new(struct tls_root_ctx *ctx)
-{
-  ASSERT(NULL != ctx);
-  CLEAR(*ctx);
-
-  ALLOC_OBJ_CLEAR(ctx->dhm_ctx, mbedtls_dhm_context);
-  ALLOC_OBJ_CLEAR(ctx->ca_chain, mbedtls_x509_crt);
-
-  ctx->endpoint = MBEDTLS_SSL_IS_CLIENT;
-  ctx->initialised = true;
-}
-
-void
-tls_ctx_free(struct tls_root_ctx *ctx)
-{
-  if (ctx)
-    {
-      mbedtls_pk_free(ctx->priv_key);
-      if (ctx->priv_key)
-       free(ctx->priv_key);
-
-      mbedtls_x509_crt_free(ctx->ca_chain);
-      if (ctx->ca_chain)
-       free(ctx->ca_chain);
-
-      mbedtls_x509_crt_free(ctx->crt_chain);
-      if (ctx->crt_chain)
-       free(ctx->crt_chain);
-
-      mbedtls_dhm_free(ctx->dhm_ctx);
-      if (ctx->dhm_ctx)
-       free(ctx->dhm_ctx);
-
-#if defined(ENABLE_PKCS11)
-      if (ctx->priv_key_pkcs11 != NULL) {
-         mbedtls_pkcs11_priv_key_free(ctx->priv_key_pkcs11);
-         free(ctx->priv_key_pkcs11);
-      }
-#endif
-#if defined(MANAGMENT_EXTERNAL_KEY)
-      if (ctx->external_key != NULL)
-          free(ctx->external_key);
-#endif
-
-      if (ctx->allowed_ciphers)
-       free(ctx->allowed_ciphers);
-
-      CLEAR(*ctx);
-
-      ctx->initialised = false;
-
-    }
-}
-
-bool
-tls_ctx_initialised(struct tls_root_ctx *ctx)
-{
-  ASSERT(NULL != ctx);
-  return ctx->initialised;
-}
-
-void
-key_state_export_keying_material(struct key_state_ssl *ssl,
-                                 struct tls_session *session)
-{
-}
-
-void
-tls_ctx_set_options (struct tls_root_ctx *ctx, unsigned int ssl_flags)
-{
-}
-
-static const char *
-tls_translate_cipher_name (const char * cipher_name) {
-  const tls_cipher_name_pair * pair = tls_get_cipher_name_pair(cipher_name, 
strlen(cipher_name));
-
-  if (NULL == pair)
-    {
-      // No translation found, return original
-      return cipher_name;
-    }
-
-  if (0 != strcmp(cipher_name, pair->iana_name))
-    {
-      // Deprecated name found, notify user
-      msg(M_WARN, "Deprecated cipher suite name '%s', please use IANA name 
'%s'", pair->openssl_name, pair->iana_name);
-    }
-
-  return pair->iana_name;
-}
-
-void
-tls_ctx_restrict_ciphers(struct tls_root_ctx *ctx, const char *ciphers)
-{
-  char *tmp_ciphers, *tmp_ciphers_orig, *token;
-  int i, cipher_count;
-  int ciphers_len;
-
-  if (NULL == ciphers)
-    return; /* Nothing to do */
-
-  ciphers_len = strlen (ciphers);
-
-  ASSERT (NULL != ctx);
-  ASSERT (0 != ciphers_len);
-
-  /* Get number of ciphers */
-  for (i = 0, cipher_count = 1; i < ciphers_len; i++)
-    if (ciphers[i] == ':')
-      cipher_count++;
-
-  /* Allocate an array for them */
-  ALLOC_ARRAY_CLEAR(ctx->allowed_ciphers, int, cipher_count+1)
-
-  /* Parse allowed ciphers, getting IDs */
-  i = 0;
-  tmp_ciphers_orig = tmp_ciphers = string_alloc (ciphers, NULL);
-
-  token = strtok (tmp_ciphers, ":");
-  while(token)
-    {
-      ctx->allowed_ciphers[i] = mbedtls_ssl_get_ciphersuite_id (
-         tls_translate_cipher_name (token));
-      if (0 != ctx->allowed_ciphers[i])
-       i++;
-      token = strtok (NULL, ":");
-    }
-  free(tmp_ciphers_orig);
-}
-
-void
-tls_ctx_check_cert_time (const struct tls_root_ctx *ctx)
-{
-  ASSERT (ctx);
-  if (ctx->crt_chain == NULL)
-    {
-      return; /* Nothing to check if there is no certificate */
-    }
-
-  if (mbedtls_x509_time_is_future (&ctx->crt_chain->valid_from))
-    {
-      msg (M_WARN, "WARNING: Your certificate is not yet valid!");
-    }
-
-  if (mbedtls_x509_time_is_past (&ctx->crt_chain->valid_to))
-    {
-      msg (M_WARN, "WARNING: Your certificate has expired!");
-    }
-}
-
-void
-tls_ctx_load_dh_params (struct tls_root_ctx *ctx, const char *dh_file,
-    const char *dh_inline
-    )
-{
-  if (!strcmp (dh_file, INLINE_FILE_TAG) && dh_inline)
-    {
-      if (!mbed_ok(mbedtls_dhm_parse_dhm(ctx->dhm_ctx,
-         (const unsigned char *) dh_inline, strlen(dh_inline)+1)))
-       msg (M_FATAL, "Cannot read inline DH parameters");
-  }
-else
-  {
-    if (!mbed_ok(mbedtls_dhm_parse_dhmfile(ctx->dhm_ctx, dh_file)))
-      msg (M_FATAL, "Cannot read DH parameters from file %s", dh_file);
-  }
-
-  msg (D_TLS_DEBUG_LOW, "Diffie-Hellman initialized with " counter_format " 
bit key",
-      (counter_type) 8 * mbedtls_mpi_size(&ctx->dhm_ctx->P));
-}
-
-void
-tls_ctx_load_ecdh_params (struct tls_root_ctx *ctx, const char *curve_name
-    )
-{
-    if (NULL != curve_name)
-      msg(M_WARN, "WARNING: mbed TLS builds do not support specifying an ECDH "
-                  "curve, using default curves.");
-}
-
-int
-tls_ctx_load_pkcs12(struct tls_root_ctx *ctx, const char *pkcs12_file,
-    const char *pkcs12_file_inline,
-    bool load_ca_file
-    )
-{
-  msg(M_FATAL, "PKCS #12 files not yet supported for mbed TLS.");
-  return 0;
-}
-
-#ifdef ENABLE_CRYPTOAPI
-void
-tls_ctx_load_cryptoapi(struct tls_root_ctx *ctx, const char *cryptoapi_cert)
-{
-  msg(M_FATAL, "Windows CryptoAPI not yet supported for mbed TLS.");
-}
-#endif /* WIN32 */
-
-void
-tls_ctx_load_cert_file (struct tls_root_ctx *ctx, const char *cert_file,
-    const char *cert_inline
-    )
-{
-  ASSERT(NULL != ctx);
-
-  if (!ctx->crt_chain)
-    {
-      ALLOC_OBJ_CLEAR(ctx->crt_chain, mbedtls_x509_crt);
-    }
-
-  if (!strcmp (cert_file, INLINE_FILE_TAG) && cert_inline)
-    {
-      if (!mbed_ok(mbedtls_x509_crt_parse(ctx->crt_chain,
-         (const unsigned char *) cert_inline, strlen(cert_inline)+1)))
-        msg (M_FATAL, "Cannot load inline certificate file");
-    }
-  else
-    {
-      if (!mbed_ok(mbedtls_x509_crt_parse_file(ctx->crt_chain, cert_file)))
-       {
-         msg (M_FATAL, "Cannot load certificate file %s", cert_file);
-       }
-    }
-}
-
-int
-tls_ctx_load_priv_file (struct tls_root_ctx *ctx, const char *priv_key_file,
-    const char *priv_key_inline
-    )
-{
-  int status;
-  ASSERT(NULL != ctx);
-
-  if (!ctx->priv_key)
-    {
-      ALLOC_OBJ_CLEAR(ctx->priv_key, mbedtls_pk_context);
-    }
-
-  if (!strcmp (priv_key_file, INLINE_FILE_TAG) && priv_key_inline)
-    {
-      status = mbedtls_pk_parse_key(ctx->priv_key,
-         (const unsigned char *) priv_key_inline, strlen(priv_key_inline)+1,
-         NULL, 0);
-
-      if (MBEDTLS_ERR_PK_PASSWORD_REQUIRED == status)
-       {
-         char passbuf[512] = {0};
-         pem_password_callback(passbuf, 512, 0, NULL);
-         status = mbedtls_pk_parse_key(ctx->priv_key,
-             (const unsigned char *) priv_key_inline,
-             strlen(priv_key_inline)+1, (unsigned char *) passbuf,
-             strlen(passbuf));
-       }
-    }
-  else
-    {
-      status = mbedtls_pk_parse_keyfile(ctx->priv_key, priv_key_file, NULL);
-      if (MBEDTLS_ERR_PK_PASSWORD_REQUIRED == status)
-       {
-         char passbuf[512] = {0};
-         pem_password_callback(passbuf, 512, 0, NULL);
-         status = mbedtls_pk_parse_keyfile(ctx->priv_key, priv_key_file, 
passbuf);
-       }
-    }
-  if (!mbed_ok(status))
-    {
-#ifdef ENABLE_MANAGEMENT
-      if (management && (MBEDTLS_ERR_PK_PASSWORD_MISMATCH == status))
-         management_auth_failure (management, UP_TYPE_PRIVATE_KEY, NULL);
-#endif
-      msg (M_WARN, "Cannot load private key file %s", priv_key_file);
-      return 1;
-    }
-
-  warn_if_group_others_accessible (priv_key_file);
-
-  /* TODO: Check Private Key */
-#if 0
-  if (!SSL_CTX_check_private_key (ctx))
-    msg (M_SSLERR, "Private key does not match the certificate");
-#endif
-  return 0;
-}
-
-#ifdef MANAGMENT_EXTERNAL_KEY
-
-
-struct external_context {
-  size_t signature_length;
-};
-
-/**
- * external_pkcs1_sign implements a mbed TLS rsa_sign_func callback, that uses
- * the management interface to request an RSA signature for the supplied hash.
- *
- * @param ctx_voidptr   Management external key context.
- * @param f_rng         (Unused)
- * @param p_rng         (Unused)
- * @param mode          RSA mode (should be RSA_PRIVATE).
- * @param md_alg        Message digest ('hash') algorithm type.
- * @param hashlen       Length of hash (overridden by length specified by 
md_alg
- *                      if md_alg != MBEDTLS_MD_NONE).
- * @param hash          The digest ('hash') to sign. Should have a size
- *                      matching the length of md_alg (if != MBEDTLS_MD_NONE),
- *                      or hashlen otherwise.
- * @param sig           Buffer that returns the signature. Should be at least 
of
- *                      size ctx->signature_length.
- *
- * @return 0 on success, non-zero mbed TLS error code on failure.
- */
-static inline int external_pkcs1_sign( void *ctx_voidptr,
-    int (*f_rng)(void *, unsigned char *, size_t), void *p_rng, int mode,
-    mbedtls_md_type_t md_alg, unsigned int hashlen, const unsigned char *hash,
-    unsigned char *sig )
-{
-  struct external_context * const ctx = ctx_voidptr;
-  char *in_b64 = NULL;
-  char *out_b64 = NULL;
-  int rv;
-  unsigned char *p = sig;
-  size_t asn_len = 0, oid_size = 0, sig_len = 0;
-  const char *oid = NULL;
-
-  if( NULL == ctx )
-    return MBEDTLS_ERR_RSA_BAD_INPUT_DATA;
-
-  if( MBEDTLS_RSA_PRIVATE != mode )
-    return MBEDTLS_ERR_RSA_BAD_INPUT_DATA;
-
-  /*
-   * Support a wide range of hashes. TLSv1.1 and before only need SIG_RSA_RAW,
-   * but TLSv1.2 needs the full suite of hashes.
-   *
-   * This code has been taken from mbed TLS pkcs11_sign(), under the GPLv2.0+.
-   */
-  if( md_alg != MBEDTLS_MD_NONE )
-    {
-      const mbedtls_md_info_t *md_info = mbedtls_md_info_from_type( md_alg );
-      if( md_info == NULL )
-        return( MBEDTLS_ERR_RSA_BAD_INPUT_DATA );
-
-      if (!mbed_ok(mbedtls_oid_get_oid_by_md( md_alg, &oid, &oid_size )))
-        return( MBEDTLS_ERR_RSA_BAD_INPUT_DATA );
-
-      hashlen = mbedtls_md_get_size( md_info );
-      asn_len = 10 + oid_size;
-    }
-
-  sig_len = ctx->signature_length;
-  if ( (SIZE_MAX - hashlen) < asn_len || (hashlen + asn_len) > sig_len )
-    return MBEDTLS_ERR_RSA_BAD_INPUT_DATA;
-
-  if( md_alg != MBEDTLS_MD_NONE )
-    {
-      /*
-       * DigestInfo ::= SEQUENCE {
-       *   digestAlgorithm DigestAlgorithmIdentifier,
-       *   digest Digest }
-       *
-       * DigestAlgorithmIdentifier ::= AlgorithmIdentifier
-       *
-       * Digest ::= OCTET STRING
-       */
-      *p++ = MBEDTLS_ASN1_SEQUENCE | MBEDTLS_ASN1_CONSTRUCTED;
-      *p++ = (unsigned char) ( 0x08 + oid_size + hashlen );
-      *p++ = MBEDTLS_ASN1_SEQUENCE | MBEDTLS_ASN1_CONSTRUCTED;
-      *p++ = (unsigned char) ( 0x04 + oid_size );
-      *p++ = MBEDTLS_ASN1_OID;
-      *p++ = oid_size & 0xFF;
-      memcpy( p, oid, oid_size );
-      p += oid_size;
-      *p++ = MBEDTLS_ASN1_NULL;
-      *p++ = 0x00;
-      *p++ = MBEDTLS_ASN1_OCTET_STRING;
-      *p++ = hashlen;
-
-      /* Determine added ASN length */
-      asn_len = p - sig;
-  }
-
-  /* Copy the hash to be signed */
-  memcpy( p, hash, hashlen );
-
-  /* convert 'from' to base64 */
-  if (openvpn_base64_encode (sig, asn_len + hashlen, &in_b64) <= 0)
-    {
-      rv = MBEDTLS_ERR_RSA_BAD_INPUT_DATA;
-      goto done;
-    }
-
-  /* call MI for signature */
-  if (management)
-    out_b64 = management_query_rsa_sig (management, in_b64);
-  if (!out_b64)
-    {
-      rv = MBEDTLS_ERR_RSA_PRIVATE_FAILED;
-      goto done;
-    }
-
-  /* decode base64 signature to binary and verify length */
-  if ( openvpn_base64_decode (out_b64, sig, ctx->signature_length) !=
-       ctx->signature_length )
-    {
-      rv = MBEDTLS_ERR_RSA_PRIVATE_FAILED;
-      goto done;
-    }
-
-  rv = 0;
-
-done:
-  if (in_b64)
-    free (in_b64);
-  if (out_b64)
-    free (out_b64);
-  return rv;
-}
-
-static inline size_t external_key_len(void *vctx)
-{
-  struct external_context * const ctx = vctx;
-
-  return ctx->signature_length;
-}
-
-int
-tls_ctx_use_external_private_key (struct tls_root_ctx *ctx,
-    const char *cert_file, const char *cert_file_inline)
-{
-  ASSERT(NULL != ctx);
-
-  tls_ctx_load_cert_file(ctx, cert_file, cert_file_inline);
-
-  if (ctx->crt_chain == NULL)
-    return 0;
-
-  ALLOC_OBJ_CLEAR (ctx->external_key, struct external_context);
-  ctx->external_key->signature_length = mbedtls_pk_get_len 
(&ctx->crt_chain->pk);
-
-  ALLOC_OBJ_CLEAR (ctx->priv_key, mbedtls_pk_context);
-  if (!mbed_ok (mbedtls_pk_setup_rsa_alt (ctx->priv_key, ctx->external_key,
-           NULL, external_pkcs1_sign, external_key_len)))
-    return 0;
-
-  return 1;
-}
-#endif
-
-void tls_ctx_load_ca (struct tls_root_ctx *ctx, const char *ca_file,
-    const char *ca_inline, const char *ca_path, bool tls_server
-    )
-{
-  if (ca_path)
-      msg(M_FATAL, "ERROR: mbed TLS cannot handle the capath directive");
-
-  if (ca_file && !strcmp (ca_file, INLINE_FILE_TAG) && ca_inline)
-    {
-      if (!mbed_ok (mbedtls_x509_crt_parse (ctx->ca_chain,
-         (const unsigned char *) ca_inline, strlen(ca_inline)+1)))
-       msg (M_FATAL, "Cannot load inline CA certificates");
-    }
-  else
-    {
-      /* Load CA file for verifying peer supplied certificate */
-      if (!mbed_ok (mbedtls_x509_crt_parse_file (ctx->ca_chain, ca_file)))
-       msg (M_FATAL, "Cannot load CA certificate file %s", ca_file);
-    }
-}
-
-void
-tls_ctx_load_extra_certs (struct tls_root_ctx *ctx, const char 
*extra_certs_file,
-    const char *extra_certs_inline
-    )
-{
-  ASSERT(NULL != ctx);
-
-  if (!ctx->crt_chain)
-    {
-      ALLOC_OBJ_CLEAR (ctx->crt_chain, mbedtls_x509_crt);
-    }
-
-  if (!strcmp (extra_certs_file, INLINE_FILE_TAG) && extra_certs_inline)
-    {
-      if (!mbed_ok(mbedtls_x509_crt_parse(ctx->crt_chain,
-          (const unsigned char *) extra_certs_inline,
-         strlen(extra_certs_inline)+1)))
-        msg (M_FATAL, "Cannot load inline extra-certs file");
-    }
-  else
-    {
-      if (!mbed_ok(mbedtls_x509_crt_parse_file(ctx->crt_chain, 
extra_certs_file)))
-       msg (M_FATAL, "Cannot load extra-certs file: %s", extra_certs_file);
-    }
-}
-
-/* **************************************
- *
- * Key-state specific functions
- *
- ***************************************/
-
-/*
- * "Endless buffer"
- */
-
-static inline void buf_free_entry(buffer_entry *entry)
-{
-  if (NULL != entry)
-    {
-      free(entry->data);
-      free(entry);
-    }
-}
-
-static void buf_free_entries(endless_buffer *buf)
-{
-  while(buf->first_block)
-    {
-      buffer_entry *cur_block = buf->first_block;
-      buf->first_block = cur_block->next_block;
-      buf_free_entry(cur_block);
-    }
-  buf->last_block = NULL;
-}
-
-static int endless_buf_read( endless_buffer *in, unsigned char * out, size_t 
out_len )
-{
-  size_t read_len = 0;
-
-  if (in->first_block == NULL)
-    return MBEDTLS_ERR_SSL_WANT_READ;
-
-  while (in->first_block != NULL && read_len < out_len)
-    {
-      int block_len = in->first_block->length - in->data_start;
-      if (block_len <= out_len - read_len)
-       {
-         buffer_entry *cur_entry = in->first_block;
-         memcpy(out + read_len, cur_entry->data + in->data_start,
-             block_len);
-
-         read_len += block_len;
-
-         in->first_block = cur_entry->next_block;
-         in->data_start = 0;
-
-         if (in->first_block == NULL)
-           in->last_block = NULL;
-
-         buf_free_entry(cur_entry);
-       }
-      else
-       {
-         memcpy(out + read_len, in->first_block->data + in->data_start,
-             out_len - read_len);
-         in->data_start += out_len - read_len;
-         read_len = out_len;
-       }
-    }
-
-  return read_len;
-}
-
-static int endless_buf_write( endless_buffer *out, const unsigned char *in, 
size_t len )
-{
-  buffer_entry *new_block = malloc(sizeof(buffer_entry));
-  if (NULL == new_block)
-    return MBEDTLS_ERR_NET_SEND_FAILED;
-
-  new_block->data = malloc(len);
-  if (NULL == new_block->data)
-    {
-      free(new_block);
-      return MBEDTLS_ERR_NET_SEND_FAILED;
-    }
-
-  new_block->length = len;
-  new_block->next_block = NULL;
-
-  memcpy(new_block->data, in, len);
-
-  if (NULL == out->first_block)
-    out->first_block = new_block;
-
-  if (NULL != out->last_block)
-    out->last_block->next_block = new_block;
-
-  out->last_block = new_block;
-
-  return len;
-}
-
-static int ssl_bio_read( void *ctx, unsigned char *out, size_t out_len)
-{
-  bio_ctx *my_ctx = (bio_ctx *) ctx;
-  return endless_buf_read (&my_ctx->in, out, out_len);
-}
-
-static int ssl_bio_write( void *ctx, const unsigned char *in, size_t in_len)
-{
-  bio_ctx *my_ctx = (bio_ctx *) ctx;
-  return endless_buf_write (&my_ctx->out, in, in_len);
-}
-
-static void my_debug( void *ctx, int level, const char *file, int line,
-    const char *str )
-{
-  int my_loglevel = (level < 3) ? D_TLS_DEBUG_MED : D_TLS_DEBUG;
-  msg (my_loglevel, "mbed TLS msg (%s:%d): %s", file, line, str);
-}
-
-/*
- * Further personalise the RNG using a hash of the public key
- */
-void tls_ctx_personalise_random(struct tls_root_ctx *ctx)
-{
-  static char old_sha256_hash[32] = {0};
-  unsigned char sha256_hash[32] = {0};
-  mbedtls_ctr_drbg_context *cd_ctx = rand_ctx_get();
-
-  if (NULL != ctx->crt_chain)
-    {
-      mbedtls_x509_crt *cert = ctx->crt_chain;
-
-      mbedtls_sha256(cert->tbs.p, cert->tbs.len, sha256_hash, false);
-      if ( 0 != memcmp(old_sha256_hash, sha256_hash, sizeof(sha256_hash)))
-       {
-         mbedtls_ctr_drbg_update(cd_ctx, sha256_hash, 32);
-         memcpy(old_sha256_hash, sha256_hash, sizeof(old_sha256_hash));
-       }
-    }
-}
-
-int
-tls_version_max(void)
-{
-#if defined(SSL_MAJOR_VERSION_3) && defined(SSL_MINOR_VERSION_3)
-  return TLS_VER_1_2;
-#elif defined(SSL_MAJOR_VERSION_3) && defined(SSL_MINOR_VERSION_2)
-  return TLS_VER_1_1;
-#else
-  return TLS_VER_1_0;
-#endif
-}
-
-/**
- * Convert an OpenVPN tls-version variable to mbed TLS format (i.e. a major and
- * minor ssl version number).
- *
- * @param tls_ver      The tls-version variable to convert.
- * @param major                Returns the TLS major version in mbed TLS 
format.
- *                     Must be a valid pointer.
- * @param minor                Returns the TLS minor version in mbed TLS 
format.
- *                     Must be a valid pointer.
- */
-static void tls_version_to_major_minor(int tls_ver, int *major, int *minor) {
-  ASSERT(major);
-  ASSERT(minor);
-
-  switch (tls_ver)
-  {
-    case TLS_VER_1_0:
-      *major = MBEDTLS_SSL_MAJOR_VERSION_3;
-      *minor = MBEDTLS_SSL_MINOR_VERSION_1;
-      break;
-    case TLS_VER_1_1:
-      *major = MBEDTLS_SSL_MAJOR_VERSION_3;
-      *minor = MBEDTLS_SSL_MINOR_VERSION_2;
-      break;
-    case TLS_VER_1_2:
-      *major = MBEDTLS_SSL_MAJOR_VERSION_3;
-      *minor = MBEDTLS_SSL_MINOR_VERSION_3;
-      break;
-    default:
-      msg(M_FATAL, "%s: invalid TLS version %d", __func__, tls_ver);
-      break;
-  }
-}
-
-void key_state_ssl_init(struct key_state_ssl *ks_ssl,
-    const struct tls_root_ctx *ssl_ctx, bool is_server, struct tls_session 
*session)
-{
-  ASSERT(NULL != ssl_ctx);
-  ASSERT(ks_ssl);
-  CLEAR(*ks_ssl);
-
-  /* Initialise SSL config */
-  mbedtls_ssl_config_init(&ks_ssl->ssl_config);
-  mbedtls_ssl_config_defaults(&ks_ssl->ssl_config, ssl_ctx->endpoint,
-      MBEDTLS_SSL_TRANSPORT_STREAM, MBEDTLS_SSL_PRESET_DEFAULT);
-  mbedtls_debug_set_threshold(3);
-  mbedtls_ssl_conf_dbg (&ks_ssl->ssl_config, my_debug, NULL);
-  mbedtls_ssl_conf_rng (&ks_ssl->ssl_config, mbedtls_ctr_drbg_random,
-      rand_ctx_get());
-
-  if (ssl_ctx->allowed_ciphers)
-    mbedtls_ssl_conf_ciphersuites (&ks_ssl->ssl_config, 
ssl_ctx->allowed_ciphers);
-
-  /* Disable record splitting (for now).  OpenVPN assumes records are sent
-   * unfragmented, and changing that will require thorough review and
-   * testing.  Since OpenVPN is not susceptible to BEAST, we can just
-   * disable record splitting as a quick fix. */
-#if defined(MBEDTLS_SSL_CBC_RECORD_SPLITTING)
-  mbedtls_ssl_conf_cbc_record_splitting (&ks_ssl->ssl_config,
-      MBEDTLS_SSL_CBC_RECORD_SPLITTING_DISABLED);
-#endif /* MBEDTLS_SSL_CBC_RECORD_SPLITTING */
-
-  /* Initialise authentication information */
-  if (is_server)
-    mbed_ok (mbedtls_ssl_conf_dh_param_ctx(&ks_ssl->ssl_config,
-       ssl_ctx->dhm_ctx));
-
-  mbed_ok (mbedtls_ssl_conf_own_cert(&ks_ssl->ssl_config, ssl_ctx->crt_chain,
-      ssl_ctx->priv_key));
-
-  /* Initialise SSL verification */
-#if P2MP_SERVER
-  if (session->opt->ssl_flags & SSLF_CLIENT_CERT_OPTIONAL)
-    {
-      mbedtls_ssl_conf_authmode(&ks_ssl->ssl_config, 
MBEDTLS_SSL_VERIFY_OPTIONAL);
-    }
-  else if (!(session->opt->ssl_flags & SSLF_CLIENT_CERT_NOT_REQUIRED))
-#endif
-  {
-    mbedtls_ssl_conf_authmode (&ks_ssl->ssl_config, 
MBEDTLS_SSL_VERIFY_REQUIRED);
-  }
-  mbedtls_ssl_conf_verify (&ks_ssl->ssl_config, verify_callback, session);
-
-  /* TODO: mbed TLS does not currently support sending the CA chain to the 
client */
-  mbedtls_ssl_conf_ca_chain (&ks_ssl->ssl_config, ssl_ctx->ca_chain, NULL );
-
-  /* Initialize minimum TLS version */
-  {
-    const int tls_version_min =
-       (session->opt->ssl_flags >> SSLF_TLS_VERSION_MIN_SHIFT) &
-       SSLF_TLS_VERSION_MIN_MASK;
-
-    /* default to TLS 1.0 */
-    int major = MBEDTLS_SSL_MAJOR_VERSION_3;
-    int minor = MBEDTLS_SSL_MINOR_VERSION_1;
-
-    if (tls_version_min > TLS_VER_UNSPEC)
-      tls_version_to_major_minor(tls_version_min, &major, &minor);
-
-    mbedtls_ssl_conf_min_version(&ks_ssl->ssl_config, major, minor);
-  }
-
-  /* Initialize maximum TLS version */
-  {
-    const int tls_version_max =
-       (session->opt->ssl_flags >> SSLF_TLS_VERSION_MAX_SHIFT) &
-       SSLF_TLS_VERSION_MAX_MASK;
-
-    if (tls_version_max > TLS_VER_UNSPEC)
-      {
-       int major, minor;
-       tls_version_to_major_minor(tls_version_max, &major, &minor);
-       mbedtls_ssl_conf_max_version(&ks_ssl->ssl_config, major, minor);
-      }
-  }
-
-  /* Initialise SSL context */
-  ALLOC_OBJ_CLEAR(ks_ssl->ctx, mbedtls_ssl_context);
-  mbedtls_ssl_init(ks_ssl->ctx);
-  mbedtls_ssl_setup(ks_ssl->ctx, &ks_ssl->ssl_config);
-
-  /* Initialise BIOs */
-  CLEAR (ks_ssl->bio_ctx);
-  mbedtls_ssl_set_bio (ks_ssl->ctx, &ks_ssl->bio_ctx, ssl_bio_write,
-      ssl_bio_read, NULL);
-}
-
-void
-key_state_ssl_free(struct key_state_ssl *ks_ssl)
-{
-  if (ks_ssl) {
-      if (ks_ssl->ctx)
-       {
-         mbedtls_ssl_free(ks_ssl->ctx);
-         free(ks_ssl->ctx);
-       }
-      mbedtls_ssl_config_free(&ks_ssl->ssl_config);
-      buf_free_entries(&ks_ssl->bio_ctx.in);
-      buf_free_entries(&ks_ssl->bio_ctx.out);
-      CLEAR(*ks_ssl);
-  }
-}
-
-int
-key_state_write_plaintext (struct key_state_ssl *ks, struct buffer *buf)
-{
-  int retval = 0;
-
-  ASSERT (buf);
-
-  retval = key_state_write_plaintext_const(ks, BPTR(buf), BLEN(buf));
-
-  if (1 == retval)
-    {
-      memset (BPTR (buf), 0, BLEN (buf)); /* erase data just written */
-      buf->len = 0;
-    }
-
-  return retval;
-}
-
-int
-key_state_write_plaintext_const (struct key_state_ssl *ks, const uint8_t 
*data, int len)
-{
-  int retval = 0;
-  perf_push (PERF_BIO_WRITE_PLAINTEXT);
-
-  ASSERT (NULL != ks);
-  ASSERT (len >= 0);
-
-  if (0 == len)
-    {
-      perf_pop ();
-      return 0;
-    }
-
-  ASSERT (data);
-
-  retval = mbedtls_ssl_write(ks->ctx, data, len);
-
-  if (retval < 0)
-    {
-      perf_pop ();
-      if (MBEDTLS_ERR_SSL_WANT_WRITE == retval || MBEDTLS_ERR_SSL_WANT_READ == 
retval)
-       return 0;
-      mbed_log_err (D_TLS_ERRORS, retval,
-         "TLS ERROR: write tls_write_plaintext_const error");
-      return -1;
-    }
-
-  if (retval != len)
-    {
-      msg (D_TLS_ERRORS,
-         "TLS ERROR: write tls_write_plaintext_const incomplete %d/%d",
-         retval, len);
-      perf_pop ();
-      return -1;
-    }
-
-  /* successful write */
-  dmsg (D_HANDSHAKE_VERBOSE, "write tls_write_plaintext_const %d bytes", 
retval);
-
-  perf_pop ();
-  return 1;
-}
-
-int
-key_state_read_ciphertext (struct key_state_ssl *ks, struct buffer *buf,
-    int maxlen)
-{
-  int retval = 0;
-  int len = 0;
-
-  perf_push (PERF_BIO_READ_CIPHERTEXT);
-
-  ASSERT (NULL != ks);
-  ASSERT (buf);
-  ASSERT (buf->len >= 0);
-
-  if (buf->len)
-    {
-      perf_pop ();
-      return 0;
-    }
-
-  len = buf_forward_capacity (buf);
-  if (maxlen < len)
-    len = maxlen;
-
-  retval = endless_buf_read(&ks->bio_ctx.out, BPTR(buf), len);
-
-  /* Error during read, check for retry error */
-  if (retval < 0)
-    {
-      perf_pop ();
-      if (MBEDTLS_ERR_SSL_WANT_WRITE == retval || MBEDTLS_ERR_SSL_WANT_READ == 
retval)
-       return 0;
-      mbed_log_err (D_TLS_ERRORS, retval, "TLS_ERROR: read tls_read_ciphertext 
error");
-      buf->len = 0;
-      return -1;
-    }
-  /* Nothing read, try again */
-  if (0 == retval)
-    {
-      buf->len = 0;
-      perf_pop ();
-      return 0;
-    }
-
-  /* successful read */
-  dmsg (D_HANDSHAKE_VERBOSE, "read tls_read_ciphertext %d bytes", retval);
-  buf->len = retval;
-  perf_pop ();
-  return 1;
-}
-
-int
-key_state_write_ciphertext (struct key_state_ssl *ks, struct buffer *buf)
-{
-  int retval = 0;
-  perf_push (PERF_BIO_WRITE_CIPHERTEXT);
-
-  ASSERT (NULL != ks);
-  ASSERT (buf);
-  ASSERT (buf->len >= 0);
-
-  if (0 == buf->len)
-    {
-      perf_pop ();
-      return 0;
-    }
-
-  retval = endless_buf_write(&ks->bio_ctx.in, BPTR(buf), buf->len);
-
-  if (retval < 0)
-    {
-      perf_pop ();
-
-      if (MBEDTLS_ERR_SSL_WANT_WRITE == retval || MBEDTLS_ERR_SSL_WANT_READ == 
retval)
-       return 0;
-      mbed_log_err (D_TLS_ERRORS, retval,
-         "TLS ERROR: write tls_write_ciphertext error");
-      return -1;
-    }
-
-  if (retval != buf->len)
-    {
-      msg (D_TLS_ERRORS, "TLS ERROR: write tls_write_ciphertext incomplete 
%d/%d",
-         retval, buf->len);
-      perf_pop ();
-      return -1;
-    }
-
-  /* successful write */
-  dmsg (D_HANDSHAKE_VERBOSE, "write tls_write_ciphertext %d bytes", retval);
-
-  memset (BPTR (buf), 0, BLEN (buf)); /* erase data just written */
-  buf->len = 0;
-
-  perf_pop ();
-  return 1;
-}
-
-int
-key_state_read_plaintext (struct key_state_ssl *ks, struct buffer *buf,
-    int maxlen)
-{
-  int retval = 0;
-  int len = 0;
-
-  perf_push (PERF_BIO_READ_PLAINTEXT);
-
-  ASSERT (NULL != ks);
-  ASSERT (buf);
-  ASSERT (buf->len >= 0);
-
-  if (buf->len)
-    {
-      perf_pop ();
-      return 0;
-    }
-
-  len = buf_forward_capacity (buf);
-  if (maxlen < len)
-    len = maxlen;
-
-  retval = mbedtls_ssl_read(ks->ctx, BPTR(buf), len);
-
-  /* Error during read, check for retry error */
-  if (retval < 0)
-    {
-      if (MBEDTLS_ERR_SSL_WANT_WRITE == retval || MBEDTLS_ERR_SSL_WANT_READ == 
retval)
-       return 0;
-      mbed_log_err (D_TLS_ERRORS, retval, "TLS_ERROR: read tls_read_plaintext 
error");
-      buf->len = 0;
-      perf_pop ();
-      return -1;
-    }
-  /* Nothing read, try again */
-  if (0 == retval)
-    {
-      buf->len = 0;
-      perf_pop ();
-      return 0;
-    }
-
-  /* successful read */
-  dmsg (D_HANDSHAKE_VERBOSE, "read tls_read_plaintext %d bytes", retval);
-  buf->len = retval;
-
-  perf_pop ();
-  return 1;
-}
-
-/* **************************************
- *
- * Information functions
- *
- * Print information for the end user.
- *
- ***************************************/
-void
-print_details (struct key_state_ssl * ks_ssl, const char *prefix)
-{
-  const mbedtls_x509_crt *cert;
-  char s1[256];
-  char s2[256];
-
-  s1[0] = s2[0] = 0;
-  openvpn_snprintf (s1, sizeof (s1), "%s %s, cipher %s",
-                   prefix,
-                   mbedtls_ssl_get_version (ks_ssl->ctx),
-                   mbedtls_ssl_get_ciphersuite (ks_ssl->ctx));
-
-  cert = mbedtls_ssl_get_peer_cert (ks_ssl->ctx);
-  if (cert != NULL)
-    {
-      openvpn_snprintf (s2, sizeof (s2), ", %zu bit key",
-         mbedtls_pk_get_bitlen (&cert->pk));
-    }
-
-  msg (D_HANDSHAKE, "%s%s", s1, s2);
-}
-
-void
-show_available_tls_ciphers (const char *cipher_list)
-{
-  struct tls_root_ctx tls_ctx;
-  const int *ciphers = mbedtls_ssl_list_ciphersuites ();
-
-  tls_ctx_server_new(&tls_ctx);
-  tls_ctx_restrict_ciphers(&tls_ctx, cipher_list);
-
-  if (tls_ctx.allowed_ciphers)
-    ciphers = tls_ctx.allowed_ciphers;
-
-#ifndef ENABLE_SMALL
-  printf ("Available TLS Ciphers,\n");
-  printf ("listed in order of preference:\n\n");
-#endif
-
-  while (*ciphers != 0)
-    {
-      printf ("%s\n", mbedtls_ssl_get_ciphersuite_name (*ciphers));
-      ciphers++;
-    }
-  printf ("\n" SHOW_TLS_CIPHER_LIST_WARNING);
-
-  tls_ctx_free(&tls_ctx);
-}
-
-void
-show_available_curves (void)
-{
-  const mbedtls_ecp_curve_info *pcurve = mbedtls_ecp_curve_list ();
-
-  if (NULL == pcurve)
-    msg (M_FATAL, "Cannot retrieve curve list from mbed TLS");
-
-  /* Print curve list */
-  printf ("Available Elliptic curves, listed in order of preference:\n\n");
-  while (MBEDTLS_ECP_DP_NONE != pcurve->grp_id)
-    {
-      printf("%s\n", pcurve->name);
-      pcurve++;
-    }
-}
-
-void
-get_highest_preference_tls_cipher (char *buf, int size)
-{
-  const char *cipher_name;
-  const int *ciphers = mbedtls_ssl_list_ciphersuites();
-  if (*ciphers == 0)
-    msg (M_FATAL, "Cannot retrieve list of supported SSL ciphers.");
-
-  cipher_name = mbedtls_ssl_get_ciphersuite_name(*ciphers);
-  strncpynt (buf, cipher_name, size);
-}
-
-const char *
-get_ssl_library_version(void)
-{
-    static char mbedtls_version[30];
-    unsigned int pv = mbedtls_version_get_number();
-    sprintf( mbedtls_version, "mbed TLS %d.%d.%d",
-               (pv>>24)&0xff, (pv>>16)&0xff, (pv>>8)&0xff );
-    return mbedtls_version;
-}
-
-#endif /* defined(ENABLE_CRYPTO) && defined(ENABLE_CRYPTO_MBEDTLS) */
diff --git a/src/openvpn/ssl_polarssl.h b/src/openvpn/ssl_polarssl.h
deleted file mode 100644
index 6f778ef..0000000
--- a/src/openvpn/ssl_polarssl.h
+++ /dev/null
@@ -1,92 +0,0 @@
-/*
- *  OpenVPN -- An application to securely tunnel IP networks
- *             over a single TCP/UDP port, with support for SSL/TLS-based
- *             session authentication and key exchange,
- *             packet encryption, packet authentication, and
- *             packet compression.
- *
- *  Copyright (C) 2002-2010 OpenVPN Technologies, Inc. <sa...@openvpn.net>
- *  Copyright (C) 2010 Fox Crypto B.V. <open...@fox-it.com>
- *
- *  This program is free software; you can redistribute it and/or modify
- *  it under the terms of the GNU General Public License version 2
- *  as published by the Free Software Foundation.
- *
- *  This program is distributed in the hope that it will be useful,
- *  but WITHOUT ANY WARRANTY; without even the implied warranty of
- *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- *  GNU General Public License for more details.
- *
- *  You should have received a copy of the GNU General Public License
- *  along with this program (see the file COPYING included with this
- *  distribution); if not, write to the Free Software Foundation, Inc.,
- *  59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
- */
-
-/**
- * @file Control Channel mbed TLS Backend
- */
-
-#ifndef SSL_MBEDTLS_H_
-#define SSL_MBEDTLS_H_
-
-#include "syshead.h"
-
-#include <mbedtls/ssl.h>
-#include <mbedtls/x509_crt.h>
-
-#if defined(ENABLE_PKCS11)
-#include <mbedtls/pkcs11.h>
-#endif
-
-typedef struct _buffer_entry buffer_entry;
-
-struct _buffer_entry {
-    size_t length;
-    uint8_t *data;
-    buffer_entry *next_block;
-};
-
-typedef struct {
-    size_t data_start;
-    buffer_entry *first_block;
-    buffer_entry *last_block;
-} endless_buffer;
-
-typedef struct {
-    endless_buffer in;
-    endless_buffer out;
-} bio_ctx;
-
-/**
- * Structure that wraps the TLS context. Contents differ depending on the
- * SSL library used.
- *
- * Either \c priv_key_pkcs11 or \c priv_key must be filled in.
- */
-struct tls_root_ctx {
-    bool initialised;          /**< True if the context has been initialised */
-
-    int endpoint;              /**< Whether or not this is a server or a 
client */
-
-    mbedtls_dhm_context *dhm_ctx;      /**< Diffie-Helmann-Merkle context */
-    mbedtls_x509_crt *crt_chain;       /**< Local Certificate chain */
-    mbedtls_x509_crt *ca_chain;                /**< CA chain for remote 
verification */
-    mbedtls_pk_context *priv_key;      /**< Local private key */
-#if defined(ENABLE_PKCS11)
-    mbedtls_pkcs11_context *priv_key_pkcs11;   /**< PKCS11 private key */
-#endif
-#ifdef MANAGMENT_EXTERNAL_KEY
-    struct external_context *external_key; /**< Management external key */
-#endif
-    int * allowed_ciphers;     /**< List of allowed ciphers for this 
connection */
-};
-
-struct key_state_ssl {
-    mbedtls_ssl_config ssl_config;     /**< mbedTLS global ssl config */
-    mbedtls_ssl_context *ctx;          /**< mbedTLS connection context */
-    bio_ctx bio_ctx;
-};
-
-
-#endif /* SSL_MBEDTLS_H_ */
diff --git a/src/openvpn/ssl_verify.h b/src/openvpn/ssl_verify.h
index 5eb1843..f693b2a 100644
--- a/src/openvpn/ssl_verify.h
+++ b/src/openvpn/ssl_verify.h
@@ -41,7 +41,7 @@
 #include "ssl_verify_openssl.h"
 #endif
 #ifdef ENABLE_CRYPTO_MBEDTLS
-#include "ssl_verify_polarssl.h"
+#include "ssl_verify_mbedtls.h"
 #endif

 #include "ssl_verify_backend.h"
diff --git a/src/openvpn/ssl_verify_mbedtls.c b/src/openvpn/ssl_verify_mbedtls.c
new file mode 100644
index 0000000..ffe196e
--- /dev/null
+++ b/src/openvpn/ssl_verify_mbedtls.c
@@ -0,0 +1,508 @@
+/*
+ *  OpenVPN -- An application to securely tunnel IP networks
+ *             over a single TCP/UDP port, with support for SSL/TLS-based
+ *             session authentication and key exchange,
+ *             packet encryption, packet authentication, and
+ *             packet compression.
+ *
+ *  Copyright (C) 2002-2010 OpenVPN Technologies, Inc. <sa...@openvpn.net>
+ *  Copyright (C) 2010 Fox Crypto B.V. <open...@fox-it.com>
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License version 2
+ *  as published by the Free Software Foundation.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program (see the file COPYING included with this
+ *  distribution); if not, write to the Free Software Foundation, Inc.,
+ *  59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+/**
+ * @file Control Channel Verification Module mbed TLS backend
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#elif defined(_MSC_VER)
+#include "config-msvc.h"
+#endif
+
+#include "syshead.h"
+
+#if defined(ENABLE_CRYPTO) && defined(ENABLE_CRYPTO_MBEDTLS)
+
+#include "crypto_mbedtls.h"
+#include "ssl_verify.h"
+#include <mbedtls/asn1.h>
+#include <mbedtls/error.h>
+#include <mbedtls/bignum.h>
+#include <mbedtls/oid.h>
+#include <mbedtls/sha1.h>
+
+#define MAX_SUBJECT_LENGTH 256
+
+int
+verify_callback (void *session_obj, mbedtls_x509_crt *cert, int cert_depth,
+    uint32_t *flags)
+{
+  struct tls_session *session = (struct tls_session *) session_obj;
+  struct gc_arena gc = gc_new();
+
+  ASSERT (cert);
+  ASSERT (session);
+
+  session->verified = false;
+
+  /* Remember certificate hash */
+  cert_hash_remember (session, cert_depth, x509_get_sha1_hash(cert, &gc));
+
+  /* did peer present cert which was signed by our root cert? */
+  if (*flags != 0)
+    {
+      char *subject = x509_get_subject(cert, &gc);
+
+      if (subject)
+       msg (D_TLS_ERRORS, "VERIFY ERROR: depth=%d, flags=%x, %s", cert_depth, 
*flags, subject);
+      else
+       msg (D_TLS_ERRORS, "VERIFY ERROR: depth=%d, flags=%x, could not extract 
X509 "
+             "subject string from certificate", *flags, cert_depth);
+
+      /* Leave flags set to non-zero to indicate that the cert is not ok */
+    }
+  else if (SUCCESS != verify_cert(session, cert, cert_depth))
+    {
+      *flags |= MBEDTLS_X509_BADCERT_OTHER;
+    }
+
+  gc_free(&gc);
+
+  /*
+   * PolarSSL/mbed TLS-1.2.0+ expects 0 on anything except fatal errors.
+   */
+  return 0;
+}
+
+#ifdef ENABLE_X509ALTUSERNAME
+# warning "X509 alt user name not yet supported for mbed TLS"
+#endif
+
+result_t
+backend_x509_get_username (char *cn, int cn_len,
+    char *x509_username_field, mbedtls_x509_crt *cert)
+{
+  mbedtls_x509_name *name;
+
+  ASSERT( cn != NULL );
+
+  name = &cert->subject;
+
+  /* Find common name */
+  while( name != NULL )
+  {
+      if (0 == memcmp (name->oid.p, MBEDTLS_OID_AT_CN,
+         MBEDTLS_OID_SIZE (MBEDTLS_OID_AT_CN)))
+       break;
+
+      name = name->next;
+  }
+
+  /* Not found, return an error if this is the peer's certificate */
+  if( name == NULL )
+      return FAILURE;
+
+  /* Found, extract CN */
+  if (cn_len > name->val.len)
+    {
+      memcpy( cn, name->val.p, name->val.len );
+      cn[name->val.len] = '\0';
+    }
+  else
+    {
+      memcpy( cn, name->val.p, cn_len);
+      cn[cn_len-1] = '\0';
+    }
+
+  return SUCCESS;
+}
+
+char *
+backend_x509_get_serial (mbedtls_x509_crt *cert, struct gc_arena *gc)
+{
+  char *buf = NULL;
+  size_t buflen = 0;
+  mbedtls_mpi serial_mpi = { 0 };
+
+  /* Transform asn1 integer serial into mbed TLS MPI */
+  mbedtls_mpi_init(&serial_mpi);
+  if (!mbed_ok(mbedtls_mpi_read_binary(&serial_mpi, cert->serial.p,
+      cert->serial.len)))
+    {
+      msg(M_WARN, "Failed to retrieve serial from certificate.");
+      return NULL;
+    }
+
+  /* Determine decimal representation length, allocate buffer */
+  mbedtls_mpi_write_string(&serial_mpi, 10, NULL, 0, &buflen);
+  buf = gc_malloc(buflen, true, gc);
+
+  /* Write MPI serial as decimal string into buffer */
+  if (!mbed_ok(mbedtls_mpi_write_string(&serial_mpi, 10, buf, buflen, 
&buflen)))
+    {
+      msg(M_WARN, "Failed to write serial to string.");
+      return NULL;
+    }
+
+  return buf;
+}
+
+char *
+backend_x509_get_serial_hex (mbedtls_x509_crt *cert, struct gc_arena *gc)
+{
+  char *buf = NULL;
+  size_t len = cert->serial.len * 3 + 1;
+
+  buf = gc_malloc(len, true, gc);
+
+  if(mbedtls_x509_serial_gets(buf, len-1, &cert->serial) < 0)
+    buf = NULL;
+
+  return buf;
+}
+
+unsigned char *
+x509_get_sha1_hash (mbedtls_x509_crt *cert, struct gc_arena *gc)
+{
+  unsigned char *sha1_hash = gc_malloc(SHA_DIGEST_LENGTH, false, gc);
+  mbedtls_sha1(cert->raw.p, cert->tbs.len, sha1_hash);
+  return sha1_hash;
+}
+
+char *
+x509_get_subject(mbedtls_x509_crt *cert, struct gc_arena *gc)
+{
+  char tmp_subject[MAX_SUBJECT_LENGTH] = {0};
+  char *subject = NULL;
+
+  int ret = 0;
+
+  ret = mbedtls_x509_dn_gets( tmp_subject, MAX_SUBJECT_LENGTH-1, 
&cert->subject );
+  if (ret > 0)
+    {
+      /* Allocate the required space for the subject */
+      subject = string_alloc(tmp_subject, gc);
+    }
+
+  return subject;
+}
+
+static void
+do_setenv_x509 (struct env_set *es, const char *name, char *value, int depth)
+{
+  char *name_expand;
+  size_t name_expand_size;
+
+  string_mod (value, CC_ANY, CC_CRLF, '?');
+  msg (D_X509_ATTR, "X509 ATTRIBUTE name='%s' value='%s' depth=%d", name, 
value, depth);
+  name_expand_size = 64 + strlen (name);
+  name_expand = (char *) malloc (name_expand_size);
+  check_malloc_return (name_expand);
+  openvpn_snprintf (name_expand, name_expand_size, "X509_%d_%s", depth, name);
+  setenv_str (es, name_expand, value);
+  free (name_expand);
+}
+
+static char *
+asn1_buf_to_c_string(const mbedtls_asn1_buf *orig, struct gc_arena *gc)
+{
+  size_t i;
+  char *val;
+
+  for (i = 0; i < orig->len; ++i)
+    if (orig->p[i] == '\0')
+      return "ERROR: embedded null value";
+  val = gc_malloc(orig->len+1, false, gc);
+  memcpy(val, orig->p, orig->len);
+  val[orig->len] = '\0';
+  return val;
+}
+
+static void
+do_setenv_name(struct env_set *es, const struct x509_track *xt,
+              const mbedtls_x509_crt *cert, int depth, struct gc_arena *gc)
+{
+  const mbedtls_x509_name *xn;
+  for (xn = &cert->subject; xn != NULL; xn = xn->next)
+    {
+      const char *xn_short_name = NULL;
+      if (0 == mbedtls_oid_get_attr_short_name (&xn->oid, &xn_short_name) &&
+         0 == strcmp (xt->name, xn_short_name))
+       {
+         char *val_str = asn1_buf_to_c_string (&xn->val, gc);
+         do_setenv_x509 (es, xt->name, val_str, depth);
+       }
+    }
+}
+
+void
+x509_track_add (const struct x509_track **ll_head, const char *name, int 
msglevel, struct gc_arena *gc)
+{
+  struct x509_track *xt;
+  ALLOC_OBJ_CLEAR_GC (xt, struct x509_track, gc);
+  if (*name == '+')
+    {
+      xt->flags |= XT_FULL_CHAIN;
+      ++name;
+    }
+  xt->name = name;
+  xt->next = *ll_head;
+  *ll_head = xt;
+}
+
+void
+x509_setenv_track (const struct x509_track *xt, struct env_set *es,
+    const int depth, mbedtls_x509_crt *cert)
+{
+  struct gc_arena gc = gc_new();
+  while (xt)
+    {
+      if (depth == 0 || (xt->flags & XT_FULL_CHAIN))
+       {
+         if (0 == strcmp(xt->name, "SHA1"))
+           {
+             /* SHA1 fingerprint is not part of X509 structure */
+             unsigned char *sha1_hash = x509_get_sha1_hash(cert, &gc);
+             char *sha1_fingerprint = format_hex_ex(sha1_hash, 
SHA_DIGEST_LENGTH, 0, 1 | FHE_CAPS, ":", &gc);
+             do_setenv_x509(es, xt->name, sha1_fingerprint, depth);
+           }
+         else
+           {
+             do_setenv_name(es, xt, cert, depth, &gc);
+           }
+       }
+      xt = xt->next;
+    }
+  gc_free(&gc);
+}
+
+/*
+ * Save X509 fields to environment, using the naming convention:
+ *
+ * X509_{cert_depth}_{name}={value}
+ */
+void
+x509_setenv (struct env_set *es, int cert_depth, mbedtls_x509_crt *cert)
+{
+  int i;
+  unsigned char c;
+  const mbedtls_x509_name *name;
+  char s[128];
+
+  name = &cert->subject;
+
+  memset( s, 0, sizeof( s ) );
+
+  while( name != NULL )
+    {
+      char name_expand[64+8];
+      const char *shortname;
+
+      if( 0 == mbedtls_oid_get_attr_short_name(&name->oid, &shortname) )
+       {
+         openvpn_snprintf (name_expand, sizeof(name_expand), "X509_%d_%s",
+             cert_depth, shortname);
+       }
+      else
+       {
+         openvpn_snprintf (name_expand, sizeof(name_expand), "X509_%d_\?\?",
+             cert_depth);
+       }
+
+      for( i = 0; i < name->val.len; i++ )
+       {
+         if( i >= (int) sizeof( s ) - 1 )
+             break;
+
+         c = name->val.p[i];
+         if( c < 32 || c == 127 || ( c > 128 && c < 160 ) )
+              s[i] = '?';
+         else s[i] = c;
+       }
+       s[i] = '\0';
+
+       /* Check both strings, set environment variable */
+       string_mod (name_expand, CC_PRINT, CC_CRLF, '_');
+       string_mod ((char*)s, CC_PRINT, CC_CRLF, '_');
+       setenv_str_incr (es, name_expand, (char*)s);
+
+       name = name->next;
+    }
+}
+
+result_t
+x509_verify_ns_cert_type(const mbedtls_x509_crt *cert, const int usage)
+{
+  if (usage == NS_CERT_CHECK_NONE)
+    return SUCCESS;
+  if (usage == NS_CERT_CHECK_CLIENT)
+    return ((cert->ext_types & MBEDTLS_X509_EXT_NS_CERT_TYPE)
+       && (cert->ns_cert_type & MBEDTLS_X509_NS_CERT_TYPE_SSL_CLIENT)) ?
+           SUCCESS : FAILURE;
+  if (usage == NS_CERT_CHECK_SERVER)
+    return ((cert->ext_types & MBEDTLS_X509_EXT_NS_CERT_TYPE)
+       && (cert->ns_cert_type & MBEDTLS_X509_NS_CERT_TYPE_SSL_SERVER)) ?
+           SUCCESS : FAILURE;
+
+  return FAILURE;
+}
+
+result_t
+x509_verify_cert_ku (mbedtls_x509_crt *cert, const unsigned * const 
expected_ku,
+    int expected_len)
+{
+  result_t fFound = FAILURE;
+
+  if(!(cert->ext_types & MBEDTLS_X509_EXT_KEY_USAGE))
+    {
+      msg (D_HANDSHAKE, "Certificate does not have key usage extension");
+    }
+  else
+    {
+      int i;
+      unsigned nku = cert->key_usage;
+
+      msg (D_HANDSHAKE, "Validating certificate key usage");
+      for (i=0; SUCCESS != fFound && i<expected_len; i++)
+       {
+         if (expected_ku[i] != 0)
+           {
+             msg (D_HANDSHAKE, "++ Certificate has key usage  %04x, expects "
+                 "%04x", nku, expected_ku[i]);
+
+             if (nku == expected_ku[i])
+               {
+                 fFound = SUCCESS;
+               }
+           }
+       }
+    }
+  return fFound;
+}
+
+result_t
+x509_verify_cert_eku (mbedtls_x509_crt *cert, const char * const expected_oid)
+{
+  result_t fFound = FAILURE;
+
+  if (!(cert->ext_types & MBEDTLS_X509_EXT_EXTENDED_KEY_USAGE))
+    {
+      msg (D_HANDSHAKE, "Certificate does not have extended key usage 
extension");
+    }
+  else
+    {
+      mbedtls_x509_sequence *oid_seq = &(cert->ext_key_usage);
+
+      msg (D_HANDSHAKE, "Validating certificate extended key usage");
+      while (oid_seq != NULL)
+       {
+         mbedtls_x509_buf *oid = &oid_seq->buf;
+         char oid_num_str[1024];
+         const char *oid_str;
+
+         if (0 == mbedtls_oid_get_extended_key_usage( oid, &oid_str ))
+           {
+             msg (D_HANDSHAKE, "++ Certificate has EKU (str) %s, expects %s",
+                 oid_str, expected_oid);
+             if (!strcmp (expected_oid, oid_str))
+               {
+                 fFound = SUCCESS;
+                 break;
+               }
+           }
+
+         if (0 < mbedtls_oid_get_numeric_string( oid_num_str,
+             sizeof (oid_num_str), oid))
+           {
+             msg (D_HANDSHAKE, "++ Certificate has EKU (oid) %s, expects %s",
+                 oid_num_str, expected_oid);
+             if (!strcmp (expected_oid, oid_num_str))
+               {
+                 fFound = SUCCESS;
+                 break;
+               }
+           }
+         oid_seq = oid_seq->next;
+       }
+    }
+
+    return fFound;
+}
+
+result_t
+x509_write_pem(FILE *peercert_file, mbedtls_x509_crt *peercert)
+{
+    msg (M_WARN, "mbed TLS does not support writing peer certificate in PEM 
format");
+    return FAILURE;
+}
+
+/*
+ * check peer cert against CRL
+ */
+result_t
+x509_verify_crl(const char *crl_file, const char *crl_inline,
+                mbedtls_x509_crt *cert, const char *subject)
+{
+  result_t retval = FAILURE;
+  mbedtls_x509_crl crl = {0};
+  struct gc_arena gc = gc_new();
+  char *serial;
+
+  if (!strcmp (crl_file, INLINE_FILE_TAG) && crl_inline)
+    {
+      if (!mbed_ok(mbedtls_x509_crl_parse(&crl,
+         (const unsigned char *)crl_inline, strlen(crl_inline)+1)))
+        {
+           msg (M_WARN, "CRL: cannot parse inline CRL");
+           goto end;
+        }
+    }
+  else
+    {
+      if (!mbed_ok(mbedtls_x509_crl_parse_file(&crl, crl_file)))
+      {
+          msg (M_WARN, "CRL: cannot read CRL from file %s", crl_file);
+          goto end;
+      }
+  }
+
+  if(cert->issuer_raw.len != crl.issuer_raw.len ||
+      memcmp(crl.issuer_raw.p, cert->issuer_raw.p, crl.issuer_raw.len) != 0)
+    {
+      msg (M_WARN, "CRL: CRL %s is from a different issuer than the issuer of "
+         "certificate %s", crl_file, subject);
+      retval = SUCCESS;
+      goto end;
+    }
+
+  if (!mbed_ok(mbedtls_x509_crt_is_revoked(cert, &crl)))
+    {
+      serial = backend_x509_get_serial_hex(cert, &gc);
+      msg (D_HANDSHAKE, "CRL CHECK FAILED: %s (serial %s) is REVOKED", 
subject, (serial ? serial : "NOT AVAILABLE"));
+      goto end;
+    }
+
+  retval = SUCCESS;
+  msg (D_HANDSHAKE, "CRL CHECK OK: %s",subject);
+
+end:
+  gc_free(&gc);
+  mbedtls_x509_crl_free(&crl);
+  return retval;
+}
+
+#endif /* #if defined(ENABLE_CRYPTO) && defined(ENABLE_CRYPTO_MBEDTLS) */
diff --git a/src/openvpn/ssl_verify_mbedtls.h b/src/openvpn/ssl_verify_mbedtls.h
new file mode 100644
index 0000000..e26d08f
--- /dev/null
+++ b/src/openvpn/ssl_verify_mbedtls.h
@@ -0,0 +1,78 @@
+/*
+ *  OpenVPN -- An application to securely tunnel IP networks
+ *             over a single TCP/UDP port, with support for SSL/TLS-based
+ *             session authentication and key exchange,
+ *             packet encryption, packet authentication, and
+ *             packet compression.
+ *
+ *  Copyright (C) 2002-2010 OpenVPN Technologies, Inc. <sa...@openvpn.net>
+ *  Copyright (C) 2010 Fox Crypto B.V. <open...@fox-it.com>
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License version 2
+ *  as published by the Free Software Foundation.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program (see the file COPYING included with this
+ *  distribution); if not, write to the Free Software Foundation, Inc.,
+ *  59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+/**
+ * @file Control Channel Verification Module mbed TLS backend
+ */
+
+#ifndef SSL_VERIFY_MBEDTLS_H_
+#define SSL_VERIFY_MBEDTLS_H_
+
+#include "syshead.h"
+#include <mbedtls/x509_crt.h>
+
+#ifndef __OPENVPN_X509_CERT_T_DECLARED
+#define __OPENVPN_X509_CERT_T_DECLARED
+typedef mbedtls_x509_crt openvpn_x509_cert_t;
+#endif
+
+/** @name Function for authenticating a new connection from a remote OpenVPN 
peer
+ *  @{ */
+
+/**
+ * Verify that the remote OpenVPN peer's certificate allows setting up a
+ * VPN tunnel.
+ * @ingroup control_tls
+ *
+ * This callback function is called when a new TLS session is being setup to
+ * determine whether the remote OpenVPN peer's certificate is allowed to
+ * connect. It is called for once for every certificate in the chain. The
+ * callback functionality is configured in the \c init_ssl() function, which
+ * calls the mbed TLS library's \c ssl_set_verify_callback() function with \c
+ * verify_callback() as its callback argument.
+ *
+ * It checks *flags and registers the certificate hash. If these steps succeed,
+ * it calls the \c verify_cert() function, which performs OpenVPN-specific
+ * verification.
+ *
+ * @param session_obj  - The OpenVPN \c tls_session associated with this 
object,
+ *                       as set during SSL session setup.
+ * @param cert         - The certificate used by mbed TLS.
+ * @param cert_depth   - The depth of the current certificate in the chain, 
with
+ *                       0 being the actual certificate.
+ * @param flags        - Whether the remote OpenVPN peer's certificate
+ *                       passed verification.  A value of 0 means it
+ *                       verified successfully, any other value means it
+ *                       failed. \c verify_callback() is considered to have
+ *                       ok'ed this certificate if flags is 0 when it returns.
+ *
+ * @return The return value is 0 unless a fatal error occurred.
+ */
+int verify_callback (void *session_obj, mbedtls_x509_crt *cert, int cert_depth,
+    uint32_t *flags);
+
+/** @} name Function for authenticating a new connection from a remote OpenVPN 
peer */
+
+#endif /* SSL_VERIFY_MBEDTLS_H_ */
diff --git a/src/openvpn/ssl_verify_polarssl.c 
b/src/openvpn/ssl_verify_polarssl.c
deleted file mode 100644
index ff76d3d..0000000
--- a/src/openvpn/ssl_verify_polarssl.c
+++ /dev/null
@@ -1,508 +0,0 @@
-/*
- *  OpenVPN -- An application to securely tunnel IP networks
- *             over a single TCP/UDP port, with support for SSL/TLS-based
- *             session authentication and key exchange,
- *             packet encryption, packet authentication, and
- *             packet compression.
- *
- *  Copyright (C) 2002-2010 OpenVPN Technologies, Inc. <sa...@openvpn.net>
- *  Copyright (C) 2010 Fox Crypto B.V. <open...@fox-it.com>
- *
- *  This program is free software; you can redistribute it and/or modify
- *  it under the terms of the GNU General Public License version 2
- *  as published by the Free Software Foundation.
- *
- *  This program is distributed in the hope that it will be useful,
- *  but WITHOUT ANY WARRANTY; without even the implied warranty of
- *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- *  GNU General Public License for more details.
- *
- *  You should have received a copy of the GNU General Public License
- *  along with this program (see the file COPYING included with this
- *  distribution); if not, write to the Free Software Foundation, Inc.,
- *  59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
- */
-
-/**
- * @file Control Channel Verification Module mbed TLS backend
- */
-
-#ifdef HAVE_CONFIG_H
-#include "config.h"
-#elif defined(_MSC_VER)
-#include "config-msvc.h"
-#endif
-
-#include "syshead.h"
-
-#if defined(ENABLE_CRYPTO) && defined(ENABLE_CRYPTO_MBEDTLS)
-
-#include "crypto_polarssl.h"
-#include "ssl_verify.h"
-#include <mbedtls/asn1.h>
-#include <mbedtls/error.h>
-#include <mbedtls/bignum.h>
-#include <mbedtls/oid.h>
-#include <mbedtls/sha1.h>
-
-#define MAX_SUBJECT_LENGTH 256
-
-int
-verify_callback (void *session_obj, mbedtls_x509_crt *cert, int cert_depth,
-    uint32_t *flags)
-{
-  struct tls_session *session = (struct tls_session *) session_obj;
-  struct gc_arena gc = gc_new();
-
-  ASSERT (cert);
-  ASSERT (session);
-
-  session->verified = false;
-
-  /* Remember certificate hash */
-  cert_hash_remember (session, cert_depth, x509_get_sha1_hash(cert, &gc));
-
-  /* did peer present cert which was signed by our root cert? */
-  if (*flags != 0)
-    {
-      char *subject = x509_get_subject(cert, &gc);
-
-      if (subject)
-       msg (D_TLS_ERRORS, "VERIFY ERROR: depth=%d, flags=%x, %s", cert_depth, 
*flags, subject);
-      else
-       msg (D_TLS_ERRORS, "VERIFY ERROR: depth=%d, flags=%x, could not extract 
X509 "
-             "subject string from certificate", *flags, cert_depth);
-
-      /* Leave flags set to non-zero to indicate that the cert is not ok */
-    }
-  else if (SUCCESS != verify_cert(session, cert, cert_depth))
-    {
-      *flags |= MBEDTLS_X509_BADCERT_OTHER;
-    }
-
-  gc_free(&gc);
-
-  /*
-   * PolarSSL/mbed TLS-1.2.0+ expects 0 on anything except fatal errors.
-   */
-  return 0;
-}
-
-#ifdef ENABLE_X509ALTUSERNAME
-# warning "X509 alt user name not yet supported for mbed TLS"
-#endif
-
-result_t
-backend_x509_get_username (char *cn, int cn_len,
-    char *x509_username_field, mbedtls_x509_crt *cert)
-{
-  mbedtls_x509_name *name;
-
-  ASSERT( cn != NULL );
-
-  name = &cert->subject;
-
-  /* Find common name */
-  while( name != NULL )
-  {
-      if (0 == memcmp (name->oid.p, MBEDTLS_OID_AT_CN,
-         MBEDTLS_OID_SIZE (MBEDTLS_OID_AT_CN)))
-       break;
-
-      name = name->next;
-  }
-
-  /* Not found, return an error if this is the peer's certificate */
-  if( name == NULL )
-      return FAILURE;
-
-  /* Found, extract CN */
-  if (cn_len > name->val.len)
-    {
-      memcpy( cn, name->val.p, name->val.len );
-      cn[name->val.len] = '\0';
-    }
-  else
-    {
-      memcpy( cn, name->val.p, cn_len);
-      cn[cn_len-1] = '\0';
-    }
-
-  return SUCCESS;
-}
-
-char *
-backend_x509_get_serial (mbedtls_x509_crt *cert, struct gc_arena *gc)
-{
-  char *buf = NULL;
-  size_t buflen = 0;
-  mbedtls_mpi serial_mpi = { 0 };
-
-  /* Transform asn1 integer serial into mbed TLS MPI */
-  mbedtls_mpi_init(&serial_mpi);
-  if (!mbed_ok(mbedtls_mpi_read_binary(&serial_mpi, cert->serial.p,
-      cert->serial.len)))
-    {
-      msg(M_WARN, "Failed to retrieve serial from certificate.");
-      return NULL;
-    }
-
-  /* Determine decimal representation length, allocate buffer */
-  mbedtls_mpi_write_string(&serial_mpi, 10, NULL, 0, &buflen);
-  buf = gc_malloc(buflen, true, gc);
-
-  /* Write MPI serial as decimal string into buffer */
-  if (!mbed_ok(mbedtls_mpi_write_string(&serial_mpi, 10, buf, buflen, 
&buflen)))
-    {
-      msg(M_WARN, "Failed to write serial to string.");
-      return NULL;
-    }
-
-  return buf;
-}
-
-char *
-backend_x509_get_serial_hex (mbedtls_x509_crt *cert, struct gc_arena *gc)
-{
-  char *buf = NULL;
-  size_t len = cert->serial.len * 3 + 1;
-
-  buf = gc_malloc(len, true, gc);
-
-  if(mbedtls_x509_serial_gets(buf, len-1, &cert->serial) < 0)
-    buf = NULL;
-
-  return buf;
-}
-
-unsigned char *
-x509_get_sha1_hash (mbedtls_x509_crt *cert, struct gc_arena *gc)
-{
-  unsigned char *sha1_hash = gc_malloc(SHA_DIGEST_LENGTH, false, gc);
-  mbedtls_sha1(cert->raw.p, cert->tbs.len, sha1_hash);
-  return sha1_hash;
-}
-
-char *
-x509_get_subject(mbedtls_x509_crt *cert, struct gc_arena *gc)
-{
-  char tmp_subject[MAX_SUBJECT_LENGTH] = {0};
-  char *subject = NULL;
-
-  int ret = 0;
-
-  ret = mbedtls_x509_dn_gets( tmp_subject, MAX_SUBJECT_LENGTH-1, 
&cert->subject );
-  if (ret > 0)
-    {
-      /* Allocate the required space for the subject */
-      subject = string_alloc(tmp_subject, gc);
-    }
-
-  return subject;
-}
-
-static void
-do_setenv_x509 (struct env_set *es, const char *name, char *value, int depth)
-{
-  char *name_expand;
-  size_t name_expand_size;
-
-  string_mod (value, CC_ANY, CC_CRLF, '?');
-  msg (D_X509_ATTR, "X509 ATTRIBUTE name='%s' value='%s' depth=%d", name, 
value, depth);
-  name_expand_size = 64 + strlen (name);
-  name_expand = (char *) malloc (name_expand_size);
-  check_malloc_return (name_expand);
-  openvpn_snprintf (name_expand, name_expand_size, "X509_%d_%s", depth, name);
-  setenv_str (es, name_expand, value);
-  free (name_expand);
-}
-
-static char *
-asn1_buf_to_c_string(const mbedtls_asn1_buf *orig, struct gc_arena *gc)
-{
-  size_t i;
-  char *val;
-
-  for (i = 0; i < orig->len; ++i)
-    if (orig->p[i] == '\0')
-      return "ERROR: embedded null value";
-  val = gc_malloc(orig->len+1, false, gc);
-  memcpy(val, orig->p, orig->len);
-  val[orig->len] = '\0';
-  return val;
-}
-
-static void
-do_setenv_name(struct env_set *es, const struct x509_track *xt,
-              const mbedtls_x509_crt *cert, int depth, struct gc_arena *gc)
-{
-  const mbedtls_x509_name *xn;
-  for (xn = &cert->subject; xn != NULL; xn = xn->next)
-    {
-      const char *xn_short_name = NULL;
-      if (0 == mbedtls_oid_get_attr_short_name (&xn->oid, &xn_short_name) &&
-         0 == strcmp (xt->name, xn_short_name))
-       {
-         char *val_str = asn1_buf_to_c_string (&xn->val, gc);
-         do_setenv_x509 (es, xt->name, val_str, depth);
-       }
-    }
-}
-
-void
-x509_track_add (const struct x509_track **ll_head, const char *name, int 
msglevel, struct gc_arena *gc)
-{
-  struct x509_track *xt;
-  ALLOC_OBJ_CLEAR_GC (xt, struct x509_track, gc);
-  if (*name == '+')
-    {
-      xt->flags |= XT_FULL_CHAIN;
-      ++name;
-    }
-  xt->name = name;
-  xt->next = *ll_head;
-  *ll_head = xt;
-}
-
-void
-x509_setenv_track (const struct x509_track *xt, struct env_set *es,
-    const int depth, mbedtls_x509_crt *cert)
-{
-  struct gc_arena gc = gc_new();
-  while (xt)
-    {
-      if (depth == 0 || (xt->flags & XT_FULL_CHAIN))
-       {
-         if (0 == strcmp(xt->name, "SHA1"))
-           {
-             /* SHA1 fingerprint is not part of X509 structure */
-             unsigned char *sha1_hash = x509_get_sha1_hash(cert, &gc);
-             char *sha1_fingerprint = format_hex_ex(sha1_hash, 
SHA_DIGEST_LENGTH, 0, 1 | FHE_CAPS, ":", &gc);
-             do_setenv_x509(es, xt->name, sha1_fingerprint, depth);
-           }
-         else
-           {
-             do_setenv_name(es, xt, cert, depth, &gc);
-           }
-       }
-      xt = xt->next;
-    }
-  gc_free(&gc);
-}
-
-/*
- * Save X509 fields to environment, using the naming convention:
- *
- * X509_{cert_depth}_{name}={value}
- */
-void
-x509_setenv (struct env_set *es, int cert_depth, mbedtls_x509_crt *cert)
-{
-  int i;
-  unsigned char c;
-  const mbedtls_x509_name *name;
-  char s[128];
-
-  name = &cert->subject;
-
-  memset( s, 0, sizeof( s ) );
-
-  while( name != NULL )
-    {
-      char name_expand[64+8];
-      const char *shortname;
-
-      if( 0 == mbedtls_oid_get_attr_short_name(&name->oid, &shortname) )
-       {
-         openvpn_snprintf (name_expand, sizeof(name_expand), "X509_%d_%s",
-             cert_depth, shortname);
-       }
-      else
-       {
-         openvpn_snprintf (name_expand, sizeof(name_expand), "X509_%d_\?\?",
-             cert_depth);
-       }
-
-      for( i = 0; i < name->val.len; i++ )
-       {
-         if( i >= (int) sizeof( s ) - 1 )
-             break;
-
-         c = name->val.p[i];
-         if( c < 32 || c == 127 || ( c > 128 && c < 160 ) )
-              s[i] = '?';
-         else s[i] = c;
-       }
-       s[i] = '\0';
-
-       /* Check both strings, set environment variable */
-       string_mod (name_expand, CC_PRINT, CC_CRLF, '_');
-       string_mod ((char*)s, CC_PRINT, CC_CRLF, '_');
-       setenv_str_incr (es, name_expand, (char*)s);
-
-       name = name->next;
-    }
-}
-
-result_t
-x509_verify_ns_cert_type(const mbedtls_x509_crt *cert, const int usage)
-{
-  if (usage == NS_CERT_CHECK_NONE)
-    return SUCCESS;
-  if (usage == NS_CERT_CHECK_CLIENT)
-    return ((cert->ext_types & MBEDTLS_X509_EXT_NS_CERT_TYPE)
-       && (cert->ns_cert_type & MBEDTLS_X509_NS_CERT_TYPE_SSL_CLIENT)) ?
-           SUCCESS : FAILURE;
-  if (usage == NS_CERT_CHECK_SERVER)
-    return ((cert->ext_types & MBEDTLS_X509_EXT_NS_CERT_TYPE)
-       && (cert->ns_cert_type & MBEDTLS_X509_NS_CERT_TYPE_SSL_SERVER)) ?
-           SUCCESS : FAILURE;
-
-  return FAILURE;
-}
-
-result_t
-x509_verify_cert_ku (mbedtls_x509_crt *cert, const unsigned * const 
expected_ku,
-    int expected_len)
-{
-  result_t fFound = FAILURE;
-
-  if(!(cert->ext_types & MBEDTLS_X509_EXT_KEY_USAGE))
-    {
-      msg (D_HANDSHAKE, "Certificate does not have key usage extension");
-    }
-  else
-    {
-      int i;
-      unsigned nku = cert->key_usage;
-
-      msg (D_HANDSHAKE, "Validating certificate key usage");
-      for (i=0; SUCCESS != fFound && i<expected_len; i++)
-       {
-         if (expected_ku[i] != 0)
-           {
-             msg (D_HANDSHAKE, "++ Certificate has key usage  %04x, expects "
-                 "%04x", nku, expected_ku[i]);
-
-             if (nku == expected_ku[i])
-               {
-                 fFound = SUCCESS;
-               }
-           }
-       }
-    }
-  return fFound;
-}
-
-result_t
-x509_verify_cert_eku (mbedtls_x509_crt *cert, const char * const expected_oid)
-{
-  result_t fFound = FAILURE;
-
-  if (!(cert->ext_types & MBEDTLS_X509_EXT_EXTENDED_KEY_USAGE))
-    {
-      msg (D_HANDSHAKE, "Certificate does not have extended key usage 
extension");
-    }
-  else
-    {
-      mbedtls_x509_sequence *oid_seq = &(cert->ext_key_usage);
-
-      msg (D_HANDSHAKE, "Validating certificate extended key usage");
-      while (oid_seq != NULL)
-       {
-         mbedtls_x509_buf *oid = &oid_seq->buf;
-         char oid_num_str[1024];
-         const char *oid_str;
-
-         if (0 == mbedtls_oid_get_extended_key_usage( oid, &oid_str ))
-           {
-             msg (D_HANDSHAKE, "++ Certificate has EKU (str) %s, expects %s",
-                 oid_str, expected_oid);
-             if (!strcmp (expected_oid, oid_str))
-               {
-                 fFound = SUCCESS;
-                 break;
-               }
-           }
-
-         if (0 < mbedtls_oid_get_numeric_string( oid_num_str,
-             sizeof (oid_num_str), oid))
-           {
-             msg (D_HANDSHAKE, "++ Certificate has EKU (oid) %s, expects %s",
-                 oid_num_str, expected_oid);
-             if (!strcmp (expected_oid, oid_num_str))
-               {
-                 fFound = SUCCESS;
-                 break;
-               }
-           }
-         oid_seq = oid_seq->next;
-       }
-    }
-
-    return fFound;
-}
-
-result_t
-x509_write_pem(FILE *peercert_file, mbedtls_x509_crt *peercert)
-{
-    msg (M_WARN, "mbed TLS does not support writing peer certificate in PEM 
format");
-    return FAILURE;
-}
-
-/*
- * check peer cert against CRL
- */
-result_t
-x509_verify_crl(const char *crl_file, const char *crl_inline,
-                mbedtls_x509_crt *cert, const char *subject)
-{
-  result_t retval = FAILURE;
-  mbedtls_x509_crl crl = {0};
-  struct gc_arena gc = gc_new();
-  char *serial;
-
-  if (!strcmp (crl_file, INLINE_FILE_TAG) && crl_inline)
-    {
-      if (!mbed_ok(mbedtls_x509_crl_parse(&crl,
-         (const unsigned char *)crl_inline, strlen(crl_inline)+1)))
-        {
-           msg (M_WARN, "CRL: cannot parse inline CRL");
-           goto end;
-        }
-    }
-  else
-    {
-      if (!mbed_ok(mbedtls_x509_crl_parse_file(&crl, crl_file)))
-      {
-          msg (M_WARN, "CRL: cannot read CRL from file %s", crl_file);
-          goto end;
-      }
-  }
-
-  if(cert->issuer_raw.len != crl.issuer_raw.len ||
-      memcmp(crl.issuer_raw.p, cert->issuer_raw.p, crl.issuer_raw.len) != 0)
-    {
-      msg (M_WARN, "CRL: CRL %s is from a different issuer than the issuer of "
-         "certificate %s", crl_file, subject);
-      retval = SUCCESS;
-      goto end;
-    }
-
-  if (!mbed_ok(mbedtls_x509_crt_is_revoked(cert, &crl)))
-    {
-      serial = backend_x509_get_serial_hex(cert, &gc);
-      msg (D_HANDSHAKE, "CRL CHECK FAILED: %s (serial %s) is REVOKED", 
subject, (serial ? serial : "NOT AVAILABLE"));
-      goto end;
-    }
-
-  retval = SUCCESS;
-  msg (D_HANDSHAKE, "CRL CHECK OK: %s",subject);
-
-end:
-  gc_free(&gc);
-  mbedtls_x509_crl_free(&crl);
-  return retval;
-}
-
-#endif /* #if defined(ENABLE_CRYPTO) && defined(ENABLE_CRYPTO_MBEDTLS) */
diff --git a/src/openvpn/ssl_verify_polarssl.h 
b/src/openvpn/ssl_verify_polarssl.h
deleted file mode 100644
index e26d08f..0000000
--- a/src/openvpn/ssl_verify_polarssl.h
+++ /dev/null
@@ -1,78 +0,0 @@
-/*
- *  OpenVPN -- An application to securely tunnel IP networks
- *             over a single TCP/UDP port, with support for SSL/TLS-based
- *             session authentication and key exchange,
- *             packet encryption, packet authentication, and
- *             packet compression.
- *
- *  Copyright (C) 2002-2010 OpenVPN Technologies, Inc. <sa...@openvpn.net>
- *  Copyright (C) 2010 Fox Crypto B.V. <open...@fox-it.com>
- *
- *  This program is free software; you can redistribute it and/or modify
- *  it under the terms of the GNU General Public License version 2
- *  as published by the Free Software Foundation.
- *
- *  This program is distributed in the hope that it will be useful,
- *  but WITHOUT ANY WARRANTY; without even the implied warranty of
- *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- *  GNU General Public License for more details.
- *
- *  You should have received a copy of the GNU General Public License
- *  along with this program (see the file COPYING included with this
- *  distribution); if not, write to the Free Software Foundation, Inc.,
- *  59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
- */
-
-/**
- * @file Control Channel Verification Module mbed TLS backend
- */
-
-#ifndef SSL_VERIFY_MBEDTLS_H_
-#define SSL_VERIFY_MBEDTLS_H_
-
-#include "syshead.h"
-#include <mbedtls/x509_crt.h>
-
-#ifndef __OPENVPN_X509_CERT_T_DECLARED
-#define __OPENVPN_X509_CERT_T_DECLARED
-typedef mbedtls_x509_crt openvpn_x509_cert_t;
-#endif
-
-/** @name Function for authenticating a new connection from a remote OpenVPN 
peer
- *  @{ */
-
-/**
- * Verify that the remote OpenVPN peer's certificate allows setting up a
- * VPN tunnel.
- * @ingroup control_tls
- *
- * This callback function is called when a new TLS session is being setup to
- * determine whether the remote OpenVPN peer's certificate is allowed to
- * connect. It is called for once for every certificate in the chain. The
- * callback functionality is configured in the \c init_ssl() function, which
- * calls the mbed TLS library's \c ssl_set_verify_callback() function with \c
- * verify_callback() as its callback argument.
- *
- * It checks *flags and registers the certificate hash. If these steps succeed,
- * it calls the \c verify_cert() function, which performs OpenVPN-specific
- * verification.
- *
- * @param session_obj  - The OpenVPN \c tls_session associated with this 
object,
- *                       as set during SSL session setup.
- * @param cert         - The certificate used by mbed TLS.
- * @param cert_depth   - The depth of the current certificate in the chain, 
with
- *                       0 being the actual certificate.
- * @param flags        - Whether the remote OpenVPN peer's certificate
- *                       passed verification.  A value of 0 means it
- *                       verified successfully, any other value means it
- *                       failed. \c verify_callback() is considered to have
- *                       ok'ed this certificate if flags is 0 when it returns.
- *
- * @return The return value is 0 unless a fatal error occurred.
- */
-int verify_callback (void *session_obj, mbedtls_x509_crt *cert, int cert_depth,
-    uint32_t *flags);
-
-/** @} name Function for authenticating a new connection from a remote OpenVPN 
peer */
-
-#endif /* SSL_VERIFY_MBEDTLS_H_ */
-- 
2.5.0


Reply via email to