diff options
Diffstat (limited to 'main/openvpn/src/openvpn/crypto_openssl.c')
-rw-r--r-- | main/openvpn/src/openvpn/crypto_openssl.c | 162 |
1 files changed, 129 insertions, 33 deletions
diff --git a/main/openvpn/src/openvpn/crypto_openssl.c b/main/openvpn/src/openvpn/crypto_openssl.c index 0ac89a19..ef487944 100644 --- a/main/openvpn/src/openvpn/crypto_openssl.c +++ b/main/openvpn/src/openvpn/crypto_openssl.c @@ -45,6 +45,8 @@ #include <openssl/objects.h> #include <openssl/evp.h> #include <openssl/des.h> +#include <openssl/ssl.h> +#include <openssl/err.h> /* * Check for key size creepage. @@ -100,13 +102,14 @@ setup_engine (const char *engine) if ((e = ENGINE_by_id (engine)) == NULL && (e = try_load_engine (engine)) == NULL) { - msg (M_FATAL, "OpenSSL error: cannot load engine '%s'", engine); + crypto_msg (M_FATAL, "OpenSSL error: cannot load engine '%s'", + engine); } if (!ENGINE_set_default (e, ENGINE_METHOD_ALL)) { - msg (M_FATAL, "OpenSSL error: ENGINE_set_default failed on engine '%s'", - engine); + crypto_msg (M_FATAL, "OpenSSL error: ENGINE_set_default failed on " + "engine '%s'", engine); } msg (M_INFO, "Initializing OpenSSL support for engine '%s'", @@ -195,6 +198,26 @@ crypto_clear_error (void) ERR_clear_error (); } +void +crypto_print_openssl_errors(const unsigned int flags) { + size_t err = 0; + + while ((err = ERR_get_error ())) + { + /* Be more clear about frequently occurring "no shared cipher" error */ + if (err == ERR_PACK(ERR_LIB_SSL,SSL_F_SSL3_GET_CLIENT_HELLO, + SSL_R_NO_SHARED_CIPHER)) + { + 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)); + } +} + + /* * * OpenSSL memory debugging. If dmalloc debugging is enabled, tell @@ -231,17 +254,17 @@ crypto_init_dmalloc (void) } #endif /* DMALLOC */ -const char * -translate_cipher_name_from_openvpn (const char *cipher_name) { - // OpenSSL doesn't require any translation - return cipher_name; -} +const cipher_name_pair cipher_name_translation_table[] = { + { "AES-128-CCM", "id-aes128-CCM" }, + { "AES-192-CCM", "id-aes192-CCM" }, + { "AES-256-CCM", "id-aes256-CCM" }, + { "AES-128-GCM", "id-aes128-GCM" }, + { "AES-192-GCM", "id-aes192-GCM" }, + { "AES-256-GCM", "id-aes256-GCM" }, +}; +const size_t cipher_name_translation_table_count = + sizeof (cipher_name_translation_table) / sizeof (*cipher_name_translation_table); -const char * -translate_cipher_name_to_openvpn (const char *cipher_name) { - // OpenSSL doesn't require any translation - return cipher_name; -} void show_available_ciphers () @@ -249,12 +272,12 @@ show_available_ciphers () int nid; #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. In static key mode only CBC mode is allowed.\n\n"); + 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"); #endif for (nid = 0; nid < 10000; ++nid) /* is there a better way to get the size of the nid list? */ @@ -266,17 +289,20 @@ show_available_ciphers () #ifdef ENABLE_OFB_CFB_MODE || cipher_kt_mode_ofb_cfb(cipher) #endif +#ifdef HAVE_AEAD_CIPHER_MODES + || cipher_kt_mode_aead(cipher) +#endif ) { const char *var_key_size = (EVP_CIPHER_flags (cipher) & EVP_CIPH_VARIABLE_LENGTH) ? "variable" : "fixed"; - const char *ssl_only = cipher_kt_mode_ofb_cfb(cipher) ? - " (TLS client/server mode)" : ""; + const char *ssl_only = cipher_kt_mode_cbc(cipher) ? + "" : " (TLS client/server mode)"; - printf ("%s %d bit default key (%s)%s\n", OBJ_nid2sn (nid), - EVP_CIPHER_key_length (cipher) * 8, var_key_size, - ssl_only); + printf ("%s %d bit default key (%s)%s\n", + translate_cipher_name_to_openvpn(OBJ_nid2sn (nid)), + EVP_CIPHER_key_length (cipher) * 8, var_key_size, ssl_only); } } } @@ -386,17 +412,20 @@ key_des_check (uint8_t *key, int key_len, int ndc) DES_cblock *dc = (DES_cblock*) buf_read_alloc (&b, sizeof (DES_cblock)); if (!dc) { - msg (D_CRYPT_ERRORS, "CRYPTO INFO: check_key_DES: insufficient key material"); + msg (D_CRYPT_ERRORS, "CRYPTO INFO: check_key_DES: insufficient key " + "material"); goto err; } if (DES_is_weak_key(dc)) { - msg (D_CRYPT_ERRORS, "CRYPTO INFO: check_key_DES: weak key detected"); + crypto_msg (D_CRYPT_ERRORS, "CRYPTO INFO: check_key_DES: weak key " + "detected"); goto err; } if (!DES_check_key_parity (dc)) { - msg (D_CRYPT_ERRORS, "CRYPTO INFO: check_key_DES: bad parity detected"); + crypto_msg (D_CRYPT_ERRORS, "CRYPTO INFO: check_key_DES: bad parity " + "detected"); goto err; } } @@ -445,7 +474,7 @@ cipher_kt_get (const char *ciphername) cipher = EVP_get_cipherbyname (ciphername); if (NULL == cipher) - msg (M_SSLERR, "Cipher algorithm '%s' not found", ciphername); + crypto_msg (M_FATAL, "Cipher algorithm '%s' not found", ciphername); if (EVP_CIPHER_key_length (cipher) > 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)", @@ -483,6 +512,15 @@ cipher_kt_block_size (const EVP_CIPHER *cipher_kt) } int +cipher_kt_tag_size (const EVP_CIPHER *cipher_kt) +{ + if (cipher_kt_mode_aead(cipher_kt)) + return OPENVPN_AEAD_TAG_LENGTH; + else + return 0; +} + +int cipher_kt_mode (const EVP_CIPHER *cipher_kt) { ASSERT(NULL != cipher_kt); @@ -512,6 +550,17 @@ cipher_kt_mode_ofb_cfb(const cipher_kt_t *cipher) ; } +bool +cipher_kt_mode_aead(const cipher_kt_t *cipher) +{ +#ifdef HAVE_AEAD_CIPHER_MODES + return (cipher_kt_mode(cipher) == OPENVPN_MODE_GCM || + cipher_kt_mode(cipher) == OPENVPN_MODE_CCM); +#else + return false; +#endif +} + /* * * Generic cipher context functions @@ -529,13 +578,13 @@ cipher_ctx_init (EVP_CIPHER_CTX *ctx, uint8_t *key, int key_len, EVP_CIPHER_CTX_init (ctx); if (!EVP_CipherInit (ctx, kt, NULL, NULL, enc)) - msg (M_SSLERR, "EVP cipher init #1"); + crypto_msg (M_FATAL, "EVP cipher init #1"); #ifdef HAVE_EVP_CIPHER_CTX_SET_KEY_LENGTH if (!EVP_CIPHER_CTX_set_key_length (ctx, key_len)) - msg (M_SSLERR, "EVP set key size"); + crypto_msg (M_FATAL, "EVP set key size"); #endif if (!EVP_CipherInit (ctx, NULL, key, NULL, enc)) - msg (M_SSLERR, "EVP cipher init #2"); + crypto_msg (M_FATAL, "EVP cipher init #2"); /* make sure we used a big enough key */ ASSERT (EVP_CIPHER_CTX_key_length (ctx) <= key_len); @@ -553,6 +602,15 @@ cipher_ctx_iv_length (const EVP_CIPHER_CTX *ctx) return EVP_CIPHER_CTX_iv_length (ctx); } +int cipher_ctx_get_tag (EVP_CIPHER_CTX *ctx, uint8_t *tag_buf, int tag_size) +{ +#ifdef HAVE_AEAD_CIPHER_MODES + return EVP_CIPHER_CTX_ctrl (ctx, EVP_CTRL_GCM_GET_TAG, tag_size, tag_buf); +#else + ASSERT (0); +#endif +} + int cipher_ctx_block_size(const EVP_CIPHER_CTX *ctx) { @@ -579,6 +637,17 @@ cipher_ctx_reset (EVP_CIPHER_CTX *ctx, uint8_t *iv_buf) } int +cipher_ctx_update_ad (EVP_CIPHER_CTX *ctx, uint8_t* src, int src_len) +{ +#ifdef HAVE_AEAD_CIPHER_MODES + int len; + return EVP_CipherUpdate (ctx, NULL, &len, src, src_len); +#else + ASSERT (0); +#endif +} + +int cipher_ctx_update (EVP_CIPHER_CTX *ctx, uint8_t *dst, int *dst_len, uint8_t *src, int src_len) { @@ -591,6 +660,21 @@ cipher_ctx_final (EVP_CIPHER_CTX *ctx, uint8_t *dst, int *dst_len) return EVP_CipherFinal (ctx, dst, dst_len); } +int +cipher_ctx_final_check_tag (EVP_CIPHER_CTX *ctx, uint8_t *dst, int *dst_len, + const uint8_t *tag, size_t tag_len) +{ +#ifdef HAVE_AEAD_CIPHER_MODES + /* Setting a tag does not change the tag, so casting away const... */ + if (!EVP_CIPHER_CTX_ctrl (ctx, EVP_CTRL_GCM_SET_TAG, tag_len, + (uint8_t *) tag)) + return 0; + + return cipher_ctx_final (ctx, dst, dst_len); +#else + ASSERT (0); +#endif +} void cipher_des_encrypt_ecb (const unsigned char key[DES_KEY_LENGTH], @@ -617,9 +701,11 @@ md_kt_get (const char *digest) ASSERT (digest); md = EVP_get_digestbyname (digest); if (!md) - msg (M_SSLERR, "Message hash algorithm '%s' not found", digest); + crypto_msg (M_FATAL, "Message hash algorithm '%s' not found", digest); if (EVP_MD_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)", + 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); @@ -747,4 +833,14 @@ hmac_ctx_final (HMAC_CTX *ctx, uint8_t *dst) HMAC_Final (ctx, dst, &in_hmac_len); } +bool +crypto_aead_mode (int mode) +{ +#ifdef HAVE_AEAD_CIPHER_MODES + return mode == OPENVPN_MODE_CCM || mode == OPENVPN_MODE_GCM; +#else + return false; +#endif +} + #endif /* ENABLE_CRYPTO && ENABLE_CRYPTO_OPENSSL */ |