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.c1735
1 files changed, 779 insertions, 956 deletions
diff --git a/src/openvpn/ssl.c b/src/openvpn/ssl.c
index cf66899..d66299f 100644
--- a/src/openvpn/ssl.c
+++ b/src/openvpn/ssl.c
@@ -5,9 +5,9 @@
* packet encryption, packet authentication, and
* packet compression.
*
- * Copyright (C) 2002-2018 OpenVPN Inc <sales@openvpn.net>
- * Copyright (C) 2010-2018 Fox Crypto B.V. <openvpn@fox-it.com>
- * Copyright (C) 2008-2013 David Sommerseth <dazo@users.sourceforge.net>
+ * Copyright (C) 2002-2021 OpenVPN Inc <sales@openvpn.net>
+ * Copyright (C) 2010-2021 Fox Crypto B.V. <openvpn@foxcrypto.com>
+ * Copyright (C) 2008-2021 David Sommerseth <dazo@eurephia.org>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2
@@ -43,8 +43,6 @@
#include "syshead.h"
#include "win32.h"
-#if defined(ENABLE_CRYPTO)
-
#include "error.h"
#include "common.h"
#include "socket.h"
@@ -61,23 +59,11 @@
#include "ssl.h"
#include "ssl_verify.h"
#include "ssl_backend.h"
+#include "ssl_ncp.h"
+#include "auth_token.h"
#include "memdbg.h"
-#ifndef ENABLE_OCC
-static const char ssl_default_options_string[] = "V0 UNDEF";
-#endif
-
-static inline const char *
-local_options_string(const struct tls_session *session)
-{
-#ifdef ENABLE_OCC
- return session->opt->local_options;
-#else
- return ssl_default_options_string;
-#endif
-}
-
#ifdef MEASURE_TLS_HANDSHAKE_STATS
static int tls_handshake_success; /* GLOBAL */
@@ -296,7 +282,7 @@ tls_get_cipher_name_pair(const char *cipher_name, size_t len)
static void
tls_limit_reneg_bytes(const cipher_kt_t *cipher, int *reneg_bytes)
{
- if (cipher && (cipher_kt_block_size(cipher) < 128/8))
+ if (cipher && cipher_kt_insecure(cipher))
{
if (*reneg_bytes == -1) /* Not user-specified */
{
@@ -402,7 +388,7 @@ static bool auth_user_pass_enabled; /* GLOBAL */
static struct user_pass auth_user_pass; /* GLOBAL */
static struct user_pass auth_token; /* GLOBAL */
-#ifdef ENABLE_CLIENT_CR
+#ifdef ENABLE_MANAGEMENT
static char *auth_challenge; /* GLOBAL */
#endif
@@ -412,10 +398,7 @@ auth_user_pass_setup(const char *auth_file, const struct static_challenge_info *
auth_user_pass_enabled = true;
if (!auth_user_pass.defined && !auth_token.defined)
{
-#if AUTO_USERID
- get_user_pass_auto_userid(&auth_user_pass, auth_file);
-#else
-#ifdef ENABLE_CLIENT_CR
+#ifdef ENABLE_MANAGEMENT
if (auth_challenge) /* dynamic challenge/response */
{
get_user_pass_cr(&auth_user_pass,
@@ -438,9 +421,8 @@ auth_user_pass_setup(const char *auth_file, const struct static_challenge_info *
sci->challenge_text);
}
else
-#endif /* ifdef ENABLE_CLIENT_CR */
+#endif /* ifdef ENABLE_MANAGEMENT */
get_user_pass(&auth_user_pass, auth_file, UP_TYPE_AUTH, GET_USER_PASS_MANAGEMENT);
-#endif /* if AUTO_USERID */
}
}
@@ -452,8 +434,6 @@ ssl_set_auth_nocache(void)
{
passbuf.nocache = true;
auth_user_pass.nocache = true;
- /* wait for push-reply, because auth-token may still need the username */
- auth_user_pass.wait_for_push = true;
}
/*
@@ -465,11 +445,17 @@ ssl_set_auth_token(const char *token)
set_auth_token(&auth_user_pass, &auth_token, token);
}
+void
+ssl_set_auth_token_user(const char *username)
+{
+ set_auth_token_user(&auth_token, username);
+}
+
/*
* Cleans an auth token and checks if it was active
*/
bool
-ssl_clean_auth_token (void)
+ssl_clean_auth_token(void)
{
bool wasdefined = auth_token.defined;
purge_user_pass(&auth_token, true);
@@ -490,12 +476,12 @@ ssl_purge_auth(const bool auth_user_pass_only)
purge_user_pass(&passbuf, true);
}
purge_user_pass(&auth_user_pass, true);
-#ifdef ENABLE_CLIENT_CR
+#ifdef ENABLE_MANAGEMENT
ssl_purge_auth_challenge();
#endif
}
-#ifdef ENABLE_CLIENT_CR
+#ifdef ENABLE_MANAGEMENT
void
ssl_purge_auth_challenge(void)
@@ -561,7 +547,7 @@ tls_version_parse(const char *vstr, const char *extra)
*/
static void
tls_ctx_reload_crl(struct tls_root_ctx *ssl_ctx, const char *crl_file,
- const char *crl_file_inline)
+ bool crl_file_inline)
{
/* if something goes wrong with stat(), we'll store 0 as mtime */
platform_stat_t crl_stat = {0};
@@ -578,7 +564,15 @@ tls_ctx_reload_crl(struct tls_root_ctx *ssl_ctx, const char *crl_file,
}
else if (platform_stat(crl_file, &crl_stat) < 0)
{
- msg(M_WARN, "WARNING: Failed to stat CRL file, not (re)loading CRL.");
+ /* If crl_last_mtime is zero, the CRL file has not been read before. */
+ if (ssl_ctx->crl_last_mtime == 0)
+ {
+ msg(M_FATAL, "ERROR: Failed to stat CRL file during initialization, exiting.");
+ }
+ else
+ {
+ msg(M_WARN, "WARNING: Failed to stat CRL file, not reloading CRL.");
+ }
return;
}
@@ -603,7 +597,7 @@ tls_ctx_reload_crl(struct tls_root_ctx *ssl_ctx, const char *crl_file,
* All files are in PEM format.
*/
void
-init_ssl(const struct options *options, struct tls_root_ctx *new_ctx)
+init_ssl(const struct options *options, struct tls_root_ctx *new_ctx, bool in_chroot)
{
ASSERT(NULL != new_ctx);
@@ -633,6 +627,12 @@ init_ssl(const struct options *options, struct tls_root_ctx *new_ctx)
tls_ctx_restrict_ciphers(new_ctx, options->cipher_list);
tls_ctx_restrict_ciphers_tls13(new_ctx, options->cipher_list_tls13);
+ /* Set the allow groups/curves for TLS if we want to override them */
+ if (options->tls_groups)
+ {
+ tls_ctx_set_tls_groups(new_ctx, options->tls_groups);
+ }
+
if (!tls_ctx_set_options(new_ctx, options->ssl_flags))
{
goto err;
@@ -663,42 +663,38 @@ init_ssl(const struct options *options, struct tls_root_ctx *new_ctx)
tls_ctx_load_cryptoapi(new_ctx, options->cryptoapi_cert);
}
#endif
-#ifdef MANAGMENT_EXTERNAL_KEY
- else if ((options->management_flags & MF_EXTERNAL_KEY)
- && (options->cert_file || options->management_flags & MF_EXTERNAL_CERT))
+#ifdef ENABLE_MANAGEMENT
+ else if (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);
- }
+ char *cert = management_query_cert(management,
+ options->management_certificate);
+ tls_ctx_load_cert_file(new_ctx, cert, true);
+ free(cert);
}
#endif
- else
+ else if (options->cert_file)
{
- /* Load Certificate */
- if (options->cert_file)
+ tls_ctx_load_cert_file(new_ctx, options->cert_file, options->cert_file_inline);
+ }
+
+ if (options->priv_key_file)
+ {
+ if (0 != tls_ctx_load_priv_file(new_ctx, options->priv_key_file,
+ options->priv_key_file_inline))
{
- tls_ctx_load_cert_file(new_ctx, options->cert_file, options->cert_file_inline);
+ goto err;
}
-
- /* Load Private Key */
- if (options->priv_key_file)
+ }
+#ifdef ENABLE_MANAGEMENT
+ else if (options->management_flags & MF_EXTERNAL_KEY)
+ {
+ if (tls_ctx_use_management_external_key(new_ctx))
{
- if (0 != tls_ctx_load_priv_file(new_ctx, options->priv_key_file, options->priv_key_file_inline))
- {
- goto err;
- }
+ msg(M_WARN, "Cannot initialize mamagement-external-key");
+ goto err;
}
}
+#endif
if (options->ca_file || options->ca_path)
{
@@ -719,7 +715,24 @@ init_ssl(const struct options *options, struct tls_root_ctx *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);
+ /* If we're running with the chroot option, we may run init_ssl() before
+ * and after chroot-ing. We can use the crl_file path as-is if we're
+ * not going to chroot, or if we already are inside the chroot.
+ *
+ * If we're going to chroot later, we need to prefix the path of the
+ * chroot directory to crl_file.
+ */
+ if (!options->chroot_dir || in_chroot || options->crl_file_inline)
+ {
+ tls_ctx_reload_crl(new_ctx, options->crl_file, options->crl_file_inline);
+ }
+ else
+ {
+ struct gc_arena gc = gc_new();
+ struct buffer crl_file_buf = prepend_dir(options->chroot_dir, options->crl_file, &gc);
+ tls_ctx_reload_crl(new_ctx, BSTR(&crl_file_buf), options->crl_file_inline);
+ gc_free(&gc);
+ }
}
/* Once keys and cert are loaded, load ECDH parameters */
@@ -771,9 +784,6 @@ state_name(int state)
case S_ACTIVE:
return "S_ACTIVE";
- case S_NORMAL_OP:
- return "S_NORMAL_OP";
-
case S_ERROR:
return "S_ERROR";
@@ -799,6 +809,9 @@ packet_opcode_name(int op)
case P_CONTROL_HARD_RESET_SERVER_V2:
return "P_CONTROL_HARD_RESET_SERVER_V2";
+ case P_CONTROL_HARD_RESET_CLIENT_V3:
+ return "P_CONTROL_HARD_RESET_CLIENT_V3";
+
case P_CONTROL_SOFT_RESET_V1:
return "P_CONTROL_SOFT_RESET_V1";
@@ -844,10 +857,9 @@ session_index_name(int index)
static const char *
print_key_id(struct tls_multi *multi, struct gc_arena *gc)
{
- int i;
struct buffer out = alloc_buf_gc(256, gc);
- for (i = 0; i < KEY_SCAN_SIZE; ++i)
+ for (int i = 0; i < KEY_SCAN_SIZE; ++i)
{
struct key_state *ks = multi->key_scan[i];
buf_printf(&out, " [key#%d state=%s id=%d sid=%s]", i,
@@ -859,22 +871,12 @@ print_key_id(struct tls_multi *multi, struct gc_arena *gc)
}
bool
-is_hard_reset(int op, int key_method)
+is_hard_reset_method2(int op)
{
- if (!key_method || key_method == 1)
- {
- if (op == P_CONTROL_HARD_RESET_CLIENT_V1 || op == P_CONTROL_HARD_RESET_SERVER_V1)
- {
- return true;
- }
- }
-
- if (!key_method || key_method >= 2)
+ if (op == P_CONTROL_HARD_RESET_CLIENT_V2 || op == P_CONTROL_HARD_RESET_SERVER_V2
+ || op == P_CONTROL_HARD_RESET_CLIENT_V3)
{
- if (op == P_CONTROL_HARD_RESET_CLIENT_V2 || op == P_CONTROL_HARD_RESET_SERVER_V2)
- {
- return true;
- }
+ return true;
}
return false;
@@ -1094,16 +1096,14 @@ tls_session_init(struct tls_multi *multi, struct tls_session *session)
}
/* Are we a TLS server or client? */
- ASSERT(session->opt->key_method >= 1);
- if (session->opt->key_method == 1)
+ if (session->opt->server)
{
- session->initial_opcode = session->opt->server ?
- P_CONTROL_HARD_RESET_SERVER_V1 : P_CONTROL_HARD_RESET_CLIENT_V1;
+ session->initial_opcode = P_CONTROL_HARD_RESET_SERVER_V2;
}
- else /* session->opt->key_method >= 2 */
+ else
{
- session->initial_opcode = session->opt->server ?
- P_CONTROL_HARD_RESET_SERVER_V2 : P_CONTROL_HARD_RESET_CLIENT_V2;
+ session->initial_opcode = session->opt->tls_crypt_v2 ?
+ P_CONTROL_HARD_RESET_CLIENT_V3 : P_CONTROL_HARD_RESET_CLIENT_V2;
}
/* Initialize control channel authentication parameters */
@@ -1143,16 +1143,9 @@ tls_session_init(struct tls_multi *multi, struct tls_session *session)
static void
tls_session_free(struct tls_session *session, bool clear)
{
- int i;
+ tls_wrap_free(&session->tls_wrap);
- 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)
+ for (size_t i = 0; i < KS_SIZE; ++i)
{
key_state_free(&session->key[i], false);
}
@@ -1234,11 +1227,10 @@ lame_duck_must_die(const struct tls_session *session, interval_t *wakeup)
const struct key_state *lame = &session->key[KS_LAME_DUCK];
if (lame->state >= S_INITIAL)
{
- const time_t local_now = now;
ASSERT(lame->must_die); /* a lame duck key must always have an expiration */
- if (local_now < lame->must_die)
+ if (now < lame->must_die)
{
- compute_earliest_wakeup(wakeup, lame->must_die - local_now);
+ compute_earliest_wakeup(wakeup, lame->must_die - now);
return false;
}
else
@@ -1337,11 +1329,9 @@ tls_multi_init_set_options(struct tls_multi *multi,
const char *local,
const char *remote)
{
-#ifdef ENABLE_OCC
/* initialize options string */
multi->opt.local_options = local;
multi->opt.remote_options = remote;
-#endif
}
/*
@@ -1350,17 +1340,11 @@ tls_multi_init_set_options(struct tls_multi *multi,
void
tls_multi_free(struct tls_multi *multi, bool clear)
{
- int i;
-
ASSERT(multi);
-#ifdef MANAGEMENT_DEF_AUTH
- man_def_auth_set_client_reason(multi, NULL);
+ auth_set_client_reason(multi, NULL);
-#endif
-#if P2MP_SERVER
free(multi->peer_info);
-#endif
if (multi->locked_cn)
{
@@ -1374,15 +1358,11 @@ tls_multi_free(struct tls_multi *multi, bool clear)
cert_hash_free(multi->locked_cert_hash_set);
- if (multi->auth_token)
- {
- secure_memzero(multi->auth_token, AUTH_TOKEN_SIZE);
- free(multi->auth_token);
- }
+ wipe_auth_token(multi);
free(multi->remote_ciphername);
- for (i = 0; i < TM_SIZE; ++i)
+ for (int i = 0; i < TM_SIZE; ++i)
{
tls_session_free(&multi->session[i], false);
}
@@ -1410,11 +1390,10 @@ tls_multi_free(struct tls_multi *multi, bool clear)
static bool
swap_hmac(struct buffer *buf, const struct crypto_options *co, bool incoming)
{
- const struct key_ctx *ctx;
-
ASSERT(co);
- ctx = (incoming ? &co->key_ctx_bi.decrypt : &co->key_ctx_bi.encrypt);
+ const struct key_ctx *ctx = (incoming ? &co->key_ctx_bi.decrypt :
+ &co->key_ctx_bi.encrypt);
ASSERT(ctx->hmac);
{
@@ -1478,6 +1457,8 @@ write_control_auth(struct tls_session *session,
ASSERT(reliable_ack_write
(ks->rec_ack, buf, &ks->session_id_remote, max_ack, prepend_ack));
+ msg(D_TLS_DEBUG, "%s(): %s", __func__, packet_opcode_name(opcode));
+
if (session->tls_wrap.mode == TLS_WRAP_AUTH
|| session->tls_wrap.mode == TLS_WRAP_NONE)
{
@@ -1495,17 +1476,26 @@ write_control_auth(struct tls_session *session,
ASSERT(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));
- if (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;
- }
- else
+ if (!tls_crypt_wrap(buf, &session->tls_wrap.work, &session->tls_wrap.opt))
{
buf->len = 0;
return;
}
+
+ if (opcode == P_CONTROL_HARD_RESET_CLIENT_V3)
+ {
+ if (!buf_copy(&session->tls_wrap.work,
+ session->tls_wrap.tls_crypt_v2_wkc))
+ {
+ msg(D_TLS_ERRORS, "Could not append tls-crypt-v2 client key");
+ buf->len = 0;
+ return;
+ }
+ }
+
+ /* 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;
}
@@ -1516,11 +1506,22 @@ write_control_auth(struct tls_session *session,
static bool
read_control_auth(struct buffer *buf,
struct tls_wrap_ctx *ctx,
- const struct link_socket_actual *from)
+ const struct link_socket_actual *from,
+ const struct tls_options *opt)
{
struct gc_arena gc = gc_new();
bool ret = false;
+ const uint8_t opcode = *(BPTR(buf)) >> P_OPCODE_SHIFT;
+ if (opcode == P_CONTROL_HARD_RESET_CLIENT_V3
+ && !tls_crypt_v2_extract_client_key(buf, ctx, opt))
+ {
+ msg(D_TLS_ERRORS,
+ "TLS Error: can not extract tls-crypt-v2 client key from %s",
+ print_link_socket_actual(from, &gc));
+ goto cleanup;
+ }
+
if (ctx->mode == TLS_WRAP_AUTH)
{
struct buffer null = clear_buf();
@@ -1560,6 +1561,18 @@ read_control_auth(struct buffer *buf,
ASSERT(buf_copy(buf, &tmp));
buf_clear(&tmp);
}
+ else if (ctx->tls_crypt_v2_server_key.cipher)
+ {
+ /* If tls-crypt-v2 is enabled, require *some* wrapping */
+ msg(D_TLS_ERRORS, "TLS Error: could not determine wrapping from %s",
+ print_link_socket_actual(from, &gc));
+ /* TODO Do we want to support using tls-crypt-v2 and no control channel
+ * wrapping at all simultaneously? That would allow server admins to
+ * upgrade clients one-by-one without running a second instance, but we
+ * should not enable it by default because it breaks DoS-protection.
+ * So, add something like --tls-crypt-v2-allow-insecure-fallback ? */
+ goto cleanup;
+ }
if (ctx->mode == TLS_WRAP_NONE || ctx->mode == TLS_WRAP_AUTH)
{
@@ -1632,25 +1645,21 @@ tls1_P_hash(const md_kt_t *md_kt,
int olen)
{
struct gc_arena gc = gc_new();
- int chunk;
- hmac_ctx_t *ctx;
- hmac_ctx_t *ctx_tmp;
uint8_t A1[MAX_HMAC_KEY_LENGTH];
- unsigned int A1_len;
#ifdef ENABLE_DEBUG
const int olen_orig = olen;
const uint8_t *out_orig = out;
#endif
- ctx = hmac_ctx_new();
- ctx_tmp = hmac_ctx_new();
+ hmac_ctx_t *ctx = hmac_ctx_new();
+ hmac_ctx_t *ctx_tmp = hmac_ctx_new();
dmsg(D_SHOW_KEY_SOURCE, "tls1_P_hash sec: %s", format_hex(sec, sec_len, 0, &gc));
dmsg(D_SHOW_KEY_SOURCE, "tls1_P_hash seed: %s", format_hex(seed, seed_len, 0, &gc));
- chunk = md_kt_size(md_kt);
- A1_len = md_kt_size(md_kt);
+ int chunk = md_kt_size(md_kt);
+ unsigned int A1_len = md_kt_size(md_kt);
hmac_ctx_init(ctx, sec, sec_len, md_kt);
hmac_ctx_init(ctx_tmp, sec, sec_len, md_kt);
@@ -1720,21 +1729,18 @@ tls1_PRF(const uint8_t *label,
struct gc_arena gc = gc_new();
const md_kt_t *md5 = md_kt_get("MD5");
const md_kt_t *sha1 = md_kt_get("SHA1");
- int len,i;
- const uint8_t *S1,*S2;
- uint8_t *out2;
- out2 = (uint8_t *) gc_malloc(olen, false, &gc);
+ uint8_t *out2 = (uint8_t *) gc_malloc(olen, false, &gc);
- len = slen/2;
- S1 = sec;
- S2 = &(sec[len]);
+ int len = slen/2;
+ const uint8_t *S1 = sec;
+ const uint8_t *S2 = &(sec[len]);
len += (slen&1); /* add for odd, make longer */
tls1_P_hash(md5,S1,len,label,label_len,out1,olen);
tls1_P_hash(sha1,S2,len,label,label_len,out2,olen);
- for (i = 0; i<olen; i++)
+ for (int i = 0; i<olen; i++)
{
out1[i] ^= out2[i];
}
@@ -1891,40 +1897,6 @@ key_ctx_update_implicit_iv(struct key_ctx *ctx, uint8_t *key, size_t key_len)
}
}
-bool
-tls_item_in_cipher_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;
-}
-
-void
-tls_poor_mans_ncp(struct options *o, const char *remote_ciphername)
-{
- if (o->ncp_enabled && remote_ciphername
- && 0 != strcmp(o->ciphername, remote_ciphername))
- {
- if (tls_item_in_cipher_list(remote_ciphername, o->ncp_ciphers))
- {
- o->ciphername = string_alloc(remote_ciphername, &o->gc);
- msg(D_TLS_DEBUG_LOW, "Using peer cipher '%s'", o->ciphername);
- }
- }
-}
-
/**
* Generate data channel keys for the supplied TLS session.
*
@@ -1941,7 +1913,11 @@ tls_session_generate_data_channel_keys(struct tls_session *session)
const struct session_id *server_sid = !session->opt->server ?
&ks->session_id_remote : &session->session_id;
- ASSERT(ks->authenticated);
+ if (ks->authenticated == KS_AUTH_FALSE)
+ {
+ msg(D_TLS_ERRORS, "TLS Error: key_state not authenticated");
+ goto cleanup;
+ }
ks->crypto_options.flags = session->opt->crypto_flags;
if (!generate_key_expansion(&ks->crypto_options.key_ctx_bi,
@@ -1971,13 +1947,14 @@ tls_session_update_crypto_params(struct tls_session *session,
return true;
}
- if (!session->opt->server
- && 0 != strcmp(options->ciphername, session->opt->config_ciphername)
+ bool cipher_allowed_as_fallback = options->enable_ncp_fallback
+ && streq(options->ciphername, session->opt->config_ciphername);
+
+ if (!session->opt->server && !cipher_allowed_as_fallback
&& !tls_item_in_cipher_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);
+ msg(D_TLS_ERRORS, "Error: pushed cipher not allowed - %s not in %s",
+ options->ciphername, options->ncp_ciphers);
/* undo cipher push, abort connection setup */
options->ciphername = session->opt->config_ciphername;
return false;
@@ -1993,6 +1970,13 @@ tls_session_update_crypto_params(struct tls_session *session,
options->keysize = 0;
}
}
+ else
+ {
+ /* Very hacky workaround and quick fix for frame calculation
+ * different when adjusting frame size when the original and new cipher
+ * are identical to avoid a regression with client without NCP */
+ return tls_session_generate_data_channel_keys(session);
+ }
init_key_type(&session->opt->key_type, options->ciphername,
options->authname, options->keysize, true, true);
@@ -2007,7 +1991,7 @@ tls_session_update_crypto_params(struct tls_session *session,
/* Update frame parameters: undo worst-case overhead, add actual overhead */
frame_remove_from_extra_frame(frame, crypto_max_overhead());
crypto_adjust_frame_parameters(frame, &session->opt->key_type,
- options->use_iv, options->replay, packet_id_long_form);
+ 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);
@@ -2024,7 +2008,7 @@ tls_session_update_crypto_params(struct tls_session *session,
{
frame_remove_from_extra_frame(frame_fragment, crypto_max_overhead());
crypto_adjust_frame_parameters(frame_fragment, &session->opt->key_type,
- options->use_iv, options->replay, packet_id_long_form);
+ options->replay, packet_id_long_form);
frame_set_mtu_dynamic(frame_fragment, options->ce.fragment, SET_MTU_UPPER_BOUND);
frame_print(frame_fragment, D_MTU_INFO, "Fragmentation MTU parms");
}
@@ -2220,63 +2204,15 @@ read_string_alloc(struct buffer *buf)
return str;
}
-/*
- * Handle the reading and writing of key data to and from
- * the TLS control channel (cleartext).
- */
-
-static bool
-key_method_1_write(struct buffer *buf, struct tls_session *session)
-{
- struct key key;
- struct key_state *ks = &session->key[KS_PRIMARY]; /* primary key */
-
- ASSERT(session->opt->key_method == 1);
- ASSERT(buf_init(buf, 0));
-
- generate_key_random(&key, &session->opt->key_type);
- if (!check_key(&key, &session->opt->key_type))
- {
- msg(D_TLS_ERRORS, "TLS Error: Bad encrypting key generated");
- return false;
- }
-
- if (!write_key(&key, &session->opt->key_type, buf))
- {
- msg(D_TLS_ERRORS, "TLS Error: write_key failed");
- return false;
- }
-
- init_key_ctx(&ks->crypto_options.key_ctx_bi.encrypt, &key,
- &session->opt->key_type, OPENVPN_OP_ENCRYPT,
- "Data Channel Encrypt");
- secure_memzero(&key, sizeof(key));
-
- /* send local options string */
- {
- const char *local_options = local_options_string(session);
- const int optlen = strlen(local_options) + 1;
- if (!buf_write(buf, local_options, optlen))
- {
- msg(D_TLS_ERRORS, "TLS Error: KM1 write options failed");
- return false;
- }
- }
-
- return true;
-}
-
static bool
push_peer_info(struct buffer *buf, struct tls_session *session)
{
struct gc_arena gc = gc_new();
bool ret = false;
-#ifdef ENABLE_PUSH_PEER_INFO
if (session->opt->push_peer_info_detail > 0)
{
struct env_set *es = session->opt->es;
- struct env_item *e;
struct buffer out = alloc_buf_gc(512*3, &gc);
/* push version */
@@ -2302,13 +2238,30 @@ push_peer_info(struct buffer *buf, struct tls_session *session)
#endif
/* support for P_DATA_V2 */
- buf_printf(&out, "IV_PROTO=2\n");
+ int iv_proto = IV_PROTO_DATA_V2;
+
+ /* support for receiving push_reply before sending
+ * push request, also signal that the client wants
+ * to get push-reply messages without without requiring a round
+ * trip for a push request message*/
+ if(session->opt->pull)
+ {
+ iv_proto |= IV_PROTO_REQUEST_PUSH;
+ }
+
+ buf_printf(&out, "IV_PROTO=%d\n", iv_proto);
- /* support for Negotiable Crypto Paramters */
+ /* support for Negotiable Crypto Parameters */
if (session->opt->ncp_enabled
&& (session->opt->mode == MODE_SERVER || session->opt->pull))
{
- buf_printf(&out, "IV_NCP=2\n");
+ if (tls_item_in_cipher_list("AES-128-GCM", session->opt->config_ncp_ciphers)
+ && tls_item_in_cipher_list("AES-256-GCM", session->opt->config_ncp_ciphers))
+ {
+
+ buf_printf(&out, "IV_NCP=2\n");
+ }
+ buf_printf(&out, "IV_CIPHERS=%s\n", session->opt->config_ncp_ciphers);
}
/* push compression status */
@@ -2320,7 +2273,7 @@ push_peer_info(struct buffer *buf, struct tls_session *session)
{
/* push mac addr */
struct route_gateway_info rgi;
- get_default_gateway(&rgi);
+ get_default_gateway(&rgi, session->opt->net_ctx);
if (rgi.flags & RGI_HWADDR_DEFINED)
{
buf_printf(&out, "IV_HWADDR=%s\n", format_hex_ex(rgi.hwaddr, 6, 0, 1, ":", &gc));
@@ -2332,14 +2285,16 @@ push_peer_info(struct buffer *buf, struct tls_session *session)
}
/* push env vars that begin with UV_, IV_PLAT_VER and IV_GUI_VER */
- for (e = es->list; e != NULL; e = e->next)
+ for (struct env_item *e = es->list; e != NULL; e = e->next)
{
if (e->string)
{
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))
+ || (strncmp(e->string,"IV_GUI_VER=",sizeof("IV_GUI_VER=")-1)==0)
+ || (strncmp(e->string,"IV_SSO=",sizeof("IV_SSO=")-1)==0)
+ )
&& buf_safe(&out, strlen(e->string)+1))
{
buf_printf(&out, "%s\n", e->string);
@@ -2353,7 +2308,6 @@ push_peer_info(struct buffer *buf, struct tls_session *session)
}
}
else
-#endif /* ifdef ENABLE_PUSH_PEER_INFO */
{
if (!write_empty_string(buf)) /* no peer info */
{
@@ -2367,12 +2321,16 @@ error:
return ret;
}
+/**
+ * Handle the writing of key data, peer-info, username/password, OCC
+ * to the TLS control channel (cleartext).
+ */
static bool
-key_method_2_write(struct buffer *buf, struct tls_session *session)
+key_method_2_write(struct buffer *buf, struct tls_multi *multi,
+ struct tls_session *session)
{
struct key_state *ks = &session->key[KS_PRIMARY]; /* primary key */
- ASSERT(session->opt->key_method == 2);
ASSERT(buf_init(buf, 0));
/* write a uint32 0 */
@@ -2382,7 +2340,7 @@ key_method_2_write(struct buffer *buf, struct tls_session *session)
}
/* write key_method + flags */
- if (!buf_write_u8(buf, (session->opt->key_method & KEY_METHOD_MASK)))
+ if (!buf_write_u8(buf, KEY_METHOD_2))
{
goto error;
}
@@ -2395,16 +2353,16 @@ key_method_2_write(struct buffer *buf, struct tls_session *session)
/* write options string */
{
- if (!write_string(buf, local_options_string(session), TLS_OPTIONS_LEN))
+ if (!write_string(buf, session->opt->local_options, TLS_OPTIONS_LEN))
{
goto error;
}
}
- /* write username/password if specified */
- if (auth_user_pass_enabled)
+ /* write username/password if specified or we are using a auth-token */
+ if (auth_user_pass_enabled || (auth_token.token_defined && auth_token.defined))
{
-#ifdef ENABLE_CLIENT_CR
+#ifdef ENABLE_MANAGEMENT
auth_user_pass_setup(session->opt->auth_user_pass_file, session->opt->sci);
#else
auth_user_pass_setup(session->opt->auth_user_pass_file, NULL);
@@ -2415,8 +2373,10 @@ key_method_2_write(struct buffer *buf, struct tls_session *session)
* If we have a valid auth-token, send that instead of real
* username/password
*/
- if (auth_token.defined)
+ if (auth_token.token_defined && auth_token.defined)
+ {
up = &auth_token;
+ }
if (!write_string(buf, up->username, -1))
{
@@ -2428,14 +2388,15 @@ key_method_2_write(struct buffer *buf, struct tls_session *session)
}
/* if auth-nocache was specified, the auth_user_pass object reaches
* a "complete" state only after having received the push-reply
- * message.
+ * message. The push message might contain an auth-token that needs
+ * the username of auth_user_pass.
*
* For this reason, skip the purge operation here if no push-reply
* message has been received yet.
*
* This normally happens upon first negotiation only.
*/
- if (!auth_user_pass.wait_for_push)
+ if (!session->opt->pull)
{
purge_user_pass(&auth_user_pass, false);
}
@@ -2457,15 +2418,19 @@ key_method_2_write(struct buffer *buf, struct tls_session *session)
goto error;
}
- /* 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.
+ /*
+ * Generate tunnel keys if we're a TLS server.
+ *
+ * If we're a p2mp server to allow NCP, the first key
+ * generation is postponed until after the connect script finished and the
+ * NCP options can be processed. Since that always happens at after connect
+ * script options are available the CAS_SUCCEEDED status is identical to
+ * NCP options are processed and we have no extra state for NCP finished.
*/
- if (session->opt->server && !(session->opt->ncp_enabled
- && session->opt->mode == MODE_SERVER && ks->key_id <= 0))
+ if (session->opt->server && (session->opt->mode != MODE_SERVER
+ || multi->multi_state == CAS_SUCCEEDED))
{
- if (ks->authenticated)
+ if (ks->authenticated > KS_AUTH_FALSE)
{
if (!tls_session_generate_data_channel_keys(session))
{
@@ -2483,73 +2448,15 @@ error:
return false;
}
-static bool
-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 */
-
- ASSERT(session->opt->key_method == 1);
-
- if (!session->verified)
- {
- msg(D_TLS_ERRORS,
- "TLS Error: Certificate verification failed (key-method 1)");
- goto error;
- }
-
- status = read_key(&key, &session->opt->key_type, buf);
- if (status != 1)
- {
- msg(D_TLS_ERRORS,
- "TLS Error: Error reading data channel key from plaintext buffer");
- goto error;
- }
-
- if (!check_key(&key, &session->opt->key_type))
- {
- msg(D_TLS_ERRORS, "TLS Error: Bad decrypting key received from peer");
- goto error;
- }
-
- if (buf->len < 1)
- {
- msg(D_TLS_ERRORS, "TLS Error: Missing options string");
- goto error;
- }
-
-#ifdef ENABLE_OCC
- /* compare received remote options string
- * with our locally computed options string */
- if (!session->opt->disable_occ
- && !options_cmp_equal_safe((char *) BPTR(buf), session->opt->remote_options, buf->len))
- {
- options_warning_safe((char *) BPTR(buf), session->opt->remote_options, buf->len);
- }
-#endif
-
- buf_clear(buf);
-
- init_key_ctx(&ks->crypto_options.key_ctx_bi.decrypt, &key,
- &session->opt->key_type, OPENVPN_OP_DECRYPT,
- "Data Channel Decrypt");
- secure_memzero(&key, sizeof(key));
- ks->authenticated = true;
- return true;
-
-error:
- buf_clear(buf);
- secure_memzero(&key, sizeof(key));
- return false;
-}
-
+/**
+ * Handle reading key data, peer-info, username/password, OCC
+ * from the TLS control channel (cleartext).
+ */
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 */
- int key_method_flags;
bool username_status, password_status;
struct gc_arena gc = gc_new();
@@ -2559,8 +2466,6 @@ key_method_2_read(struct buffer *buf, struct tls_multi *multi, struct tls_sessio
/* allocate temporary objects */
ALLOC_ARRAY_CLEAR_GC(options, char, TLS_OPTIONS_LEN, &gc);
- ASSERT(session->opt->key_method == 2);
-
/* discard leading uint32 */
if (!buf_advance(buf, 4))
{
@@ -2570,7 +2475,7 @@ key_method_2_read(struct buffer *buf, struct tls_multi *multi, struct tls_sessio
}
/* get key method */
- key_method_flags = buf_read_u8(buf);
+ int key_method_flags = buf_read_u8(buf);
if ((key_method_flags & KEY_METHOD_MASK) != 2)
{
msg(D_TLS_ERRORS,
@@ -2593,7 +2498,7 @@ key_method_2_read(struct buffer *buf, struct tls_multi *multi, struct tls_sessio
goto error;
}
- ks->authenticated = false;
+ ks->authenticated = KS_AUTH_FALSE;
/* always extract username + password fields from buf, even if not
* authenticating for it, because otherwise we can't get at the
@@ -2603,7 +2508,6 @@ key_method_2_read(struct buffer *buf, struct tls_multi *multi, struct tls_sessio
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);
@@ -2616,18 +2520,13 @@ key_method_2_read(struct buffer *buf, struct tls_multi *multi, struct tls_sessio
multi->remote_ciphername =
options_string_extract_option(options, "cipher", NULL);
- if (tls_peer_info_ncp_ver(multi->peer_info) < 2)
+ /* In OCC we send '[null-cipher]' instead 'none' */
+ if (multi->remote_ciphername
+ && strcmp(multi->remote_ciphername, "[null-cipher]") == 0)
{
- /* Peer does not support NCP, but leave NCP enabled if the local and
- * remote cipher do not match to attempt 'poor-man's NCP'.
- */
- if (multi->remote_ciphername == NULL
- || 0 == strcmp(multi->remote_ciphername, multi->opt.config_ciphername))
- {
- session->opt->ncp_enabled = false;
- }
+ free(multi->remote_ciphername);
+ multi->remote_ciphername = string_alloc("none", NULL);
}
-#endif /* if P2MP_SERVER */
if (tls_session_user_pass_enabled(session))
{
@@ -2653,19 +2552,18 @@ key_method_2_read(struct buffer *buf, struct tls_multi *multi, struct tls_sessio
"TLS Error: Certificate verification failed (key-method 2)");
goto error;
}
- ks->authenticated = true;
+ ks->authenticated = KS_AUTH_TRUE;
}
/* clear username and password from memory */
secure_memzero(up, sizeof(*up));
/* Perform final authentication checks */
- if (ks->authenticated)
+ if (ks->authenticated > KS_AUTH_FALSE)
{
verify_final_auth_checks(multi, session);
}
-#ifdef ENABLE_OCC
/* check options consistency */
if (!session->opt->disable_occ
&& !options_cmp_equal(options, session->opt->remote_options))
@@ -2674,10 +2572,9 @@ key_method_2_read(struct buffer *buf, struct tls_multi *multi, struct tls_sessio
if (session->opt->ssl_flags & SSLF_OPT_VERIFY)
{
msg(D_TLS_ERRORS, "Option inconsistency warnings triggering disconnect due to --opt-verify");
- ks->authenticated = false;
+ ks->authenticated = KS_AUTH_FALSE;
}
}
-#endif
buf_clear(buf);
@@ -2685,13 +2582,14 @@ key_method_2_read(struct buffer *buf, struct tls_multi *multi, struct tls_sessio
* Call OPENVPN_PLUGIN_TLS_FINAL plugin if defined, for final
* veto opportunity over authentication decision.
*/
- if (ks->authenticated && plugin_defined(session->opt->plugins, OPENVPN_PLUGIN_TLS_FINAL))
+ if ((ks->authenticated > KS_AUTH_FALSE)
+ && 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;
+ ks->authenticated = KS_AUTH_FALSE;
}
setenv_del(session->opt->es, "exported_keying_material");
@@ -2715,6 +2613,7 @@ key_method_2_read(struct buffer *buf, struct tls_multi *multi, struct tls_sessio
return true;
error:
+ ks->authenticated = KS_AUTH_FALSE;
secure_memzero(ks->key_src, sizeof(*ks->key_src));
if (up)
{
@@ -2777,9 +2676,9 @@ tls_process(struct tls_multi *multi,
&& ks->n_packets >= session->opt->renegotiate_packets)
|| (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",
- (int)(ks->established + session->opt->renegotiate_seconds - now),
+ msg(D_TLS_DEBUG_LOW, "TLS: soft reset sec=%d/%d bytes=" counter_format
+ "/%d pkts=" counter_format "/%d",
+ (int) (now - ks->established), session->opt->renegotiate_seconds,
ks->n_bytes, session->opt->renegotiate_bytes,
ks->n_packets, session->opt->renegotiate_packets);
key_state_soft_reset(session);
@@ -2847,21 +2746,12 @@ tls_process(struct tls_multi *multi,
}
/* Are we timed out on receive? */
- if (now >= ks->must_negotiate)
+ if (now >= ks->must_negotiate && 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;
}
/* Wait for Initial Handshake ACK */
@@ -2901,10 +2791,12 @@ tls_process(struct tls_multi *multi,
}
state_change = true;
ks->state = S_ACTIVE;
+ /* Cancel negotiation timeout */
+ ks->must_negotiate = 0;
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);
+ link_socket_set_outgoing_addr(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);
@@ -2992,23 +2884,9 @@ tls_process(struct tls_multi *multi,
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 (!key_method_1_write(buf, session))
- {
- goto error;
- }
- }
- else if (session->opt->key_method == 2)
+ if (!key_method_2_write(buf, multi, session))
{
- if (!key_method_2_write(buf, session))
- {
- goto error;
- }
- }
- else
- {
- ASSERT(0);
+ goto error;
}
state_change = true;
@@ -3022,23 +2900,9 @@ tls_process(struct tls_multi *multi,
&& ((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
+ if (!key_method_2_read(buf, multi, session))
{
- ASSERT(0);
+ goto error;
}
state_change = true;
@@ -3162,10 +3026,8 @@ tls_multi_process(struct tls_multi *multi,
interval_t *wakeup)
{
struct gc_arena gc = gc_new();
- int i;
int active = TLSMP_INACTIVE;
bool error = false;
- int tas;
perf_push(PERF_TLS_MULTI_PROCESS);
@@ -3176,7 +3038,7 @@ tls_multi_process(struct tls_multi *multi,
* and which has a defined remote IP addr.
*/
- for (i = 0; i < TM_SIZE; ++i)
+ for (int i = 0; i < TM_SIZE; ++i)
{
struct tls_session *session = &multi->session[i];
struct key_state *ks = &session->key[KS_PRIMARY];
@@ -3251,7 +3113,7 @@ tls_multi_process(struct tls_multi *multi,
update_time();
- tas = tls_authentication_status(multi, TLS_MULTI_AUTH_STATUS_INTERVAL);
+ int tas = tls_authentication_status(multi, TLS_MULTI_AUTH_STATUS_INTERVAL);
/*
* If lame duck session expires, kill it.
@@ -3284,7 +3146,7 @@ tls_multi_process(struct tls_multi *multi,
*/
if (error)
{
- for (i = 0; i < (int) SIZE(multi->key_scan); ++i)
+ for (int i = 0; i < (int) SIZE(multi->key_scan); ++i)
{
if (multi->key_scan[i]->state >= S_ACTIVE)
{
@@ -3301,7 +3163,7 @@ nohard:
const int throw_level = GREMLIN_CONNECTION_FLOOD_LEVEL(multi->opt.gremlin);
if (throw_level)
{
- for (i = 0; i < (int) SIZE(multi->key_scan); ++i)
+ for (int i = 0; i < (int) SIZE(multi->key_scan); ++i)
{
if (multi->key_scan[i]->state >= throw_level)
{
@@ -3324,6 +3186,95 @@ nohard:
* to implement a multiplexed TLS channel over the TCP/UDP port.
*/
+static inline void
+handle_data_channel_packet(struct tls_multi *multi,
+ const struct link_socket_actual *from,
+ struct buffer *buf,
+ struct crypto_options **opt,
+ bool floated,
+ const uint8_t **ad_start)
+{
+ struct gc_arena gc = gc_new();
+
+ uint8_t c = *BPTR(buf);
+ int op = c >> P_OPCODE_SHIFT;
+ int key_id = c & P_KEY_ID_MASK;
+
+ /* data channel packet */
+ for (int i = 0; i < KEY_SCAN_SIZE; ++i)
+ {
+ struct key_state *ks = multi->key_scan[i];
+
+ /*
+ * This is the basic test of TLS state compatibility between a local OpenVPN
+ * instance and its remote peer.
+ *
+ * If the test fails, it tells us that we are getting a packet from a source
+ * which claims reference to a prior negotiated TLS session, but the local
+ * OpenVPN instance has no memory of such a negotiation.
+ *
+ * It almost always occurs on UDP sessions when the passive side of the
+ * connection is restarted without the active side restarting as well (the
+ * passive side is the server which only listens for the connections, the
+ * active side is the client which initiates connections).
+ */
+ if (DECRYPT_KEY_ENABLED(multi, ks)
+ && key_id == ks->key_id
+ && (ks->authenticated == KS_AUTH_TRUE)
+ && (floated || link_socket_actual_match(from, &ks->remote_addr)))
+ {
+ if (!ks->crypto_options.key_ctx_bi.initialized)
+ {
+ msg(D_MULTI_DROPPED,
+ "Key %s [%d] not initialized (yet), dropping packet.",
+ print_link_socket_actual(from, &gc), key_id);
+ goto done;
+ }
+
+ /* 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",
+ print_link_socket_actual(from, &gc));
+ ++multi->n_soft_errors;
+ goto done;
+ }
+ ASSERT(buf_advance(buf, 3));
+ }
+
+ ++ks->n_packets;
+ ks->n_bytes += buf->len;
+ dmsg(D_TLS_KEYSELECT,
+ "TLS: tls_pre_decrypt, key_id=%d, IP=%s",
+ key_id, print_link_socket_actual(from, &gc));
+ gc_free(&gc);
+ return;
+ }
+ }
+
+ msg(D_TLS_ERRORS,
+ "TLS Error: local/remote TLS keys are out of sync: %s [%d]",
+ print_link_socket_actual(from, &gc), key_id);
+
+done:
+ tls_clear_error();
+ buf->len = 0;
+ *opt = NULL;
+ gc_free(&gc);
+}
+
/*
*
* When we are in TLS mode, this is the first routine which sees
@@ -3357,448 +3308,374 @@ tls_pre_decrypt(struct tls_multi *multi,
bool floated,
const uint8_t **ad_start)
{
+
+ if (buf->len <= 0)
+ {
+ buf->len = 0;
+ *opt = NULL;
+ return false;
+ }
+
struct gc_arena gc = gc_new();
bool ret = false;
- if (buf->len > 0)
+ /* get opcode */
+ uint8_t pkt_firstbyte = *BPTR(buf);
+ int op = pkt_firstbyte >> P_OPCODE_SHIFT;
+
+ if ((op == P_DATA_V1) || (op == P_DATA_V2))
{
- int i;
- int op;
- int key_id;
+ handle_data_channel_packet(multi, from, buf, opt, floated, ad_start);
+ return false;
+ }
+
+ /* get key_id */
+ int key_id = pkt_firstbyte & P_KEY_ID_MASK;
+
+ /* control channel packet */
+ bool do_burst = false;
+ bool new_link = false;
+ struct session_id sid; /* remote session ID */
- /* get opcode and key ID */
+ /* verify legal opcode */
+ if (op < P_FIRST_OPCODE || op > P_LAST_OPCODE)
+ {
+ if (op == P_CONTROL_HARD_RESET_CLIENT_V1
+ || op == P_CONTROL_HARD_RESET_SERVER_V1)
{
- uint8_t c = *BPTR(buf);
- op = c >> P_OPCODE_SHIFT;
- key_id = c & P_KEY_ID_MASK;
+ msg(D_TLS_ERRORS, "Peer tried unsupported key-method 1");
}
+ msg(D_TLS_ERRORS,
+ "TLS Error: unknown opcode received from %s op=%d",
+ print_link_socket_actual(from, &gc), op);
+ goto error;
+ }
- if ((op == P_DATA_V1) || (op == P_DATA_V2))
+ /* hard reset ? */
+ if (is_hard_reset_method2(op))
+ {
+ /* verify client -> server or server -> client connection */
+ if (((op == P_CONTROL_HARD_RESET_CLIENT_V2
+ || op == P_CONTROL_HARD_RESET_CLIENT_V3) && !multi->opt.server)
+ || ((op == P_CONTROL_HARD_RESET_SERVER_V2) && multi->opt.server))
{
- /* data channel packet */
- for (i = 0; i < KEY_SCAN_SIZE; ++i)
- {
- struct key_state *ks = multi->key_scan[i];
-
- /*
- * This is the basic test of TLS state compatibility between a local OpenVPN
- * instance and its remote peer.
- *
- * If the test fails, it tells us that we are getting a packet from a source
- * which claims reference to a prior negotiated TLS session, but the local
- * OpenVPN instance has no memory of such a negotiation.
- *
- * It almost always occurs on UDP sessions when the passive side of the
- * connection is restarted without the active side restarting as well (the
- * passive side is the server which only listens for the connections, the
- * active side is the client which initiates connections).
- */
- if (DECRYPT_KEY_ENABLED(multi, ks)
- && key_id == ks->key_id
- && ks->authenticated
-#ifdef ENABLE_DEF_AUTH
- && !ks->auth_deferred
-#endif
- && (floated || link_socket_actual_match(from, &ks->remote_addr)))
- {
- if (!ks->crypto_options.key_ctx_bi.initialized)
- {
- msg(D_MULTI_DROPPED,
- "Key %s [%d] not initialized (yet), dropping packet.",
- print_link_socket_actual(from, &gc), key_id);
- goto error_lite;
- }
-
- /* 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",
- print_link_socket_actual(from, &gc));
- goto error;
- }
- ASSERT(buf_advance(buf, 3));
- }
+ msg(D_TLS_ERRORS,
+ "TLS Error: client->client or server->server connection attempted from %s",
+ print_link_socket_actual(from, &gc));
+ goto error;
+ }
+ }
- ++ks->n_packets;
- ks->n_bytes += buf->len;
- dmsg(D_TLS_KEYSELECT,
- "TLS: tls_pre_decrypt, key_id=%d, IP=%s",
- key_id, print_link_socket_actual(from, &gc));
- gc_free(&gc);
- return ret;
- }
- }
+ /*
+ * Authenticate Packet
+ */
+ dmsg(D_TLS_DEBUG, "TLS: control channel, op=%s, IP=%s",
+ packet_opcode_name(op), print_link_socket_actual(from, &gc));
+ /* get remote session-id */
+ {
+ struct buffer tmp = *buf;
+ buf_advance(&tmp, 1);
+ if (!session_id_read(&sid, &tmp) || !session_id_defined(&sid))
+ {
msg(D_TLS_ERRORS,
- "TLS Error: local/remote TLS keys are out of sync: %s [%d]",
- print_link_socket_actual(from, &gc), key_id);
- goto error_lite;
+ "TLS Error: session-id not found in packet from %s",
+ print_link_socket_actual(from, &gc));
+ goto error;
}
- else /* control channel packet */
- {
- bool do_burst = false;
- bool new_link = false;
- struct session_id sid; /* remote session ID */
+ }
- /* verify legal opcode */
- if (op < P_FIRST_OPCODE || op > P_LAST_OPCODE)
+ int i;
+ /* use session ID to match up packet with appropriate tls_session object */
+ for (i = 0; i < TM_SIZE; ++i)
+ {
+ struct tls_session *session = &multi->session[i];
+ struct key_state *ks = &session->key[KS_PRIMARY];
+
+ dmsg(D_TLS_DEBUG,
+ "TLS: initial packet test, i=%d state=%s, mysid=%s, rec-sid=%s, rec-ip=%s, stored-sid=%s, stored-ip=%s",
+ i,
+ state_name(ks->state),
+ session_id_print(&session->session_id, &gc),
+ session_id_print(&sid, &gc),
+ print_link_socket_actual(from, &gc),
+ session_id_print(&ks->session_id_remote, &gc),
+ print_link_socket_actual(&ks->remote_addr, &gc));
+
+ if (session_id_equal(&ks->session_id_remote, &sid))
+ /* found a match */
+ {
+ if (i == TM_LAME_DUCK)
{
msg(D_TLS_ERRORS,
- "TLS Error: unknown opcode received from %s op=%d",
- print_link_socket_actual(from, &gc), op);
+ "TLS ERROR: received control packet with stale session-id=%s",
+ session_id_print(&sid, &gc));
goto error;
}
+ dmsg(D_TLS_DEBUG,
+ "TLS: found match, session[%d], sid=%s",
+ i, session_id_print(&sid, &gc));
+ break;
+ }
+ }
- /* hard reset ? */
- if (is_hard_reset(op, 0))
- {
- /* verify client -> server or server -> client connection */
- if (((op == P_CONTROL_HARD_RESET_CLIENT_V1
- || op == P_CONTROL_HARD_RESET_CLIENT_V2) && !multi->opt.server)
- || ((op == P_CONTROL_HARD_RESET_SERVER_V1
- || op == P_CONTROL_HARD_RESET_SERVER_V2) && multi->opt.server))
- {
- msg(D_TLS_ERRORS,
- "TLS Error: client->client or server->server connection attempted from %s",
- print_link_socket_actual(from, &gc));
- goto error;
- }
- }
-
- /*
- * Authenticate Packet
- */
- dmsg(D_TLS_DEBUG, "TLS: control channel, op=%s, IP=%s",
- packet_opcode_name(op), print_link_socket_actual(from, &gc));
+ /*
+ * Hard reset and session id does not match any session in
+ * multi->session: Possible initial packet
+ */
+ if (i == TM_SIZE && is_hard_reset_method2(op))
+ {
+ struct tls_session *session = &multi->session[TM_ACTIVE];
+ struct key_state *ks = &session->key[KS_PRIMARY];
- /* get remote session-id */
+ /*
+ * If we have no session currently in progress, the initial packet will
+ * open a new session in TM_ACTIVE rather than TM_UNTRUSTED.
+ */
+ if (!session_id_defined(&ks->session_id_remote))
+ {
+ if (multi->opt.single_session && multi->n_sessions)
{
- struct buffer tmp = *buf;
- buf_advance(&tmp, 1);
- if (!session_id_read(&sid, &tmp) || !session_id_defined(&sid))
- {
- msg(D_TLS_ERRORS,
- "TLS Error: session-id not found in packet from %s",
- print_link_socket_actual(from, &gc));
- goto error;
- }
+ msg(D_TLS_ERRORS,
+ "TLS Error: Cannot accept new session request from %s due to session context expire or --single-session [1]",
+ print_link_socket_actual(from, &gc));
+ goto error;
}
- /* use session ID to match up packet with appropriate tls_session object */
- for (i = 0; i < TM_SIZE; ++i)
+#ifdef ENABLE_MANAGEMENT
+ if (management)
{
- struct tls_session *session = &multi->session[i];
- struct key_state *ks = &session->key[KS_PRIMARY];
-
- dmsg(D_TLS_DEBUG,
- "TLS: initial packet test, i=%d state=%s, mysid=%s, rec-sid=%s, rec-ip=%s, stored-sid=%s, stored-ip=%s",
- i,
- state_name(ks->state),
- session_id_print(&session->session_id, &gc),
- session_id_print(&sid, &gc),
- print_link_socket_actual(from, &gc),
- session_id_print(&ks->session_id_remote, &gc),
- print_link_socket_actual(&ks->remote_addr, &gc));
-
- if (session_id_equal(&ks->session_id_remote, &sid))
- /* found a match */
- {
- if (i == TM_LAME_DUCK)
- {
- msg(D_TLS_ERRORS,
- "TLS ERROR: received control packet with stale session-id=%s",
- session_id_print(&sid, &gc));
- goto error;
- }
- dmsg(D_TLS_DEBUG,
- "TLS: found match, session[%d], sid=%s",
- i, session_id_print(&sid, &gc));
- break;
- }
+ management_set_state(management,
+ OPENVPN_STATE_AUTH,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL);
}
+#endif
- /*
- * Initial packet received.
- */
-
- if (i == TM_SIZE && is_hard_reset(op, 0))
- {
- struct tls_session *session = &multi->session[TM_ACTIVE];
- struct key_state *ks = &session->key[KS_PRIMARY];
-
- if (!is_hard_reset(op, multi->opt.key_method))
- {
- msg(D_TLS_ERRORS, "TLS ERROR: initial packet local/remote key_method mismatch, local key_method=%d, op=%s",
- multi->opt.key_method,
- packet_opcode_name(op));
- goto error;
- }
+ msg(D_TLS_DEBUG_LOW,
+ "TLS: Initial packet from %s, sid=%s",
+ print_link_socket_actual(from, &gc),
+ session_id_print(&sid, &gc));
- /*
- * If we have no session currently in progress, the initial packet will
- * open a new session in TM_ACTIVE rather than TM_UNTRUSTED.
- */
- if (!session_id_defined(&ks->session_id_remote))
- {
- if (multi->opt.single_session && multi->n_sessions)
- {
- msg(D_TLS_ERRORS,
- "TLS Error: Cannot accept new session request from %s due to session context expire or --single-session [1]",
- print_link_socket_actual(from, &gc));
- goto error;
- }
+ do_burst = true;
+ new_link = true;
+ i = TM_ACTIVE;
+ session->untrusted_addr = *from;
+ }
+ }
-#ifdef ENABLE_MANAGEMENT
- if (management)
- {
- management_set_state(management,
- OPENVPN_STATE_AUTH,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL);
- }
-#endif
+ /*
+ * If we detected new session in the last if block, variable i has
+ * changed to TM_ACTIVE, so check the condition again.
+ */
+ if (i == TM_SIZE && is_hard_reset_method2(op))
+ {
+ /*
+ * No match with existing sessions,
+ * probably a new session.
+ */
+ struct tls_session *session = &multi->session[TM_UNTRUSTED];
- msg(D_TLS_DEBUG_LOW,
- "TLS: Initial packet from %s, sid=%s",
- print_link_socket_actual(from, &gc),
- session_id_print(&sid, &gc));
+ /*
+ * If --single-session, don't allow any hard-reset connection request
+ * unless it the first packet of the session.
+ */
+ if (multi->opt.single_session)
+ {
+ msg(D_TLS_ERRORS,
+ "TLS Error: Cannot accept new session request from %s due to session context expire or --single-session [2]",
+ print_link_socket_actual(from, &gc));
+ goto error;
+ }
- do_burst = true;
- new_link = true;
- i = TM_ACTIVE;
- session->untrusted_addr = *from;
- }
- }
+ if (!read_control_auth(buf, &session->tls_wrap, from,
+ session->opt))
+ {
+ goto error;
+ }
- if (i == TM_SIZE && is_hard_reset(op, 0))
- {
- /*
- * No match with existing sessions,
- * probably a new session.
- */
- struct tls_session *session = &multi->session[TM_UNTRUSTED];
-
- /*
- * If --single-session, don't allow any hard-reset connection request
- * unless it the the first packet of the session.
- */
- if (multi->opt.single_session)
- {
- msg(D_TLS_ERRORS,
- "TLS Error: Cannot accept new session request from %s due to session context expire or --single-session [2]",
- print_link_socket_actual(from, &gc));
- goto error;
- }
+ /*
+ * New session-initiating control packet is authenticated at this point,
+ * assuming that the --tls-auth command line option was used.
+ *
+ * Without --tls-auth, we leave authentication entirely up to TLS.
+ */
+ msg(D_TLS_DEBUG_LOW,
+ "TLS: new session incoming connection from %s",
+ print_link_socket_actual(from, &gc));
- if (!is_hard_reset(op, multi->opt.key_method))
- {
- msg(D_TLS_ERRORS, "TLS ERROR: new session local/remote key_method mismatch, local key_method=%d, op=%s",
- multi->opt.key_method,
- packet_opcode_name(op));
- goto error;
- }
+ new_link = true;
+ i = TM_UNTRUSTED;
+ session->untrusted_addr = *from;
+ }
+ else
+ {
+ struct tls_session *session = &multi->session[i];
+ struct key_state *ks = &session->key[KS_PRIMARY];
- if (!read_control_auth(buf, &session->tls_wrap, from))
- {
- goto error;
- }
+ /*
+ * Packet must belong to an existing session.
+ */
+ if (i != TM_ACTIVE && i != TM_UNTRUSTED)
+ {
+ msg(D_TLS_ERRORS,
+ "TLS Error: Unroutable control packet received from %s (si=%d op=%s)",
+ print_link_socket_actual(from, &gc),
+ i,
+ packet_opcode_name(op));
+ goto error;
+ }
- /*
- * New session-initiating control packet is authenticated at this point,
- * assuming that the --tls-auth command line option was used.
- *
- * Without --tls-auth, we leave authentication entirely up to TLS.
- */
- msg(D_TLS_DEBUG_LOW,
- "TLS: new session incoming connection from %s",
- print_link_socket_actual(from, &gc));
+ /*
+ * Verify remote IP address
+ */
+ if (!new_link && !link_socket_actual_match(&ks->remote_addr, from))
+ {
+ msg(D_TLS_ERRORS, "TLS Error: Received control packet from unexpected IP addr: %s",
+ print_link_socket_actual(from, &gc));
+ goto error;
+ }
- new_link = true;
- i = TM_UNTRUSTED;
- session->untrusted_addr = *from;
- }
- else
+ /*
+ * Remote is requesting a key renegotiation
+ */
+ if (op == P_CONTROL_SOFT_RESET_V1
+ && DECRYPT_KEY_ENABLED(multi, ks))
+ {
+ if (!read_control_auth(buf, &session->tls_wrap, from,
+ session->opt))
{
- struct tls_session *session = &multi->session[i];
- struct key_state *ks = &session->key[KS_PRIMARY];
+ goto error;
+ }
- /*
- * Packet must belong to an existing session.
- */
- if (i != TM_ACTIVE && i != TM_UNTRUSTED)
- {
- msg(D_TLS_ERRORS,
- "TLS Error: Unroutable control packet received from %s (si=%d op=%s)",
- print_link_socket_actual(from, &gc),
- i,
- packet_opcode_name(op));
- goto error;
- }
+ key_state_soft_reset(session);
- /*
- * Verify remote IP address
- */
- if (!new_link && !link_socket_actual_match(&ks->remote_addr, from))
- {
- msg(D_TLS_ERRORS, "TLS Error: Received control packet from unexpected IP addr: %s",
- print_link_socket_actual(from, &gc));
- goto error;
- }
+ dmsg(D_TLS_DEBUG,
+ "TLS: received P_CONTROL_SOFT_RESET_V1 s=%d sid=%s",
+ i, session_id_print(&sid, &gc));
+ }
+ else
+ {
+ /*
+ * Remote responding to our key renegotiation request?
+ */
+ if (op == P_CONTROL_SOFT_RESET_V1)
+ {
+ do_burst = true;
+ }
- /*
- * Remote is requesting a key renegotiation
- */
- if (op == P_CONTROL_SOFT_RESET_V1
- && DECRYPT_KEY_ENABLED(multi, ks))
- {
- if (!read_control_auth(buf, &session->tls_wrap, from))
- {
- goto error;
- }
+ if (!read_control_auth(buf, &session->tls_wrap, from,
+ session->opt))
+ {
+ goto error;
+ }
- key_state_soft_reset(session);
+ dmsg(D_TLS_DEBUG,
+ "TLS: received control channel packet s#=%d sid=%s",
+ i, session_id_print(&sid, &gc));
+ }
+ }
- dmsg(D_TLS_DEBUG,
- "TLS: received P_CONTROL_SOFT_RESET_V1 s=%d sid=%s",
- i, session_id_print(&sid, &gc));
- }
- else
- {
- /*
- * Remote responding to our key renegotiation request?
- */
- if (op == P_CONTROL_SOFT_RESET_V1)
- {
- do_burst = true;
- }
+ /*
+ * We have an authenticated control channel packet (if --tls-auth was set).
+ * Now pass to our reliability layer which deals with
+ * packet acknowledgements, retransmits, sequencing, etc.
+ */
+ struct tls_session *session = &multi->session[i];
+ struct key_state *ks = &session->key[KS_PRIMARY];
- if (!read_control_auth(buf, &session->tls_wrap, from))
- {
- goto error;
- }
+ /* Make sure we were initialized and that we're not in an error state */
+ ASSERT(ks->state != S_UNDEF);
+ ASSERT(ks->state != S_ERROR);
+ ASSERT(session_id_defined(&session->session_id));
- dmsg(D_TLS_DEBUG,
- "TLS: received control channel packet s#=%d sid=%s",
- i, session_id_print(&sid, &gc));
- }
- }
+ /* Let our caller know we processed a control channel packet */
+ ret = true;
- /*
- * We have an authenticated control channel packet (if --tls-auth was set).
- * Now pass to our reliability layer which deals with
- * packet acknowledgements, retransmits, sequencing, etc.
- */
- {
- struct tls_session *session = &multi->session[i];
- struct key_state *ks = &session->key[KS_PRIMARY];
+ /*
+ * Set our remote address and remote session_id
+ */
+ if (new_link)
+ {
+ ks->session_id_remote = sid;
+ ks->remote_addr = *from;
+ ++multi->n_sessions;
+ }
+ else if (!link_socket_actual_match(&ks->remote_addr, from))
+ {
+ msg(D_TLS_ERRORS,
+ "TLS Error: Existing session control channel packet from unknown IP address: %s",
+ print_link_socket_actual(from, &gc));
+ goto error;
+ }
- /* Make sure we were initialized and that we're not in an error state */
- ASSERT(ks->state != S_UNDEF);
- ASSERT(ks->state != S_ERROR);
- ASSERT(session_id_defined(&session->session_id));
+ /*
+ * Should we do a retransmit of all unacknowledged packets in
+ * the send buffer? This improves the start-up efficiency of the
+ * initial key negotiation after the 2nd peer comes online.
+ */
+ if (do_burst && !session->burst)
+ {
+ reliable_schedule_now(ks->send_reliable);
+ session->burst = true;
+ }
- /* Let our caller know we processed a control channel packet */
- ret = true;
+ /* Check key_id */
+ if (ks->key_id != key_id)
+ {
+ msg(D_TLS_ERRORS,
+ "TLS ERROR: local/remote key IDs out of sync (%d/%d) ID: %s",
+ ks->key_id, key_id, print_key_id(multi, &gc));
+ goto error;
+ }
- /*
- * Set our remote address and remote session_id
- */
- if (new_link)
- {
- ks->session_id_remote = sid;
- ks->remote_addr = *from;
- ++multi->n_sessions;
- }
- else if (!link_socket_actual_match(&ks->remote_addr, from))
- {
- msg(D_TLS_ERRORS,
- "TLS Error: Existing session control channel packet from unknown IP address: %s",
- print_link_socket_actual(from, &gc));
- goto error;
- }
+ /*
+ * Process incoming ACKs for packets we can now
+ * delete from reliable send buffer
+ */
+ {
+ /* buffers all packet IDs to delete from send_reliable */
+ struct reliable_ack send_ack;
- /*
- * Should we do a retransmit of all unacknowledged packets in
- * the send buffer? This improves the start-up efficiency of the
- * initial key negotiation after the 2nd peer comes online.
- */
- if (do_burst && !session->burst)
- {
- reliable_schedule_now(ks->send_reliable);
- session->burst = true;
- }
+ send_ack.len = 0;
+ if (!reliable_ack_read(&send_ack, buf, &session->session_id))
+ {
+ msg(D_TLS_ERRORS,
+ "TLS Error: reading acknowledgement record from packet");
+ goto error;
+ }
+ reliable_send_purge(ks->send_reliable, &send_ack);
+ }
- /* Check key_id */
- if (ks->key_id != key_id)
- {
- msg(D_TLS_ERRORS,
- "TLS ERROR: local/remote key IDs out of sync (%d/%d) ID: %s",
- ks->key_id, key_id, print_key_id(multi, &gc));
- goto error;
- }
+ if (op != P_ACK_V1 && reliable_can_get(ks->rec_reliable))
+ {
+ packet_id_type id;
- /*
- * Process incoming ACKs for packets we can now
- * delete from reliable send buffer
- */
+ /* Extract the packet ID from the packet */
+ if (reliable_ack_read_packet_id(buf, &id))
+ {
+ /* Avoid deadlock by rejecting packet that would de-sequentialize receive buffer */
+ if (reliable_wont_break_sequentiality(ks->rec_reliable, id))
+ {
+ if (reliable_not_replay(ks->rec_reliable, id))
{
- /* buffers all packet IDs to delete from send_reliable */
- struct reliable_ack send_ack;
-
- send_ack.len = 0;
- if (!reliable_ack_read(&send_ack, buf, &session->session_id))
+ /* Save incoming ciphertext packet to reliable buffer */
+ struct buffer *in = reliable_get_buf(ks->rec_reliable);
+ ASSERT(in);
+ if (!buf_copy(in, buf))
{
- msg(D_TLS_ERRORS,
- "TLS Error: reading acknowledgement record from packet");
+ msg(D_MULTI_DROPPED,
+ "Incoming control channel packet too big, dropping.");
goto error;
}
- reliable_send_purge(ks->send_reliable, &send_ack);
+ reliable_mark_active_incoming(ks->rec_reliable, in, id, op);
}
- if (op != P_ACK_V1 && reliable_can_get(ks->rec_reliable))
- {
- packet_id_type id;
-
- /* Extract the packet ID from the packet */
- if (reliable_ack_read_packet_id(buf, &id))
- {
- /* Avoid deadlock by rejecting packet that would de-sequentialize receive buffer */
- if (reliable_wont_break_sequentiality(ks->rec_reliable, id))
- {
- if (reliable_not_replay(ks->rec_reliable, id))
- {
- /* Save incoming ciphertext packet to reliable buffer */
- struct buffer *in = reliable_get_buf(ks->rec_reliable);
- ASSERT(in);
- if(!buf_copy(in, buf))
- {
- msg(D_MULTI_DROPPED,
- "Incoming control channel packet too big, dropping.");
- goto error;
- }
- reliable_mark_active_incoming(ks->rec_reliable, in, id, op);
- }
-
- /* Process outgoing acknowledgment for packet just received, even if it's a replay */
- reliable_ack_acknowledge_packet_id(ks->rec_ack, id);
- }
- }
- }
+ /* Process outgoing acknowledgment for packet just received, even if it's a replay */
+ reliable_ack_acknowledge_packet_id(ks->rec_ack, id);
}
}
}
@@ -3811,7 +3688,6 @@ done:
error:
++multi->n_soft_errors;
-error_lite:
tls_clear_error();
goto done;
}
@@ -3833,94 +3709,91 @@ tls_pre_decrypt_lite(const struct tls_auth_standalone *tas,
const struct buffer *buf)
{
- struct gc_arena gc = gc_new();
- bool ret = false;
-
- if (buf->len > 0)
+ if (buf->len <= 0)
{
- int op;
- int key_id;
+ return false;
+ }
+ struct gc_arena gc = gc_new();
- /* get opcode and key ID */
- {
- uint8_t c = *BPTR(buf);
- op = c >> P_OPCODE_SHIFT;
- key_id = c & P_KEY_ID_MASK;
- }
+ /* get opcode and key ID */
+ uint8_t pkt_firstbyte = *BPTR(buf);
+ int op = pkt_firstbyte >> P_OPCODE_SHIFT;
+ int key_id = pkt_firstbyte & P_KEY_ID_MASK;
- /* this packet is from an as-yet untrusted source, so
- * scrutinize carefully */
+ /* this packet is from an as-yet untrusted source, so
+ * scrutinize carefully */
- if (op != P_CONTROL_HARD_RESET_CLIENT_V2)
- {
- /*
- * This can occur due to bogus data or DoS packets.
- */
- dmsg(D_TLS_STATE_ERRORS,
- "TLS State Error: No TLS state for client %s, opcode=%d",
- print_link_socket_actual(from, &gc),
- op);
- goto error;
- }
+ if (op != P_CONTROL_HARD_RESET_CLIENT_V2
+ && op != P_CONTROL_HARD_RESET_CLIENT_V3)
+ {
+ /*
+ * This can occur due to bogus data or DoS packets.
+ */
+ dmsg(D_TLS_STATE_ERRORS,
+ "TLS State Error: No TLS state for client %s, opcode=%d",
+ print_link_socket_actual(from, &gc),
+ op);
+ goto error;
+ }
- if (key_id != 0)
- {
- dmsg(D_TLS_STATE_ERRORS,
- "TLS State Error: Unknown key ID (%d) received from %s -- 0 was expected",
- key_id,
- print_link_socket_actual(from, &gc));
- goto error;
- }
+ if (key_id != 0)
+ {
+ dmsg(D_TLS_STATE_ERRORS,
+ "TLS State Error: Unknown key ID (%d) received from %s -- 0 was expected",
+ key_id,
+ print_link_socket_actual(from, &gc));
+ goto error;
+ }
- if (buf->len > EXPANDED_SIZE_DYNAMIC(&tas->frame))
- {
- dmsg(D_TLS_STATE_ERRORS,
- "TLS State Error: Large packet (size %d) received from %s -- a packet no larger than %d bytes was expected",
- buf->len,
- print_link_socket_actual(from, &gc),
- EXPANDED_SIZE_DYNAMIC(&tas->frame));
- goto error;
- }
+ if (buf->len > EXPANDED_SIZE_DYNAMIC(&tas->frame))
+ {
+ dmsg(D_TLS_STATE_ERRORS,
+ "TLS State Error: Large packet (size %d) received from %s -- a packet no larger than %d bytes was expected",
+ buf->len,
+ print_link_socket_actual(from, &gc),
+ EXPANDED_SIZE_DYNAMIC(&tas->frame));
+ goto error;
+ }
- {
- struct buffer newbuf = clone_buf(buf);
- struct tls_wrap_ctx tls_wrap_tmp = tas->tls_wrap;
- bool status;
-
- /* HMAC test, if --tls-auth was specified */
- status = read_control_auth(&newbuf, &tls_wrap_tmp, from);
- free_buf(&newbuf);
- if (!status)
- {
- goto error;
- }
- /*
- * At this point, if --tls-auth is being used, we know that
- * the packet has passed the HMAC test, but we don't know if
- * it is a replay yet. We will attempt to defeat replays
- * by not advancing to the S_START state until we
- * receive an ACK from our first reply to the client
- * that includes an HMAC of our randomly generated 64 bit
- * session ID.
- *
- * On the other hand if --tls-auth is not being used, we
- * will proceed to begin the TLS authentication
- * handshake with only cursory integrity checks having
- * been performed, since we will be leaving the task
- * of authentication solely up to TLS.
- */
+ struct buffer newbuf = clone_buf(buf);
+ struct tls_wrap_ctx tls_wrap_tmp = tas->tls_wrap;
- ret = true;
- }
+ /* HMAC test, if --tls-auth was specified */
+ bool status = read_control_auth(&newbuf, &tls_wrap_tmp, from, NULL);
+ free_buf(&newbuf);
+ free_buf(&tls_wrap_tmp.tls_crypt_v2_metadata);
+ if (tls_wrap_tmp.cleanup_key_ctx)
+ {
+ free_key_ctx_bi(&tls_wrap_tmp.opt.key_ctx_bi);
}
+ if (!status)
+ {
+ goto error;
+ }
+
+ /*
+ * At this point, if --tls-auth is being used, we know that
+ * the packet has passed the HMAC test, but we don't know if
+ * it is a replay yet. We will attempt to defeat replays
+ * by not advancing to the S_START state until we
+ * receive an ACK from our first reply to the client
+ * that includes an HMAC of our randomly generated 64 bit
+ * session ID.
+ *
+ * On the other hand if --tls-auth is not being used, we
+ * will proceed to begin the TLS authentication
+ * handshake with only cursory integrity checks having
+ * been performed, since we will be leaving the task
+ * of authentication solely up to TLS.
+ */
gc_free(&gc);
- return ret;
+ return true;
error:
tls_clear_error();
gc_free(&gc);
- return ret;
+ return false;
}
/* Choose the key with which to encrypt a data packet */
@@ -3929,51 +3802,51 @@ tls_pre_encrypt(struct tls_multi *multi,
struct buffer *buf, struct crypto_options **opt)
{
multi->save_ks = NULL;
- if (buf->len > 0)
+ if (buf->len <= 0)
+ {
+ buf->len = 0;
+ *opt = NULL;
+ return;
+ }
+
+ struct key_state *ks_select = NULL;
+ for (int i = 0; i < KEY_SCAN_SIZE; ++i)
{
- int i;
- struct key_state *ks_select = NULL;
- for (i = 0; i < KEY_SCAN_SIZE; ++i)
+ struct key_state *ks = multi->key_scan[i];
+ if (ks->state >= S_ACTIVE
+ && (ks->authenticated == KS_AUTH_TRUE)
+ && ks->crypto_options.key_ctx_bi.initialized
+ )
{
- 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
- )
+ if (!ks_select)
{
- if (!ks_select)
- {
- ks_select = ks;
- }
- if (now >= ks->auth_deferred_expire)
- {
- ks_select = ks;
- break;
- }
+ ks_select = ks;
+ }
+ if (now >= ks->auth_deferred_expire)
+ {
+ ks_select = ks;
+ break;
}
}
+ }
- if (ks_select)
- {
- *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;
- }
- else
- {
- struct gc_arena gc = gc_new();
- dmsg(D_TLS_KEYSELECT, "TLS Warning: no data channel send key available: %s",
- print_key_id(multi, &gc));
- gc_free(&gc);
- }
+ if (ks_select)
+ {
+ *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;
}
+ else
+ {
+ struct gc_arena gc = gc_new();
+ dmsg(D_TLS_KEYSELECT, "TLS Warning: no data channel send key available: %s",
+ print_key_id(multi, &gc));
+ gc_free(&gc);
- buf->len = 0;
- *opt = NULL;
+ *opt = NULL;
+ buf->len = 0;
+ }
}
void
@@ -4097,13 +3970,11 @@ 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)
+ for (int i = 0; i < TM_SIZE; ++i)
{
struct tls_session *session = &multi->session[i];
- for (j = 0; j < KS_SIZE; ++j)
+ for (int j = 0; j < KS_SIZE; ++j)
{
struct key_state *ks = &session->key[j];
@@ -4123,45 +3994,6 @@ tls_update_remote_addr(struct tls_multi *multi, const struct link_socket_actual
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;
-}
-
void
show_available_tls_ciphers(const char *cipher_list,
const char *cipher_list_tls13,
@@ -4169,21 +4001,20 @@ show_available_tls_ciphers(const char *cipher_list,
{
printf("Available TLS Ciphers, listed in order of preference:\n");
-#if (ENABLE_CRYPTO_OPENSSL && OPENSSL_VERSION_NUMBER >= 0x1010100fL)
- printf("\nFor TLS 1.3 and newer (--tls-ciphersuites):\n\n");
- show_available_tls_ciphers_list(cipher_list_tls13, tls_cert_profile, true);
-#else
- (void) cipher_list_tls13; /* Avoid unused warning */
-#endif
+ if (tls_version_max() >= TLS_VER_1_3)
+ {
+ printf("\nFor TLS 1.3 and newer (--tls-ciphersuites):\n\n");
+ show_available_tls_ciphers_list(cipher_list_tls13, tls_cert_profile, true);
+ }
printf("\nFor TLS 1.2 and older (--tls-cipher):\n\n");
show_available_tls_ciphers_list(cipher_list, tls_cert_profile, false);
printf("\n"
- "Be aware that that whether a cipher suite in this list can actually work\n"
- "depends on the specific setup of both peers. See the man page entries of\n"
- "--tls-cipher and --show-tls for more details.\n\n"
- );
+ "Be aware that that whether a cipher suite in this list can actually work\n"
+ "depends on the specific setup of both peers. See the man page entries of\n"
+ "--tls-cipher and --show-tls for more details.\n\n"
+ );
}
/*
@@ -4309,15 +4140,7 @@ done:
}
void
-delayed_auth_pass_purge(void)
+ssl_clean_user_pass(void)
{
- auth_user_pass.wait_for_push = false;
purge_user_pass(&auth_user_pass, false);
}
-
-#else /* if defined(ENABLE_CRYPTO) */
-static void
-dummy(void)
-{
-}
-#endif /* ENABLE_CRYPTO */