6825182b |
/*
* 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> |
6825182b |
*
* 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. |
6825182b |
*/
/**
* @file Data Channel Cryptography OpenSSL-specific backend interface
*/
|
c110b289 |
#ifdef HAVE_CONFIG_H
#include "config.h"
#elif defined(_MSC_VER)
#include "config-msvc.h"
#endif
|
6825182b |
#include "syshead.h"
|
c7ca9133 |
#if defined(ENABLE_CRYPTO_OPENSSL) |
31ea2ee4 |
|
6825182b |
#include "basic.h"
#include "buffer.h"
#include "integer.h" |
d344820f |
#include "crypto.h" |
6825182b |
#include "crypto_backend.h" |
c481ef00 |
#include "openssl_compat.h" |
c3e1809f |
|
6825182b |
#include <openssl/des.h> |
c3e1809f |
#include <openssl/err.h>
#include <openssl/evp.h>
#include <openssl/objects.h> |
6ede22c4 |
#include <openssl/rand.h> |
c3e1809f |
#include <openssl/ssl.h> |
6825182b |
/* |
23ee3563 |
* Check for key size creepage.
*/
#if MAX_CIPHER_KEY_LENGTH < EVP_MAX_KEY_LENGTH
#warning Some OpenSSL EVP ciphers now support key lengths greater than MAX_CIPHER_KEY_LENGTH -- consider increasing MAX_CIPHER_KEY_LENGTH
#endif
#if MAX_HMAC_KEY_LENGTH < EVP_MAX_MD_SIZE
#warning Some OpenSSL HMAC message digests now support key lengths greater than MAX_HMAC_KEY_LENGTH -- consider increasing MAX_HMAC_KEY_LENGTH
#endif
|
9b33b5a4 |
#if HAVE_OPENSSL_ENGINE |
b01cb9ef |
#include <openssl/engine.h>
static bool engine_initialized = false; /* GLOBAL */
static ENGINE *engine_persist = NULL; /* GLOBAL */
/* Try to load an engine in a shareable library */
static ENGINE * |
81d882d5 |
try_load_engine(const char *engine) |
b01cb9ef |
{ |
81d882d5 |
ENGINE *e = ENGINE_by_id("dynamic");
if (e) |
b01cb9ef |
{ |
81d882d5 |
if (!ENGINE_ctrl_cmd_string(e, "SO_PATH", engine, 0)
|| !ENGINE_ctrl_cmd_string(e, "LOAD", NULL, 0))
{
ENGINE_free(e);
e = NULL;
} |
b01cb9ef |
} |
81d882d5 |
return e; |
b01cb9ef |
}
static ENGINE * |
81d882d5 |
setup_engine(const char *engine) |
b01cb9ef |
{ |
81d882d5 |
ENGINE *e = NULL; |
b01cb9ef |
|
81d882d5 |
ENGINE_load_builtin_engines(); |
b01cb9ef |
|
81d882d5 |
if (engine) |
b01cb9ef |
{ |
81d882d5 |
if (strcmp(engine, "auto") == 0)
{
msg(M_INFO, "Initializing OpenSSL auto engine support");
ENGINE_register_all_complete();
return NULL;
}
if ((e = ENGINE_by_id(engine)) == NULL
&& (e = try_load_engine(engine)) == NULL)
{
crypto_msg(M_FATAL, "OpenSSL error: cannot load engine '%s'",
engine);
}
if (!ENGINE_set_default(e, ENGINE_METHOD_ALL))
{
crypto_msg(M_FATAL,
"OpenSSL error: ENGINE_set_default failed on engine '%s'",
engine);
}
msg(M_INFO, "Initializing OpenSSL support for engine '%s'",
ENGINE_get_id(e)); |
b01cb9ef |
} |
81d882d5 |
return e; |
b01cb9ef |
}
|
9b33b5a4 |
#endif /* HAVE_OPENSSL_ENGINE */ |
b01cb9ef |
void |
81d882d5 |
crypto_init_lib_engine(const char *engine_name) |
b01cb9ef |
{ |
9b33b5a4 |
#if HAVE_OPENSSL_ENGINE |
81d882d5 |
if (!engine_initialized) |
b01cb9ef |
{ |
81d882d5 |
ASSERT(engine_name);
ASSERT(!engine_persist);
engine_persist = setup_engine(engine_name);
engine_initialized = true; |
b01cb9ef |
} |
81d882d5 |
#else /* if HAVE_OPENSSL_ENGINE */
msg(M_WARN, "Note: OpenSSL hardware crypto engine functionality is not available"); |
7151f3f7 |
#endif |
b01cb9ef |
}
/*
*
* Functions related to the core crypto library
*
*/
void |
81d882d5 |
crypto_init_lib(void) |
b01cb9ef |
{ |
81d882d5 |
/*
* If you build the OpenSSL library and OpenVPN with
* CRYPTO_MDEBUG, you will get a listing of OpenSSL
* memory leaks on program termination.
*/ |
39b54baa |
|
b01cb9ef |
#ifdef CRYPTO_MDEBUG |
81d882d5 |
CRYPTO_mem_ctrl(CRYPTO_MEM_CHECK_ON); |
b01cb9ef |
#endif
}
void |
81d882d5 |
crypto_uninit_lib(void) |
b01cb9ef |
{
#ifdef CRYPTO_MDEBUG |
81d882d5 |
FILE *fp = fopen("sdlog", "w");
ASSERT(fp);
CRYPTO_mem_leaks_fp(fp);
fclose(fp); |
b01cb9ef |
#endif
|
9b33b5a4 |
#if HAVE_OPENSSL_ENGINE |
81d882d5 |
if (engine_initialized) |
b01cb9ef |
{ |
81d882d5 |
ENGINE_cleanup();
engine_persist = NULL;
engine_initialized = false; |
b01cb9ef |
}
#endif
} |
7151f3f7 |
void |
81d882d5 |
crypto_clear_error(void) |
330715f0 |
{ |
81d882d5 |
ERR_clear_error(); |
330715f0 |
}
|
e795d6ba |
void |
4cd4899e |
crypto_print_openssl_errors(const unsigned int flags)
{ |
81d882d5 |
size_t err = 0; |
e795d6ba |
|
81d882d5 |
while ((err = ERR_get_error())) |
c3e1809f |
{ |
81d882d5 |
/* Be more clear about frequently occurring "no shared cipher" error */ |
6ddc43d1 |
if (ERR_GET_REASON(err) == SSL_R_NO_SHARED_CIPHER) |
81d882d5 |
{
msg(D_CRYPT_ERRORS, "TLS error: The server has no TLS ciphersuites "
"in common with the client. Your --tls-cipher setting might be "
"too restrictive.");
}
msg(flags, "OpenSSL: %s", ERR_error_string(err, NULL)); |
c3e1809f |
} |
e795d6ba |
}
|
b01cb9ef |
/*
*
* OpenSSL memory debugging. If dmalloc debugging is enabled, tell
* OpenSSL to use our private malloc/realloc/free functions so that
* we can dispatch them to dmalloc.
*
*/
#ifdef DMALLOC
static void * |
81d882d5 |
crypto_malloc(size_t size, const char *file, int line) |
b01cb9ef |
{ |
81d882d5 |
return dmalloc_malloc(file, line, size, DMALLOC_FUNC_MALLOC, 0, 0); |
b01cb9ef |
}
static void * |
81d882d5 |
crypto_realloc(void *ptr, size_t size, const char *file, int line) |
b01cb9ef |
{ |
81d882d5 |
return dmalloc_realloc(file, line, ptr, size, DMALLOC_FUNC_REALLOC, 0); |
b01cb9ef |
}
static void |
81d882d5 |
crypto_free(void *ptr) |
b01cb9ef |
{ |
81d882d5 |
dmalloc_free(__FILE__, __LINE__, ptr, DMALLOC_FUNC_FREE); |
b01cb9ef |
}
void |
81d882d5 |
crypto_init_dmalloc(void) |
b01cb9ef |
{ |
81d882d5 |
CRYPTO_set_mem_ex_functions(crypto_malloc,
crypto_realloc,
crypto_free); |
b01cb9ef |
}
#endif /* DMALLOC */
|
44dc5d30 |
const cipher_name_pair cipher_name_translation_table[] = {
{ "AES-128-GCM", "id-aes128-GCM" },
{ "AES-192-GCM", "id-aes192-GCM" },
{ "AES-256-GCM", "id-aes256-GCM" }, |
6d0d0af9 |
{ "CHACHA20-POLY1305", "ChaCha20-Poly1305" }, |
44dc5d30 |
};
const size_t cipher_name_translation_table_count = |
81d882d5 |
sizeof(cipher_name_translation_table) / sizeof(*cipher_name_translation_table); |
f499b921 |
|
c94b3ff0 |
static int
cipher_name_cmp(const void *a, const void *b)
{ |
81d882d5 |
const EVP_CIPHER *const *cipher_a = a;
const EVP_CIPHER *const *cipher_b = b; |
c94b3ff0 |
|
81d882d5 |
const char *cipher_name_a =
translate_cipher_name_to_openvpn(EVP_CIPHER_name(*cipher_a));
const char *cipher_name_b =
translate_cipher_name_to_openvpn(EVP_CIPHER_name(*cipher_b)); |
c94b3ff0 |
|
81d882d5 |
return strcmp(cipher_name_a, cipher_name_b); |
c94b3ff0 |
}
static void
print_cipher(const EVP_CIPHER *cipher)
{ |
81d882d5 |
const char *var_key_size =
(EVP_CIPHER_flags(cipher) & EVP_CIPH_VARIABLE_LENGTH) ?
" by default" : "";
const char *ssl_only = cipher_kt_mode_cbc(cipher) ?
"" : ", TLS client/server mode only"; |
c94b3ff0 |
|
81d882d5 |
printf("%s (%d bit key%s, %d bit block%s)\n",
translate_cipher_name_to_openvpn(EVP_CIPHER_name(cipher)),
EVP_CIPHER_key_length(cipher) * 8, var_key_size,
cipher_kt_block_size(cipher) * 8, ssl_only); |
c94b3ff0 |
}
|
330715f0 |
void |
e2a0cad4 |
show_available_ciphers(void) |
7151f3f7 |
{ |
81d882d5 |
int nid;
size_t i; |
7151f3f7 |
|
81d882d5 |
/* If we ever exceed this, we must be more selective */ |
db1b4d96 |
const EVP_CIPHER *cipher_list[1000]; |
81d882d5 |
size_t num_ciphers = 0; |
7151f3f7 |
#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 use as a\n"
"parameter to the --cipher option. The default key size is\n"
"shown as well as whether or not it can be changed with the\n"
"--keysize directive. Using a CBC or GCM mode is recommended.\n"
"In static key mode only CBC mode is allowed.\n\n"); |
7151f3f7 |
#endif
|
81d882d5 |
for (nid = 0; nid < 10000; ++nid) |
7151f3f7 |
{ |
81d882d5 |
const EVP_CIPHER *cipher = EVP_get_cipherbynid(nid);
if (cipher && (cipher_kt_mode_cbc(cipher) |
c353af2f |
#ifdef ENABLE_OFB_CFB_MODE |
81d882d5 |
|| cipher_kt_mode_ofb_cfb(cipher) |
7151f3f7 |
#endif |
66407e11 |
#ifdef HAVE_AEAD_CIPHER_MODES |
81d882d5 |
|| cipher_kt_mode_aead(cipher) |
66407e11 |
#endif |
81d882d5 |
))
{
cipher_list[num_ciphers++] = cipher;
} |
db1b4d96 |
if (num_ciphers == (sizeof(cipher_list)/sizeof(*cipher_list))) |
81d882d5 |
{
msg(M_WARN, "WARNING: Too many ciphers, not showing all");
break;
} |
7151f3f7 |
} |
c94b3ff0 |
|
81d882d5 |
qsort(cipher_list, num_ciphers, sizeof(*cipher_list), cipher_name_cmp); |
c94b3ff0 |
|
81d882d5 |
for (i = 0; i < num_ciphers; i++) { |
6d0d0af9 |
if (!cipher_kt_insecure(cipher_list[i])) |
81d882d5 |
{
print_cipher(cipher_list[i]);
}
} |
c94b3ff0 |
|
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");
for (i = 0; i < num_ciphers; i++) { |
6d0d0af9 |
if (cipher_kt_insecure(cipher_list[i])) |
81d882d5 |
{
print_cipher(cipher_list[i]);
}
}
printf("\n"); |
7151f3f7 |
}
void |
e2a0cad4 |
show_available_digests(void) |
7151f3f7 |
{ |
81d882d5 |
int nid; |
7151f3f7 |
#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"); |
7151f3f7 |
#endif
|
81d882d5 |
for (nid = 0; nid < 10000; ++nid) |
7151f3f7 |
{ |
81d882d5 |
const EVP_MD *digest = EVP_get_digestbynid(nid);
if (digest)
{
printf("%s %d bit digest size\n",
OBJ_nid2sn(nid), EVP_MD_size(digest) * 8);
} |
7151f3f7 |
} |
81d882d5 |
printf("\n"); |
7151f3f7 |
}
void |
e2a0cad4 |
show_available_engines(void) |
7151f3f7 |
{ |
9b33b5a4 |
#if HAVE_OPENSSL_ENGINE /* Only defined for OpenSSL */ |
81d882d5 |
ENGINE *e; |
7151f3f7 |
|
81d882d5 |
printf("OpenSSL Crypto Engines\n\n"); |
7151f3f7 |
|
81d882d5 |
ENGINE_load_builtin_engines(); |
7151f3f7 |
|
81d882d5 |
e = ENGINE_get_first();
while (e) |
7151f3f7 |
{ |
81d882d5 |
printf("%s [%s]\n",
ENGINE_get_name(e),
ENGINE_get_id(e));
e = ENGINE_get_next(e); |
7151f3f7 |
} |
81d882d5 |
ENGINE_cleanup();
#else /* if HAVE_OPENSSL_ENGINE */
printf("Sorry, OpenSSL hardware crypto engine functionality is not available.\n"); |
7151f3f7 |
#endif
}
|
a5d35a01 |
bool
crypto_pem_encode(const char *name, struct buffer *dst,
const struct buffer *src, struct gc_arena *gc)
{
bool ret = false;
BIO *bio = BIO_new(BIO_s_mem());
if (!bio || !PEM_write_bio(bio, name, "", BPTR(src), BLEN(src)))
{
ret = false;
goto cleanup;
}
BUF_MEM *bptr;
BIO_get_mem_ptr(bio, &bptr);
*dst = alloc_buf_gc(bptr->length, gc);
ASSERT(buf_write(dst, bptr->data, bptr->length));
ret = true;
cleanup:
if (!BIO_free(bio))
{
ret = false;;
}
return ret;
}
bool
crypto_pem_decode(const char *name, struct buffer *dst,
const struct buffer *src)
{
bool ret = false;
BIO *bio = BIO_new_mem_buf((char *)BPTR(src), BLEN(src));
if (!bio)
{
crypto_msg(M_FATAL, "Cannot open memory BIO for PEM decode");
}
char *name_read = NULL;
char *header_read = NULL;
uint8_t *data_read = NULL;
long data_read_len = 0;
if (!PEM_read_bio(bio, &name_read, &header_read, &data_read,
&data_read_len))
{
dmsg(D_CRYPT_ERRORS, "%s: PEM decode failed", __func__);
goto cleanup;
}
if (strcmp(name, name_read))
{
dmsg(D_CRYPT_ERRORS,
"%s: unexpected PEM name (got '%s', expected '%s')",
__func__, name_read, name);
goto cleanup;
}
uint8_t *dst_data = buf_write_alloc(dst, data_read_len);
if (!dst_data)
{
dmsg(D_CRYPT_ERRORS, "%s: dst too small (%i, needs %li)", __func__,
BCAP(dst), data_read_len);
goto cleanup;
}
memcpy(dst_data, data_read, data_read_len);
ret = true;
cleanup:
OPENSSL_free(name_read);
OPENSSL_free(header_read);
OPENSSL_free(data_read);
if (!BIO_free(bio))
{
ret = false;;
}
return ret;
}
|
7151f3f7 |
/*
* |
6825182b |
* 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.
*
*/
|
81d882d5 |
int
rand_bytes(uint8_t *output, int len) |
6825182b |
{ |
81d882d5 |
if (unlikely(1 != RAND_bytes(output, len))) |
756602e7 |
{ |
81d882d5 |
crypto_msg(D_CRYPT_ERRORS, "RAND_bytes() failed");
return 0; |
756602e7 |
} |
81d882d5 |
return 1; |
6825182b |
}
|
183c3d19 |
/*
*
* Key functions, allow manipulation of keys.
*
*/
int |
81d882d5 |
key_des_num_cblocks(const EVP_CIPHER *kt) |
183c3d19 |
{ |
81d882d5 |
int ret = 0;
const char *name = OBJ_nid2sn(EVP_CIPHER_nid(kt));
if (name) |
183c3d19 |
{ |
81d882d5 |
if (!strncmp(name, "DES-", 4))
{
ret = EVP_CIPHER_key_length(kt) / sizeof(DES_cblock);
}
else if (!strncmp(name, "DESX-", 5))
{
ret = 1;
} |
183c3d19 |
} |
81d882d5 |
dmsg(D_CRYPTO_DEBUG, "CRYPTO INFO: n_DES_cblocks=%d", ret);
return ret; |
183c3d19 |
}
bool |
81d882d5 |
key_des_check(uint8_t *key, int key_len, int ndc) |
183c3d19 |
{ |
81d882d5 |
int i;
struct buffer b; |
183c3d19 |
|
81d882d5 |
buf_set_read(&b, key, key_len); |
183c3d19 |
|
81d882d5 |
for (i = 0; i < ndc; ++i) |
183c3d19 |
{ |
81d882d5 |
DES_cblock *dc = (DES_cblock *) buf_read_alloc(&b, sizeof(DES_cblock));
if (!dc)
{
crypto_msg(D_CRYPT_ERRORS,
"CRYPTO INFO: check_key_DES: insufficient key material");
goto err;
}
if (DES_is_weak_key(dc))
{
crypto_msg(D_CRYPT_ERRORS,
"CRYPTO INFO: check_key_DES: weak key detected");
goto err;
}
if (!DES_check_key_parity(dc))
{
crypto_msg(D_CRYPT_ERRORS,
"CRYPTO INFO: check_key_DES: bad parity detected");
goto err;
} |
183c3d19 |
} |
81d882d5 |
return true; |
183c3d19 |
|
81d882d5 |
err:
ERR_clear_error();
return false; |
183c3d19 |
}
void |
81d882d5 |
key_des_fixup(uint8_t *key, int key_len, int ndc) |
183c3d19 |
{ |
81d882d5 |
int i;
struct buffer b; |
183c3d19 |
|
81d882d5 |
buf_set_read(&b, key, key_len);
for (i = 0; i < ndc; ++i) |
183c3d19 |
{ |
81d882d5 |
DES_cblock *dc = (DES_cblock *) buf_read_alloc(&b, sizeof(DES_cblock));
if (!dc)
{
msg(D_CRYPT_ERRORS, "CRYPTO INFO: fixup_key_DES: insufficient key material");
ERR_clear_error();
return;
}
DES_set_odd_parity(dc); |
183c3d19 |
}
} |
4a5a6033 |
|
670f9dd9 |
/*
*
* Generic cipher key type functions
*
*/
const EVP_CIPHER * |
81d882d5 |
cipher_kt_get(const char *ciphername) |
670f9dd9 |
{ |
81d882d5 |
const EVP_CIPHER *cipher = NULL; |
670f9dd9 |
|
81d882d5 |
ASSERT(ciphername); |
670f9dd9 |
|
81d882d5 |
cipher = EVP_get_cipherbyname(ciphername); |
670f9dd9 |
|
81d882d5 |
if (NULL == cipher) |
dc4fa3c4 |
{ |
81d882d5 |
crypto_msg(D_LOW, "Cipher algorithm '%s' not found", ciphername);
return NULL; |
dc4fa3c4 |
}
|
670f9dd9 |
|
81d882d5 |
if (EVP_CIPHER_key_length(cipher) > 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, EVP_CIPHER_key_length(cipher),
MAX_CIPHER_KEY_LENGTH);
return NULL; |
dc4fa3c4 |
} |
670f9dd9 |
|
81d882d5 |
return cipher; |
670f9dd9 |
}
const char * |
81d882d5 |
cipher_kt_name(const EVP_CIPHER *cipher_kt) |
670f9dd9 |
{ |
81d882d5 |
if (NULL == cipher_kt)
{
return "[null-cipher]";
}
return EVP_CIPHER_name(cipher_kt); |
670f9dd9 |
}
int |
81d882d5 |
cipher_kt_key_size(const EVP_CIPHER *cipher_kt) |
670f9dd9 |
{ |
81d882d5 |
return EVP_CIPHER_key_length(cipher_kt); |
670f9dd9 |
}
int |
81d882d5 |
cipher_kt_iv_size(const EVP_CIPHER *cipher_kt) |
670f9dd9 |
{ |
81d882d5 |
return EVP_CIPHER_iv_length(cipher_kt); |
670f9dd9 |
}
int |
4cd4899e |
cipher_kt_block_size(const EVP_CIPHER *cipher)
{
/*
* OpenSSL reports OFB/CFB/GCM cipher block sizes as '1 byte'. To work |
81d882d5 |
* around that, try to replace the mode with 'CBC' and return the block size
* reported for that cipher, if possible. If that doesn't work, just return
* the value reported by OpenSSL.
*/
char *name = NULL;
char *mode_str = NULL;
const char *orig_name = NULL;
const EVP_CIPHER *cbc_cipher = NULL;
int block_size = EVP_CIPHER_block_size(cipher);
orig_name = cipher_kt_name(cipher);
if (!orig_name)
{
goto cleanup;
}
name = string_alloc(translate_cipher_name_to_openvpn(orig_name), NULL);
mode_str = strrchr(name, '-');
if (!mode_str || strlen(mode_str) < 4)
{
goto cleanup;
}
strcpy(mode_str, "-CBC");
cbc_cipher = EVP_get_cipherbyname(translate_cipher_name_from_openvpn(name));
if (cbc_cipher)
{
block_size = EVP_CIPHER_block_size(cbc_cipher);
} |
c94b3ff0 |
cleanup: |
81d882d5 |
free(name);
return block_size; |
670f9dd9 |
}
|
6449a149 |
int |
81d882d5 |
cipher_kt_tag_size(const EVP_CIPHER *cipher_kt) |
66407e11 |
{ |
81d882d5 |
if (cipher_kt_mode_aead(cipher_kt))
{
return OPENVPN_AEAD_TAG_LENGTH;
}
else
{
return 0;
} |
66407e11 |
}
|
6d0d0af9 |
bool
cipher_kt_insecure(const EVP_CIPHER *cipher)
{
return !(cipher_kt_block_size(cipher) >= 128 / 8
#ifdef NID_chacha20_poly1305
|| EVP_CIPHER_nid(cipher) == NID_chacha20_poly1305
#endif
);
}
|
66407e11 |
int |
81d882d5 |
cipher_kt_mode(const EVP_CIPHER *cipher_kt) |
670f9dd9 |
{ |
81d882d5 |
ASSERT(NULL != cipher_kt);
return EVP_CIPHER_mode(cipher_kt); |
670f9dd9 |
}
|
a4b27b64 |
bool
cipher_kt_mode_cbc(const cipher_kt_t *cipher)
{ |
81d882d5 |
return cipher && cipher_kt_mode(cipher) == OPENVPN_MODE_CBC |
a4b27b64 |
#ifdef EVP_CIPH_FLAG_AEAD_CIPHER |
81d882d5 |
/* Exclude AEAD cipher modes, they require a different API */
&& !(EVP_CIPHER_flags(cipher) & EVP_CIPH_FLAG_AEAD_CIPHER) |
a4b27b64 |
#endif
;
}
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 |
#ifdef EVP_CIPH_FLAG_AEAD_CIPHER |
81d882d5 |
/* Exclude AEAD cipher modes, they require a different API */
&& !(EVP_CIPHER_flags(cipher) & EVP_CIPH_FLAG_AEAD_CIPHER) |
a4b27b64 |
#endif
;
}
|
66407e11 |
bool
cipher_kt_mode_aead(const cipher_kt_t *cipher)
{
#ifdef HAVE_AEAD_CIPHER_MODES |
6d0d0af9 |
if (cipher)
{
switch (EVP_CIPHER_nid(cipher))
{
case NID_aes_128_gcm:
case NID_aes_192_gcm:
case NID_aes_256_gcm:
#ifdef NID_chacha20_poly1305
case NID_chacha20_poly1305:
#endif
return true;
}
} |
66407e11 |
#endif |
6d0d0af9 |
return false; |
66407e11 |
}
|
485c5f76 |
/*
*
* Generic cipher context functions
*
*/
|
6cbd48a3 |
cipher_ctx_t *
cipher_ctx_new(void)
{
EVP_CIPHER_CTX *ctx = EVP_CIPHER_CTX_new();
check_malloc_return(ctx);
return ctx;
}
void
cipher_ctx_free(EVP_CIPHER_CTX *ctx)
{
EVP_CIPHER_CTX_free(ctx);
} |
485c5f76 |
void |
5e6e4b7d |
cipher_ctx_init(EVP_CIPHER_CTX *ctx, const uint8_t *key, int key_len, |
81d882d5 |
const EVP_CIPHER *kt, int enc) |
485c5f76 |
{ |
81d882d5 |
ASSERT(NULL != kt && NULL != ctx); |
485c5f76 |
|
81d882d5 |
EVP_CIPHER_CTX_init(ctx);
if (!EVP_CipherInit(ctx, kt, NULL, NULL, enc))
{
crypto_msg(M_FATAL, "EVP cipher init #1");
} |
485c5f76 |
#ifdef HAVE_EVP_CIPHER_CTX_SET_KEY_LENGTH |
81d882d5 |
if (!EVP_CIPHER_CTX_set_key_length(ctx, key_len))
{
crypto_msg(M_FATAL, "EVP set key size");
} |
485c5f76 |
#endif |
8d00afae |
if (!EVP_CipherInit_ex(ctx, NULL, NULL, key, NULL, enc)) |
81d882d5 |
{
crypto_msg(M_FATAL, "EVP cipher init #2");
} |
485c5f76 |
|
81d882d5 |
/* make sure we used a big enough key */
ASSERT(EVP_CIPHER_CTX_key_length(ctx) <= key_len); |
485c5f76 |
}
void |
81d882d5 |
cipher_ctx_cleanup(EVP_CIPHER_CTX *ctx) |
485c5f76 |
{ |
81d882d5 |
EVP_CIPHER_CTX_cleanup(ctx); |
485c5f76 |
}
int |
81d882d5 |
cipher_ctx_iv_length(const EVP_CIPHER_CTX *ctx) |
485c5f76 |
{ |
81d882d5 |
return EVP_CIPHER_CTX_iv_length(ctx); |
485c5f76 |
}
|
81d882d5 |
int
cipher_ctx_get_tag(EVP_CIPHER_CTX *ctx, uint8_t *tag_buf, int tag_size) |
66407e11 |
{
#ifdef HAVE_AEAD_CIPHER_MODES |
81d882d5 |
return EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_GCM_GET_TAG, tag_size, tag_buf); |
66407e11 |
#else |
81d882d5 |
ASSERT(0); |
66407e11 |
#endif
}
|
485c5f76 |
int
cipher_ctx_block_size(const EVP_CIPHER_CTX *ctx)
{ |
81d882d5 |
return EVP_CIPHER_CTX_block_size(ctx); |
485c5f76 |
}
int |
81d882d5 |
cipher_ctx_mode(const EVP_CIPHER_CTX *ctx) |
485c5f76 |
{ |
81d882d5 |
return EVP_CIPHER_CTX_mode(ctx); |
485c5f76 |
}
|
a4b27b64 |
const cipher_kt_t * |
81d882d5 |
cipher_ctx_get_cipher_kt(const cipher_ctx_t *ctx) |
a4b27b64 |
{ |
81d882d5 |
return ctx ? EVP_CIPHER_CTX_cipher(ctx) : NULL; |
a4b27b64 |
}
|
485c5f76 |
int |
5e6e4b7d |
cipher_ctx_reset(EVP_CIPHER_CTX *ctx, const uint8_t *iv_buf) |
485c5f76 |
{ |
8d00afae |
return EVP_CipherInit_ex(ctx, NULL, NULL, NULL, iv_buf, -1); |
485c5f76 |
}
int |
81d882d5 |
cipher_ctx_update_ad(EVP_CIPHER_CTX *ctx, const uint8_t *src, int src_len) |
66407e11 |
{
#ifdef HAVE_AEAD_CIPHER_MODES |
81d882d5 |
int len;
if (!EVP_CipherUpdate(ctx, NULL, &len, src, src_len))
{
crypto_msg(M_FATAL, "%s: EVP_CipherUpdate() failed", __func__);
}
return 1;
#else /* ifdef HAVE_AEAD_CIPHER_MODES */
ASSERT(0); |
66407e11 |
#endif
}
int |
81d882d5 |
cipher_ctx_update(EVP_CIPHER_CTX *ctx, uint8_t *dst, int *dst_len,
uint8_t *src, int src_len) |
485c5f76 |
{ |
81d882d5 |
if (!EVP_CipherUpdate(ctx, dst, dst_len, src, src_len))
{
crypto_msg(M_FATAL, "%s: EVP_CipherUpdate() failed", __func__);
}
return 1; |
485c5f76 |
}
int |
81d882d5 |
cipher_ctx_final(EVP_CIPHER_CTX *ctx, uint8_t *dst, int *dst_len) |
485c5f76 |
{ |
81d882d5 |
return EVP_CipherFinal(ctx, dst, dst_len); |
485c5f76 |
}
|
66407e11 |
int |
81d882d5 |
cipher_ctx_final_check_tag(EVP_CIPHER_CTX *ctx, uint8_t *dst, int *dst_len,
uint8_t *tag, size_t tag_len) |
66407e11 |
{
#ifdef HAVE_AEAD_CIPHER_MODES |
81d882d5 |
ASSERT(tag_len < SIZE_MAX);
if (!EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_GCM_SET_TAG, tag_len, tag))
{
return 0;
} |
66407e11 |
|
81d882d5 |
return cipher_ctx_final(ctx, dst, dst_len);
#else /* ifdef HAVE_AEAD_CIPHER_MODES */
ASSERT(0); |
66407e11 |
#endif
} |
485c5f76 |
|
4a5a6033 |
void |
81d882d5 |
cipher_des_encrypt_ecb(const unsigned char key[DES_KEY_LENGTH],
unsigned char *src,
unsigned char *dst) |
4a5a6033 |
{ |
899e9e4c |
DES_key_schedule sched; |
4a5a6033 |
|
81d882d5 |
DES_set_key_unchecked((DES_cblock *)key, &sched); |
6e8b90ec |
DES_ecb_encrypt((DES_cblock *)src, (DES_cblock *)dst, &sched, DES_ENCRYPT); |
4a5a6033 |
} |
902f674e |
/*
*
* Generic message digest information functions
*
*/
const EVP_MD * |
81d882d5 |
md_kt_get(const char *digest)
{
const EVP_MD *md = NULL;
ASSERT(digest);
md = EVP_get_digestbyname(digest);
if (!md)
{
crypto_msg(M_FATAL, "Message hash algorithm '%s' not found", digest);
}
if (EVP_MD_size(md) > MAX_HMAC_KEY_LENGTH) |
98ea2ec5 |
{ |
81d882d5 |
crypto_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, EVP_MD_size(md), MAX_HMAC_KEY_LENGTH); |
98ea2ec5 |
} |
81d882d5 |
return md; |
902f674e |
}
const char * |
81d882d5 |
md_kt_name(const EVP_MD *kt) |
902f674e |
{ |
81d882d5 |
if (NULL == kt)
{
return "[null-digest]";
}
return EVP_MD_name(kt); |
902f674e |
}
int |
81d882d5 |
md_kt_size(const EVP_MD *kt) |
902f674e |
{ |
81d882d5 |
return EVP_MD_size(kt); |
902f674e |
} |
d5f44617 |
/*
*
* Generic message digest functions
*
*/
int |
81d882d5 |
md_full(const EVP_MD *kt, const uint8_t *src, int src_len, uint8_t *dst) |
d5f44617 |
{ |
81d882d5 |
unsigned int in_md_len = 0; |
d5f44617 |
|
81d882d5 |
return EVP_Digest(src, src_len, dst, &in_md_len, kt, NULL); |
d5f44617 |
}
|
c481ef00 |
EVP_MD_CTX *
md_ctx_new(void)
{
EVP_MD_CTX *ctx = EVP_MD_CTX_new();
check_malloc_return(ctx);
return ctx;
}
void md_ctx_free(EVP_MD_CTX *ctx)
{
EVP_MD_CTX_free(ctx);
}
|
d5f44617 |
void |
81d882d5 |
md_ctx_init(EVP_MD_CTX *ctx, const EVP_MD *kt) |
d5f44617 |
{ |
81d882d5 |
ASSERT(NULL != ctx && NULL != kt); |
d5f44617 |
|
81d882d5 |
EVP_MD_CTX_init(ctx);
EVP_DigestInit(ctx, kt); |
d5f44617 |
}
void
md_ctx_cleanup(EVP_MD_CTX *ctx)
{ |
c481ef00 |
EVP_MD_CTX_reset(ctx); |
d5f44617 |
}
int |
81d882d5 |
md_ctx_size(const EVP_MD_CTX *ctx) |
d5f44617 |
{ |
81d882d5 |
return EVP_MD_CTX_size(ctx); |
d5f44617 |
}
void |
81d882d5 |
md_ctx_update(EVP_MD_CTX *ctx, const uint8_t *src, int src_len) |
d5f44617 |
{ |
81d882d5 |
EVP_DigestUpdate(ctx, src, src_len); |
d5f44617 |
}
void |
81d882d5 |
md_ctx_final(EVP_MD_CTX *ctx, uint8_t *dst) |
d5f44617 |
{ |
81d882d5 |
unsigned int in_md_len = 0; |
d5f44617 |
|
81d882d5 |
EVP_DigestFinal(ctx, dst, &in_md_len); |
d5f44617 |
} |
e8c950f1 |
/*
*
* Generic HMAC functions
*
*/
|
aba98e90 |
HMAC_CTX *
hmac_ctx_new(void)
{
HMAC_CTX *ctx = HMAC_CTX_new();
check_malloc_return(ctx);
return ctx;
}
void
hmac_ctx_free(HMAC_CTX *ctx)
{
HMAC_CTX_free(ctx);
} |
e8c950f1 |
void |
81d882d5 |
hmac_ctx_init(HMAC_CTX *ctx, const uint8_t *key, int key_len,
const EVP_MD *kt) |
e8c950f1 |
{ |
81d882d5 |
ASSERT(NULL != kt && NULL != ctx); |
e8c950f1 |
|
64b8a4ae |
HMAC_CTX_reset(ctx); |
81d882d5 |
HMAC_Init_ex(ctx, key, key_len, kt, NULL); |
e8c950f1 |
|
81d882d5 |
/* make sure we used a big enough key */
ASSERT(HMAC_size(ctx) <= key_len); |
e8c950f1 |
}
void
hmac_ctx_cleanup(HMAC_CTX *ctx)
{ |
aba98e90 |
HMAC_CTX_reset(ctx); |
e8c950f1 |
}
int |
81d882d5 |
hmac_ctx_size(const HMAC_CTX *ctx) |
e8c950f1 |
{ |
81d882d5 |
return HMAC_size(ctx); |
e8c950f1 |
}
void |
81d882d5 |
hmac_ctx_reset(HMAC_CTX *ctx) |
e8c950f1 |
{ |
81d882d5 |
HMAC_Init_ex(ctx, NULL, 0, NULL, NULL); |
e8c950f1 |
}
void |
81d882d5 |
hmac_ctx_update(HMAC_CTX *ctx, const uint8_t *src, int src_len) |
e8c950f1 |
{ |
81d882d5 |
HMAC_Update(ctx, src, src_len); |
e8c950f1 |
}
void |
81d882d5 |
hmac_ctx_final(HMAC_CTX *ctx, uint8_t *dst) |
e8c950f1 |
{ |
81d882d5 |
unsigned int in_hmac_len = 0; |
e8c950f1 |
|
81d882d5 |
HMAC_Final(ctx, dst, &in_hmac_len); |
e8c950f1 |
} |
31ea2ee4 |
|
c7ca9133 |
#endif /* ENABLE_CRYPTO_OPENSSL */ |