src/openvpn/ssl_mbedtls.c
53f97e1e
 /*
  *  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.
  *
49979459
  *  Copyright (C) 2002-2018 OpenVPN Inc <sales@openvpn.net>
  *  Copyright (C) 2010-2018 Fox Crypto B.V. <openvpn@fox-it.com>
32f07c8e
  *  Copyright (C) 2006-2010, Brainspark B.V.
53f97e1e
  *
  *  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.
  *
caa54ac3
  *  You should have received a copy of the GNU General Public License along
  *  with this program; if not, write to the Free Software Foundation, Inc.,
  *  51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
53f97e1e
  */
 
 /**
86d8cd68
  * @file Control Channel mbed TLS Backend
53f97e1e
  */
 
c110b289
 #ifdef HAVE_CONFIG_H
 #include "config.h"
 #elif defined(_MSC_VER)
 #include "config-msvc.h"
 #endif
 
53f97e1e
 #include "syshead.h"
31ea2ee4
 
c7ca9133
 #if defined(ENABLE_CRYPTO_MBEDTLS)
31ea2ee4
 
53f97e1e
 #include "errlevel.h"
 #include "ssl_backend.h"
9048d50b
 #include "base64.h"
53f97e1e
 #include "buffer.h"
 #include "misc.h"
 #include "manage.h"
 #include "ssl_common.h"
 
86d8cd68
 #include <mbedtls/havege.h>
6efeaa2e
 
74586c65
 #include "ssl_verify_mbedtls.h"
86d8cd68
 #include <mbedtls/debug.h>
 #include <mbedtls/error.h>
c00919e8
 #include <mbedtls/version.h>
 
 #if MBEDTLS_VERSION_NUMBER >= 0x02040000
     #include <mbedtls/net_sockets.h>
 #else
     #include <mbedtls/net.h>
 #endif
 
86d8cd68
 #include <mbedtls/oid.h>
 #include <mbedtls/pem.h>
53f97e1e
 
aba75874
 static const mbedtls_x509_crt_profile openvpn_x509_crt_profile_legacy =
 {
     /* Hashes from SHA-1 and above */
     MBEDTLS_X509_ID_FLAG( MBEDTLS_MD_SHA1 ) |
     MBEDTLS_X509_ID_FLAG( MBEDTLS_MD_RIPEMD160 ) |
     MBEDTLS_X509_ID_FLAG( MBEDTLS_MD_SHA224 ) |
     MBEDTLS_X509_ID_FLAG( MBEDTLS_MD_SHA256 ) |
     MBEDTLS_X509_ID_FLAG( MBEDTLS_MD_SHA384 ) |
     MBEDTLS_X509_ID_FLAG( MBEDTLS_MD_SHA512 ),
     0xFFFFFFF, /* Any PK alg    */
     0xFFFFFFF, /* Any curve     */
     1024,      /* RSA-1024 and larger */
 };
 
 static const mbedtls_x509_crt_profile openvpn_x509_crt_profile_preferred =
 {
     /* SHA-2 and above */
     MBEDTLS_X509_ID_FLAG( MBEDTLS_MD_SHA224 ) |
     MBEDTLS_X509_ID_FLAG( MBEDTLS_MD_SHA256 ) |
     MBEDTLS_X509_ID_FLAG( MBEDTLS_MD_SHA384 ) |
     MBEDTLS_X509_ID_FLAG( MBEDTLS_MD_SHA512 ),
     0xFFFFFFF, /* Any PK alg    */
     0xFFFFFFF, /* Any curve     */
     2048,      /* RSA-2048 and larger */
 };
 
 #define openvpn_x509_crt_profile_suiteb mbedtls_x509_crt_profile_suiteb;
 
53f97e1e
 void
e2a0cad4
 tls_init_lib(void)
53f97e1e
 {
 }
 
 void
e2a0cad4
 tls_free_lib(void)
53f97e1e
 {
 }
 
 void
e2a0cad4
 tls_clear_error(void)
53f97e1e
 {
 }
 
 void
 tls_ctx_server_new(struct tls_root_ctx *ctx)
 {
81d882d5
     ASSERT(NULL != ctx);
     CLEAR(*ctx);
53f97e1e
 
81d882d5
     ALLOC_OBJ_CLEAR(ctx->dhm_ctx, mbedtls_dhm_context);
53f97e1e
 
81d882d5
     ALLOC_OBJ_CLEAR(ctx->ca_chain, mbedtls_x509_crt);
53f97e1e
 
81d882d5
     ctx->endpoint = MBEDTLS_SSL_IS_SERVER;
     ctx->initialised = true;
53f97e1e
 }
 
 void
 tls_ctx_client_new(struct tls_root_ctx *ctx)
 {
81d882d5
     ASSERT(NULL != ctx);
     CLEAR(*ctx);
53f97e1e
 
81d882d5
     ALLOC_OBJ_CLEAR(ctx->dhm_ctx, mbedtls_dhm_context);
     ALLOC_OBJ_CLEAR(ctx->ca_chain, mbedtls_x509_crt);
53f97e1e
 
81d882d5
     ctx->endpoint = MBEDTLS_SSL_IS_CLIENT;
     ctx->initialised = true;
53f97e1e
 }
 
 void
 tls_ctx_free(struct tls_root_ctx *ctx)
 {
81d882d5
     if (ctx)
53f97e1e
     {
81d882d5
         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);
         }
 
         mbedtls_x509_crl_free(ctx->crl);
         if (ctx->crl)
         {
             free(ctx->crl);
         }
160504a2
 
53f97e1e
 #if defined(ENABLE_PKCS11)
81d882d5
         if (ctx->priv_key_pkcs11 != NULL)
         {
             mbedtls_pkcs11_priv_key_free(ctx->priv_key_pkcs11);
             free(ctx->priv_key_pkcs11);
         }
53f97e1e
 #endif
38ace48c
 #if defined(MANAGMENT_EXTERNAL_KEY)
81d882d5
         if (ctx->external_key != NULL)
         {
             free(ctx->external_key);
         }
38ace48c
 #endif
53f97e1e
 
81d882d5
         if (ctx->allowed_ciphers)
         {
             free(ctx->allowed_ciphers);
         }
53f97e1e
 
81d882d5
         CLEAR(*ctx);
53f97e1e
 
81d882d5
         ctx->initialised = false;
53f97e1e
 
     }
 }
 
 bool
 tls_ctx_initialised(struct tls_root_ctx *ctx)
 {
81d882d5
     ASSERT(NULL != ctx);
     return ctx->initialised;
53f97e1e
 }
 
 void
685e486e
 key_state_export_keying_material(struct key_state_ssl *ssl,
                                  struct tls_session *session)
 {
 }
 
0e8a30c0
 bool
81d882d5
 tls_ctx_set_options(struct tls_root_ctx *ctx, unsigned int ssl_flags)
53f97e1e
 {
0e8a30c0
     return true;
53f97e1e
 }
 
3b23b18d
 static const char *
4cd4899e
 tls_translate_cipher_name(const char *cipher_name)
 {
81d882d5
     const tls_cipher_name_pair *pair = tls_get_cipher_name_pair(cipher_name, strlen(cipher_name));
3b23b18d
 
81d882d5
     if (NULL == pair)
3b23b18d
     {
81d882d5
         /* No translation found, return original */
         return cipher_name;
3b23b18d
     }
 
81d882d5
     if (0 != strcmp(cipher_name, pair->iana_name))
3b23b18d
     {
81d882d5
         /* Deprecated name found, notify user */
         msg(M_WARN, "Deprecated cipher suite name '%s', please use IANA name '%s'", pair->openssl_name, pair->iana_name);
3b23b18d
     }
 
81d882d5
     return pair->iana_name;
3b23b18d
 }
 
53f97e1e
 void
 tls_ctx_restrict_ciphers(struct tls_root_ctx *ctx, const char *ciphers)
 {
81d882d5
     char *tmp_ciphers, *tmp_ciphers_orig, *token;
     int i, cipher_count;
     int ciphers_len;
e83313a8
 
81d882d5
     if (NULL == ciphers)
     {
         return; /* Nothing to do */
e83313a8
 
81d882d5
     }
     ciphers_len = strlen(ciphers);
53f97e1e
 
81d882d5
     ASSERT(NULL != ctx);
     ASSERT(0 != ciphers_len);
53f97e1e
 
81d882d5
     /* Get number of ciphers */
     for (i = 0, cipher_count = 1; i < ciphers_len; i++)
4cd4899e
     {
81d882d5
         if (ciphers[i] == ':')
         {
             cipher_count++;
         }
4cd4899e
     }
53f97e1e
 
81d882d5
     /* Allocate an array for them */
     ALLOC_ARRAY_CLEAR(ctx->allowed_ciphers, int, cipher_count+1)
53f97e1e
 
81d882d5
     /* Parse allowed ciphers, getting IDs */
     i = 0;
     tmp_ciphers_orig = tmp_ciphers = string_alloc(ciphers, NULL);
1d90851e
 
81d882d5
     token = strtok(tmp_ciphers, ":");
     while (token)
1d90851e
     {
81d882d5
         ctx->allowed_ciphers[i] = mbedtls_ssl_get_ciphersuite_id(
             tls_translate_cipher_name(token));
         if (0 != ctx->allowed_ciphers[i])
         {
             i++;
         }
         token = strtok(NULL, ":");
1d90851e
     }
81d882d5
     free(tmp_ciphers_orig);
53f97e1e
 }
 
 void
aba75874
 tls_ctx_set_cert_profile(struct tls_root_ctx *ctx, const char *profile)
 {
     if (!profile || 0 == strcmp(profile, "legacy"))
     {
         ctx->cert_profile = openvpn_x509_crt_profile_legacy;
     }
     else if (0 == strcmp(profile, "preferred"))
     {
         ctx->cert_profile = openvpn_x509_crt_profile_preferred;
     }
     else if (0 == strcmp(profile, "suiteb"))
     {
         ctx->cert_profile = openvpn_x509_crt_profile_suiteb;
     }
     else
     {
         msg (M_FATAL, "ERROR: Invalid cert profile: %s", profile);
     }
 }
 
 void
81d882d5
 tls_ctx_check_cert_time(const struct tls_root_ctx *ctx)
091edd8e
 {
81d882d5
     ASSERT(ctx);
     if (ctx->crt_chain == NULL)
868d9d01
     {
81d882d5
         return; /* Nothing to check if there is no certificate */
868d9d01
     }
 
81d882d5
     if (mbedtls_x509_time_is_future(&ctx->crt_chain->valid_from))
091edd8e
     {
81d882d5
         msg(M_WARN, "WARNING: Your certificate is not yet valid!");
091edd8e
     }
 
81d882d5
     if (mbedtls_x509_time_is_past(&ctx->crt_chain->valid_to))
091edd8e
     {
81d882d5
         msg(M_WARN, "WARNING: Your certificate has expired!");
091edd8e
     }
 }
 
 void
81d882d5
 tls_ctx_load_dh_params(struct tls_root_ctx *ctx, const char *dh_file,
                        const char *dh_inline
                        )
53f97e1e
 {
81d882d5
     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));
53f97e1e
 }
 
609e8131
 void
81d882d5
 tls_ctx_load_ecdh_params(struct tls_root_ctx *ctx, const char *curve_name
                          )
609e8131
 {
     if (NULL != curve_name)
81d882d5
     {
         msg(M_WARN, "WARNING: mbed TLS builds do not support specifying an ECDH "
             "curve, using default curves.");
     }
609e8131
 }
 
53f97e1e
 int
 tls_ctx_load_pkcs12(struct tls_root_ctx *ctx, const char *pkcs12_file,
81d882d5
                     const char *pkcs12_file_inline,
                     bool load_ca_file
                     )
53f97e1e
 {
81d882d5
     msg(M_FATAL, "PKCS #12 files not yet supported for mbed TLS.");
     return 0;
53f97e1e
 }
 
93c22ecc
 #ifdef ENABLE_CRYPTOAPI
53f97e1e
 void
 tls_ctx_load_cryptoapi(struct tls_root_ctx *ctx, const char *cryptoapi_cert)
 {
81d882d5
     msg(M_FATAL, "Windows CryptoAPI not yet supported for mbed TLS.");
53f97e1e
 }
445b192a
 #endif /* _WIN32 */
53f97e1e
 
 void
81d882d5
 tls_ctx_load_cert_file(struct tls_root_ctx *ctx, const char *cert_file,
                        const char *cert_inline
                        )
53f97e1e
 {
81d882d5
     ASSERT(NULL != ctx);
53f97e1e
 
81d882d5
     if (!ctx->crt_chain)
444a93ea
     {
81d882d5
         ALLOC_OBJ_CLEAR(ctx->crt_chain, mbedtls_x509_crt);
444a93ea
     }
 
81d882d5
     if (!strcmp(cert_file, INLINE_FILE_TAG) && cert_inline)
53f97e1e
     {
81d882d5
         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");
         }
53f97e1e
     }
81d882d5
     else
53f97e1e
     {
81d882d5
         if (!mbed_ok(mbedtls_x509_crt_parse_file(ctx->crt_chain, cert_file)))
         {
             msg(M_FATAL, "Cannot load certificate file %s", cert_file);
         }
53f97e1e
     }
47712706
 }
 
53f97e1e
 int
81d882d5
 tls_ctx_load_priv_file(struct tls_root_ctx *ctx, const char *priv_key_file,
                        const char *priv_key_inline
                        )
53f97e1e
 {
81d882d5
     int status;
     ASSERT(NULL != ctx);
53f97e1e
 
81d882d5
     if (!ctx->priv_key)
444a93ea
     {
81d882d5
         ALLOC_OBJ_CLEAR(ctx->priv_key, mbedtls_pk_context);
444a93ea
     }
 
81d882d5
     if (!strcmp(priv_key_file, INLINE_FILE_TAG) && priv_key_inline)
53f97e1e
     {
81d882d5
         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));
         }
53f97e1e
     }
81d882d5
     else
53f97e1e
     {
81d882d5
         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);
         }
53f97e1e
     }
81d882d5
     if (!mbed_ok(status))
53f97e1e
     {
 #ifdef ENABLE_MANAGEMENT
81d882d5
         if (management && (MBEDTLS_ERR_PK_PASSWORD_MISMATCH == status))
         {
             management_auth_failure(management, UP_TYPE_PRIVATE_KEY, NULL);
         }
53f97e1e
 #endif
81d882d5
         msg(M_WARN, "Cannot load private key file %s", priv_key_file);
         return 1;
53f97e1e
     }
 
81d882d5
     if (!mbed_ok(mbedtls_pk_check_pair(&ctx->crt_chain->pk, ctx->priv_key)))
5c4acf3f
     {
81d882d5
         msg(M_WARN, "Private key does not match the certificate");
         return 1;
5c4acf3f
     }
 
81d882d5
     return 0;
53f97e1e
 }
 
 #ifdef MANAGMENT_EXTERNAL_KEY
 
38ace48c
 
 struct external_context {
81d882d5
     size_t signature_length;
38ace48c
 };
 
03df3a99
 /**
86d8cd68
  * external_pkcs1_sign implements a mbed TLS rsa_sign_func callback, that uses
03df3a99
  * 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
86d8cd68
  *                      if md_alg != MBEDTLS_MD_NONE).
03df3a99
  * @param hash          The digest ('hash') to sign. Should have a size
86d8cd68
  *                      matching the length of md_alg (if != MBEDTLS_MD_NONE),
03df3a99
  *                      or hashlen otherwise.
  * @param sig           Buffer that returns the signature. Should be at least of
  *                      size ctx->signature_length.
  *
86d8cd68
  * @return 0 on success, non-zero mbed TLS error code on failure.
03df3a99
  */
81d882d5
 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 )
38ace48c
 {
81d882d5
     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)
03df3a99
     {
81d882d5
         return MBEDTLS_ERR_RSA_BAD_INPUT_DATA;
     }
03df3a99
 
81d882d5
     if (MBEDTLS_RSA_PRIVATE != mode)
     {
         return MBEDTLS_ERR_RSA_BAD_INPUT_DATA;
03df3a99
     }
 
81d882d5
     /*
      * 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;
     }
03df3a99
 
81d882d5
     sig_len = ctx->signature_length;
     if ( (SIZE_MAX - hashlen) < asn_len || (hashlen + asn_len) > sig_len)
03df3a99
     {
81d882d5
         return MBEDTLS_ERR_RSA_BAD_INPUT_DATA;
     }
03df3a99
 
81d882d5
     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;
     }
32f07c8e
 
81d882d5
     /* Copy the hash to be signed */
     memcpy( p, hash, hashlen );
03df3a99
 
81d882d5
     /* convert 'from' to base64 */
     if (openvpn_base64_encode(sig, asn_len + hashlen, &in_b64) <= 0)
38ace48c
     {
81d882d5
         rv = MBEDTLS_ERR_RSA_BAD_INPUT_DATA;
         goto done;
38ace48c
     }
 
81d882d5
     /* call MI for signature */
     if (management)
38ace48c
     {
e7995f3c
         out_b64 = management_query_pk_sig(management, in_b64);
81d882d5
     }
     if (!out_b64)
     {
         rv = MBEDTLS_ERR_RSA_PRIVATE_FAILED;
         goto done;
38ace48c
     }
 
81d882d5
     /* decode base64 signature to binary and verify length */
     if (openvpn_base64_decode(out_b64, sig, ctx->signature_length) !=
         ctx->signature_length)
38ace48c
     {
81d882d5
         rv = MBEDTLS_ERR_RSA_PRIVATE_FAILED;
         goto done;
38ace48c
     }
 
81d882d5
     rv = 0;
38ace48c
 
03df3a99
 done:
81d882d5
     if (in_b64)
     {
         free(in_b64);
     }
     if (out_b64)
     {
         free(out_b64);
     }
     return rv;
53f97e1e
 }
 
81d882d5
 static inline size_t
 external_key_len(void *vctx)
38ace48c
 {
81d882d5
     struct external_context *const ctx = vctx;
38ace48c
 
81d882d5
     return ctx->signature_length;
38ace48c
 }
67a67e39
 
 int
81d882d5
 tls_ctx_use_external_private_key(struct tls_root_ctx *ctx,
                                  const char *cert_file, const char *cert_file_inline)
67a67e39
 {
81d882d5
     ASSERT(NULL != ctx);
67a67e39
 
81d882d5
     tls_ctx_load_cert_file(ctx, cert_file, cert_file_inline);
67a67e39
 
81d882d5
     if (ctx->crt_chain == NULL)
     {
6bee1a1f
         return 1;
81d882d5
     }
67a67e39
 
81d882d5
     ALLOC_OBJ_CLEAR(ctx->external_key, struct external_context);
     ctx->external_key->signature_length = mbedtls_pk_get_len(&ctx->crt_chain->pk);
67a67e39
 
81d882d5
     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)))
     {
6bee1a1f
         return 1;
81d882d5
     }
67a67e39
 
6bee1a1f
     return 0;
67a67e39
 }
81d882d5
 #endif /* ifdef MANAGMENT_EXTERNAL_KEY */
53f97e1e
 
81d882d5
 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
                 )
53f97e1e
 {
81d882d5
     if (ca_path)
     {
         msg(M_FATAL, "ERROR: mbed TLS cannot handle the capath directive");
     }
53f97e1e
 
81d882d5
     if (ca_file && !strcmp(ca_file, INLINE_FILE_TAG) && ca_inline)
53f97e1e
     {
81d882d5
         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");
         }
53f97e1e
     }
81d882d5
     else
53f97e1e
     {
81d882d5
         /* 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);
         }
53f97e1e
     }
 }
 
 void
81d882d5
 tls_ctx_load_extra_certs(struct tls_root_ctx *ctx, const char *extra_certs_file,
                          const char *extra_certs_inline
                          )
53f97e1e
 {
81d882d5
     ASSERT(NULL != ctx);
53f97e1e
 
81d882d5
     if (!ctx->crt_chain)
444a93ea
     {
81d882d5
         ALLOC_OBJ_CLEAR(ctx->crt_chain, mbedtls_x509_crt);
444a93ea
     }
 
81d882d5
     if (!strcmp(extra_certs_file, INLINE_FILE_TAG) && extra_certs_inline)
53f97e1e
     {
81d882d5
         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");
         }
53f97e1e
     }
81d882d5
     else
53f97e1e
     {
81d882d5
         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);
         }
53f97e1e
     }
 }
 
 /* **************************************
  *
  * Key-state specific functions
  *
  ***************************************/
 
 /*
  * "Endless buffer"
  */
 
81d882d5
 static inline void
 buf_free_entry(buffer_entry *entry)
53f97e1e
 {
81d882d5
     if (NULL != entry)
53f97e1e
     {
81d882d5
         free(entry->data);
         free(entry);
53f97e1e
     }
 }
 
81d882d5
 static void
 buf_free_entries(endless_buffer *buf)
53f97e1e
 {
81d882d5
     while (buf->first_block)
53f97e1e
     {
81d882d5
         buffer_entry *cur_block = buf->first_block;
         buf->first_block = cur_block->next_block;
         buf_free_entry(cur_block);
53f97e1e
     }
81d882d5
     buf->last_block = NULL;
53f97e1e
 }
 
81d882d5
 static int
 endless_buf_read( endless_buffer *in, unsigned char *out, size_t out_len )
53f97e1e
 {
81d882d5
     size_t read_len = 0;
53f97e1e
 
81d882d5
     if (in->first_block == NULL)
53f97e1e
     {
81d882d5
         return MBEDTLS_ERR_SSL_WANT_READ;
     }
53f97e1e
 
81d882d5
     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;
         }
53f97e1e
     }
 
81d882d5
     return read_len;
53f97e1e
 }
 
81d882d5
 static int
 endless_buf_write( endless_buffer *out, const unsigned char *in, size_t len )
53f97e1e
 {
81d882d5
     buffer_entry *new_block = malloc(sizeof(buffer_entry));
     if (NULL == new_block)
     {
         return MBEDTLS_ERR_NET_SEND_FAILED;
     }
53f97e1e
 
81d882d5
     new_block->data = malloc(len);
     if (NULL == new_block->data)
53f97e1e
     {
81d882d5
         free(new_block);
         return MBEDTLS_ERR_NET_SEND_FAILED;
53f97e1e
     }
 
81d882d5
     new_block->length = len;
     new_block->next_block = NULL;
53f97e1e
 
81d882d5
     memcpy(new_block->data, in, len);
53f97e1e
 
81d882d5
     if (NULL == out->first_block)
     {
         out->first_block = new_block;
     }
53f97e1e
 
81d882d5
     if (NULL != out->last_block)
     {
         out->last_block->next_block = new_block;
     }
53f97e1e
 
81d882d5
     out->last_block = new_block;
53f97e1e
 
81d882d5
     return len;
53f97e1e
 }
 
81d882d5
 static int
 ssl_bio_read( void *ctx, unsigned char *out, size_t out_len)
86d8cd68
 {
81d882d5
     bio_ctx *my_ctx = (bio_ctx *) ctx;
     return endless_buf_read(&my_ctx->in, out, out_len);
86d8cd68
 }
 
81d882d5
 static int
 ssl_bio_write( void *ctx, const unsigned char *in, size_t in_len)
86d8cd68
 {
81d882d5
     bio_ctx *my_ctx = (bio_ctx *) ctx;
     return endless_buf_write(&my_ctx->out, in, in_len);
86d8cd68
 }
 
81d882d5
 static void
 my_debug( void *ctx, int level, const char *file, int line,
           const char *str )
53f97e1e
 {
81d882d5
     int my_loglevel = (level < 3) ? D_TLS_DEBUG_MED : D_TLS_DEBUG;
     msg(my_loglevel, "mbed TLS msg (%s:%d): %s", file, line, str);
53f97e1e
 }
 
6efeaa2e
 /*
  * Further personalise the RNG using a hash of the public key
  */
81d882d5
 void
 tls_ctx_personalise_random(struct tls_root_ctx *ctx)
6efeaa2e
 {
81d882d5
     static char old_sha256_hash[32] = {0};
     unsigned char sha256_hash[32] = {0};
     mbedtls_ctr_drbg_context *cd_ctx = rand_ctx_get();
6efeaa2e
 
81d882d5
     if (NULL != ctx->crt_chain)
6efeaa2e
     {
f22e89bd
         const md_kt_t *sha256_kt = md_kt_get("SHA256");
81d882d5
         mbedtls_x509_crt *cert = ctx->crt_chain;
 
dd1da0e4
         if (!md_full(sha256_kt, cert->tbs.p, cert->tbs.len, sha256_hash))
f22e89bd
         {
             msg(M_WARN, "WARNING: failed to personalise random");
         }
 
81d882d5
         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));
         }
6efeaa2e
     }
 }
 
4b67f984
 int
 tls_version_max(void)
 {
8215b7a8
 #if defined(MBEDTLS_SSL_MAJOR_VERSION_3) && defined(MBEDTLS_SSL_MINOR_VERSION_3)
81d882d5
     return TLS_VER_1_2;
8215b7a8
 #elif defined(MBEDTLS_SSL_MAJOR_VERSION_3) && defined(MBEDTLS_SSL_MINOR_VERSION_2)
81d882d5
     return TLS_VER_1_1;
4b67f984
 #else
81d882d5
     return TLS_VER_1_0;
4b67f984
 #endif
 }
 
6cb15b90
 /**
86d8cd68
  * Convert an OpenVPN tls-version variable to mbed TLS format (i.e. a major and
6cb15b90
  * minor ssl version number).
  *
81d882d5
  * @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.
6cb15b90
  */
81d882d5
 static void
4cd4899e
 tls_version_to_major_minor(int tls_ver, int *major, int *minor)
 {
81d882d5
     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;
     }
6cb15b90
 }
 
160504a2
 void
ce91c187
 backend_tls_ctx_reload_crl(struct tls_root_ctx *ctx, const char *crl_file,
81d882d5
                            const char *crl_inline)
160504a2
 {
81d882d5
     ASSERT(crl_file);
160504a2
 
81d882d5
     if (ctx->crl == NULL)
160504a2
     {
81d882d5
         ALLOC_OBJ_CLEAR(ctx->crl, mbedtls_x509_crl);
160504a2
     }
81d882d5
     mbedtls_x509_crl_free(ctx->crl);
160504a2
 
81d882d5
     if (!strcmp(crl_file, INLINE_FILE_TAG) && crl_inline)
160504a2
     {
81d882d5
         if (!mbed_ok(mbedtls_x509_crl_parse(ctx->crl,
                                             (const unsigned char *)crl_inline, strlen(crl_inline)+1)))
         {
             msg(M_WARN, "CRL: cannot parse inline CRL");
             goto err;
         }
160504a2
     }
81d882d5
     else
160504a2
     {
81d882d5
         if (!mbed_ok(mbedtls_x509_crl_parse_file(ctx->crl, crl_file)))
         {
             msg(M_WARN, "CRL: cannot read CRL from file %s", crl_file);
             goto err;
         }
160504a2
     }
81d882d5
     return;
160504a2
 
 err:
81d882d5
     mbedtls_x509_crl_free(ctx->crl);
160504a2
 }
 
81d882d5
 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)
53f97e1e
 {
81d882d5
     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);
b63f9863
 #ifdef MBEDTLS_DEBUG_C
81d882d5
     mbedtls_debug_set_threshold(3);
b63f9863
 #endif
81d882d5
     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());
86d8cd68
 
aba75874
     mbedtls_ssl_conf_cert_profile(&ks_ssl->ssl_config, &ssl_ctx->cert_profile);
 
81d882d5
     if (ssl_ctx->allowed_ciphers)
     {
         mbedtls_ssl_conf_ciphersuites(&ks_ssl->ssl_config, ssl_ctx->allowed_ciphers);
     }
86d8cd68
 
81d882d5
     /* 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. */
86d8cd68
 #if defined(MBEDTLS_SSL_CBC_RECORD_SPLITTING)
81d882d5
     mbedtls_ssl_conf_cbc_record_splitting(&ks_ssl->ssl_config,
                                           MBEDTLS_SSL_CBC_RECORD_SPLITTING_DISABLED);
86d8cd68
 #endif /* MBEDTLS_SSL_CBC_RECORD_SPLITTING */
 
81d882d5
     /* Initialise authentication information */
     if (is_server)
     {
         mbed_ok(mbedtls_ssl_conf_dh_param_ctx(&ks_ssl->ssl_config,
                                               ssl_ctx->dhm_ctx));
     }
86d8cd68
 
81d882d5
     mbed_ok(mbedtls_ssl_conf_own_cert(&ks_ssl->ssl_config, ssl_ctx->crt_chain,
                                       ssl_ctx->priv_key));
86d8cd68
 
81d882d5
     /* Initialise SSL verification */
86d8cd68
 #if P2MP_SERVER
81d882d5
     if (session->opt->ssl_flags & SSLF_CLIENT_CERT_OPTIONAL)
53f97e1e
     {
81d882d5
         mbedtls_ssl_conf_authmode(&ks_ssl->ssl_config, MBEDTLS_SSL_VERIFY_OPTIONAL);
86d8cd68
     }
81d882d5
     else if (!(session->opt->ssl_flags & SSLF_CLIENT_CERT_NOT_REQUIRED))
86d8cd68
 #endif
81d882d5
     {
         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, ssl_ctx->crl);
 
     /* 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);
53f97e1e
 }
 
 void
 key_state_ssl_free(struct key_state_ssl *ks_ssl)
 {
81d882d5
     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);
     }
53f97e1e
 }
 
 int
81d882d5
 key_state_write_plaintext(struct key_state_ssl *ks, struct buffer *buf)
53f97e1e
 {
81d882d5
     int retval = 0;
53f97e1e
 
81d882d5
     ASSERT(buf);
53f97e1e
 
81d882d5
     retval = key_state_write_plaintext_const(ks, BPTR(buf), BLEN(buf));
53f97e1e
 
81d882d5
     if (1 == retval)
53f97e1e
     {
81d882d5
         memset(BPTR(buf), 0, BLEN(buf));  /* erase data just written */
         buf->len = 0;
53f97e1e
     }
 
81d882d5
     return retval;
53f97e1e
 }
 
 int
81d882d5
 key_state_write_plaintext_const(struct key_state_ssl *ks, const uint8_t *data, int len)
53f97e1e
 {
81d882d5
     int retval = 0;
     perf_push(PERF_BIO_WRITE_PLAINTEXT);
53f97e1e
 
81d882d5
     ASSERT(NULL != ks);
     ASSERT(len >= 0);
53f97e1e
 
81d882d5
     if (0 == len)
53f97e1e
     {
81d882d5
         perf_pop();
         return 0;
53f97e1e
     }
 
81d882d5
     ASSERT(data);
53f97e1e
 
81d882d5
     retval = mbedtls_ssl_write(ks->ctx, data, len);
53f97e1e
 
81d882d5
     if (retval < 0)
53f97e1e
     {
81d882d5
         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;
53f97e1e
     }
 
81d882d5
     if (retval != len)
53f97e1e
     {
81d882d5
         msg(D_TLS_ERRORS,
             "TLS ERROR: write tls_write_plaintext_const incomplete %d/%d",
             retval, len);
         perf_pop();
         return -1;
53f97e1e
     }
 
81d882d5
     /* successful write */
     dmsg(D_HANDSHAKE_VERBOSE, "write tls_write_plaintext_const %d bytes", retval);
53f97e1e
 
81d882d5
     perf_pop();
     return 1;
53f97e1e
 }
 
 int
81d882d5
 key_state_read_ciphertext(struct key_state_ssl *ks, struct buffer *buf,
                           int maxlen)
53f97e1e
 {
81d882d5
     int retval = 0;
     int len = 0;
53f97e1e
 
81d882d5
     perf_push(PERF_BIO_READ_CIPHERTEXT);
53f97e1e
 
81d882d5
     ASSERT(NULL != ks);
     ASSERT(buf);
     ASSERT(buf->len >= 0);
53f97e1e
 
81d882d5
     if (buf->len)
53f97e1e
     {
81d882d5
         perf_pop();
         return 0;
53f97e1e
     }
 
81d882d5
     len = buf_forward_capacity(buf);
     if (maxlen < len)
     {
         len = maxlen;
     }
53f97e1e
 
81d882d5
     retval = endless_buf_read(&ks->bio_ctx.out, BPTR(buf), len);
53f97e1e
 
81d882d5
     /* Error during read, check for retry error */
     if (retval < 0)
53f97e1e
     {
81d882d5
         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;
53f97e1e
     }
81d882d5
     /* Nothing read, try again */
     if (0 == retval)
53f97e1e
     {
81d882d5
         buf->len = 0;
         perf_pop();
         return 0;
53f97e1e
     }
 
81d882d5
     /* successful read */
     dmsg(D_HANDSHAKE_VERBOSE, "read tls_read_ciphertext %d bytes", retval);
     buf->len = retval;
     perf_pop();
     return 1;
53f97e1e
 }
 
 int
81d882d5
 key_state_write_ciphertext(struct key_state_ssl *ks, struct buffer *buf)
53f97e1e
 {
81d882d5
     int retval = 0;
     perf_push(PERF_BIO_WRITE_CIPHERTEXT);
53f97e1e
 
81d882d5
     ASSERT(NULL != ks);
     ASSERT(buf);
     ASSERT(buf->len >= 0);
53f97e1e
 
81d882d5
     if (0 == buf->len)
53f97e1e
     {
81d882d5
         perf_pop();
         return 0;
53f97e1e
     }
 
81d882d5
     retval = endless_buf_write(&ks->bio_ctx.in, BPTR(buf), buf->len);
53f97e1e
 
81d882d5
     if (retval < 0)
53f97e1e
     {
81d882d5
         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;
53f97e1e
     }
 
81d882d5
     if (retval != buf->len)
53f97e1e
     {
81d882d5
         msg(D_TLS_ERRORS, "TLS ERROR: write tls_write_ciphertext incomplete %d/%d",
             retval, buf->len);
         perf_pop();
         return -1;
53f97e1e
     }
 
81d882d5
     /* successful write */
     dmsg(D_HANDSHAKE_VERBOSE, "write tls_write_ciphertext %d bytes", retval);
53f97e1e
 
81d882d5
     memset(BPTR(buf), 0, BLEN(buf));  /* erase data just written */
     buf->len = 0;
53f97e1e
 
81d882d5
     perf_pop();
     return 1;
53f97e1e
 }
 
 int
81d882d5
 key_state_read_plaintext(struct key_state_ssl *ks, struct buffer *buf,
                          int maxlen)
53f97e1e
 {
81d882d5
     int retval = 0;
     int len = 0;
53f97e1e
 
81d882d5
     perf_push(PERF_BIO_READ_PLAINTEXT);
53f97e1e
 
81d882d5
     ASSERT(NULL != ks);
     ASSERT(buf);
     ASSERT(buf->len >= 0);
53f97e1e
 
81d882d5
     if (buf->len)
53f97e1e
     {
81d882d5
         perf_pop();
         return 0;
53f97e1e
     }
 
81d882d5
     len = buf_forward_capacity(buf);
     if (maxlen < len)
     {
         len = maxlen;
     }
53f97e1e
 
81d882d5
     retval = mbedtls_ssl_read(ks->ctx, BPTR(buf), len);
53f97e1e
 
81d882d5
     /* Error during read, check for retry error */
     if (retval < 0)
53f97e1e
     {
81d882d5
         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;
53f97e1e
     }
81d882d5
     /* Nothing read, try again */
     if (0 == retval)
53f97e1e
     {
81d882d5
         buf->len = 0;
         perf_pop();
         return 0;
53f97e1e
     }
 
81d882d5
     /* successful read */
     dmsg(D_HANDSHAKE_VERBOSE, "read tls_read_plaintext %d bytes", retval);
     buf->len = retval;
53f97e1e
 
81d882d5
     perf_pop();
     return 1;
53f97e1e
 }
 
 /* **************************************
  *
  * Information functions
  *
  * Print information for the end user.
  *
  ***************************************/
 void
81d882d5
 print_details(struct key_state_ssl *ks_ssl, const char *prefix)
53f97e1e
 {
81d882d5
     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)
53f97e1e
     {
81d882d5
         openvpn_snprintf(s2, sizeof(s2), ", %u bit key",
                          (unsigned int) mbedtls_pk_get_bitlen(&cert->pk));
53f97e1e
     }
 
81d882d5
     msg(D_HANDSHAKE, "%s%s", s1, s2);
53f97e1e
 }
 
 void
aba75874
 show_available_tls_ciphers(const char *cipher_list,
                            const char *tls_cert_profile)
53f97e1e
 {
81d882d5
     struct tls_root_ctx tls_ctx;
     const int *ciphers = mbedtls_ssl_list_ciphersuites();
53f97e1e
 
81d882d5
     tls_ctx_server_new(&tls_ctx);
aba75874
     tls_ctx_set_cert_profile(&tls_ctx, tls_cert_profile);
81d882d5
     tls_ctx_restrict_ciphers(&tls_ctx, cipher_list);
e83313a8
 
81d882d5
     if (tls_ctx.allowed_ciphers)
     {
         ciphers = tls_ctx.allowed_ciphers;
     }
cb03dca8
 
53f97e1e
 #ifndef ENABLE_SMALL
81d882d5
     printf("Available TLS Ciphers,\n");
     printf("listed in order of preference:\n\n");
53f97e1e
 #endif
 
81d882d5
     while (*ciphers != 0)
53f97e1e
     {
81d882d5
         printf("%s\n", mbedtls_ssl_get_ciphersuite_name(*ciphers));
         ciphers++;
53f97e1e
     }
81d882d5
     printf("\n" SHOW_TLS_CIPHER_LIST_WARNING);
e83313a8
 
81d882d5
     tls_ctx_free(&tls_ctx);
53f97e1e
 }
 
 void
81d882d5
 show_available_curves(void)
609e8131
 {
81d882d5
     const mbedtls_ecp_curve_info *pcurve = mbedtls_ecp_curve_list();
609e8131
 
81d882d5
     if (NULL == pcurve)
     {
         msg(M_FATAL, "Cannot retrieve curve list from mbed TLS");
     }
609e8131
 
81d882d5
     /* Print curve list */
     printf("Available Elliptic curves, listed in order of preference:\n\n");
     while (MBEDTLS_ECP_DP_NONE != pcurve->grp_id)
609e8131
     {
81d882d5
         printf("%s\n", pcurve->name);
         pcurve++;
609e8131
     }
 }
 
 void
81d882d5
 get_highest_preference_tls_cipher(char *buf, int size)
53f97e1e
 {
81d882d5
     const char *cipher_name;
     const int *ciphers = mbedtls_ssl_list_ciphersuites();
     if (*ciphers == 0)
     {
         msg(M_FATAL, "Cannot retrieve list of supported SSL ciphers.");
     }
53f97e1e
 
81d882d5
     cipher_name = mbedtls_ssl_get_ciphersuite_name(*ciphers);
     strncpynt(buf, cipher_name, size);
53f97e1e
 }
31ea2ee4
 
5b17803e
 const char *
1ec984b1
 get_ssl_library_version(void)
 {
86d8cd68
     static char mbedtls_version[30];
     unsigned int pv = mbedtls_version_get_number();
     sprintf( mbedtls_version, "mbed TLS %d.%d.%d",
81d882d5
              (pv>>24)&0xff, (pv>>16)&0xff, (pv>>8)&0xff );
86d8cd68
     return mbedtls_version;
1ec984b1
 }
 
c7ca9133
 #endif /* defined(ENABLE_CRYPTO_MBEDTLS) */