summaryrefslogtreecommitdiff
path: root/src/openvpn/ssl.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/openvpn/ssl.c')
-rw-r--r--src/openvpn/ssl.c1132
1 files changed, 717 insertions, 415 deletions
diff --git a/src/openvpn/ssl.c b/src/openvpn/ssl.c
index 9e31c3c..dc06350 100644
--- a/src/openvpn/ssl.c
+++ b/src/openvpn/ssl.c
@@ -35,7 +35,6 @@
* Both the TLS session and the data channel are multiplexed
* over the same TCP/UDP port.
*/
-
#ifdef HAVE_CONFIG_H
#include "config.h"
#elif defined(_MSC_VER)
@@ -45,11 +44,10 @@
#include "syshead.h"
#include "win32.h"
-#if defined(ENABLE_CRYPTO) && defined(ENABLE_SSL)
+#if defined(ENABLE_CRYPTO)
#include "error.h"
#include "common.h"
-#include "integer.h"
#include "socket.h"
#include "misc.h"
#include "fdmisc.h"
@@ -58,9 +56,8 @@
#include "status.h"
#include "gremlin.h"
#include "pkcs11.h"
-#include "list.h"
-#include "base64.h"
#include "route.h"
+#include "tls_crypt.h"
#include "ssl.h"
#include "ssl_verify.h"
@@ -150,6 +147,7 @@ static const tls_cipher_name_pair tls_cipher_name_translation_table[] = {
{"DHE-RSA-CAMELLIA128-SHA", "TLS-DHE-RSA-WITH-CAMELLIA-128-CBC-SHA"},
{"DHE-RSA-CAMELLIA256-SHA256", "TLS-DHE-RSA-WITH-CAMELLIA-256-CBC-SHA256"},
{"DHE-RSA-CAMELLIA256-SHA", "TLS-DHE-RSA-WITH-CAMELLIA-256-CBC-SHA"},
+ {"DHE-RSA-CHACHA20-POLY1305", "TLS-DHE-RSA-WITH-CHACHA20-POLY1305-SHA256"},
{"DHE-RSA-SEED-SHA", "TLS-DHE-RSA-WITH-SEED-CBC-SHA"},
{"DH-RSA-SEED-SHA", "TLS-DH-RSA-WITH-SEED-CBC-SHA"},
{"ECDH-ECDSA-AES128-GCM-SHA256", "TLS-ECDH-ECDSA-WITH-AES-128-GCM-SHA256"},
@@ -178,6 +176,7 @@ static const tls_cipher_name_pair tls_cipher_name_translation_table[] = {
{"ECDHE-ECDSA-CAMELLIA128-SHA", "TLS-ECDHE-ECDSA-WITH-CAMELLIA-128-CBC-SHA"},
{"ECDHE-ECDSA-CAMELLIA256-SHA256", "TLS-ECDHE-ECDSA-WITH-CAMELLIA-256-CBC-SHA256"},
{"ECDHE-ECDSA-CAMELLIA256-SHA", "TLS-ECDHE-ECDSA-WITH-CAMELLIA-256-CBC-SHA"},
+ {"ECDHE-ECDSA-CHACHA20-POLY1305", "TLS-ECDHE-ECDSA-WITH-CHACHA20-POLY1305-SHA256"},
{"ECDHE-ECDSA-DES-CBC3-SHA", "TLS-ECDHE-ECDSA-WITH-3DES-EDE-CBC-SHA"},
{"ECDHE-ECDSA-DES-CBC-SHA", "TLS-ECDHE-ECDSA-WITH-DES-CBC-SHA"},
{"ECDHE-ECDSA-RC4-SHA", "TLS-ECDHE-ECDSA-WITH-RC4-128-SHA"},
@@ -193,6 +192,7 @@ static const tls_cipher_name_pair tls_cipher_name_translation_table[] = {
{"ECDHE-RSA-CAMELLIA128-SHA", "TLS-ECDHE-RSA-WITH-CAMELLIA-128-CBC-SHA"},
{"ECDHE-RSA-CAMELLIA256-SHA256", "TLS-ECDHE-RSA-WITH-CAMELLIA-256-CBC-SHA256"},
{"ECDHE-RSA-CAMELLIA256-SHA", "TLS-ECDHE-RSA-WITH-CAMELLIA-256-CBC-SHA"},
+ {"ECDHE-RSA-CHACHA20-POLY1305", "TLS-ECDHE-RSA-WITH-CHACHA20-POLY1305-SHA256"},
{"ECDHE-RSA-DES-CBC3-SHA", "TLS-ECDHE-RSA-WITH-3DES-EDE-CBC-SHA"},
{"ECDHE-RSA-DES-CBC-SHA", "TLS-ECDHE-RSA-WITH-DES-CBC-SHA"},
{"ECDHE-RSA-RC4-SHA", "TLS-ECDHE-RSA-WITH-RC4-128-SHA"},
@@ -237,21 +237,37 @@ static const tls_cipher_name_pair tls_cipher_name_translation_table[] = {
{"SRP-RSA-AES-128-CBC-SHA", "TLS-SRP-SHA-RSA-WITH-AES-128-CBC-SHA"},
{"SRP-RSA-AES-256-CBC-SHA", "TLS-SRP-SHA-RSA-WITH-AES-256-CBC-SHA"},
#ifdef ENABLE_CRYPTO_OPENSSL
+ /* OpenSSL-specific group names */
{"DEFAULT", "DEFAULT"},
{"ALL", "ALL"},
- {"HIGH", "HIGH"},
- {"MEDIUM", "MEDIUM"},
- {"LOW", "LOW"},
- {"ECDH", "ECDH"},
- {"ECDSA", "ECDSA"},
- {"EDH", "EDH"},
- {"EXP", "EXP"},
- {"RSA", "RSA"},
- {"SRP", "SRP"},
+ {"HIGH", "HIGH"}, {"!HIGH", "!HIGH"},
+ {"MEDIUM", "MEDIUM"}, {"!MEDIUM", "!MEDIUM"},
+ {"LOW", "LOW"}, {"!LOW", "!LOW"},
+ {"ECDH", "ECDH"}, {"!ECDH", "!ECDH"},
+ {"ECDSA", "ECDSA"}, {"!ECDSA", "!ECDSA"},
+ {"EDH", "EDH"}, {"!EDH", "!EDH"},
+ {"EXP", "EXP"}, {"!EXP", "!EXP"},
+ {"RSA", "RSA"}, {"!RSA", "!RSA"},
+ {"kRSA", "kRSA"}, {"!kRSA", "!kRSA"},
+ {"SRP", "SRP"}, {"!SRP", "!SRP"},
#endif
{NULL, NULL}
};
+/**
+ * Update the implicit IV for a key_ctx_bi based on TLS session ids and cipher
+ * used.
+ *
+ * Note that the implicit IV is based on the HMAC key, but only in AEAD modes
+ * where the HMAC key is not used for an actual HMAC.
+ *
+ * @param ctx Encrypt/decrypt key context
+ * @param key HMAC key, used to calculate implicit IV
+ * @param key_len HMAC key length
+ */
+static void
+key_ctx_update_implicit_iv(struct key_ctx *ctx, uint8_t *key, size_t key_len);
+
const tls_cipher_name_pair *
tls_get_cipher_name_pair (const char * cipher_name, size_t len) {
const tls_cipher_name_pair * pair = tls_cipher_name_translation_table;
@@ -268,6 +284,27 @@ tls_get_cipher_name_pair (const char * cipher_name, size_t len) {
return NULL;
}
+/**
+ * Limit the reneg_bytes value when using a small-block (<128 bytes) cipher.
+ *
+ * @param cipher The current cipher (may be NULL).
+ * @param reneg_bytes Pointer to the current reneg_bytes, updated if needed.
+ * May *not* be NULL.
+ */
+static void
+tls_limit_reneg_bytes (const cipher_kt_t *cipher, int *reneg_bytes)
+{
+ if (cipher && (cipher_kt_block_size(cipher) < 128/8))
+ {
+ if (*reneg_bytes == -1) /* Not user-specified */
+ {
+ msg (M_WARN, "WARNING: cipher with small block size in use, "
+ "reducing reneg-bytes to 64MB to mitigate SWEET32 attacks.");
+ *reneg_bytes = 64 * 1024 * 1024;
+ }
+ }
+}
+
/*
* Max number of bytes we will add
* for data structures common to both
@@ -488,12 +525,15 @@ init_ssl (const struct options *options, struct tls_root_ctx *new_ctx)
if (options->tls_server)
{
- tls_ctx_server_new(new_ctx, options->ssl_flags);
- tls_ctx_load_dh_params(new_ctx, options->dh_file, options->dh_file_inline);
+ tls_ctx_server_new(new_ctx);
+
+ if (options->dh_file)
+ tls_ctx_load_dh_params(new_ctx, options->dh_file,
+ options->dh_file_inline);
}
else /* if client */
{
- tls_ctx_client_new(new_ctx, options->ssl_flags);
+ tls_ctx_client_new(new_ctx);
}
tls_ctx_set_options(new_ctx, options->ssl_flags);
@@ -522,10 +562,19 @@ init_ssl (const struct options *options, struct tls_root_ctx *new_ctx)
}
#endif
#ifdef MANAGMENT_EXTERNAL_KEY
- else if ((options->management_flags & MF_EXTERNAL_KEY) && options->cert_file)
- {
- tls_ctx_use_external_private_key(new_ctx, options->cert_file,
- options->cert_file_inline);
+ else if ((options->management_flags & MF_EXTERNAL_KEY) &&
+ (options->cert_file || options->management_flags & MF_EXTERNAL_CERT))
+ {
+ if (options->cert_file) {
+ tls_ctx_use_external_private_key(new_ctx, options->cert_file,
+ options->cert_file_inline);
+ } else {
+ char *external_certificate = management_query_cert(management,
+ options->management_certificate);
+ tls_ctx_use_external_private_key(new_ctx, INLINE_FILE_TAG,
+ external_certificate);
+ free(external_certificate);
+ }
}
#endif
else
@@ -552,7 +601,7 @@ init_ssl (const struct options *options, struct tls_root_ctx *new_ctx)
/* Load extra certificates that are part of our own certificate
chain but shouldn't be included in the verify chain */
- if (options->extra_certs_file || options->extra_certs_file_inline)
+ if (options->extra_certs_file)
{
tls_ctx_load_extra_certs(new_ctx, options->extra_certs_file, options->extra_certs_file_inline);
}
@@ -560,10 +609,20 @@ init_ssl (const struct options *options, struct tls_root_ctx *new_ctx)
/* Check certificate notBefore and notAfter */
tls_ctx_check_cert_time(new_ctx);
+ /* Read CRL */
+ if (options->crl_file && !(options->ssl_flags & SSLF_CRL_VERIFY_DIR))
+ {
+ tls_ctx_reload_crl(new_ctx, options->crl_file, options->crl_file_inline);
+ }
+
+ /* Once keys and cert are loaded, load ECDH parameters */
+ if (options->tls_server)
+ tls_ctx_load_ecdh_params(new_ctx, options->ecdh_curve);
+
/* Allowable ciphers */
tls_ctx_restrict_ciphers(new_ctx, options->cipher_list);
-#ifdef ENABLE_CRYPTO_POLARSSL
+#ifdef ENABLE_CRYPTO_MBEDTLS
/* Personalise the random by mixing in the certificate */
tls_ctx_personalise_random (new_ctx);
#endif
@@ -766,11 +825,17 @@ key_state_init (struct tls_session *session, struct key_state *ks)
reliable_set_timeout (ks->send_reliable, session->opt->packet_timeout);
/* init packet ID tracker */
- packet_id_init (&ks->packet_id,
- session->opt->tcp_mode,
- session->opt->replay_window,
- session->opt->replay_time,
- "SSL", ks->key_id);
+ if (session->opt->replay)
+ {
+ packet_id_init (&ks->crypto_options.packet_id,
+ session->opt->replay_window, session->opt->replay_time, "SSL",
+ ks->key_id);
+ }
+
+ ks->crypto_options.pid_persist = NULL;
+ ks->crypto_options.flags = session->opt->crypto_flags;
+ ks->crypto_options.flags &= session->opt->crypto_flags_and;
+ ks->crypto_options.flags |= session->opt->crypto_flags_or;
#ifdef MANAGEMENT_DEF_AUTH
ks->mda_key_id = session->opt->mda_context->mda_key_id_counter++;
@@ -798,7 +863,7 @@ key_state_free (struct key_state *ks, bool clear)
key_state_ssl_free(&ks->ks_ssl);
- free_key_ctx_bi (&ks->key);
+ free_key_ctx_bi (&ks->crypto_options.key_ctx_bi);
free_buf (&ks->plaintext_read_buf);
free_buf (&ks->plaintext_write_buf);
free_buf (&ks->ack_write_buf);
@@ -822,7 +887,7 @@ key_state_free (struct key_state *ks, bool clear)
if (ks->key_src)
free (ks->key_src);
- packet_id_free (&ks->packet_id);
+ packet_id_free (&ks->crypto_options.packet_id);
#ifdef PLUGIN_DEF_AUTH
key_state_rm_auth_control_file (ks);
@@ -837,11 +902,23 @@ key_state_free (struct key_state *ks, bool clear)
/** @} addtogroup control_processor */
-/*
- * Must be called if we move a tls_session in memory.
+/**
+ * Returns whether or not the server should check for username/password
+ *
+ * @param session The current TLS session
+ *
+ * @return true if username and password verification is enabled,
+ * false if not.
*/
-static inline void tls_session_set_self_referential_pointers (struct tls_session* session) {
- session->tls_auth.packet_id = &session->tls_auth_pid;
+static inline bool
+tls_session_user_pass_enabled(struct tls_session *session)
+{
+ return (session->opt->auth_user_pass_verify_script
+ || plugin_defined (session->opt->plugins, OPENVPN_PLUGIN_AUTH_USER_PASS_VERIFY)
+#ifdef MANAGEMENT_DEF_AUTH
+ || management_enable_def_auth (management)
+#endif
+ );
}
@@ -895,20 +972,18 @@ tls_session_init (struct tls_multi *multi, struct tls_session *session)
}
/* Initialize control channel authentication parameters */
- session->tls_auth = session->opt->tls_auth;
-
- /* Set session internal pointers (also called if session object is moved in memory) */
- tls_session_set_self_referential_pointers (session);
+ session->tls_wrap = session->opt->tls_wrap;
+ session->tls_wrap.work = alloc_buf (TLS_CHANNEL_BUF_SIZE);
/* initialize packet ID replay window for --tls-auth */
- packet_id_init (session->tls_auth.packet_id,
- session->opt->tcp_mode,
+ packet_id_init (&session->tls_wrap.opt.packet_id,
session->opt->replay_window,
session->opt->replay_time,
- "TLS_AUTH", session->key_id);
+ "TLS_WRAP", session->key_id);
/* load most recent packet-id to replay protect on --tls-auth */
- packet_id_persist_load_obj (session->tls_auth.pid_persist, session->tls_auth.packet_id);
+ packet_id_persist_load_obj (session->tls_wrap.opt.pid_persist,
+ &session->tls_wrap.opt.packet_id);
key_state_init (session, &session->key[KS_PRIMARY]);
@@ -935,8 +1010,10 @@ tls_session_free (struct tls_session *session, bool clear)
{
int i;
- if (session->tls_auth.packet_id)
- packet_id_free (session->tls_auth.packet_id);
+ if (packet_id_initialized(&session->tls_wrap.opt.packet_id))
+ packet_id_free (&session->tls_wrap.opt.packet_id);
+
+ free_buf (&session->tls_wrap.work);
for (i = 0; i < KS_SIZE; ++i)
key_state_free (&session->key[i], false);
@@ -967,7 +1044,6 @@ move_session (struct tls_multi* multi, int dest, int src, bool reinit_src)
ASSERT (dest >= 0 && dest < TM_SIZE);
tls_session_free (&multi->session[dest], false);
multi->session[dest] = multi->session[src];
- tls_session_set_self_referential_pointers (&multi->session[dest]);
if (reinit_src)
tls_session_init (multi, &multi->session[src]);
@@ -984,22 +1060,6 @@ reset_session (struct tls_multi *multi, struct tls_session *session)
tls_session_init (multi, session);
}
-#if 0
-/*
- * Transmit a TLS reset on our untrusted channel.
- */
-static void
-initiate_untrusted_session (struct tls_multi *multi, struct sockaddr_in *to)
-{
- struct tls_session *session = &multi->session[TM_UNTRUSTED];
- struct key_state *ks = &session->key[KS_PRIMARY];
-
- reset_session (multi, session);
- ks->remote_addr = *to;
- msg (D_TLS_DEBUG_LOW, "TLS: initiate_untrusted_session: addr=%s", print_sockaddr (to));
-}
-#endif
-
/*
* Used to determine in how many seconds we should be
* called again.
@@ -1048,9 +1108,6 @@ tls_multi_init (struct tls_options *tls_options)
/* get command line derived options */
ret->opt = *tls_options;
- /* set up pointer to HMAC object for TLS packet authentication */
- ret->opt.tls_auth.key_ctx_bi = &ret->opt.tls_auth_key;
-
/* set up list of keys to be scanned by data channel encrypt and decrypt routines */
ASSERT (SIZE (ret->key_scan) == 3);
ret->key_scan[0] = &ret->session[TM_ACTIVE].key[KS_PRIMARY];
@@ -1088,10 +1145,14 @@ tls_auth_standalone_init (struct tls_options *tls_options,
ALLOC_OBJ_CLEAR_GC (tas, struct tls_auth_standalone, gc);
- /* set up pointer to HMAC object for TLS packet authentication */
- tas->tls_auth_key = tls_options->tls_auth_key;
- tas->tls_auth_options.key_ctx_bi = &tas->tls_auth_key;
- tas->tls_auth_options.flags |= CO_PACKET_ID_LONG_FORM;
+ tas->tls_wrap = tls_options->tls_wrap;
+
+ /*
+ * Standalone tls-auth is in read-only mode with respect to TLS
+ * control channel state. After we build a new client instance
+ * object, we will process this session-initiating packet for real.
+ */
+ tas->tls_wrap.opt.flags |= CO_IGNORE_PACKET_ID;
/* get initial frame parms, still need to finalize */
tas->frame = tls_options->frame;
@@ -1136,6 +1197,8 @@ tls_multi_free (struct tls_multi *multi, bool clear)
#ifdef MANAGEMENT_DEF_AUTH
man_def_auth_set_client_reason(multi, NULL);
+#endif
+#if P2MP_SERVER
free (multi->peer_info);
#endif
@@ -1147,6 +1210,12 @@ tls_multi_free (struct tls_multi *multi, bool clear)
cert_hash_free (multi->locked_cert_hash_set);
+ if (multi->auth_token)
+ {
+ memset (multi->auth_token, 0, AUTH_TOKEN_SIZE);
+ free (multi->auth_token);
+ }
+
for (i = 0; i < TM_SIZE; ++i)
tls_session_free (&multi->session[i], false);
@@ -1171,11 +1240,11 @@ tls_multi_free (struct tls_multi *multi, bool clear)
static bool
swap_hmac (struct buffer *buf, const struct crypto_options *co, bool incoming)
{
- struct key_ctx *ctx;
+ const struct key_ctx *ctx;
ASSERT (co);
- ctx = (incoming ? &co->key_ctx_bi->decrypt : &co->key_ctx_bi->encrypt);
+ ctx = (incoming ? &co->key_ctx_bi.decrypt : &co->key_ctx_bi.encrypt);
ASSERT (ctx->hmac);
{
@@ -1230,20 +1299,34 @@ write_control_auth (struct tls_session *session,
int max_ack,
bool prepend_ack)
{
- uint8_t *header;
+ uint8_t header = ks->key_id | (opcode << P_OPCODE_SHIFT);
struct buffer null = clear_buf ();
ASSERT (link_socket_actual_defined (&ks->remote_addr));
ASSERT (reliable_ack_write
(ks->rec_ack, buf, &ks->session_id_remote, max_ack, prepend_ack));
- ASSERT (session_id_write_prepend (&session->session_id, buf));
- ASSERT (header = buf_prepend (buf, 1));
- *header = ks->key_id | (opcode << P_OPCODE_SHIFT);
- if (session->tls_auth.key_ctx_bi->encrypt.hmac)
+
+ if (session->tls_wrap.mode == TLS_WRAP_AUTH ||
+ session->tls_wrap.mode == TLS_WRAP_NONE)
+ {
+ ASSERT (session_id_write_prepend (&session->session_id, buf));
+ ASSERT (buf_write_prepend (buf, &header, sizeof(header)));
+ }
+ if (session->tls_wrap.mode == TLS_WRAP_AUTH)
{
/* no encryption, only write hmac */
- openvpn_encrypt (buf, null, &session->tls_auth, NULL);
- ASSERT (swap_hmac (buf, &session->tls_auth, false));
+ openvpn_encrypt (buf, null, &session->tls_wrap.opt);
+ ASSERT (swap_hmac (buf, &session->tls_wrap.opt, false));
+ }
+ else if (session->tls_wrap.mode == TLS_WRAP_CRYPT)
+ {
+ buf_init (&session->tls_wrap.work, buf->offset);
+ ASSERT (buf_write (&session->tls_wrap.work, &header, sizeof(header)));
+ ASSERT (session_id_write (&session->session_id, &session->tls_wrap.work));
+ ASSERT (tls_crypt_wrap (buf, &session->tls_wrap.work, &session->tls_wrap.opt));
+ /* Don't change the original data in buf, it's used by the reliability
+ * layer to resend on failure. */
+ *buf = session->tls_wrap.work;
}
*to_link_addr = &ks->remote_addr;
}
@@ -1253,17 +1336,18 @@ write_control_auth (struct tls_session *session,
*/
static bool
read_control_auth (struct buffer *buf,
- const struct crypto_options *co,
+ struct tls_wrap_ctx *ctx,
const struct link_socket_actual *from)
{
struct gc_arena gc = gc_new ();
+ bool ret = false;
- if (co->key_ctx_bi->decrypt.hmac)
+ if (ctx->mode == TLS_WRAP_AUTH)
{
struct buffer null = clear_buf ();
/* move the hmac record to the front of the packet */
- if (!swap_hmac (buf, co, true))
+ if (!swap_hmac (buf, &ctx->opt, true))
{
msg (D_TLS_ERRORS,
"TLS Error: cannot locate HMAC in incoming packet from %s",
@@ -1274,24 +1358,41 @@ read_control_auth (struct buffer *buf,
/* authenticate only (no decrypt) and remove the hmac record
from the head of the buffer */
- openvpn_decrypt (buf, null, co, NULL);
+ openvpn_decrypt (buf, null, &ctx->opt, NULL, BPTR (buf));
if (!buf->len)
{
msg (D_TLS_ERRORS,
"TLS Error: incoming packet authentication failed from %s",
print_link_socket_actual (from, &gc));
- gc_free (&gc);
- return false;
+ goto cleanup;
}
}
+ else if (ctx->mode == TLS_WRAP_CRYPT)
+ {
+ struct buffer tmp = alloc_buf (buf_forward_capacity_total (buf));
+ if (!tls_crypt_unwrap (buf, &tmp, &ctx->opt))
+ {
+ msg (D_TLS_ERRORS, "TLS Error: tls-crypt unwrapping failed from %s",
+ print_link_socket_actual (from, &gc));
+ goto cleanup;
+ }
+ ASSERT (buf_init (buf, buf->offset));
+ ASSERT (buf_copy (buf, &tmp));
+ free_buf (&tmp);
+ }
- /* advance buffer pointer past opcode & session_id since our caller
- already read it */
- buf_advance (buf, SID_SIZE + 1);
+ if (ctx->mode == TLS_WRAP_NONE || ctx->mode == TLS_WRAP_AUTH)
+ {
+ /* advance buffer pointer past opcode & session_id since our caller
+ already read it */
+ buf_advance (buf, SID_SIZE + 1);
+ }
+ ret = true;
+cleanup:
gc_free (&gc);
- return true;
+ return ret;
}
/*
@@ -1352,7 +1453,7 @@ tls1_P_hash(const md_kt_t *md_kt,
int olen)
{
struct gc_arena gc = gc_new ();
- int chunk,n;
+ int chunk;
hmac_ctx_t ctx;
hmac_ctx_t ctx_tmp;
uint8_t A1[MAX_HMAC_KEY_LENGTH];
@@ -1378,7 +1479,6 @@ tls1_P_hash(const md_kt_t *md_kt,
hmac_ctx_update(&ctx,seed,seed_len);
hmac_ctx_final(&ctx, A1);
- n=0;
for (;;)
{
hmac_ctx_reset(&ctx);
@@ -1429,7 +1529,7 @@ tls1_P_hash(const md_kt_t *md_kt,
* (2) The pre-master secret is generated by the client.
*/
static void
-tls1_PRF(uint8_t *label,
+tls1_PRF(const uint8_t *label,
int label_len,
const uint8_t *sec,
int slen,
@@ -1581,6 +1681,13 @@ generate_key_expansion (struct key_ctx_bi *key,
OPENVPN_OP_DECRYPT,
"Data Channel Decrypt");
+ /* Initialize implicit IVs */
+ key_ctx_update_implicit_iv (&key->encrypt, key2.keys[(int)server].hmac,
+ MAX_HMAC_KEY_LENGTH);
+ key_ctx_update_implicit_iv (&key->decrypt, key2.keys[1-(int)server].hmac,
+ MAX_HMAC_KEY_LENGTH);
+
+ key->initialized = true;
ret = true;
exit:
@@ -1590,6 +1697,96 @@ generate_key_expansion (struct key_ctx_bi *key,
return ret;
}
+static void
+key_ctx_update_implicit_iv(struct key_ctx *ctx, uint8_t *key, size_t key_len) {
+ const cipher_kt_t *cipher_kt = cipher_ctx_get_cipher_kt (ctx->cipher);
+
+ /* Only use implicit IV in AEAD cipher mode, where HMAC key is not used */
+ if (cipher_kt_mode_aead (cipher_kt))
+ {
+ size_t impl_iv_len = 0;
+ ASSERT (cipher_kt_iv_size (cipher_kt) >= OPENVPN_AEAD_MIN_IV_LEN);
+ impl_iv_len = cipher_kt_iv_size (cipher_kt) - sizeof (packet_id_type);
+ ASSERT (impl_iv_len <= OPENVPN_MAX_IV_LENGTH);
+ ASSERT (impl_iv_len <= key_len);
+ memcpy (ctx->implicit_iv, key, impl_iv_len);
+ ctx->implicit_iv_len = impl_iv_len;
+ }
+}
+
+static bool
+item_in_list(const char *item, const char *list)
+{
+ char *tmp_ciphers = string_alloc (list, NULL);
+ char *tmp_ciphers_orig = tmp_ciphers;
+
+ const char *token = strtok (tmp_ciphers, ":");
+ while(token)
+ {
+ if (0 == strcmp (token, item))
+ break;
+ token = strtok (NULL, ":");
+ }
+ free(tmp_ciphers_orig);
+
+ return token != NULL;
+}
+
+bool
+tls_session_update_crypto_params(struct tls_session *session,
+ const struct options *options, struct frame *frame)
+{
+ bool ret = false;
+ struct key_state *ks = &session->key[KS_PRIMARY]; /* primary key */
+
+ ASSERT (ks->authenticated);
+
+ if (!session->opt->server &&
+ 0 != strcmp(options->ciphername, session->opt->config_ciphername) &&
+ !item_in_list(options->ciphername, options->ncp_ciphers))
+ {
+ msg (D_TLS_ERRORS, "Error: pushed cipher not allowed - %s not in %s or %s",
+ options->ciphername, session->opt->config_ciphername,
+ options->ncp_ciphers);
+ return false;
+ }
+
+ init_key_type (&session->opt->key_type, options->ciphername,
+ options->authname, options->keysize, true, true);
+
+ bool packet_id_long_form = cipher_kt_mode_ofb_cfb (session->opt->key_type.cipher);
+ session->opt->crypto_flags_and &= ~(CO_PACKET_ID_LONG_FORM);
+ if (packet_id_long_form)
+ session->opt->crypto_flags_and = CO_PACKET_ID_LONG_FORM;
+
+ /* Update frame parameters: undo worst-case overhead, add actual overhead */
+ frame_add_to_extra_frame (frame, -(crypto_max_overhead()));
+ crypto_adjust_frame_parameters (frame, &session->opt->key_type,
+ options->use_iv, options->replay, packet_id_long_form);
+ frame_finalize(frame, options->ce.link_mtu_defined, options->ce.link_mtu,
+ options->ce.tun_mtu_defined, options->ce.tun_mtu);
+ frame_init_mssfix(frame, options);
+ frame_print (frame, D_MTU_INFO, "Data Channel MTU parms");
+
+ const struct session_id *client_sid = session->opt->server ?
+ &ks->session_id_remote : &session->session_id;
+ const struct session_id *server_sid = !session->opt->server ?
+ &ks->session_id_remote : &session->session_id;
+ if (!generate_key_expansion (&ks->crypto_options.key_ctx_bi,
+ &session->opt->key_type, ks->key_src, client_sid, server_sid,
+ session->opt->server))
+ {
+ msg (D_TLS_ERRORS, "TLS Error: server generate_key_expansion failed");
+ goto cleanup;
+ }
+ tls_limit_reneg_bytes (session->opt->key_type.cipher,
+ &session->opt->renegotiate_bytes);
+ ret = true;
+cleanup:
+ CLEAR (*ks->key_src);
+ return ret;
+}
+
static bool
random_bytes_to_buf (struct buffer *buf,
uint8_t *out,
@@ -1762,7 +1959,6 @@ key_method_1_write (struct buffer *buf, struct tls_session *session)
{
struct key key;
struct key_state *ks = &session->key[KS_PRIMARY]; /* primary key */
- struct key_state *ks_lame = &session->key[KS_LAME_DUCK]; /* retiring key */
ASSERT (session->opt->key_method == 1);
ASSERT (buf_init (buf, 0));
@@ -1780,8 +1976,9 @@ key_method_1_write (struct buffer *buf, struct tls_session *session)
return false;
}
- init_key_ctx (&ks->key.encrypt, &key, &session->opt->key_type,
- OPENVPN_OP_ENCRYPT, "Data Channel Encrypt");
+ init_key_ctx (&ks->crypto_options.key_ctx_bi.encrypt, &key,
+ &session->opt->key_type, OPENVPN_OP_ENCRYPT,
+ "Data Channel Encrypt");
CLEAR (key);
/* send local options string */
@@ -1827,17 +2024,30 @@ push_peer_info(struct buffer *buf, struct tls_session *session)
buf_printf (&out, "IV_PLAT=netbsd\n");
#elif defined(TARGET_FREEBSD)
buf_printf (&out, "IV_PLAT=freebsd\n");
-#elif defined(WIN32)
+#elif defined(TARGET_ANDROID)
+ buf_printf (&out, "IV_PLAT=android\n");
+#elif defined(_WIN32)
buf_printf (&out, "IV_PLAT=win\n");
#endif
- /* push LZO status */
-#ifdef ENABLE_LZO_STUB
- buf_printf (&out, "IV_LZO_STUB=1\n");
-#endif
/* support for P_DATA_V2 */
buf_printf(&out, "IV_PROTO=2\n");
+ /* support for Negotiable Crypto Paramters */
+ if (session->opt->ncp_enabled &&
+ (session->opt->mode == MODE_SERVER || session->opt->pull))
+ {
+ buf_printf(&out, "IV_NCP=2\n");
+ }
+
+ /* push compression status */
+#ifdef USE_COMP
+ comp_generate_peer_info_string(&session->opt->comp_options, &out);
+#endif
+
+ /* support for redirecting IPv6 gateway */
+ buf_printf(&out, "IV_RGI6=1\n");
+
if (session->opt->push_peer_info_detail >= 2)
{
/* push mac addr */
@@ -1846,17 +2056,19 @@ push_peer_info(struct buffer *buf, struct tls_session *session)
if (rgi.flags & RGI_HWADDR_DEFINED)
buf_printf (&out, "IV_HWADDR=%s\n", format_hex_ex (rgi.hwaddr, 6, 0, 1, ":", &gc));
buf_printf (&out, "IV_SSL=%s\n", get_ssl_library_version() );
-#if defined(WIN32)
+#if defined(_WIN32)
buf_printf (&out, "IV_PLAT_VER=%s\n", win32_version_string (&gc, false));
#endif
}
- /* push env vars that begin with UV_ and IV_GUI_VER */
+ /* push env vars that begin with UV_, IV_PLAT_VER and IV_GUI_VER */
for (e=es->list; e != NULL; e=e->next)
{
if (e->string)
{
- if (((strncmp(e->string, "UV_", 3)==0 && session->opt->push_peer_info_detail >= 2)
+ if ((((strncmp(e->string, "UV_", 3)==0 ||
+ strncmp(e->string, "IV_PLAT_VER=", sizeof("IV_PLAT_VER=")-1)==0)
+ && session->opt->push_peer_info_detail >= 2)
|| (strncmp(e->string,"IV_GUI_VER=",sizeof("IV_GUI_VER=")-1)==0))
&& buf_safe(&out, strlen(e->string)+1))
buf_printf (&out, "%s\n", e->string);
@@ -1883,7 +2095,6 @@ static bool
key_method_2_write (struct buffer *buf, struct tls_session *session)
{
struct key_state *ks = &session->key[KS_PRIMARY]; /* primary key */
- struct key_state *ks_lame = &session->key[KS_LAME_DUCK]; /* retiring key */
ASSERT (session->opt->key_method == 2);
ASSERT (buf_init (buf, 0));
@@ -1931,14 +2142,17 @@ key_method_2_write (struct buffer *buf, struct tls_session *session)
if (!push_peer_info (buf, session))
goto error;
- /*
- * generate tunnel keys if server
+ /* Generate tunnel keys if we're a TLS server.
+ * If we're a p2mp server and IV_NCP >= 2 is negotiated, the first key
+ * generation is postponed until after the pull/push, so we can process pushed
+ * cipher directives.
*/
- if (session->opt->server)
+ if (session->opt->server && !(session->opt->ncp_enabled &&
+ session->opt->mode == MODE_SERVER && ks->key_id <= 0))
{
if (ks->authenticated)
{
- if (!generate_key_expansion (&ks->key,
+ if (!generate_key_expansion (&ks->crypto_options.key_ctx_bi,
&session->opt->key_type,
ks->key_src,
&ks->session_id_remote,
@@ -1951,6 +2165,8 @@ key_method_2_write (struct buffer *buf, struct tls_session *session)
}
CLEAR (*ks->key_src);
+ tls_limit_reneg_bytes (session->opt->key_type.cipher,
+ &session->opt->renegotiate_bytes);
}
return true;
@@ -1967,7 +2183,6 @@ key_method_1_read (struct buffer *buf, struct tls_session *session)
int status;
struct key key;
struct key_state *ks = &session->key[KS_PRIMARY]; /* primary key */
- struct key_state *ks_lame = &session->key[KS_LAME_DUCK]; /* retiring key */
ASSERT (session->opt->key_method == 1);
@@ -2010,8 +2225,9 @@ key_method_1_read (struct buffer *buf, struct tls_session *session)
buf_clear (buf);
- init_key_ctx (&ks->key.decrypt, &key, &session->opt->key_type,
- OPENVPN_OP_DECRYPT, "Data Channel Decrypt");
+ init_key_ctx (&ks->crypto_options.key_ctx_bi.decrypt, &key,
+ &session->opt->key_type, OPENVPN_OP_DECRYPT,
+ "Data Channel Decrypt");
CLEAR (key);
ks->authenticated = true;
return true;
@@ -2026,13 +2242,13 @@ static bool
key_method_2_read (struct buffer *buf, struct tls_multi *multi, struct tls_session *session)
{
struct key_state *ks = &session->key[KS_PRIMARY]; /* primary key */
- struct key_state *ks_lame = &session->key[KS_LAME_DUCK]; /* retiring key */
int key_method_flags;
bool username_status, password_status;
struct gc_arena gc = gc_new ();
char *options;
+ struct user_pass *up;
/* allocate temporary objects */
ALLOC_ARRAY_CLEAR_GC (options, char, TLS_OPTIONS_LEN, &gc);
@@ -2072,15 +2288,31 @@ key_method_2_read (struct buffer *buf, struct tls_multi *multi, struct tls_sessi
ks->authenticated = false;
- if (verify_user_pass_enabled(session))
- {
- /* Perform username/password authentication */
- struct user_pass *up;
+ /* always extract username + password fields from buf, even if not
+ * authenticating for it, because otherwise we can't get at the
+ * peer_info data which follows behind
+ */
+ ALLOC_OBJ_CLEAR_GC (up, struct user_pass, &gc);
+ username_status = read_string (buf, up->username, USER_PASS_LEN);
+ password_status = read_string (buf, up->password, USER_PASS_LEN);
+
+#if P2MP_SERVER
+ /* get peer info from control channel */
+ free (multi->peer_info);
+ multi->peer_info = read_string_alloc (buf);
+ if ( multi->peer_info )
+ output_peer_info_env (session->opt->es, multi->peer_info);
- ALLOC_OBJ_CLEAR_GC (up, struct user_pass, &gc);
- username_status = read_string (buf, up->username, USER_PASS_LEN);
- password_status = read_string (buf, up->password, USER_PASS_LEN);
+ if (tls_peer_info_ncp_ver (multi->peer_info) < 2)
+ {
+ /* Peer does not support NCP */
+ session->opt->ncp_enabled = false;
+ }
+#endif
+ if (tls_session_user_pass_enabled(session))
+ {
+ /* Perform username/password authentication */
if (!username_status || !password_status)
{
CLEAR (*up);
@@ -2091,14 +2323,7 @@ key_method_2_read (struct buffer *buf, struct tls_multi *multi, struct tls_sessi
}
}
-#ifdef MANAGEMENT_DEF_AUTH
- /* get peer info from control channel */
- free (multi->peer_info);
- multi->peer_info = read_string_alloc (buf);
-#endif
-
verify_user_pass(up, multi, session);
- CLEAR (*up);
}
else
{
@@ -2112,6 +2337,9 @@ key_method_2_read (struct buffer *buf, struct tls_multi *multi, struct tls_sessi
ks->authenticated = true;
}
+ /* clear username and password from memory */
+ CLEAR (*up);
+
/* Perform final authentication checks */
if (ks->authenticated)
{
@@ -2140,16 +2368,22 @@ key_method_2_read (struct buffer *buf, struct tls_multi *multi, struct tls_sessi
*/
if (ks->authenticated && plugin_defined (session->opt->plugins, OPENVPN_PLUGIN_TLS_FINAL))
{
+ key_state_export_keying_material(&ks->ks_ssl, session);
+
if (plugin_call (session->opt->plugins, OPENVPN_PLUGIN_TLS_FINAL, NULL, NULL, session->opt->es) != OPENVPN_PLUGIN_FUNC_SUCCESS)
ks->authenticated = false;
+
+ setenv_del (session->opt->es, "exported_keying_material");
}
/*
- * Generate tunnel keys if client
+ * Generate tunnel keys if we're a client.
+ * If --pull is enabled, the first key generation is postponed until after the
+ * pull/push, so we can process pushed cipher directives.
*/
- if (!session->opt->server)
+ if (!session->opt->server && (!session->opt->pull || ks->key_id > 0))
{
- if (!generate_key_expansion (&ks->key,
+ if (!generate_key_expansion (&ks->crypto_options.key_ctx_bi,
&session->opt->key_type,
ks->key_src,
&session->session_id,
@@ -2159,8 +2393,10 @@ key_method_2_read (struct buffer *buf, struct tls_multi *multi, struct tls_sessi
msg (D_TLS_ERRORS, "TLS Error: client generate_key_expansion failed");
goto error;
}
-
+
CLEAR (*ks->key_src);
+ tls_limit_reneg_bytes (session->opt->key_type.cipher,
+ &session->opt->renegotiate_bytes);
}
gc_free (&gc);
@@ -2217,11 +2453,11 @@ tls_process (struct tls_multi *multi,
if (ks->state >= S_ACTIVE &&
((session->opt->renegotiate_seconds
&& now >= ks->established + session->opt->renegotiate_seconds)
- || (session->opt->renegotiate_bytes
+ || (session->opt->renegotiate_bytes > 0
&& ks->n_bytes >= session->opt->renegotiate_bytes)
|| (session->opt->renegotiate_packets
&& ks->n_packets >= session->opt->renegotiate_packets)
- || (packet_id_close_to_wrapping (&ks->packet_id.send))))
+ || (packet_id_close_to_wrapping (&ks->crypto_options.packet_id.send))))
{
msg (D_TLS_DEBUG_LOW,
"TLS: soft reset sec=%d bytes=" counter_format "/%d pkts=" counter_format "/%d",
@@ -2257,269 +2493,274 @@ tls_process (struct tls_multi *multi,
* CHANGED with 2.0 -> now we may send tunnel configuration
* info over the control channel.
*/
- if (true)
+
+ /* Initial handshake */
+ if (ks->state == S_INITIAL)
{
- /* Initial handshake */
- if (ks->state == S_INITIAL)
+ buf = reliable_get_buf_output_sequenced (ks->send_reliable);
+ if (buf)
{
- buf = reliable_get_buf_output_sequenced (ks->send_reliable);
- if (buf)
- {
- ks->must_negotiate = now + session->opt->handshake_window;
- ks->auth_deferred_expire = now + auth_deferred_expire_window (session->opt);
+ ks->must_negotiate = now + session->opt->handshake_window;
+ ks->auth_deferred_expire = now + auth_deferred_expire_window (session->opt);
- /* null buffer */
- reliable_mark_active_outgoing (ks->send_reliable, buf, ks->initial_opcode);
- INCR_GENERATED;
+ /* null buffer */
+ reliable_mark_active_outgoing (ks->send_reliable, buf, ks->initial_opcode);
+ INCR_GENERATED;
- ks->state = S_PRE_START;
- state_change = true;
- dmsg (D_TLS_DEBUG, "TLS: Initial Handshake, sid=%s",
- session_id_print (&session->session_id, &gc));
+ ks->state = S_PRE_START;
+ state_change = true;
+ dmsg (D_TLS_DEBUG, "TLS: Initial Handshake, sid=%s",
+ session_id_print (&session->session_id, &gc));
#ifdef ENABLE_MANAGEMENT
- if (management && ks->initial_opcode != P_CONTROL_SOFT_RESET_V1)
- {
- management_set_state (management,
- OPENVPN_STATE_WAIT,
- NULL,
- 0,
- 0);
- }
-#endif
+ if (management && ks->initial_opcode != P_CONTROL_SOFT_RESET_V1)
+ {
+ management_set_state (management,
+ OPENVPN_STATE_WAIT,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL);
}
+#endif
}
+ }
- /* Are we timed out on receive? */
- if (now >= ks->must_negotiate)
+ /* Are we timed out on receive? */
+ if (now >= ks->must_negotiate)
+ {
+ if (ks->state < S_ACTIVE)
{
- if (ks->state < S_ACTIVE)
- {
- msg (D_TLS_ERRORS,
- "TLS Error: TLS key negotiation failed to occur within %d seconds (check your network connectivity)",
- session->opt->handshake_window);
- goto error;
- }
- else /* assume that ks->state == S_ACTIVE */
- {
- dmsg (D_TLS_DEBUG_MED, "STATE S_NORMAL_OP");
- ks->state = S_NORMAL_OP;
- ks->must_negotiate = 0;
- }
+ msg (D_TLS_ERRORS,
+ "TLS Error: TLS key negotiation failed to occur within %d seconds (check your network connectivity)",
+ session->opt->handshake_window);
+ goto error;
}
+ else /* assume that ks->state == S_ACTIVE */
+ {
+ dmsg (D_TLS_DEBUG_MED, "STATE S_NORMAL_OP");
+ ks->state = S_NORMAL_OP;
+ ks->must_negotiate = 0;
+ }
+ }
- /* Wait for Initial Handshake ACK */
- if (ks->state == S_PRE_START && FULL_SYNC)
+ /* Wait for Initial Handshake ACK */
+ if (ks->state == S_PRE_START && FULL_SYNC)
+ {
+ ks->state = S_START;
+ state_change = true;
+
+ /* Reload the CRL before TLS negotiation */
+ if (session->opt->crl_file &&
+ !(session->opt->ssl_flags & SSLF_CRL_VERIFY_DIR))
{
- ks->state = S_START;
- state_change = true;
- dmsg (D_TLS_DEBUG_MED, "STATE S_START");
+ tls_ctx_reload_crl(&session->opt->ssl_ctx,
+ session->opt->crl_file, session->opt->crl_file_inline);
}
- /* Wait for ACK */
- if (((ks->state == S_GOT_KEY && !session->opt->server) ||
- (ks->state == S_SENT_KEY && session->opt->server)))
+ dmsg (D_TLS_DEBUG_MED, "STATE S_START");
+ }
+
+ /* Wait for ACK */
+ if (((ks->state == S_GOT_KEY && !session->opt->server) ||
+ (ks->state == S_SENT_KEY && session->opt->server)))
+ {
+ if (FULL_SYNC)
{
- if (FULL_SYNC)
- {
- ks->established = now;
- dmsg (D_TLS_DEBUG_MED, "STATE S_ACTIVE");
- if (check_debug_level (D_HANDSHAKE))
- print_details (&ks->ks_ssl, "Control Channel:");
- state_change = true;
- ks->state = S_ACTIVE;
- INCR_SUCCESS;
+ ks->established = now;
+ dmsg (D_TLS_DEBUG_MED, "STATE S_ACTIVE");
+ if (check_debug_level (D_HANDSHAKE))
+ print_details (&ks->ks_ssl, "Control Channel:");
+ state_change = true;
+ ks->state = S_ACTIVE;
+ INCR_SUCCESS;
- /* Set outgoing address for data channel packets */
- link_socket_set_outgoing_addr (NULL, to_link_socket_info, &ks->remote_addr, session->common_name, session->opt->es);
+ /* Set outgoing address for data channel packets */
+ link_socket_set_outgoing_addr (NULL, to_link_socket_info, &ks->remote_addr, session->common_name, session->opt->es);
- /* Flush any payload packets that were buffered before our state transitioned to S_ACTIVE */
- flush_payload_buffer (ks);
+ /* Flush any payload packets that were buffered before our state transitioned to S_ACTIVE */
+ flush_payload_buffer (ks);
#ifdef MEASURE_TLS_HANDSHAKE_STATS
- show_tls_performance_stats();
+ show_tls_performance_stats();
#endif
- }
}
+ }
- /* Reliable buffer to outgoing TCP/UDP (send up to CONTROL_SEND_ACK_MAX ACKs
- for previously received packets) */
- if (!to_link->len && reliable_can_send (ks->send_reliable))
- {
- int opcode;
- struct buffer b;
-
- buf = reliable_send (ks->send_reliable, &opcode);
- ASSERT (buf);
- b = *buf;
- INCR_SENT;
-
- write_control_auth (session, ks, &b, to_link_addr, opcode,
- CONTROL_SEND_ACK_MAX, true);
- *to_link = b;
- active = true;
- state_change = true;
- dmsg (D_TLS_DEBUG, "Reliable -> TCP/UDP");
- break;
- }
+ /* Reliable buffer to outgoing TCP/UDP (send up to CONTROL_SEND_ACK_MAX ACKs
+ for previously received packets) */
+ if (!to_link->len && reliable_can_send (ks->send_reliable))
+ {
+ int opcode;
+ struct buffer b;
+
+ buf = reliable_send (ks->send_reliable, &opcode);
+ ASSERT (buf);
+ b = *buf;
+ INCR_SENT;
+
+ write_control_auth (session, ks, &b, to_link_addr, opcode,
+ CONTROL_SEND_ACK_MAX, true);
+ *to_link = b;
+ active = true;
+ state_change = true;
+ dmsg (D_TLS_DEBUG, "Reliable -> TCP/UDP");
+ break;
+ }
#ifndef TLS_AGGREGATE_ACK
- /* Send 1 or more ACKs (each received control packet gets one ACK) */
- if (!to_link->len && !reliable_ack_empty (ks->rec_ack))
- {
- buf = &ks->ack_write_buf;
- ASSERT (buf_init (buf, FRAME_HEADROOM (&multi->opt.frame)));
- write_control_auth (session, ks, buf, to_link_addr, P_ACK_V1,
- RELIABLE_ACK_SIZE, false);
- *to_link = *buf;
- active = true;
- state_change = true;
- dmsg (D_TLS_DEBUG, "Dedicated ACK -> TCP/UDP");
- break;
- }
+ /* Send 1 or more ACKs (each received control packet gets one ACK) */
+ if (!to_link->len && !reliable_ack_empty (ks->rec_ack))
+ {
+ buf = &ks->ack_write_buf;
+ ASSERT (buf_init (buf, FRAME_HEADROOM (&multi->opt.frame)));
+ write_control_auth (session, ks, buf, to_link_addr, P_ACK_V1,
+ RELIABLE_ACK_SIZE, false);
+ *to_link = *buf;
+ active = true;
+ state_change = true;
+ dmsg (D_TLS_DEBUG, "Dedicated ACK -> TCP/UDP");
+ break;
+ }
#endif
- /* Write incoming ciphertext to TLS object */
- buf = reliable_get_buf_sequenced (ks->rec_reliable);
- if (buf)
- {
- int status = 0;
- if (buf->len)
- {
- status = key_state_write_ciphertext (&ks->ks_ssl, buf);
- if (status == -1)
- {
- msg (D_TLS_ERRORS,
- "TLS Error: Incoming Ciphertext -> TLS object write error");
- goto error;
- }
- }
- else
- {
- status = 1;
- }
- if (status == 1)
- {
- reliable_mark_deleted (ks->rec_reliable, buf, true);
- state_change = true;
- dmsg (D_TLS_DEBUG, "Incoming Ciphertext -> TLS");
- }
- }
-
- /* Read incoming plaintext from TLS object */
- buf = &ks->plaintext_read_buf;
- if (!buf->len)
+ /* Write incoming ciphertext to TLS object */
+ buf = reliable_get_buf_sequenced (ks->rec_reliable);
+ if (buf)
+ {
+ int status = 0;
+ if (buf->len)
{
- int status;
-
- ASSERT (buf_init (buf, 0));
- status = key_state_read_plaintext (&ks->ks_ssl, buf, TLS_CHANNEL_BUF_SIZE);
- update_time ();
+ status = key_state_write_ciphertext (&ks->ks_ssl, buf);
if (status == -1)
{
- msg (D_TLS_ERRORS, "TLS Error: TLS object -> incoming plaintext read error");
+ msg (D_TLS_ERRORS,
+ "TLS Error: Incoming Ciphertext -> TLS object write error");
goto error;
}
- if (status == 1)
- {
- state_change = true;
- dmsg (D_TLS_DEBUG, "TLS -> Incoming Plaintext");
- }
-#if 0 /* show null plaintext reads */
- if (!status)
- msg (M_INFO, "TLS plaintext read -> NULL return");
-#endif
}
-
- /* Send Key */
- buf = &ks->plaintext_write_buf;
- if (!buf->len && ((ks->state == S_START && !session->opt->server) ||
- (ks->state == S_GOT_KEY && session->opt->server)))
+ else
{
- if (session->opt->key_method == 1)
- {
- if (!key_method_1_write (buf, session))
- goto error;
- }
- else if (session->opt->key_method == 2)
- {
- if (!key_method_2_write (buf, session))
- goto error;
- }
- else
- {
- ASSERT (0);
- }
+ status = 1;
+ }
+ if (status == 1)
+ {
+ reliable_mark_deleted (ks->rec_reliable, buf, true);
+ state_change = true;
+ dmsg (D_TLS_DEBUG, "Incoming Ciphertext -> TLS");
+ }
+ }
+
+ /* Read incoming plaintext from TLS object */
+ buf = &ks->plaintext_read_buf;
+ if (!buf->len)
+ {
+ int status;
+ ASSERT (buf_init (buf, 0));
+ status = key_state_read_plaintext (&ks->ks_ssl, buf, TLS_CHANNEL_BUF_SIZE);
+ update_time ();
+ if (status == -1)
+ {
+ msg (D_TLS_ERRORS, "TLS Error: TLS object -> incoming plaintext read error");
+ goto error;
+ }
+ if (status == 1)
+ {
state_change = true;
- dmsg (D_TLS_DEBUG_MED, "STATE S_SENT_KEY");
- ks->state = S_SENT_KEY;
+ dmsg (D_TLS_DEBUG, "TLS -> Incoming Plaintext");
}
+ }
- /* Receive Key */
- buf = &ks->plaintext_read_buf;
- if (buf->len
- && ((ks->state == S_SENT_KEY && !session->opt->server)
- || (ks->state == S_START && session->opt->server)))
+ /* Send Key */
+ buf = &ks->plaintext_write_buf;
+ if (!buf->len && ((ks->state == S_START && !session->opt->server) ||
+ (ks->state == S_GOT_KEY && session->opt->server)))
+ {
+ if (session->opt->key_method == 1)
{
- if (session->opt->key_method == 1)
- {
- if (!key_method_1_read (buf, session))
- goto error;
- }
- else if (session->opt->key_method == 2)
- {
- if (!key_method_2_read (buf, multi, session))
- goto error;
- }
- else
- {
- ASSERT (0);
- }
+ if (!key_method_1_write (buf, session))
+ goto error;
+ }
+ else if (session->opt->key_method == 2)
+ {
+ if (!key_method_2_write (buf, session))
+ goto error;
+ }
+ else
+ {
+ ASSERT (0);
+ }
+
+ state_change = true;
+ dmsg (D_TLS_DEBUG_MED, "STATE S_SENT_KEY");
+ ks->state = S_SENT_KEY;
+ }
+ /* Receive Key */
+ buf = &ks->plaintext_read_buf;
+ if (buf->len
+ && ((ks->state == S_SENT_KEY && !session->opt->server)
+ || (ks->state == S_START && session->opt->server)))
+ {
+ if (session->opt->key_method == 1)
+ {
+ if (!key_method_1_read (buf, session))
+ goto error;
+ }
+ else if (session->opt->key_method == 2)
+ {
+ if (!key_method_2_read (buf, multi, session))
+ goto error;
+ }
+ else
+ {
+ ASSERT (0);
+ }
+
+ state_change = true;
+ dmsg (D_TLS_DEBUG_MED, "STATE S_GOT_KEY");
+ ks->state = S_GOT_KEY;
+ }
+
+ /* Write outgoing plaintext to TLS object */
+ buf = &ks->plaintext_write_buf;
+ if (buf->len)
+ {
+ int status = key_state_write_plaintext (&ks->ks_ssl, buf);
+ if (status == -1)
+ {
+ msg (D_TLS_ERRORS,
+ "TLS ERROR: Outgoing Plaintext -> TLS object write error");
+ goto error;
+ }
+ if (status == 1)
+ {
state_change = true;
- dmsg (D_TLS_DEBUG_MED, "STATE S_GOT_KEY");
- ks->state = S_GOT_KEY;
+ dmsg (D_TLS_DEBUG, "Outgoing Plaintext -> TLS");
}
+ }
- /* Write outgoing plaintext to TLS object */
- buf = &ks->plaintext_write_buf;
- if (buf->len)
+ /* Outgoing Ciphertext to reliable buffer */
+ if (ks->state >= S_START)
+ {
+ buf = reliable_get_buf_output_sequenced (ks->send_reliable);
+ if (buf)
{
- int status = key_state_write_plaintext (&ks->ks_ssl, buf);
+ int status = key_state_read_ciphertext (&ks->ks_ssl, buf, PAYLOAD_SIZE_DYNAMIC (&multi->opt.frame));
if (status == -1)
{
msg (D_TLS_ERRORS,
- "TLS ERROR: Outgoing Plaintext -> TLS object write error");
+ "TLS Error: Ciphertext -> reliable TCP/UDP transport read error");
goto error;
}
if (status == 1)
{
+ reliable_mark_active_outgoing (ks->send_reliable, buf, P_CONTROL_V1);
+ INCR_GENERATED;
state_change = true;
- dmsg (D_TLS_DEBUG, "Outgoing Plaintext -> TLS");
- }
- }
-
- /* Outgoing Ciphertext to reliable buffer */
- if (ks->state >= S_START)
- {
- buf = reliable_get_buf_output_sequenced (ks->send_reliable);
- if (buf)
- {
- int status = key_state_read_ciphertext (&ks->ks_ssl, buf, PAYLOAD_SIZE_DYNAMIC (&multi->opt.frame));
- if (status == -1)
- {
- msg (D_TLS_ERRORS,
- "TLS Error: Ciphertext -> reliable TCP/UDP transport read error");
- goto error;
- }
- if (status == 1)
- {
- reliable_mark_active_outgoing (ks->send_reliable, buf, P_CONTROL_V1);
- INCR_GENERATED;
- state_change = true;
- dmsg (D_TLS_DEBUG, "Outgoing Ciphertext -> Reliable");
- }
+ dmsg (D_TLS_DEBUG, "Outgoing Ciphertext -> Reliable");
}
}
}
@@ -2532,11 +2773,11 @@ tls_process (struct tls_multi *multi,
/* Send 1 or more ACKs (each received control packet gets one ACK) */
if (!to_link->len && !reliable_ack_empty (ks->rec_ack))
{
- buf = &ks->ack_write_buf;
- ASSERT (buf_init (buf, FRAME_HEADROOM (&multi->opt.frame)));
- write_control_auth (session, ks, buf, to_link_addr, P_ACK_V1,
+ struct buffer buf = ks->ack_write_buf;
+ ASSERT (buf_init (&buf, FRAME_HEADROOM (&multi->opt.frame)));
+ write_control_auth (session, ks, &buf, to_link_addr, P_ACK_V1,
RELIABLE_ACK_SIZE, false);
- *to_link = *buf;
+ *to_link = buf;
active = true;
state_change = true;
dmsg (D_TLS_DEBUG, "Dedicated ACK -> TCP/UDP");
@@ -2775,7 +3016,9 @@ bool
tls_pre_decrypt (struct tls_multi *multi,
const struct link_socket_actual *from,
struct buffer *buf,
- struct crypto_options *opt)
+ struct crypto_options **opt,
+ bool floated,
+ const uint8_t **ad_start)
{
struct gc_arena gc = gc_new ();
bool ret = false;
@@ -2819,18 +3062,29 @@ tls_pre_decrypt (struct tls_multi *multi,
#ifdef ENABLE_DEF_AUTH
&& !ks->auth_deferred
#endif
- && link_socket_actual_match (from, &ks->remote_addr))
+ && (floated || link_socket_actual_match (from, &ks->remote_addr)))
{
- /* return appropriate data channel decrypt key in opt */
- opt->key_ctx_bi = &ks->key;
- opt->packet_id = multi->opt.replay ? &ks->packet_id : NULL;
- opt->pid_persist = NULL;
- opt->flags &= multi->opt.crypto_flags_and;
- opt->flags |= multi->opt.crypto_flags_or;
+ if (!ks->crypto_options.key_ctx_bi.initialized)
+ {
+ msg (D_TLS_DEBUG_LOW,
+ "Key %s [%d] not initialized (yet), dropping packet.",
+ print_link_socket_actual (from, &gc), key_id);
+ goto error_lite;
+ }
- ASSERT (buf_advance (buf, 1));
+ /* return appropriate data channel decrypt key in opt */
+ *opt = &ks->crypto_options;
if (op == P_DATA_V2)
{
+ *ad_start = BPTR(buf);
+ }
+ ASSERT (buf_advance (buf, 1));
+ if (op == P_DATA_V1)
+ {
+ *ad_start = BPTR(buf);
+ }
+ else if (op == P_DATA_V2)
+ {
if (buf->len < 4)
{
msg (D_TLS_ERRORS, "Protocol error: received P_DATA_V2 from %s but length is < 4",
@@ -2848,23 +3102,6 @@ tls_pre_decrypt (struct tls_multi *multi,
gc_free (&gc);
return ret;
}
-#if 0 /* keys out of sync? */
- else
- {
- dmsg (D_TLS_ERRORS, "TLS_PRE_DECRYPT: [%d] dken=%d rkid=%d lkid=%d auth=%d def=%d match=%d",
- i,
- DECRYPT_KEY_ENABLED (multi, ks),
- key_id,
- ks->key_id,
- ks->authenticated,
-#ifdef ENABLE_DEF_AUTH
- ks->auth_deferred,
-#else
- -1,
-#endif
- link_socket_actual_match (from, &ks->remote_addr));
- }
-#endif
}
msg (D_TLS_ERRORS,
@@ -2991,8 +3228,10 @@ tls_pre_decrypt (struct tls_multi *multi,
management_set_state (management,
OPENVPN_STATE_AUTH,
NULL,
- 0,
- 0);
+ NULL,
+ NULL,
+ NULL,
+ NULL);
}
#endif
@@ -3036,7 +3275,7 @@ tls_pre_decrypt (struct tls_multi *multi,
goto error;
}
- if (!read_control_auth (buf, &session->tls_auth, from))
+ if (!read_control_auth (buf, &session->tls_wrap, from))
goto error;
/*
@@ -3087,7 +3326,7 @@ tls_pre_decrypt (struct tls_multi *multi,
if (op == P_CONTROL_SOFT_RESET_V1
&& DECRYPT_KEY_ENABLED (multi, ks))
{
- if (!read_control_auth (buf, &session->tls_auth, from))
+ if (!read_control_auth (buf, &session->tls_wrap, from))
goto error;
key_state_soft_reset (session);
@@ -3104,7 +3343,7 @@ tls_pre_decrypt (struct tls_multi *multi,
if (op == P_CONTROL_SOFT_RESET_V1)
do_burst = true;
- if (!read_control_auth (buf, &session->tls_auth, from))
+ if (!read_control_auth (buf, &session->tls_wrap, from))
goto error;
dmsg (D_TLS_DEBUG,
@@ -3215,10 +3454,7 @@ tls_pre_decrypt (struct tls_multi *multi,
done:
buf->len = 0;
- opt->key_ctx_bi = NULL;
- opt->packet_id = NULL;
- opt->pid_persist = NULL;
- opt->flags &= multi->opt.crypto_flags_and;
+ *opt = NULL;
gc_free (&gc);
return ret;
@@ -3297,18 +3533,11 @@ tls_pre_decrypt_lite (const struct tls_auth_standalone *tas,
{
struct buffer newbuf = clone_buf (buf);
- struct crypto_options co = tas->tls_auth_options;
+ struct tls_wrap_ctx tls_wrap_tmp = tas->tls_wrap;
bool status;
- /*
- * We are in read-only mode at this point with respect to TLS
- * control channel state. After we build a new client instance
- * object, we will process this session-initiating packet for real.
- */
- co.flags |= CO_IGNORE_PACKET_ID;
-
/* HMAC test, if --tls-auth was specified */
- status = read_control_auth (&newbuf, &co, from);
+ status = read_control_auth (&newbuf, &tls_wrap_tmp, from);
free_buf (&newbuf);
if (!status)
goto error;
@@ -3344,7 +3573,7 @@ tls_pre_decrypt_lite (const struct tls_auth_standalone *tas,
/* Choose the key with which to encrypt a data packet */
void
tls_pre_encrypt (struct tls_multi *multi,
- struct buffer *buf, struct crypto_options *opt)
+ struct buffer *buf, struct crypto_options **opt)
{
multi->save_ks = NULL;
if (buf->len > 0)
@@ -3356,6 +3585,7 @@ tls_pre_encrypt (struct tls_multi *multi,
struct key_state *ks = multi->key_scan[i];
if (ks->state >= S_ACTIVE
&& ks->authenticated
+ && ks->crypto_options.key_ctx_bi.initialized
#ifdef ENABLE_DEF_AUTH
&& !ks->auth_deferred
#endif
@@ -3373,11 +3603,7 @@ tls_pre_encrypt (struct tls_multi *multi,
if (ks_select)
{
- opt->key_ctx_bi = &ks_select->key;
- opt->packet_id = multi->opt.replay ? &ks_select->packet_id : NULL;
- opt->pid_persist = NULL;
- opt->flags &= multi->opt.crypto_flags_and;
- opt->flags |= multi->opt.crypto_flags_or;
+ *opt = &ks_select->crypto_options;
multi->save_ks = ks_select;
dmsg (D_TLS_KEYSELECT, "TLS: tls_pre_encrypt: key_id=%d", ks_select->key_id);
return;
@@ -3392,36 +3618,48 @@ tls_pre_encrypt (struct tls_multi *multi,
}
buf->len = 0;
- opt->key_ctx_bi = NULL;
- opt->packet_id = NULL;
- opt->pid_persist = NULL;
- opt->flags &= multi->opt.crypto_flags_and;
+ *opt = NULL;
}
-/* Prepend the appropriate opcode to encrypted buffer prior to TCP/UDP send */
void
-tls_post_encrypt (struct tls_multi *multi, struct buffer *buf)
+tls_prepend_opcode_v1 (const struct tls_multi *multi, struct buffer *buf)
{
- struct key_state *ks;
- uint8_t *op;
+ struct key_state *ks = multi->save_ks;
+ uint8_t op;
+
+ msg (D_TLS_DEBUG, __func__);
+
+ ASSERT (ks);
+
+ op = (P_DATA_V1 << P_OPCODE_SHIFT) | ks->key_id;
+ ASSERT (buf_write_prepend (buf, &op, 1));
+}
+
+void
+tls_prepend_opcode_v2 (const struct tls_multi *multi, struct buffer *buf)
+{
+ struct key_state *ks = multi->save_ks;
uint32_t peer;
- ks = multi->save_ks;
+ msg (D_TLS_DEBUG, __func__);
+
+ ASSERT (ks);
+
+ peer = htonl(((P_DATA_V2 << P_OPCODE_SHIFT) | ks->key_id) << 24
+ | (multi->peer_id & 0xFFFFFF));
+ ASSERT (buf_write_prepend (buf, &peer, 4));
+}
+
+void
+tls_post_encrypt (struct tls_multi *multi, struct buffer *buf)
+{
+ struct key_state *ks = multi->save_ks;
multi->save_ks = NULL;
+
if (buf->len > 0)
{
ASSERT (ks);
- if (!multi->opt.server && multi->use_peer_id)
- {
- peer = htonl(((P_DATA_V2 << P_OPCODE_SHIFT) | ks->key_id) << 24 | (multi->peer_id & 0xFFFFFF));
- ASSERT (buf_write_prepend (buf, &peer, 4));
- }
- else
- {
- ASSERT (op = buf_prepend (buf, 1));
- *op = (P_DATA_V1 << P_OPCODE_SHIFT) | ks->key_id;
- }
++ks->n_packets;
ks->n_bytes += buf->len;
}
@@ -3494,6 +3732,70 @@ tls_rec_payload (struct tls_multi *multi,
return ret;
}
+void
+tls_update_remote_addr (struct tls_multi *multi, const struct link_socket_actual *addr)
+{
+ struct gc_arena gc = gc_new ();
+ int i, j;
+
+ for (i = 0; i < TM_SIZE; ++i)
+ {
+ struct tls_session *session = &multi->session[i];
+
+ for (j = 0; j < KS_SIZE; ++j)
+ {
+ struct key_state *ks = &session->key[j];
+
+ if (!link_socket_actual_defined(&ks->remote_addr) ||
+ link_socket_actual_match (addr, &ks->remote_addr))
+ continue;
+
+ dmsg (D_TLS_KEYSELECT, "TLS: tls_update_remote_addr from IP=%s to IP=%s",
+ print_link_socket_actual (&ks->remote_addr, &gc),
+ print_link_socket_actual (addr, &gc));
+
+ ks->remote_addr = *addr;
+ }
+ }
+ gc_free (&gc);
+}
+
+int
+tls_peer_info_ncp_ver(const char *peer_info)
+{
+ const char *ncpstr = peer_info ? strstr (peer_info, "IV_NCP=") : NULL;
+ if (ncpstr)
+ {
+ int ncp = 0;
+ int r = sscanf(ncpstr, "IV_NCP=%d", &ncp);
+ if (r == 1)
+ return ncp;
+ }
+ return 0;
+}
+
+bool
+tls_check_ncp_cipher_list(const char *list) {
+ bool unsupported_cipher_found = false;
+
+ ASSERT (list);
+
+ char * const tmp_ciphers = string_alloc (list, NULL);
+ const char *token = strtok (tmp_ciphers, ":");
+ while (token)
+ {
+ if (!cipher_kt_get (translate_cipher_name_from_openvpn (token)))
+ {
+ msg (M_WARN, "Unsupported cipher in --ncp-ciphers: %s", token);
+ unsupported_cipher_found = true;
+ }
+ token = strtok (NULL, ":");
+ }
+ free (tmp_ciphers);
+
+ return 0 < strlen(list) && !unsupported_cipher_found;
+}
+
/*
* Dump a human-readable rendition of an openvpn packet
* into a garbage collectable string which is returned.
@@ -3594,4 +3896,4 @@ done:
#else
static void dummy(void) {}
-#endif /* ENABLE_CRYPTO && ENABLE_SSL*/
+#endif /* ENABLE_CRYPTO */