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 */ |