summaryrefslogtreecommitdiff
path: root/main/openvpn/src/openvpn/crypto_openssl.c
diff options
context:
space:
mode:
Diffstat (limited to 'main/openvpn/src/openvpn/crypto_openssl.c')
-rw-r--r--main/openvpn/src/openvpn/crypto_openssl.c162
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 */