src/openvpn/crypto_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>
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 Data Channel Cryptography mbed TLS-specific backend interface
53f97e1e
  */
 
c110b289
 #ifdef HAVE_CONFIG_H
 #include "config.h"
 #elif defined(_MSC_VER)
 #include "config-msvc.h"
 #endif
 
53f97e1e
 #include "syshead.h"
 
c7ca9133
 #if defined(ENABLE_CRYPTO_MBEDTLS)
31ea2ee4
 
53f97e1e
 #include "errlevel.h"
 #include "basic.h"
 #include "buffer.h"
 #include "integer.h"
 #include "crypto_backend.h"
6efeaa2e
 #include "otime.h"
 #include "misc.h"
53f97e1e
 
a5d35a01
 #include <mbedtls/base64.h>
86d8cd68
 #include <mbedtls/des.h>
 #include <mbedtls/error.h>
 #include <mbedtls/md5.h>
 #include <mbedtls/cipher.h>
 #include <mbedtls/havege.h>
a5d35a01
 #include <mbedtls/pem.h>
86d8cd68
 
 #include <mbedtls/entropy.h>
53f97e1e
 
6efeaa2e
 
53f97e1e
 /*
  *
  * Hardware engine support. Allows loading/unloading of engines.
  *
  */
 
 void
81d882d5
 crypto_init_lib_engine(const char *engine_name)
53f97e1e
 {
81d882d5
     msg(M_WARN, "Note: mbed TLS hardware crypto engine functionality is not "
         "available");
53f97e1e
 }
 
 /*
  *
  * Functions related to the core crypto library
  *
  */
 
 void
81d882d5
 crypto_init_lib(void)
53f97e1e
 {
 }
 
 void
81d882d5
 crypto_uninit_lib(void)
53f97e1e
 {
 }
 
 void
81d882d5
 crypto_clear_error(void)
53f97e1e
 {
 }
 
81d882d5
 bool
 mbed_log_err(unsigned int flags, int errval, const char *prefix)
6ef5df14
 {
81d882d5
     if (0 != errval)
6ef5df14
     {
81d882d5
         char errstr[256];
         mbedtls_strerror(errval, errstr, sizeof(errstr));
 
         if (NULL == prefix)
         {
             prefix = "mbed TLS error";
         }
         msg(flags, "%s: %s", prefix, errstr);
6ef5df14
     }
 
81d882d5
     return 0 == errval;
6ef5df14
 }
 
81d882d5
 bool
 mbed_log_func_line(unsigned int flags, int errval, const char *func,
                    int line)
6ef5df14
 {
81d882d5
     char prefix[256];
6ef5df14
 
81d882d5
     if (!openvpn_snprintf(prefix, sizeof(prefix), "%s:%d", func, line))
     {
         return mbed_log_err(flags, errval, func);
     }
6ef5df14
 
81d882d5
     return mbed_log_err(flags, errval, prefix);
6ef5df14
 }
 
 
53f97e1e
 #ifdef DMALLOC
 void
81d882d5
 crypto_init_dmalloc(void)
53f97e1e
 {
81d882d5
     msg(M_ERR, "Error: dmalloc support is not available for mbed TLS.");
53f97e1e
 }
 #endif /* DMALLOC */
 
44dc5d30
 const cipher_name_pair cipher_name_translation_table[] = {
f499b921
     { "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" }
 };
44dc5d30
 const size_t cipher_name_translation_table_count =
81d882d5
     sizeof(cipher_name_translation_table) / sizeof(*cipher_name_translation_table);
f499b921
 
81d882d5
 static void
 print_cipher(const cipher_kt_t *info)
c94b3ff0
 {
81d882d5
     if (info && (cipher_kt_mode_cbc(info)
c94b3ff0
 #ifdef HAVE_AEAD_CIPHER_MODES
81d882d5
                  || cipher_kt_mode_aead(info)
c94b3ff0
 #endif
81d882d5
                  ))
c94b3ff0
     {
81d882d5
         const char *ssl_only = cipher_kt_mode_cbc(info) ?
                                "" : ", TLS client/server mode only";
         const char *var_key_size = info->flags & MBEDTLS_CIPHER_VARIABLE_KEY_LEN ?
                                    " by default" : "";
 
         printf("%s  (%d bit key%s, %d bit block%s)\n",
                cipher_kt_name(info), cipher_kt_key_size(info) * 8, var_key_size,
                cipher_kt_block_size(info) * 8, ssl_only);
c94b3ff0
     }
 }
 
53f97e1e
 void
e2a0cad4
 show_available_ciphers(void)
53f97e1e
 {
81d882d5
     const int *ciphers = mbedtls_cipher_list();
53f97e1e
 
 #ifndef ENABLE_SMALL
81d882d5
     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");
53f97e1e
 #endif
 
81d882d5
     while (*ciphers != 0)
53f97e1e
     {
81d882d5
         const cipher_kt_t *info = mbedtls_cipher_info_from_type(*ciphers);
         if (info && cipher_kt_block_size(info) >= 128/8)
         {
             print_cipher(info);
         }
         ciphers++;
c94b3ff0
     }
53f97e1e
 
81d882d5
     printf("\nThe following ciphers have a block size of less than 128 bits, \n"
            "and are therefore deprecated.  Do not use unless you have to.\n\n");
     ciphers = mbedtls_cipher_list();
     while (*ciphers != 0)
c94b3ff0
     {
81d882d5
         const cipher_kt_t *info = mbedtls_cipher_info_from_type(*ciphers);
         if (info && cipher_kt_block_size(info) < 128/8)
         {
             print_cipher(info);
         }
         ciphers++;
53f97e1e
     }
81d882d5
     printf("\n");
53f97e1e
 }
 
 void
e2a0cad4
 show_available_digests(void)
53f97e1e
 {
81d882d5
     const int *digests = mbedtls_md_list();
53f97e1e
 
 #ifndef ENABLE_SMALL
81d882d5
     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");
53f97e1e
 #endif
 
81d882d5
     while (*digests != 0)
53f97e1e
     {
81d882d5
         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++;
53f97e1e
     }
81d882d5
     printf("\n");
53f97e1e
 }
 
 void
e2a0cad4
 show_available_engines(void)
53f97e1e
 {
81d882d5
     printf("Sorry, mbed TLS hardware crypto engine functionality is not "
            "available\n");
53f97e1e
 }
 
a5d35a01
 bool
 crypto_pem_encode(const char *name, struct buffer *dst,
                   const struct buffer *src, struct gc_arena *gc)
 {
     /* 1000 chars is the PEM line length limit (+1 for tailing NUL) */
     char header[1000+1] = { 0 };
     char footer[1000+1] = { 0 };
 
     if (!openvpn_snprintf(header, sizeof(header), "-----BEGIN %s-----\n", name))
     {
         return false;
     }
     if (!openvpn_snprintf(footer, sizeof(footer), "-----END %s-----\n", name))
     {
         return false;
     }
 
     size_t out_len = 0;
     if (MBEDTLS_ERR_BASE64_BUFFER_TOO_SMALL !=
             mbedtls_pem_write_buffer(header, footer, BPTR(src), BLEN(src),
                                      NULL, 0, &out_len))
     {
         return false;
     }
 
     *dst = alloc_buf_gc(out_len, gc);
     if (!mbed_ok(mbedtls_pem_write_buffer(header, footer, BPTR(src), BLEN(src),
                                           BPTR(dst), BCAP(dst), &out_len))
         || !buf_inc_len(dst, out_len))
     {
         CLEAR(*dst);
         return false;
     }
 
     return true;
 }
 
 bool
 crypto_pem_decode(const char *name, struct buffer *dst,
                   const struct buffer *src)
 {
     /* 1000 chars is the PEM line length limit (+1 for tailing NUL) */
     char header[1000+1] = { 0 };
     char footer[1000+1] = { 0 };
 
     if (*(BLAST(src)) != '\0')
     {
         msg(M_WARN, "PEM decode error: source buffer not null-terminated");
         return false;
     }
     if (!openvpn_snprintf(header, sizeof(header), "-----BEGIN %s-----", name))
     {
         return false;
     }
     if (!openvpn_snprintf(footer, sizeof(footer), "-----END %s-----", name))
     {
         return false;
     }
 
     size_t use_len = 0;
     mbedtls_pem_context ctx = { 0 };
     bool ret = mbed_ok(mbedtls_pem_read_buffer(&ctx, header, footer, BPTR(src),
                                                NULL, 0, &use_len));
     if (ret && !buf_write(dst, ctx.buf, ctx.buflen))
     {
         ret = false;
         msg(M_WARN, "PEM decode error: destination buffer too small");
     }
 
     mbedtls_pem_free(&ctx);
     return ret;
 }
 
53f97e1e
 /*
  *
  * 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.
  *
  */
 
6efeaa2e
 /*
  * Initialise the given ctr_drbg context, using a personalisation string and an
  * entropy gathering function.
  */
81d882d5
 mbedtls_ctr_drbg_context *
e2a0cad4
 rand_ctx_get(void)
6efeaa2e
 {
81d882d5
     static mbedtls_entropy_context ec = {0};
     static mbedtls_ctr_drbg_context cd_ctx = {0};
     static bool rand_initialised = false;
6efeaa2e
 
81d882d5
     if (!rand_initialised)
6efeaa2e
     {
81d882d5
         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;
     }
6efeaa2e
 
81d882d5
     return &cd_ctx;
6efeaa2e
 }
 
0f25d296
 #ifdef ENABLE_PREDICTION_RESISTANCE
81d882d5
 void
e2a0cad4
 rand_ctx_enable_prediction_resistance(void)
0f25d296
 {
81d882d5
     mbedtls_ctr_drbg_context *cd_ctx = rand_ctx_get();
0f25d296
 
81d882d5
     mbedtls_ctr_drbg_set_prediction_resistance(cd_ctx, 1);
0f25d296
 }
 #endif /* ENABLE_PREDICTION_RESISTANCE */
 
6efeaa2e
 int
81d882d5
 rand_bytes(uint8_t *output, int len)
6efeaa2e
 {
81d882d5
     mbedtls_ctr_drbg_context *rng_ctx = rand_ctx_get();
6efeaa2e
 
81d882d5
     while (len > 0)
53f97e1e
     {
81d882d5
         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;
53f97e1e
     }
6efeaa2e
 
81d882d5
     return 1;
53f97e1e
 }
 
 /*
  *
  * Key functions, allow manipulation of keys.
  *
  */
 
 
 int
81d882d5
 key_des_num_cblocks(const mbedtls_cipher_info_t *kt)
53f97e1e
 {
81d882d5
     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;
     }
53f97e1e
 
81d882d5
     dmsg(D_CRYPTO_DEBUG, "CRYPTO INFO: n_DES_cblocks=%d", ret);
     return ret;
53f97e1e
 }
 
 bool
81d882d5
 key_des_check(uint8_t *key, int key_len, int ndc)
53f97e1e
 {
81d882d5
     int i;
     struct buffer b;
53f97e1e
 
81d882d5
     buf_set_read(&b, key, key_len);
53f97e1e
 
81d882d5
     for (i = 0; i < ndc; ++i)
53f97e1e
     {
81d882d5
         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;
         }
53f97e1e
     }
81d882d5
     return true;
53f97e1e
 
81d882d5
 err:
     return false;
53f97e1e
 }
 
 void
81d882d5
 key_des_fixup(uint8_t *key, int key_len, int ndc)
53f97e1e
 {
81d882d5
     int i;
     struct buffer b;
53f97e1e
 
81d882d5
     buf_set_read(&b, key, key_len);
     for (i = 0; i < ndc; ++i)
53f97e1e
     {
81d882d5
         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);
53f97e1e
     }
 }
 
 /*
  *
  * Generic cipher key type functions
  *
  */
 
 
86d8cd68
 const mbedtls_cipher_info_t *
81d882d5
 cipher_kt_get(const char *ciphername)
53f97e1e
 {
81d882d5
     const mbedtls_cipher_info_t *cipher = NULL;
53f97e1e
 
81d882d5
     ASSERT(ciphername);
53f97e1e
 
81d882d5
     cipher = mbedtls_cipher_info_from_string(ciphername);
53f97e1e
 
81d882d5
     if (NULL == cipher)
dc4fa3c4
     {
81d882d5
         msg(D_LOW, "Cipher algorithm '%s' not found", ciphername);
         return NULL;
dc4fa3c4
     }
53f97e1e
 
81d882d5
     if (cipher->key_bitlen/8 > MAX_CIPHER_KEY_LENGTH)
dc4fa3c4
     {
81d882d5
         msg(D_LOW, "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 NULL;
dc4fa3c4
     }
53f97e1e
 
81d882d5
     return cipher;
53f97e1e
 }
 
 const char *
81d882d5
 cipher_kt_name(const mbedtls_cipher_info_t *cipher_kt)
53f97e1e
 {
81d882d5
     if (NULL == cipher_kt)
     {
         return "[null-cipher]";
     }
f499b921
 
81d882d5
     return translate_cipher_name_to_openvpn(cipher_kt->name);
53f97e1e
 }
 
 int
81d882d5
 cipher_kt_key_size(const mbedtls_cipher_info_t *cipher_kt)
53f97e1e
 {
81d882d5
     if (NULL == cipher_kt)
     {
         return 0;
     }
4a56d19f
 
81d882d5
     return cipher_kt->key_bitlen/8;
53f97e1e
 }
 
 int
81d882d5
 cipher_kt_iv_size(const mbedtls_cipher_info_t *cipher_kt)
53f97e1e
 {
81d882d5
     if (NULL == cipher_kt)
     {
         return 0;
     }
     return cipher_kt->iv_size;
53f97e1e
 }
 
 int
81d882d5
 cipher_kt_block_size(const mbedtls_cipher_info_t *cipher_kt)
53f97e1e
 {
81d882d5
     if (NULL == cipher_kt)
     {
         return 0;
     }
     return cipher_kt->block_size;
53f97e1e
 }
 
6449a149
 int
81d882d5
 cipher_kt_tag_size(const mbedtls_cipher_info_t *cipher_kt)
66407e11
 {
 #ifdef HAVE_AEAD_CIPHER_MODES
81d882d5
     if (cipher_kt && cipher_kt_mode_aead(cipher_kt))
     {
         return OPENVPN_AEAD_TAG_LENGTH;
     }
66407e11
 #endif
81d882d5
     return 0;
66407e11
 }
 
 int
81d882d5
 cipher_kt_mode(const mbedtls_cipher_info_t *cipher_kt)
53f97e1e
 {
81d882d5
     ASSERT(NULL != cipher_kt);
     return cipher_kt->mode;
53f97e1e
 }
 
a4b27b64
 bool
 cipher_kt_mode_cbc(const cipher_kt_t *cipher)
 {
81d882d5
     return cipher && cipher_kt_mode(cipher) == OPENVPN_MODE_CBC;
a4b27b64
 }
 
 bool
 cipher_kt_mode_ofb_cfb(const cipher_kt_t *cipher)
 {
81d882d5
     return cipher && (cipher_kt_mode(cipher) == OPENVPN_MODE_OFB
                       || cipher_kt_mode(cipher) == OPENVPN_MODE_CFB);
a4b27b64
 }
 
66407e11
 bool
 cipher_kt_mode_aead(const cipher_kt_t *cipher)
 {
81d882d5
     return cipher && cipher_kt_mode(cipher) == OPENVPN_MODE_GCM;
66407e11
 }
 
53f97e1e
 
 /*
  *
  * Generic cipher context functions
  *
  */
 
6cbd48a3
 mbedtls_cipher_context_t *
 cipher_ctx_new(void)
 {
     mbedtls_cipher_context_t *ctx;
     ALLOC_OBJ(ctx, mbedtls_cipher_context_t);
     return ctx;
 }
 
 void
 cipher_ctx_free(mbedtls_cipher_context_t *ctx)
 {
     free(ctx);
 }
53f97e1e
 
 void
5e6e4b7d
 cipher_ctx_init(mbedtls_cipher_context_t *ctx, const uint8_t *key, int key_len,
81d882d5
                 const mbedtls_cipher_info_t *kt, const mbedtls_operation_t operation)
53f97e1e
 {
81d882d5
     ASSERT(NULL != kt && NULL != ctx);
53f97e1e
 
81d882d5
     CLEAR(*ctx);
53f97e1e
 
81d882d5
     if (!mbed_ok(mbedtls_cipher_setup(ctx, kt)))
     {
         msg(M_FATAL, "mbed TLS cipher context init #1");
     }
53f97e1e
 
81d882d5
     if (!mbed_ok(mbedtls_cipher_setkey(ctx, key, key_len*8, operation)))
     {
         msg(M_FATAL, "mbed TLS cipher set key");
     }
53f97e1e
 
81d882d5
     /* make sure we used a big enough key */
     ASSERT(ctx->key_bitlen <= key_len*8);
53f97e1e
 }
 
81d882d5
 void
 cipher_ctx_cleanup(mbedtls_cipher_context_t *ctx)
53f97e1e
 {
81d882d5
     mbedtls_cipher_free(ctx);
53f97e1e
 }
 
81d882d5
 int
 cipher_ctx_iv_length(const mbedtls_cipher_context_t *ctx)
53f97e1e
 {
81d882d5
     return mbedtls_cipher_get_iv_size(ctx);
53f97e1e
 }
 
81d882d5
 int
 cipher_ctx_get_tag(cipher_ctx_t *ctx, uint8_t *tag, int tag_len)
66407e11
 {
 #ifdef HAVE_AEAD_CIPHER_MODES
81d882d5
     if (tag_len > SIZE_MAX)
     {
         return 0;
     }
66407e11
 
81d882d5
     if (!mbed_ok(mbedtls_cipher_write_tag(ctx, (unsigned char *) tag, tag_len)))
     {
         return 0;
     }
66407e11
 
81d882d5
     return 1;
 #else  /* ifdef HAVE_AEAD_CIPHER_MODES */
     ASSERT(0);
66407e11
 #endif /* HAVE_AEAD_CIPHER_MODES */
 }
 
81d882d5
 int
 cipher_ctx_block_size(const mbedtls_cipher_context_t *ctx)
53f97e1e
 {
81d882d5
     return mbedtls_cipher_get_block_size(ctx);
53f97e1e
 }
 
81d882d5
 int
 cipher_ctx_mode(const mbedtls_cipher_context_t *ctx)
53f97e1e
 {
81d882d5
     ASSERT(NULL != ctx);
53f97e1e
 
81d882d5
     return cipher_kt_mode(ctx->cipher_info);
53f97e1e
 }
 
a4b27b64
 const cipher_kt_t *
81d882d5
 cipher_ctx_get_cipher_kt(const cipher_ctx_t *ctx)
a4b27b64
 {
81d882d5
     return ctx ? ctx->cipher_info : NULL;
a4b27b64
 }
 
81d882d5
 int
5e6e4b7d
 cipher_ctx_reset(mbedtls_cipher_context_t *ctx, const uint8_t *iv_buf)
53f97e1e
 {
81d882d5
     if (!mbed_ok(mbedtls_cipher_reset(ctx)))
     {
         return 0;
     }
03df3a99
 
81d882d5
     if (!mbed_ok(mbedtls_cipher_set_iv(ctx, iv_buf, ctx->cipher_info->iv_size)))
     {
         return 0;
     }
03df3a99
 
81d882d5
     return 1;
53f97e1e
 }
 
81d882d5
 int
 cipher_ctx_update_ad(cipher_ctx_t *ctx, const uint8_t *src, int src_len)
66407e11
 {
 #ifdef HAVE_AEAD_CIPHER_MODES
81d882d5
     if (src_len > SIZE_MAX)
     {
         return 0;
     }
66407e11
 
81d882d5
     if (!mbed_ok(mbedtls_cipher_update_ad(ctx, src, src_len)))
     {
         return 0;
     }
66407e11
 
81d882d5
     return 1;
 #else  /* ifdef HAVE_AEAD_CIPHER_MODES */
     ASSERT(0);
66407e11
 #endif /* HAVE_AEAD_CIPHER_MODES */
 }
 
81d882d5
 int
 cipher_ctx_update(mbedtls_cipher_context_t *ctx, uint8_t *dst,
                   int *dst_len, uint8_t *src, int src_len)
53f97e1e
 {
81d882d5
     size_t s_dst_len = *dst_len;
be0a08d4
 
81d882d5
     if (!mbed_ok(mbedtls_cipher_update(ctx, src, (size_t) src_len, dst,
                                        &s_dst_len)))
     {
         return 0;
     }
be0a08d4
 
81d882d5
     *dst_len = s_dst_len;
be0a08d4
 
81d882d5
     return 1;
53f97e1e
 }
 
81d882d5
 int
 cipher_ctx_final(mbedtls_cipher_context_t *ctx, uint8_t *dst, int *dst_len)
53f97e1e
 {
81d882d5
     size_t s_dst_len = *dst_len;
be0a08d4
 
81d882d5
     if (!mbed_ok(mbedtls_cipher_finish(ctx, dst, &s_dst_len)))
     {
         return 0;
     }
d17d362d
 
81d882d5
     *dst_len = s_dst_len;
be0a08d4
 
81d882d5
     return 1;
53f97e1e
 }
 
81d882d5
 int
 cipher_ctx_final_check_tag(mbedtls_cipher_context_t *ctx, uint8_t *dst,
                            int *dst_len, uint8_t *tag, size_t tag_len)
66407e11
 {
 #ifdef HAVE_AEAD_CIPHER_MODES
81d882d5
     size_t olen = 0;
86d8cd68
 
81d882d5
     if (MBEDTLS_DECRYPT != ctx->operation)
     {
         return 0;
     }
66407e11
 
81d882d5
     if (tag_len > SIZE_MAX)
     {
         return 0;
     }
66407e11
 
81d882d5
     if (!mbed_ok(mbedtls_cipher_finish(ctx, dst, &olen)))
66407e11
     {
81d882d5
         msg(D_CRYPT_ERRORS, "%s: cipher_ctx_final() failed", __func__);
         return 0;
66407e11
     }
 
81d882d5
     if (olen > INT_MAX)
     {
         return 0;
     }
     *dst_len = olen;
86d8cd68
 
81d882d5
     if (!mbed_ok(mbedtls_cipher_check_tag(ctx, (const unsigned char *) tag,
                                           tag_len)))
     {
         return 0;
     }
66407e11
 
81d882d5
     return 1;
 #else  /* ifdef HAVE_AEAD_CIPHER_MODES */
     ASSERT(0);
66407e11
 #endif /* HAVE_AEAD_CIPHER_MODES */
 }
 
53f97e1e
 void
81d882d5
 cipher_des_encrypt_ecb(const unsigned char key[DES_KEY_LENGTH],
                        unsigned char *src,
                        unsigned char *dst)
53f97e1e
 {
81d882d5
     mbedtls_des_context ctx;
53f97e1e
 
81d882d5
     ASSERT(mbed_ok(mbedtls_des_setkey_enc(&ctx, key)));
     ASSERT(mbed_ok(mbedtls_des_crypt_ecb(&ctx, src, dst)));
53f97e1e
 }
 
 
 
 /*
  *
  * Generic message digest information functions
  *
  */
 
 
86d8cd68
 const mbedtls_md_info_t *
81d882d5
 md_kt_get(const char *digest)
53f97e1e
 {
81d882d5
     const mbedtls_md_info_t *md = NULL;
     ASSERT(digest);
53f97e1e
 
81d882d5
     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;
53f97e1e
 }
 
 const char *
81d882d5
 md_kt_name(const mbedtls_md_info_t *kt)
53f97e1e
 {
81d882d5
     if (NULL == kt)
     {
         return "[null-digest]";
     }
     return mbedtls_md_get_name(kt);
53f97e1e
 }
 
 int
81d882d5
 md_kt_size(const mbedtls_md_info_t *kt)
53f97e1e
 {
81d882d5
     if (NULL == kt)
     {
         return 0;
     }
     return mbedtls_md_get_size(kt);
53f97e1e
 }
 
 /*
  *
  * Generic message digest functions
  *
  */
 
 int
81d882d5
 md_full(const md_kt_t *kt, const uint8_t *src, int src_len, uint8_t *dst)
53f97e1e
 {
81d882d5
     return 0 == mbedtls_md(kt, src, src_len, dst);
53f97e1e
 }
 
c481ef00
 mbedtls_md_context_t *
 md_ctx_new(void)
 {
     mbedtls_md_context_t *ctx;
     ALLOC_OBJ_CLEAR(ctx, mbedtls_md_context_t);
     return ctx;
 }
 
 void md_ctx_free(mbedtls_md_context_t *ctx)
 {
     free(ctx);
 }
53f97e1e
 
 void
81d882d5
 md_ctx_init(mbedtls_md_context_t *ctx, const mbedtls_md_info_t *kt)
53f97e1e
 {
81d882d5
     ASSERT(NULL != ctx && NULL != kt);
53f97e1e
 
81d882d5
     mbedtls_md_init(ctx);
     ASSERT(0 == mbedtls_md_setup(ctx, kt, 0));
     ASSERT(0 == mbedtls_md_starts(ctx));
53f97e1e
 }
 
 void
86d8cd68
 md_ctx_cleanup(mbedtls_md_context_t *ctx)
53f97e1e
 {
07036fd3
     mbedtls_md_free(ctx);
53f97e1e
 }
 
 int
81d882d5
 md_ctx_size(const mbedtls_md_context_t *ctx)
53f97e1e
 {
81d882d5
     if (NULL == ctx)
     {
         return 0;
     }
     return mbedtls_md_get_size(ctx->md_info);
53f97e1e
 }
 
 void
81d882d5
 md_ctx_update(mbedtls_md_context_t *ctx, const uint8_t *src, int src_len)
53f97e1e
 {
81d882d5
     ASSERT(0 == mbedtls_md_update(ctx, src, src_len));
53f97e1e
 }
 
 void
81d882d5
 md_ctx_final(mbedtls_md_context_t *ctx, uint8_t *dst)
53f97e1e
 {
81d882d5
     ASSERT(0 == mbedtls_md_finish(ctx, dst));
     mbedtls_md_free(ctx);
53f97e1e
 }
 
 
 /*
  *
  * Generic HMAC functions
  *
  */
 
 
 /*
  * TODO: re-enable dmsg for crypto debug
  */
aba98e90
 
 mbedtls_md_context_t *
 hmac_ctx_new(void)
 {
     mbedtls_md_context_t *ctx;
     ALLOC_OBJ(ctx, mbedtls_md_context_t);
     return ctx;
 }
 
 void
 hmac_ctx_free(mbedtls_md_context_t *ctx)
 {
     free(ctx);
 }
 
53f97e1e
 void
81d882d5
 hmac_ctx_init(mbedtls_md_context_t *ctx, const uint8_t *key, int key_len,
               const mbedtls_md_info_t *kt)
53f97e1e
 {
81d882d5
     ASSERT(NULL != kt && NULL != ctx);
53f97e1e
 
81d882d5
     mbedtls_md_init(ctx);
     ASSERT(0 == mbedtls_md_setup(ctx, kt, 1));
     ASSERT(0 == mbedtls_md_hmac_starts(ctx, key, key_len));
53f97e1e
 
81d882d5
     /* make sure we used a big enough key */
     ASSERT(mbedtls_md_get_size(kt) <= key_len);
53f97e1e
 }
 
 void
86d8cd68
 hmac_ctx_cleanup(mbedtls_md_context_t *ctx)
53f97e1e
 {
81d882d5
     mbedtls_md_free(ctx);
53f97e1e
 }
 
 int
81d882d5
 hmac_ctx_size(const mbedtls_md_context_t *ctx)
53f97e1e
 {
81d882d5
     if (NULL == ctx)
     {
         return 0;
     }
     return mbedtls_md_get_size(ctx->md_info);
53f97e1e
 }
 
 void
81d882d5
 hmac_ctx_reset(mbedtls_md_context_t *ctx)
53f97e1e
 {
81d882d5
     ASSERT(0 == mbedtls_md_hmac_reset(ctx));
53f97e1e
 }
 
 void
81d882d5
 hmac_ctx_update(mbedtls_md_context_t *ctx, const uint8_t *src, int src_len)
53f97e1e
 {
81d882d5
     ASSERT(0 == mbedtls_md_hmac_update(ctx, src, src_len));
53f97e1e
 }
 
 void
81d882d5
 hmac_ctx_final(mbedtls_md_context_t *ctx, uint8_t *dst)
53f97e1e
 {
81d882d5
     ASSERT(0 == mbedtls_md_hmac_finish(ctx, dst));
53f97e1e
 }
31ea2ee4
 
c7ca9133
 #endif /* ENABLE_CRYPTO_MBEDTLS */