diff options
Diffstat (limited to 'src/openvpn/crypto_polarssl.c')
-rw-r--r-- | src/openvpn/crypto_polarssl.c | 605 |
1 files changed, 605 insertions, 0 deletions
diff --git a/src/openvpn/crypto_polarssl.c b/src/openvpn/crypto_polarssl.c new file mode 100644 index 0000000..3978a3c --- /dev/null +++ b/src/openvpn/crypto_polarssl.c @@ -0,0 +1,605 @@ +/* + * OpenVPN -- An application to securely tunnel IP networks + * over a single TCP/UDP port, with support for SSL/TLS-based + * session authentication and key exchange, + * packet encryption, packet authentication, and + * packet compression. + * + * Copyright (C) 2002-2010 OpenVPN Technologies, Inc. <sales@openvpn.net> + * Copyright (C) 2010 Fox Crypto B.V. <openvpn@fox-it.com> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 + * as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program (see the file COPYING included with this + * distribution); if not, write to the Free Software Foundation, Inc., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +/** + * @file Data Channel Cryptography PolarSSL-specific backend interface + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#elif defined(_MSC_VER) +#include "config-msvc.h" +#endif + +#include "syshead.h" + +#if defined(ENABLE_CRYPTO) && defined(ENABLE_CRYPTO_POLARSSL) + +#include "errlevel.h" +#include "basic.h" +#include "buffer.h" +#include "integer.h" +#include "crypto_backend.h" +#include "otime.h" +#include "misc.h" + +#include <polarssl/des.h> +#include <polarssl/md5.h> +#include <polarssl/cipher.h> +#include <polarssl/havege.h> + +#include <polarssl/entropy.h> + +/* + * + * Hardware engine support. Allows loading/unloading of engines. + * + */ + +void +crypto_init_lib_engine (const char *engine_name) +{ + msg (M_WARN, "Note: PolarSSL hardware crypto engine functionality is not " + "available"); +} + +/* + * + * Functions related to the core crypto library + * + */ + +void +crypto_init_lib (void) +{ +} + +void +crypto_uninit_lib (void) +{ +} + +void +crypto_clear_error (void) +{ +} + +#ifdef DMALLOC +void +crypto_init_dmalloc (void) +{ + msg (M_ERR, "Error: dmalloc support is not available for PolarSSL."); +} +#endif /* DMALLOC */ + +void +show_available_ciphers () +{ + const int *ciphers = cipher_list(); + +#ifndef ENABLE_SMALL + printf ("The following ciphers and cipher modes are available\n" + "for use with " PACKAGE_NAME ". Each cipher shown below may be\n" + "used as a parameter to the --cipher option. The default\n" + "key size is shown as well as whether or not it can be\n" + "changed with the --keysize directive. Using a CBC mode\n" + "is recommended.\n\n"); +#endif + + while (*ciphers != 0) + { + const cipher_info_t *info = cipher_info_from_type(*ciphers); + + if (info && info->mode == POLARSSL_MODE_CBC) + printf ("%s %d bit default key\n", + info->name, info->key_length); + + ciphers++; + } + printf ("\n"); +} + +void +show_available_digests () +{ + const int *digests = md_list(); + +#ifndef ENABLE_SMALL + printf ("The following message digests are available for use with\n" + PACKAGE_NAME ". A message digest is used in conjunction with\n" + "the HMAC function, to authenticate received packets.\n" + "You can specify a message digest as parameter to\n" + "the --auth option.\n\n"); +#endif + + while (*digests != 0) + { + const md_info_t *info = md_info_from_type(*digests); + + if (info) + printf ("%s %d bit default key\n", + info->name, info->size * 8); + digests++; + } + printf ("\n"); +} + +void +show_available_engines () +{ + printf ("Sorry, PolarSSL hardware crypto engine functionality is not " + "available\n"); +} + +/* + * + * Random number functions, used in cases where we want + * reasonably strong cryptographic random number generation + * without depleting our entropy pool. Used for random + * IV values and a number of other miscellaneous tasks. + * + */ + +/* + * Initialise the given ctr_drbg context, using a personalisation string and an + * entropy gathering function. + */ +ctr_drbg_context * rand_ctx_get() +{ + static entropy_context ec = {0}; + static ctr_drbg_context cd_ctx = {0}; + static bool rand_initialised = false; + + if (!rand_initialised) + { + struct gc_arena gc = gc_new(); + struct buffer pers_string = alloc_buf_gc(100, &gc); + + /* + * Personalisation string, should be as unique as possible (see NIST + * 800-90 section 8.7.1). We have very little information at this stage. + * Include Program Name, memory address of the context and PID. + */ + buf_printf(&pers_string, "OpenVPN %0u %p %s", platform_getpid(), &cd_ctx, time_string(0, 0, 0, &gc)); + + /* Initialise PolarSSL RNG, and built-in entropy sources */ + entropy_init(&ec); + + if (0 != ctr_drbg_init(&cd_ctx, entropy_func, &ec, BPTR(&pers_string), BLEN(&pers_string))) + msg (M_FATAL, "Failed to initialize random generator"); + + gc_free(&gc); + rand_initialised = true; + } + + return &cd_ctx; +} + +#ifdef ENABLE_PREDICTION_RESISTANCE +void rand_ctx_enable_prediction_resistance() +{ + ctr_drbg_context *cd_ctx = rand_ctx_get(); + + ctr_drbg_set_prediction_resistance(cd_ctx, 1); +} +#endif /* ENABLE_PREDICTION_RESISTANCE */ + +int +rand_bytes (uint8_t *output, int len) +{ + ctr_drbg_context *rng_ctx = rand_ctx_get(); + + while (len > 0) + { + const size_t blen = min_int (len, CTR_DRBG_MAX_REQUEST); + if (0 != ctr_drbg_random(rng_ctx, output, blen)) + return 0; + + output += blen; + len -= blen; + } + + return 1; +} + +/* + * + * Key functions, allow manipulation of keys. + * + */ + + +int +key_des_num_cblocks (const cipher_info_t *kt) +{ + int ret = 0; + if (kt->type == POLARSSL_CIPHER_DES_CBC) + ret = 1; + if (kt->type == POLARSSL_CIPHER_DES_EDE_CBC) + ret = 2; + if (kt->type == POLARSSL_CIPHER_DES_EDE3_CBC) + ret = 3; + + dmsg (D_CRYPTO_DEBUG, "CRYPTO INFO: n_DES_cblocks=%d", ret); + return ret; +} + +bool +key_des_check (uint8_t *key, int key_len, int ndc) +{ + int i; + struct buffer b; + + buf_set_read (&b, key, key_len); + + for (i = 0; i < ndc; ++i) + { + unsigned char *key = buf_read_alloc(&b, DES_KEY_SIZE); + if (!key) + { + msg (D_CRYPT_ERRORS, "CRYPTO INFO: check_key_DES: insufficient key material"); + goto err; + } + if (0 != des_key_check_weak(key)) + { + msg (D_CRYPT_ERRORS, "CRYPTO INFO: check_key_DES: weak key detected"); + goto err; + } + if (0 != des_key_check_key_parity(key)) + { + msg (D_CRYPT_ERRORS, "CRYPTO INFO: check_key_DES: bad parity detected"); + goto err; + } + } + return true; + + err: + return false; +} + +void +key_des_fixup (uint8_t *key, int key_len, int ndc) +{ + int i; + struct buffer b; + + buf_set_read (&b, key, key_len); + for (i = 0; i < ndc; ++i) + { + unsigned char *key = buf_read_alloc(&b, DES_KEY_SIZE); + if (!key) + { + msg (D_CRYPT_ERRORS, "CRYPTO INFO: fixup_key_DES: insufficient key material"); + return; + } + des_key_set_parity(key); + } +} + +/* + * + * Generic cipher key type functions + * + */ + + +const cipher_info_t * +cipher_kt_get (const char *ciphername) +{ + const cipher_info_t *cipher = NULL; + + ASSERT (ciphername); + + cipher = cipher_info_from_string(ciphername); + + if (NULL == cipher) + msg (M_FATAL, "Cipher algorithm '%s' not found", ciphername); + + if (cipher->key_length/8 > MAX_CIPHER_KEY_LENGTH) + msg (M_FATAL, "Cipher algorithm '%s' uses a default key size (%d bytes) which is larger than " PACKAGE_NAME "'s current maximum key size (%d bytes)", + ciphername, + cipher->key_length/8, + MAX_CIPHER_KEY_LENGTH); + + return cipher; +} + +const char * +cipher_kt_name (const cipher_info_t *cipher_kt) +{ + if (NULL == cipher_kt) + return "[null-cipher]"; + return cipher_kt->name; +} + +int +cipher_kt_key_size (const cipher_info_t *cipher_kt) +{ + if (NULL == cipher_kt) + return 0; + return cipher_kt->key_length/8; +} + +int +cipher_kt_iv_size (const cipher_info_t *cipher_kt) +{ + if (NULL == cipher_kt) + return 0; + return cipher_kt->iv_size; +} + +int +cipher_kt_block_size (const cipher_info_t *cipher_kt) +{ + if (NULL == cipher_kt) + return 0; + return cipher_kt->block_size; +} + +int +cipher_kt_mode (const cipher_info_t *cipher_kt) +{ + ASSERT(NULL != cipher_kt); + return cipher_kt->mode; +} + + +/* + * + * Generic cipher context functions + * + */ + + +void +cipher_ctx_init (cipher_context_t *ctx, uint8_t *key, int key_len, + const cipher_info_t *kt, int enc) +{ + ASSERT(NULL != kt && NULL != ctx); + + CLEAR (*ctx); + + if (0 != cipher_init_ctx(ctx, kt)) + msg (M_FATAL, "PolarSSL cipher context init #1"); + + if (0 != cipher_setkey(ctx, key, key_len*8, enc)) + msg (M_FATAL, "PolarSSL cipher set key"); + + /* make sure we used a big enough key */ + ASSERT (ctx->key_length <= key_len*8); +} + +void cipher_ctx_cleanup (cipher_context_t *ctx) +{ + cipher_free_ctx(ctx); +} + +int cipher_ctx_iv_length (const cipher_context_t *ctx) +{ + return cipher_get_iv_size(ctx); +} + +int cipher_ctx_block_size(const cipher_context_t *ctx) +{ + return cipher_get_block_size(ctx); +} + +int cipher_ctx_mode (const cipher_context_t *ctx) +{ + ASSERT(NULL != ctx); + + return cipher_kt_mode(ctx->cipher_info); +} + +int cipher_ctx_reset (cipher_context_t *ctx, uint8_t *iv_buf) +{ + return 0 == cipher_reset(ctx, iv_buf); +} + +int cipher_ctx_update (cipher_context_t *ctx, uint8_t *dst, int *dst_len, + uint8_t *src, int src_len) +{ + int retval = 0; + size_t s_dst_len = *dst_len; + + retval = cipher_update(ctx, src, (size_t)src_len, dst, &s_dst_len); + + *dst_len = s_dst_len; + + return 0 == retval; +} + +int cipher_ctx_final (cipher_context_t *ctx, uint8_t *dst, int *dst_len) +{ + int retval = 0; + size_t s_dst_len = *dst_len; + + retval = cipher_finish(ctx, dst, &s_dst_len); + *dst_len = s_dst_len; + + return 0 == retval; +} + +void +cipher_des_encrypt_ecb (const unsigned char key[DES_KEY_LENGTH], + unsigned char *src, + unsigned char *dst) +{ + des_context ctx; + + des_setkey_enc(&ctx, key); + des_crypt_ecb(&ctx, src, dst); +} + + + +/* + * + * Generic message digest information functions + * + */ + + +const md_info_t * +md_kt_get (const char *digest) +{ + const md_info_t *md = NULL; + ASSERT (digest); + + md = md_info_from_string(digest); + if (!md) + msg (M_FATAL, "Message hash algorithm '%s' not found", digest); + if (md->size > 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, + md->size, + MAX_HMAC_KEY_LENGTH); + return md; +} + +const char * +md_kt_name (const md_info_t *kt) +{ + if (NULL == kt) + return "[null-digest]"; + return md_get_name (kt); +} + +int +md_kt_size (const md_info_t *kt) +{ + if (NULL == kt) + return 0; + return md_get_size(kt); +} + +/* + * + * Generic message digest functions + * + */ + +int +md_full (const md_kt_t *kt, const uint8_t *src, int src_len, uint8_t *dst) +{ + return 0 == md(kt, src, src_len, dst); +} + + +void +md_ctx_init (md_context_t *ctx, const md_info_t *kt) +{ + ASSERT(NULL != ctx && NULL != kt); + + CLEAR(*ctx); + + ASSERT(0 == md_init_ctx(ctx, kt)); + ASSERT(0 == md_starts(ctx)); +} + +void +md_ctx_cleanup(md_context_t *ctx) +{ +} + +int +md_ctx_size (const md_context_t *ctx) +{ + if (NULL == ctx) + return 0; + return md_get_size(ctx->md_info); +} + +void +md_ctx_update (md_context_t *ctx, const uint8_t *src, int src_len) +{ + ASSERT(0 == md_update(ctx, src, src_len)); +} + +void +md_ctx_final (md_context_t *ctx, uint8_t *dst) +{ + ASSERT(0 == md_finish(ctx, dst)); + ASSERT(0 == md_free_ctx(ctx)); +} + + +/* + * + * Generic HMAC functions + * + */ + + +/* + * TODO: re-enable dmsg for crypto debug + */ +void +hmac_ctx_init (md_context_t *ctx, const uint8_t *key, int key_len, const md_info_t *kt) +{ + ASSERT(NULL != kt && NULL != ctx); + + CLEAR(*ctx); + + ASSERT(0 == md_init_ctx(ctx, kt)); + ASSERT(0 == md_hmac_starts(ctx, key, key_len)); + + /* make sure we used a big enough key */ + ASSERT (md_get_size(kt) <= key_len); +} + +void +hmac_ctx_cleanup(md_context_t *ctx) +{ + ASSERT(0 == md_free_ctx(ctx)); +} + +int +hmac_ctx_size (const md_context_t *ctx) +{ + if (NULL == ctx) + return 0; + return md_get_size(ctx->md_info); +} + +void +hmac_ctx_reset (md_context_t *ctx) +{ + ASSERT(0 == md_hmac_reset(ctx)); +} + +void +hmac_ctx_update (md_context_t *ctx, const uint8_t *src, int src_len) +{ + ASSERT(0 == md_hmac_update(ctx, src, src_len)); +} + +void +hmac_ctx_final (md_context_t *ctx, uint8_t *dst) +{ + ASSERT(0 == md_hmac_finish(ctx, dst)); +} + +#endif /* ENABLE_CRYPTO && ENABLE_CRYPTO_POLARSSL */ |