6fbf66fa |
/*
* OpenVPN -- An application to securely tunnel IP networks
* over a single TCP/UDP port, with support for SSL/TLS-based
* session authentication and key exchange,
* packet encryption, packet authentication, and
* packet compression.
* |
49979459 |
* Copyright (C) 2002-2018 OpenVPN Inc <sales@openvpn.net>
* Copyright (C) 2010-2018 Fox Crypto B.V. <openvpn@fox-it.com> |
e3d38865 |
* Copyright (C) 2008-2013 David Sommerseth <dazo@users.sourceforge.net> |
0c1f7ad5 |
* |
6fbf66fa |
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2
* as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
* |
caa54ac3 |
* You should have received a copy of the GNU General Public License along
* with this program; if not, write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. |
6fbf66fa |
*/
|
95993a1d |
/**
* @file Control Channel SSL/Data channel negotiation Module
*/
|
6fbf66fa |
/*
* The routines in this file deal with dynamically negotiating
* the data channel HMAC and cipher keys through a TLS session.
*
* Both the TLS session and the data channel are multiplexed
* over the same TCP/UDP port.
*/ |
c110b289 |
#ifdef HAVE_CONFIG_H
#include "config.h"
#elif defined(_MSC_VER)
#include "config-msvc.h"
#endif
|
1bda73a7 |
#include "syshead.h" |
cdc65ea0 |
#include "win32.h" |
6fbf66fa |
#include "error.h"
#include "common.h"
#include "socket.h"
#include "misc.h"
#include "fdmisc.h"
#include "interval.h"
#include "perf.h"
#include "status.h"
#include "gremlin.h" |
ce98fd24 |
#include "pkcs11.h" |
7fb0e07e |
#include "route.h" |
c6e24fa3 |
#include "tls_crypt.h" |
6fbf66fa |
|
95993a1d |
#include "ssl.h"
#include "ssl_verify.h"
#include "ssl_backend.h"
|
6fbf66fa |
#include "memdbg.h"
#ifndef ENABLE_OCC
static const char ssl_default_options_string[] = "V0 UNDEF";
#endif
static inline const char * |
81d882d5 |
local_options_string(const struct tls_session *session) |
6fbf66fa |
{
#ifdef ENABLE_OCC |
81d882d5 |
return session->opt->local_options; |
6fbf66fa |
#else |
81d882d5 |
return ssl_default_options_string; |
6fbf66fa |
#endif
}
#ifdef MEASURE_TLS_HANDSHAKE_STATS
static int tls_handshake_success; /* GLOBAL */
static int tls_handshake_error; /* GLOBAL */
static int tls_packets_generated; /* GLOBAL */
static int tls_packets_sent; /* GLOBAL */
#define INCR_SENT ++tls_packets_sent
#define INCR_GENERATED ++tls_packets_generated
#define INCR_SUCCESS ++tls_handshake_success
#define INCR_ERROR ++tls_handshake_error
void
show_tls_performance_stats(void)
{ |
81d882d5 |
msg(D_TLS_DEBUG_LOW, "TLS Handshakes, success=%f%% (good=%d, bad=%d), retransmits=%f%%",
(double) tls_handshake_success / (tls_handshake_success + tls_handshake_error) * 100.0,
tls_handshake_success, tls_handshake_error,
(double) (tls_packets_sent - tls_packets_generated) / tls_packets_generated * 100.0); |
6fbf66fa |
} |
81d882d5 |
#else /* ifdef MEASURE_TLS_HANDSHAKE_STATS */ |
6fbf66fa |
#define INCR_SENT
#define INCR_GENERATED
#define INCR_SUCCESS
#define INCR_ERROR
|
81d882d5 |
#endif /* ifdef MEASURE_TLS_HANDSHAKE_STATS */ |
6fbf66fa |
|
3b23b18d |
/**
* SSL/TLS Cipher suite name translation table
*/
static const tls_cipher_name_pair tls_cipher_name_translation_table[] = {
{"ADH-SEED-SHA", "TLS-DH-anon-WITH-SEED-CBC-SHA"},
{"AES128-GCM-SHA256", "TLS-RSA-WITH-AES-128-GCM-SHA256"},
{"AES128-SHA256", "TLS-RSA-WITH-AES-128-CBC-SHA256"},
{"AES128-SHA", "TLS-RSA-WITH-AES-128-CBC-SHA"},
{"AES256-GCM-SHA384", "TLS-RSA-WITH-AES-256-GCM-SHA384"},
{"AES256-SHA256", "TLS-RSA-WITH-AES-256-CBC-SHA256"},
{"AES256-SHA", "TLS-RSA-WITH-AES-256-CBC-SHA"},
{"CAMELLIA128-SHA256", "TLS-RSA-WITH-CAMELLIA-128-CBC-SHA256"},
{"CAMELLIA128-SHA", "TLS-RSA-WITH-CAMELLIA-128-CBC-SHA"},
{"CAMELLIA256-SHA256", "TLS-RSA-WITH-CAMELLIA-256-CBC-SHA256"},
{"CAMELLIA256-SHA", "TLS-RSA-WITH-CAMELLIA-256-CBC-SHA"},
{"DES-CBC3-SHA", "TLS-RSA-WITH-3DES-EDE-CBC-SHA"},
{"DES-CBC-SHA", "TLS-RSA-WITH-DES-CBC-SHA"},
{"DH-DSS-SEED-SHA", "TLS-DH-DSS-WITH-SEED-CBC-SHA"},
{"DHE-DSS-AES128-GCM-SHA256", "TLS-DHE-DSS-WITH-AES-128-GCM-SHA256"},
{"DHE-DSS-AES128-SHA256", "TLS-DHE-DSS-WITH-AES-128-CBC-SHA256"},
{"DHE-DSS-AES128-SHA", "TLS-DHE-DSS-WITH-AES-128-CBC-SHA"},
{"DHE-DSS-AES256-GCM-SHA384", "TLS-DHE-DSS-WITH-AES-256-GCM-SHA384"},
{"DHE-DSS-AES256-SHA256", "TLS-DHE-DSS-WITH-AES-256-CBC-SHA256"},
{"DHE-DSS-AES256-SHA", "TLS-DHE-DSS-WITH-AES-256-CBC-SHA"},
{"DHE-DSS-CAMELLIA128-SHA256", "TLS-DHE-DSS-WITH-CAMELLIA-128-CBC-SHA256"},
{"DHE-DSS-CAMELLIA128-SHA", "TLS-DHE-DSS-WITH-CAMELLIA-128-CBC-SHA"},
{"DHE-DSS-CAMELLIA256-SHA256", "TLS-DHE-DSS-WITH-CAMELLIA-256-CBC-SHA256"},
{"DHE-DSS-CAMELLIA256-SHA", "TLS-DHE-DSS-WITH-CAMELLIA-256-CBC-SHA"},
{"DHE-DSS-SEED-SHA", "TLS-DHE-DSS-WITH-SEED-CBC-SHA"},
{"DHE-RSA-AES128-GCM-SHA256", "TLS-DHE-RSA-WITH-AES-128-GCM-SHA256"},
{"DHE-RSA-AES128-SHA256", "TLS-DHE-RSA-WITH-AES-128-CBC-SHA256"},
{"DHE-RSA-AES128-SHA", "TLS-DHE-RSA-WITH-AES-128-CBC-SHA"},
{"DHE-RSA-AES256-GCM-SHA384", "TLS-DHE-RSA-WITH-AES-256-GCM-SHA384"},
{"DHE-RSA-AES256-SHA256", "TLS-DHE-RSA-WITH-AES-256-CBC-SHA256"},
{"DHE-RSA-AES256-SHA", "TLS-DHE-RSA-WITH-AES-256-CBC-SHA"},
{"DHE-RSA-CAMELLIA128-SHA256", "TLS-DHE-RSA-WITH-CAMELLIA-128-CBC-SHA256"},
{"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"}, |
e7ec6a3a |
{"DHE-RSA-CHACHA20-POLY1305", "TLS-DHE-RSA-WITH-CHACHA20-POLY1305-SHA256"}, |
3b23b18d |
{"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"},
{"ECDH-ECDSA-AES128-SHA256", "TLS-ECDH-ECDSA-WITH-AES-128-CBC-SHA256"},
{"ECDH-ECDSA-AES128-SHA", "TLS-ECDH-ECDSA-WITH-AES-128-CBC-SHA"},
{"ECDH-ECDSA-AES256-GCM-SHA384", "TLS-ECDH-ECDSA-WITH-AES-256-GCM-SHA384"},
{"ECDH-ECDSA-AES256-SHA256", "TLS-ECDH-ECDSA-WITH-AES-256-CBC-SHA256"},
{"ECDH-ECDSA-AES256-SHA384", "TLS-ECDH-ECDSA-WITH-AES-256-CBC-SHA384"},
{"ECDH-ECDSA-AES256-SHA", "TLS-ECDH-ECDSA-WITH-AES-256-CBC-SHA"},
{"ECDH-ECDSA-CAMELLIA128-SHA256", "TLS-ECDH-ECDSA-WITH-CAMELLIA-128-CBC-SHA256"},
{"ECDH-ECDSA-CAMELLIA128-SHA", "TLS-ECDH-ECDSA-WITH-CAMELLIA-128-CBC-SHA"},
{"ECDH-ECDSA-CAMELLIA256-SHA256", "TLS-ECDH-ECDSA-WITH-CAMELLIA-256-CBC-SHA256"},
{"ECDH-ECDSA-CAMELLIA256-SHA", "TLS-ECDH-ECDSA-WITH-CAMELLIA-256-CBC-SHA"},
{"ECDH-ECDSA-DES-CBC3-SHA", "TLS-ECDH-ECDSA-WITH-3DES-EDE-CBC-SHA"},
{"ECDH-ECDSA-DES-CBC-SHA", "TLS-ECDH-ECDSA-WITH-DES-CBC-SHA"},
{"ECDH-ECDSA-RC4-SHA", "TLS-ECDH-ECDSA-WITH-RC4-128-SHA"},
{"ECDHE-ECDSA-AES128-GCM-SHA256", "TLS-ECDHE-ECDSA-WITH-AES-128-GCM-SHA256"},
{"ECDHE-ECDSA-AES128-SHA256", "TLS-ECDHE-ECDSA-WITH-AES-128-CBC-SHA256"},
{"ECDHE-ECDSA-AES128-SHA384", "TLS-ECDHE-ECDSA-WITH-AES-128-CBC-SHA384"},
{"ECDHE-ECDSA-AES128-SHA", "TLS-ECDHE-ECDSA-WITH-AES-128-CBC-SHA"},
{"ECDHE-ECDSA-AES256-GCM-SHA384", "TLS-ECDHE-ECDSA-WITH-AES-256-GCM-SHA384"},
{"ECDHE-ECDSA-AES256-SHA256", "TLS-ECDHE-ECDSA-WITH-AES-256-CBC-SHA256"},
{"ECDHE-ECDSA-AES256-SHA384", "TLS-ECDHE-ECDSA-WITH-AES-256-CBC-SHA384"},
{"ECDHE-ECDSA-AES256-SHA", "TLS-ECDHE-ECDSA-WITH-AES-256-CBC-SHA"},
{"ECDHE-ECDSA-CAMELLIA128-SHA256", "TLS-ECDHE-ECDSA-WITH-CAMELLIA-128-CBC-SHA256"},
{"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"}, |
e7ec6a3a |
{"ECDHE-ECDSA-CHACHA20-POLY1305", "TLS-ECDHE-ECDSA-WITH-CHACHA20-POLY1305-SHA256"}, |
3b23b18d |
{"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"},
{"ECDHE-RSA-AES128-GCM-SHA256", "TLS-ECDHE-RSA-WITH-AES-128-GCM-SHA256"},
{"ECDHE-RSA-AES128-SHA256", "TLS-ECDHE-RSA-WITH-AES-128-CBC-SHA256"},
{"ECDHE-RSA-AES128-SHA384", "TLS-ECDHE-RSA-WITH-AES-128-CBC-SHA384"},
{"ECDHE-RSA-AES128-SHA", "TLS-ECDHE-RSA-WITH-AES-128-CBC-SHA"},
{"ECDHE-RSA-AES256-GCM-SHA384", "TLS-ECDHE-RSA-WITH-AES-256-GCM-SHA384"},
{"ECDHE-RSA-AES256-SHA256", "TLS-ECDHE-RSA-WITH-AES-256-CBC-SHA256"},
{"ECDHE-RSA-AES256-SHA384", "TLS-ECDHE-RSA-WITH-AES-256-CBC-SHA384"},
{"ECDHE-RSA-AES256-SHA", "TLS-ECDHE-RSA-WITH-AES-256-CBC-SHA"},
{"ECDHE-RSA-CAMELLIA128-SHA256", "TLS-ECDHE-RSA-WITH-CAMELLIA-128-CBC-SHA256"},
{"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"}, |
e7ec6a3a |
{"ECDHE-RSA-CHACHA20-POLY1305", "TLS-ECDHE-RSA-WITH-CHACHA20-POLY1305-SHA256"}, |
3b23b18d |
{"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"},
{"ECDH-RSA-AES128-GCM-SHA256", "TLS-ECDH-RSA-WITH-AES-128-GCM-SHA256"},
{"ECDH-RSA-AES128-SHA256", "TLS-ECDH-RSA-WITH-AES-128-CBC-SHA256"},
{"ECDH-RSA-AES128-SHA384", "TLS-ECDH-RSA-WITH-AES-128-CBC-SHA384"},
{"ECDH-RSA-AES128-SHA", "TLS-ECDH-RSA-WITH-AES-128-CBC-SHA"},
{"ECDH-RSA-AES256-GCM-SHA384", "TLS-ECDH-RSA-WITH-AES-256-GCM-SHA384"},
{"ECDH-RSA-AES256-SHA256", "TLS-ECDH-RSA-WITH-AES-256-CBC-SHA256"},
{"ECDH-RSA-AES256-SHA384", "TLS-ECDH-RSA-WITH-AES-256-CBC-SHA384"},
{"ECDH-RSA-AES256-SHA", "TLS-ECDH-RSA-WITH-AES-256-CBC-SHA"},
{"ECDH-RSA-CAMELLIA128-SHA256", "TLS-ECDH-RSA-WITH-CAMELLIA-128-CBC-SHA256"},
{"ECDH-RSA-CAMELLIA128-SHA", "TLS-ECDH-RSA-WITH-CAMELLIA-128-CBC-SHA"},
{"ECDH-RSA-CAMELLIA256-SHA256", "TLS-ECDH-RSA-WITH-CAMELLIA-256-CBC-SHA256"},
{"ECDH-RSA-CAMELLIA256-SHA", "TLS-ECDH-RSA-WITH-CAMELLIA-256-CBC-SHA"},
{"ECDH-RSA-DES-CBC3-SHA", "TLS-ECDH-RSA-WITH-3DES-EDE-CBC-SHA"},
{"ECDH-RSA-DES-CBC-SHA", "TLS-ECDH-RSA-WITH-DES-CBC-SHA"},
{"ECDH-RSA-RC4-SHA", "TLS-ECDH-RSA-WITH-RC4-128-SHA"},
{"EDH-DSS-DES-CBC3-SHA", "TLS-DHE-DSS-WITH-3DES-EDE-CBC-SHA"},
{"EDH-DSS-DES-CBC-SHA", "TLS-DHE-DSS-WITH-DES-CBC-SHA"},
{"EDH-RSA-DES-CBC3-SHA", "TLS-DHE-RSA-WITH-3DES-EDE-CBC-SHA"},
{"EDH-RSA-DES-CBC-SHA", "TLS-DHE-RSA-WITH-DES-CBC-SHA"},
{"EXP-DES-CBC-SHA", "TLS-RSA-EXPORT-WITH-DES40-CBC-SHA"},
{"EXP-EDH-DSS-DES-CBC-SHA", "TLS-DH-DSS-EXPORT-WITH-DES40-CBC-SHA"},
{"EXP-EDH-RSA-DES-CBC-SHA", "TLS-DH-RSA-EXPORT-WITH-DES40-CBC-SHA"},
{"EXP-RC2-CBC-MD5", "TLS-RSA-EXPORT-WITH-RC2-CBC-40-MD5"},
{"EXP-RC4-MD5", "TLS-RSA-EXPORT-WITH-RC4-40-MD5"},
{"NULL-MD5", "TLS-RSA-WITH-NULL-MD5"},
{"NULL-SHA256", "TLS-RSA-WITH-NULL-SHA256"},
{"NULL-SHA", "TLS-RSA-WITH-NULL-SHA"},
{"PSK-3DES-EDE-CBC-SHA", "TLS-PSK-WITH-3DES-EDE-CBC-SHA"},
{"PSK-AES128-CBC-SHA", "TLS-PSK-WITH-AES-128-CBC-SHA"},
{"PSK-AES256-CBC-SHA", "TLS-PSK-WITH-AES-256-CBC-SHA"},
{"PSK-RC4-SHA", "TLS-PSK-WITH-RC4-128-SHA"},
{"RC4-MD5", "TLS-RSA-WITH-RC4-128-MD5"},
{"RC4-SHA", "TLS-RSA-WITH-RC4-128-SHA"},
{"SEED-SHA", "TLS-RSA-WITH-SEED-CBC-SHA"},
{"SRP-DSS-3DES-EDE-CBC-SHA", "TLS-SRP-SHA-DSS-WITH-3DES-EDE-CBC-SHA"},
{"SRP-DSS-AES-128-CBC-SHA", "TLS-SRP-SHA-DSS-WITH-AES-128-CBC-SHA"},
{"SRP-DSS-AES-256-CBC-SHA", "TLS-SRP-SHA-DSS-WITH-AES-256-CBC-SHA"},
{"SRP-RSA-3DES-EDE-CBC-SHA", "TLS-SRP-SHA-RSA-WITH-3DES-EDE-CBC-SHA"},
{"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"}, |
0146fd00 |
#ifdef ENABLE_CRYPTO_OPENSSL |
7246ccfd |
/* OpenSSL-specific group names */ |
0146fd00 |
{"DEFAULT", "DEFAULT"},
{"ALL", "ALL"}, |
7246ccfd |
{"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"}, |
0146fd00 |
#endif |
3b23b18d |
{NULL, NULL}
};
|
66407e11 |
/**
* 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.
* |
81d882d5 |
* @param ctx Encrypt/decrypt key context
* @param key HMAC key, used to calculate implicit IV
* @param key_len HMAC key length |
66407e11 |
*/
static void
key_ctx_update_implicit_iv(struct key_ctx *ctx, uint8_t *key, size_t key_len);
|
3b23b18d |
const tls_cipher_name_pair * |
4cd4899e |
tls_get_cipher_name_pair(const char *cipher_name, size_t len)
{ |
81d882d5 |
const tls_cipher_name_pair *pair = tls_cipher_name_translation_table; |
3b23b18d |
|
4cd4899e |
while (pair->openssl_name != NULL)
{ |
81d882d5 |
if ((strlen(pair->openssl_name) == len && 0 == memcmp(cipher_name, pair->openssl_name, len))
|| (strlen(pair->iana_name) == len && 0 == memcmp(cipher_name, pair->iana_name, len)))
{
return pair;
}
pair++;
} |
3b23b18d |
|
81d882d5 |
/* No entry found, return NULL */
return NULL; |
3b23b18d |
} |
6fbf66fa |
|
752caece |
/**
* Limit the reneg_bytes value when using a small-block (<128 bytes) cipher.
* |
81d882d5 |
* @param cipher The current cipher (may be NULL).
* @param reneg_bytes Pointer to the current reneg_bytes, updated if needed.
* May *not* be NULL. |
752caece |
*/
static void |
81d882d5 |
tls_limit_reneg_bytes(const cipher_kt_t *cipher, int *reneg_bytes) |
752caece |
{ |
81d882d5 |
if (cipher && (cipher_kt_block_size(cipher) < 128/8)) |
752caece |
{ |
81d882d5 |
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;
} |
752caece |
}
}
|
9e0963c1 |
/*
* Max number of bytes we will add
* for data structures common to both
* data and control channel packets.
* (opcode only). |
6fbf66fa |
*/
void
tls_adjust_frame_parameters(struct frame *frame)
{ |
81d882d5 |
frame_add_to_extra_frame(frame, 1); /* space for opcode */ |
6fbf66fa |
}
/*
* Max number of bytes we will add |
81d882d5 |
* to control channel packet. |
6fbf66fa |
*/
static void
tls_init_control_channel_frame_parameters(const struct frame *data_channel_frame, |
81d882d5 |
struct frame *frame) |
6fbf66fa |
{ |
81d882d5 |
/*
* frame->extra_frame is already initialized with tls_auth buffer requirements,
* if --tls-auth is enabled.
*/
/* inherit link MTU and extra_link from data channel */
frame->link_mtu = data_channel_frame->link_mtu;
frame->extra_link = data_channel_frame->extra_link;
/* set extra_frame */
tls_adjust_frame_parameters(frame);
reliable_ack_adjust_frame_parameters(frame, CONTROL_SEND_ACK_MAX);
frame_add_to_extra_frame(frame, SID_SIZE + sizeof(packet_id_type));
/* set dynamic link MTU to cap control channel packets at 1250 bytes */
ASSERT(TUN_LINK_DELTA(frame) < min_int(frame->link_mtu, 1250));
frame->link_mtu_dynamic = min_int(frame->link_mtu, 1250) - TUN_LINK_DELTA(frame); |
6fbf66fa |
}
void |
e2a0cad4 |
init_ssl_lib(void) |
6fbf66fa |
{ |
81d882d5 |
tls_init_lib(); |
6fbf66fa |
|
81d882d5 |
crypto_init_lib(); |
6fbf66fa |
}
void |
e2a0cad4 |
free_ssl_lib(void) |
6fbf66fa |
{ |
81d882d5 |
crypto_uninit_lib();
prng_uninit();
tls_free_lib(); |
6fbf66fa |
}
/*
* OpenSSL library calls pem_password_callback if the
* private key is protected by a password.
*/
static struct user_pass passbuf; /* GLOBAL */
void |
81d882d5 |
pem_password_setup(const char *auth_file) |
6fbf66fa |
{ |
81d882d5 |
if (!strlen(passbuf.password))
{
get_user_pass(&passbuf, auth_file, UP_TYPE_PRIVATE_KEY, GET_USER_PASS_MANAGEMENT|GET_USER_PASS_PASSWORD_ONLY);
} |
6fbf66fa |
}
int |
81d882d5 |
pem_password_callback(char *buf, int size, int rwflag, void *u) |
6fbf66fa |
{ |
81d882d5 |
if (buf) |
6fbf66fa |
{ |
81d882d5 |
/* prompt for password even if --askpass wasn't specified */
pem_password_setup(NULL);
strncpynt(buf, passbuf.password, size);
purge_user_pass(&passbuf, false); |
6fbf66fa |
|
81d882d5 |
return strlen(buf); |
6fbf66fa |
} |
81d882d5 |
return 0; |
6fbf66fa |
}
/*
* Auth username/password handling
*/
static bool auth_user_pass_enabled; /* GLOBAL */
static struct user_pass auth_user_pass; /* GLOBAL */
|
3cf9dd88 |
#ifdef ENABLE_CLIENT_CR
static char *auth_challenge; /* GLOBAL */
#endif
|
6fbf66fa |
void |
81d882d5 |
auth_user_pass_setup(const char *auth_file, const struct static_challenge_info *sci) |
6fbf66fa |
{ |
81d882d5 |
auth_user_pass_enabled = true;
if (!auth_user_pass.defined) |
5f31881e |
{
#if AUTO_USERID |
81d882d5 |
get_user_pass_auto_userid(&auth_user_pass, auth_file); |
5f31881e |
#else |
81d882d5 |
#ifdef ENABLE_CLIENT_CR
if (auth_challenge) /* dynamic challenge/response */
{
get_user_pass_cr(&auth_user_pass,
auth_file,
UP_TYPE_AUTH,
GET_USER_PASS_MANAGEMENT|GET_USER_PASS_DYNAMIC_CHALLENGE,
auth_challenge);
}
else if (sci) /* static challenge response */
{
int flags = GET_USER_PASS_MANAGEMENT|GET_USER_PASS_STATIC_CHALLENGE;
if (sci->flags & SC_ECHO)
{
flags |= GET_USER_PASS_STATIC_CHALLENGE_ECHO;
}
get_user_pass_cr(&auth_user_pass,
auth_file,
UP_TYPE_AUTH,
flags,
sci->challenge_text);
}
else
#endif /* ifdef ENABLE_CLIENT_CR */
get_user_pass(&auth_user_pass, auth_file, UP_TYPE_AUTH, GET_USER_PASS_MANAGEMENT);
#endif /* if AUTO_USERID */ |
5f31881e |
} |
6fbf66fa |
}
/*
* Disable password caching
*/
void |
81d882d5 |
ssl_set_auth_nocache(void) |
6fbf66fa |
{ |
81d882d5 |
passbuf.nocache = true;
auth_user_pass.nocache = true; |
57116536 |
/* wait for push-reply, because auth-token may invert nocache */
auth_user_pass.wait_for_push = true; |
6fbf66fa |
}
/* |
0db046f2 |
* Set an authentication token
*/
void |
81d882d5 |
ssl_set_auth_token(const char *token) |
0db046f2 |
{ |
57116536 |
if (auth_user_pass.nocache)
{
msg(M_INFO,
"auth-token received, disabling auth-nocache for the "
"authentication token");
auth_user_pass.nocache = false;
}
|
81d882d5 |
set_auth_token(&auth_user_pass, token); |
0db046f2 |
}
/* |
6fbf66fa |
* Forget private key password AND auth-user-pass username/password.
*/
void |
81d882d5 |
ssl_purge_auth(const bool auth_user_pass_only) |
6fbf66fa |
{ |
81d882d5 |
if (!auth_user_pass_only) |
0db046f2 |
{ |
18b5fbdf |
#ifdef ENABLE_PKCS11 |
81d882d5 |
pkcs11_logout(); |
718526e0 |
#endif |
81d882d5 |
purge_user_pass(&passbuf, true); |
0db046f2 |
} |
81d882d5 |
purge_user_pass(&auth_user_pass, true); |
3cf9dd88 |
#ifdef ENABLE_CLIENT_CR |
81d882d5 |
ssl_purge_auth_challenge(); |
3cf9dd88 |
#endif
}
#ifdef ENABLE_CLIENT_CR
void |
81d882d5 |
ssl_purge_auth_challenge(void) |
3cf9dd88 |
{ |
81d882d5 |
free(auth_challenge);
auth_challenge = NULL; |
6fbf66fa |
}
|
3cf9dd88 |
void |
81d882d5 |
ssl_put_auth_challenge(const char *cr_str) |
3cf9dd88 |
{ |
81d882d5 |
ssl_purge_auth_challenge();
auth_challenge = string_alloc(cr_str, NULL); |
3cf9dd88 |
}
#endif
|
6fbf66fa |
/* |
4b67f984 |
* Parse a TLS version string, returning a TLS_VER_x constant.
* If version string is not recognized and extra == "or-highest",
* return tls_version_max().
*/
int |
6cb15b90 |
tls_version_parse(const char *vstr, const char *extra) |
4b67f984 |
{ |
81d882d5 |
const int max_version = tls_version_max();
if (!strcmp(vstr, "1.0") && TLS_VER_1_0 <= max_version)
{
return TLS_VER_1_0;
}
else if (!strcmp(vstr, "1.1") && TLS_VER_1_1 <= max_version)
{
return TLS_VER_1_1;
}
else if (!strcmp(vstr, "1.2") && TLS_VER_1_2 <= max_version)
{
return TLS_VER_1_2;
} |
8ca9eda1 |
else if (!strcmp(vstr, "1.3") && TLS_VER_1_3 <= max_version)
{
return TLS_VER_1_3;
} |
81d882d5 |
else if (extra && !strcmp(extra, "or-highest"))
{
return max_version;
}
else
{
return TLS_VER_BAD;
} |
4b67f984 |
}
|
ce91c187 |
/**
* Load (or possibly reload) the CRL file into the SSL context.
* No reload is performed under the following conditions:
* - the CRL file was passed inline
* - the CRL file was not modified since the last (re)load
*
* @param ssl_ctx The TLS context to use when reloading the CRL
* @param crl_file The file name to load the CRL from, or
* "[[INLINE]]" in the case of inline files.
* @param crl_inline A string containing the CRL
*/
static void
tls_ctx_reload_crl(struct tls_root_ctx *ssl_ctx, const char *crl_file, |
81d882d5 |
const char *crl_file_inline) |
ce91c187 |
{ |
81d882d5 |
/* if something goes wrong with stat(), we'll store 0 as mtime */
platform_stat_t crl_stat = {0};
/*
* an inline CRL can't change at runtime, therefore there is no need to
* reload it. It will be reloaded upon config change + SIGHUP.
* Use always '1' as dummy timestamp in this case: it will trigger the
* first load, but will prevent any future reload.
*/
if (crl_file_inline) |
ce91c187 |
{ |
81d882d5 |
crl_stat.st_mtime = 1; |
ce91c187 |
} |
81d882d5 |
else if (platform_stat(crl_file, &crl_stat) < 0) |
ce91c187 |
{ |
81d882d5 |
msg(M_WARN, "WARNING: Failed to stat CRL file, not (re)loading CRL.");
return; |
ce91c187 |
}
|
81d882d5 |
/*
* Store the CRL if this is the first time or if the file was changed since
* the last load.
* Note: Windows does not support tv_nsec.
*/
if ((ssl_ctx->crl_last_size == crl_stat.st_size) |
f3705dd1 |
&& (ssl_ctx->crl_last_mtime == crl_stat.st_mtime)) |
81d882d5 |
{
return;
} |
ce91c187 |
|
f3705dd1 |
ssl_ctx->crl_last_mtime = crl_stat.st_mtime; |
81d882d5 |
ssl_ctx->crl_last_size = crl_stat.st_size;
backend_tls_ctx_reload_crl(ssl_ctx, crl_file, crl_file_inline); |
ce91c187 |
}
|
4b67f984 |
/* |
6fbf66fa |
* Initialize SSL context.
* All files are in PEM format.
*/ |
62451786 |
void |
81d882d5 |
init_ssl(const struct options *options, struct tls_root_ctx *new_ctx) |
6fbf66fa |
{ |
81d882d5 |
ASSERT(NULL != new_ctx); |
62451786 |
|
81d882d5 |
tls_clear_error(); |
6fbf66fa |
|
81d882d5 |
if (options->tls_server) |
6fbf66fa |
{ |
81d882d5 |
tls_ctx_server_new(new_ctx); |
bd9aa06f |
|
81d882d5 |
if (options->dh_file)
{
tls_ctx_load_dh_params(new_ctx, options->dh_file,
options->dh_file_inline);
} |
6fbf66fa |
} |
81d882d5 |
else /* if client */ |
6fbf66fa |
{ |
81d882d5 |
tls_ctx_client_new(new_ctx); |
6fbf66fa |
}
|
aba75874 |
/* Restrict allowed certificate crypto algorithms */
tls_ctx_set_cert_profile(new_ctx, options->tls_cert_profile);
|
26345ba6 |
/* Allowable ciphers */
/* Since @SECLEVEL also influces loading of certificates, set the
* cipher restrictions before loading certificates */
tls_ctx_restrict_ciphers(new_ctx, options->cipher_list);
|
0e8a30c0 |
if (!tls_ctx_set_options(new_ctx, options->ssl_flags))
{
goto err;
} |
ac3e8d62 |
|
81d882d5 |
if (options->pkcs12_file) |
6fbf66fa |
{ |
81d882d5 |
if (0 != tls_ctx_load_pkcs12(new_ctx, options->pkcs12_file,
options->pkcs12_file_inline, !options->ca_file))
{
goto err;
} |
6fbf66fa |
} |
ce98fd24 |
#ifdef ENABLE_PKCS11 |
81d882d5 |
else if (options->pkcs11_providers[0]) |
d1013cfe |
{ |
81d882d5 |
if (!tls_ctx_use_pkcs11(new_ctx, options->pkcs11_id_management, options->pkcs11_id))
{
msg(M_WARN, "Cannot load certificate \"%s\" using PKCS#11 interface",
options->pkcs11_id);
goto err;
} |
d1013cfe |
} |
ce98fd24 |
#endif |
93c22ecc |
#ifdef ENABLE_CRYPTOAPI |
81d882d5 |
else if (options->cryptoapi_cert) |
d1013cfe |
{ |
81d882d5 |
tls_ctx_load_cryptoapi(new_ctx, options->cryptoapi_cert); |
d1013cfe |
} |
6fbf66fa |
#endif |
cf69617b |
#ifdef MANAGMENT_EXTERNAL_KEY |
81d882d5 |
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);
} |
f4047d74 |
} |
cf69617b |
#endif |
81d882d5 |
else
{
/* Load Certificate */
if (options->cert_file)
{
tls_ctx_load_cert_file(new_ctx, options->cert_file, options->cert_file_inline);
}
/* Load Private Key */
if (options->priv_key_file)
{
if (0 != tls_ctx_load_priv_file(new_ctx, options->priv_key_file, options->priv_key_file_inline))
{
goto err;
}
} |
d67c3147 |
} |
6fbf66fa |
|
81d882d5 |
if (options->ca_file || options->ca_path) |
e83b8190 |
{ |
81d882d5 |
tls_ctx_load_ca(new_ctx, options->ca_file, options->ca_file_inline,
options->ca_path, options->tls_server); |
6fbf66fa |
} |
e83b8190 |
|
81d882d5 |
/* 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) |
7966d75a |
{ |
81d882d5 |
tls_ctx_load_extra_certs(new_ctx, options->extra_certs_file, options->extra_certs_file_inline); |
7966d75a |
}
|
81d882d5 |
/* Check certificate notBefore and notAfter */
tls_ctx_check_cert_time(new_ctx); |
091edd8e |
|
81d882d5 |
/* Read CRL */
if (options->crl_file && !(options->ssl_flags & SSLF_CRL_VERIFY_DIR)) |
160504a2 |
{ |
81d882d5 |
tls_ctx_reload_crl(new_ctx, options->crl_file, options->crl_file_inline); |
160504a2 |
}
|
81d882d5 |
/* Once keys and cert are loaded, load ECDH parameters */
if (options->tls_server)
{
tls_ctx_load_ecdh_params(new_ctx, options->ecdh_curve);
} |
609e8131 |
|
86d8cd68 |
#ifdef ENABLE_CRYPTO_MBEDTLS |
81d882d5 |
/* Personalise the random by mixing in the certificate */
tls_ctx_personalise_random(new_ctx); |
6efeaa2e |
#endif
|
81d882d5 |
tls_clear_error();
return; |
6fbf66fa |
|
81d882d5 |
err:
tls_clear_error();
tls_ctx_free(new_ctx);
return; |
6fbf66fa |
}
/*
* Map internal constants to ascii names.
*/
static const char * |
81d882d5 |
state_name(int state)
{
switch (state)
{
case S_UNDEF:
return "S_UNDEF";
case S_INITIAL:
return "S_INITIAL";
case S_PRE_START:
return "S_PRE_START";
case S_START:
return "S_START";
case S_SENT_KEY:
return "S_SENT_KEY";
case S_GOT_KEY:
return "S_GOT_KEY";
case S_ACTIVE:
return "S_ACTIVE";
case S_NORMAL_OP:
return "S_NORMAL_OP";
case S_ERROR:
return "S_ERROR";
default:
return "S_???"; |
6fbf66fa |
}
}
static const char * |
81d882d5 |
packet_opcode_name(int op)
{
switch (op)
{
case P_CONTROL_HARD_RESET_CLIENT_V1:
return "P_CONTROL_HARD_RESET_CLIENT_V1";
case P_CONTROL_HARD_RESET_SERVER_V1:
return "P_CONTROL_HARD_RESET_SERVER_V1";
case P_CONTROL_HARD_RESET_CLIENT_V2:
return "P_CONTROL_HARD_RESET_CLIENT_V2";
case P_CONTROL_HARD_RESET_SERVER_V2:
return "P_CONTROL_HARD_RESET_SERVER_V2";
case P_CONTROL_SOFT_RESET_V1:
return "P_CONTROL_SOFT_RESET_V1";
case P_CONTROL_V1:
return "P_CONTROL_V1";
case P_ACK_V1:
return "P_ACK_V1";
case P_DATA_V1:
return "P_DATA_V1";
case P_DATA_V2:
return "P_DATA_V2";
default:
return "P_???"; |
6fbf66fa |
}
}
static const char * |
81d882d5 |
session_index_name(int index) |
6fbf66fa |
{ |
81d882d5 |
switch (index) |
6fbf66fa |
{ |
81d882d5 |
case TM_ACTIVE:
return "TM_ACTIVE";
case TM_UNTRUSTED:
return "TM_UNTRUSTED";
case TM_LAME_DUCK:
return "TM_LAME_DUCK";
default:
return "TM_???"; |
6fbf66fa |
}
}
/*
* For debugging.
*/
static const char * |
81d882d5 |
print_key_id(struct tls_multi *multi, struct gc_arena *gc) |
6fbf66fa |
{ |
81d882d5 |
int i;
struct buffer out = alloc_buf_gc(256, gc); |
6fbf66fa |
|
81d882d5 |
for (i = 0; i < KEY_SCAN_SIZE; ++i) |
6fbf66fa |
{ |
81d882d5 |
struct key_state *ks = multi->key_scan[i];
buf_printf(&out, " [key#%d state=%s id=%d sid=%s]", i,
state_name(ks->state), ks->key_id,
session_id_print(&ks->session_id_remote, gc)); |
6fbf66fa |
}
|
81d882d5 |
return BSTR(&out); |
6fbf66fa |
}
|
9900e023 |
bool |
81d882d5 |
is_hard_reset(int op, int key_method) |
6fbf66fa |
{ |
81d882d5 |
if (!key_method || key_method == 1)
{
if (op == P_CONTROL_HARD_RESET_CLIENT_V1 || op == P_CONTROL_HARD_RESET_SERVER_V1)
{
return true;
}
} |
6fbf66fa |
|
81d882d5 |
if (!key_method || key_method >= 2)
{
if (op == P_CONTROL_HARD_RESET_CLIENT_V2 || op == P_CONTROL_HARD_RESET_SERVER_V2)
{
return true;
}
} |
6fbf66fa |
|
81d882d5 |
return false; |
6fbf66fa |
}
|
4c5c5974 |
/** @addtogroup control_processor
* @{ */
/** @name Functions for initialization and cleanup of key_state structures
* @{ */
/**
* Initialize a \c key_state structure.
* @ingroup control_processor
*
* This function initializes a \c key_state structure associated with a \c
* tls_session. It sets up the structure's SSL-BIO, sets the object's \c
* key_state.state to \c S_INITIAL, and sets the session ID and key ID two
* appropriate values based on the \c tls_session's internal state. It
* also initializes a new set of structures for the \link reliable
* Reliability Layer\endlink.
*
* @param session - A pointer to the \c tls_session structure
* associated with the \a ks argument.
* @param ks - A pointer to the \c key_state structure to be
* initialized. This structure should already have
* been allocated before calling this function. |
6fbf66fa |
*/
static void |
81d882d5 |
key_state_init(struct tls_session *session, struct key_state *ks)
{
update_time();
CLEAR(*ks);
/*
* Build TLS object that reads/writes ciphertext
* to/from memory BIOs.
*/
key_state_ssl_init(&ks->ks_ssl, &session->opt->ssl_ctx, session->opt->server,
session);
/* Set control-channel initiation mode */
ks->initial_opcode = session->initial_opcode;
session->initial_opcode = P_CONTROL_SOFT_RESET_V1;
ks->state = S_INITIAL;
ks->key_id = session->key_id;
/*
* key_id increments to KEY_ID_MASK then recycles back to 1.
* This way you know that if key_id is 0, it is the first key.
*/
++session->key_id;
session->key_id &= P_KEY_ID_MASK;
if (!session->key_id)
{
session->key_id = 1;
}
/* allocate key source material object */
ALLOC_OBJ_CLEAR(ks->key_src, struct key_source2);
/* allocate reliability objects */
ALLOC_OBJ_CLEAR(ks->send_reliable, struct reliable);
ALLOC_OBJ_CLEAR(ks->rec_reliable, struct reliable);
ALLOC_OBJ_CLEAR(ks->rec_ack, struct reliable_ack);
/* allocate buffers */
ks->plaintext_read_buf = alloc_buf(TLS_CHANNEL_BUF_SIZE);
ks->plaintext_write_buf = alloc_buf(TLS_CHANNEL_BUF_SIZE);
ks->ack_write_buf = alloc_buf(BUF_SIZE(&session->opt->frame));
reliable_init(ks->send_reliable, BUF_SIZE(&session->opt->frame),
FRAME_HEADROOM(&session->opt->frame), TLS_RELIABLE_N_SEND_BUFFERS,
ks->key_id ? false : session->opt->xmit_hold);
reliable_init(ks->rec_reliable, BUF_SIZE(&session->opt->frame),
FRAME_HEADROOM(&session->opt->frame), TLS_RELIABLE_N_REC_BUFFERS,
false);
reliable_set_timeout(ks->send_reliable, session->opt->packet_timeout);
/* init packet ID tracker */
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; |
2d9c6d20 |
|
90efcacb |
#ifdef MANAGEMENT_DEF_AUTH |
81d882d5 |
ks->mda_key_id = session->opt->mda_context->mda_key_id_counter++; |
90efcacb |
#endif |
6fbf66fa |
}
|
4c5c5974 |
/**
* Cleanup a \c key_state structure.
* @ingroup control_processor
*
* This function cleans up a \c key_state structure. It frees the
* associated SSL-BIO, and the structures allocated for the \link reliable
* Reliability Layer\endlink.
*
* @param ks - A pointer to the \c key_state structure to be
* cleaned up.
* @param clear - Whether the memory allocated for the \a ks object
* should be overwritten with 0s.
*/ |
6fbf66fa |
static void |
81d882d5 |
key_state_free(struct key_state *ks, bool clear) |
6fbf66fa |
{ |
81d882d5 |
ks->state = S_UNDEF; |
6fbf66fa |
|
81d882d5 |
key_state_ssl_free(&ks->ks_ssl); |
6fbf66fa |
|
81d882d5 |
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);
buffer_list_free(ks->paybuf); |
6fbf66fa |
|
81d882d5 |
if (ks->send_reliable) |
6fbf66fa |
{ |
81d882d5 |
reliable_free(ks->send_reliable);
free(ks->send_reliable); |
6fbf66fa |
}
|
81d882d5 |
if (ks->rec_reliable) |
6fbf66fa |
{ |
81d882d5 |
reliable_free(ks->rec_reliable);
free(ks->rec_reliable); |
6fbf66fa |
}
|
81d882d5 |
if (ks->rec_ack)
{
free(ks->rec_ack);
} |
6fbf66fa |
|
81d882d5 |
if (ks->key_src)
{
free(ks->key_src);
} |
6fbf66fa |
|
81d882d5 |
packet_id_free(&ks->crypto_options.packet_id); |
6fbf66fa |
|
90efcacb |
#ifdef PLUGIN_DEF_AUTH |
81d882d5 |
key_state_rm_auth_control_file(ks); |
47ae8457 |
#endif |
344ee918 |
|
81d882d5 |
if (clear)
{
secure_memzero(ks, sizeof(*ks));
} |
6fbf66fa |
}
|
4c5c5974 |
/** @} name Functions for initialization and cleanup of key_state structures */
/** @} addtogroup control_processor */
|
3ba6b9ff |
/**
* Returns whether or not the server should check for username/password
* |
81d882d5 |
* @param session The current TLS session |
3ba6b9ff |
* |
81d882d5 |
* @return true if username and password verification is enabled,
* false if not. |
3ba6b9ff |
*/
static inline bool
tls_session_user_pass_enabled(struct tls_session *session)
{ |
81d882d5 |
return (session->opt->auth_user_pass_verify_script
|| plugin_defined(session->opt->plugins, OPENVPN_PLUGIN_AUTH_USER_PASS_VERIFY) |
3ba6b9ff |
#ifdef MANAGEMENT_DEF_AUTH |
81d882d5 |
|| management_enable_def_auth(management) |
3ba6b9ff |
#endif |
81d882d5 |
); |
3ba6b9ff |
}
|
4c5c5974 |
/** @addtogroup control_processor
* @{ */
/** @name Functions for initialization and cleanup of tls_session structures
* @{ */
/**
* Initialize a \c tls_session structure.
* @ingroup control_processor
*
* This function initializes a \c tls_session structure. This includes
* generating a random session ID, and initializing the \c KS_PRIMARY \c
* key_state in the \c tls_session.key array.
*
* @param multi - A pointer to the \c tls_multi structure
* associated with the \a session argument.
* @param session - A pointer to the \c tls_session structure to be
* initialized. This structure should already have
* been allocated before calling this function. |
6fbf66fa |
*/
static void |
81d882d5 |
tls_session_init(struct tls_multi *multi, struct tls_session *session) |
6fbf66fa |
{ |
81d882d5 |
struct gc_arena gc = gc_new();
dmsg(D_TLS_DEBUG, "TLS: tls_session_init: entry"); |
6fbf66fa |
|
81d882d5 |
CLEAR(*session); |
6fbf66fa |
|
81d882d5 |
/* Set options data to point to parent's option structure */
session->opt = &multi->opt; |
6fbf66fa |
|
81d882d5 |
/* Randomize session # if it is 0 */
while (!session_id_defined(&session->session_id)) |
4cd4899e |
{ |
81d882d5 |
session_id_random(&session->session_id); |
4cd4899e |
} |
6fbf66fa |
|
81d882d5 |
/* Are we a TLS server or client? */
ASSERT(session->opt->key_method >= 1);
if (session->opt->key_method == 1) |
6fbf66fa |
{ |
81d882d5 |
session->initial_opcode = session->opt->server ?
P_CONTROL_HARD_RESET_SERVER_V1 : P_CONTROL_HARD_RESET_CLIENT_V1; |
6fbf66fa |
} |
81d882d5 |
else /* session->opt->key_method >= 2 */ |
6fbf66fa |
{ |
81d882d5 |
session->initial_opcode = session->opt->server ?
P_CONTROL_HARD_RESET_SERVER_V2 : P_CONTROL_HARD_RESET_CLIENT_V2; |
6fbf66fa |
}
|
81d882d5 |
/* Initialize control channel authentication parameters */
session->tls_wrap = session->opt->tls_wrap;
session->tls_wrap.work = alloc_buf(BUF_SIZE(&session->opt->frame)); |
6fbf66fa |
|
81d882d5 |
/* initialize packet ID replay window for --tls-auth */
packet_id_init(&session->tls_wrap.opt.packet_id,
session->opt->replay_window,
session->opt->replay_time,
"TLS_WRAP", session->key_id); |
6fbf66fa |
|
81d882d5 |
/* load most recent packet-id to replay protect on --tls-auth */
packet_id_persist_load_obj(session->tls_wrap.opt.pid_persist,
&session->tls_wrap.opt.packet_id); |
6fbf66fa |
|
81d882d5 |
key_state_init(session, &session->key[KS_PRIMARY]); |
6fbf66fa |
|
81d882d5 |
dmsg(D_TLS_DEBUG, "TLS: tls_session_init: new session object, sid=%s",
session_id_print(&session->session_id, &gc)); |
6fbf66fa |
|
81d882d5 |
gc_free(&gc); |
6fbf66fa |
}
|
4c5c5974 |
/**
* Clean up a \c tls_session structure.
* @ingroup control_processor
*
* This function cleans up a \c tls_session structure. This includes
* cleaning up all associated \c key_state structures.
*
* @param session - A pointer to the \c tls_session structure to be
* cleaned up.
* @param clear - Whether the memory allocated for the \a session
* object should be overwritten with 0s.
*/ |
6fbf66fa |
static void |
81d882d5 |
tls_session_free(struct tls_session *session, bool clear) |
6fbf66fa |
{ |
81d882d5 |
int i; |
6fbf66fa |
|
81d882d5 |
if (packet_id_initialized(&session->tls_wrap.opt.packet_id))
{
packet_id_free(&session->tls_wrap.opt.packet_id);
} |
c6e24fa3 |
|
81d882d5 |
free_buf(&session->tls_wrap.work); |
6fbf66fa |
|
81d882d5 |
for (i = 0; i < KS_SIZE; ++i) |
4cd4899e |
{ |
81d882d5 |
key_state_free(&session->key[i], false); |
4cd4899e |
} |
6fbf66fa |
|
81d882d5 |
if (session->common_name)
{
free(session->common_name);
} |
6fbf66fa |
|
81d882d5 |
cert_hash_free(session->cert_hash_set); |
ec4a500b |
|
81d882d5 |
if (clear)
{
secure_memzero(session, sizeof(*session));
} |
6fbf66fa |
}
|
4c5c5974 |
/** @} name Functions for initialization and cleanup of tls_session structures */
/** @} addtogroup control_processor */
|
6fbf66fa |
static void |
81d882d5 |
move_session(struct tls_multi *multi, int dest, int src, bool reinit_src) |
6fbf66fa |
{ |
81d882d5 |
msg(D_TLS_DEBUG_LOW, "TLS: move_session: dest=%s src=%s reinit_src=%d",
session_index_name(dest),
session_index_name(src),
reinit_src);
ASSERT(src != dest);
ASSERT(src >= 0 && src < TM_SIZE);
ASSERT(dest >= 0 && dest < TM_SIZE);
tls_session_free(&multi->session[dest], false);
multi->session[dest] = multi->session[src];
if (reinit_src)
{
tls_session_init(multi, &multi->session[src]);
}
else
{
secure_memzero(&multi->session[src], sizeof(multi->session[src]));
} |
6fbf66fa |
|
81d882d5 |
dmsg(D_TLS_DEBUG, "TLS: move_session: exit"); |
6fbf66fa |
}
static void |
81d882d5 |
reset_session(struct tls_multi *multi, struct tls_session *session) |
6fbf66fa |
{ |
81d882d5 |
tls_session_free(session, false);
tls_session_init(multi, session); |
6fbf66fa |
}
/*
* Used to determine in how many seconds we should be
* called again.
*/
static inline void |
4cd4899e |
compute_earliest_wakeup(interval_t *earliest, interval_t seconds_from_now)
{ |
81d882d5 |
if (seconds_from_now < *earliest)
{
*earliest = seconds_from_now;
}
if (*earliest < 0)
{
*earliest = 0;
} |
6fbf66fa |
}
/*
* Return true if "lame duck" or retiring key has expired and can
* no longer be used.
*/
static inline bool |
81d882d5 |
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)
{
compute_earliest_wakeup(wakeup, lame->must_die - local_now);
return false;
}
else
{
return true;
}
}
else if (lame->state == S_ERROR)
{
return true;
}
else
{
return false;
} |
6fbf66fa |
}
struct tls_multi * |
81d882d5 |
tls_multi_init(struct tls_options *tls_options) |
6fbf66fa |
{ |
81d882d5 |
struct tls_multi *ret; |
6fbf66fa |
|
81d882d5 |
ALLOC_OBJ_CLEAR(ret, struct tls_multi); |
6fbf66fa |
|
81d882d5 |
/* get command line derived options */
ret->opt = *tls_options; |
6fbf66fa |
|
81d882d5 |
/* 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];
ret->key_scan[1] = &ret->session[TM_ACTIVE].key[KS_LAME_DUCK];
ret->key_scan[2] = &ret->session[TM_LAME_DUCK].key[KS_LAME_DUCK]; |
6fbf66fa |
|
81d882d5 |
/* By default not use P_DATA_V2 */
ret->use_peer_id = false; |
65eedc35 |
|
81d882d5 |
return ret; |
6fbf66fa |
}
void |
81d882d5 |
tls_multi_init_finalize(struct tls_multi *multi, const struct frame *frame) |
6fbf66fa |
{ |
81d882d5 |
tls_init_control_channel_frame_parameters(frame, &multi->opt.frame);
/* initialize the active and untrusted sessions */ |
6fbf66fa |
|
81d882d5 |
tls_session_init(multi, &multi->session[TM_ACTIVE]); |
6fbf66fa |
|
81d882d5 |
if (!multi->opt.single_session)
{
tls_session_init(multi, &multi->session[TM_UNTRUSTED]);
} |
6fbf66fa |
}
/*
* Initialize and finalize a standalone tls-auth verification object.
*/
struct tls_auth_standalone * |
81d882d5 |
tls_auth_standalone_init(struct tls_options *tls_options,
struct gc_arena *gc) |
6fbf66fa |
{ |
81d882d5 |
struct tls_auth_standalone *tas; |
6fbf66fa |
|
81d882d5 |
ALLOC_OBJ_CLEAR_GC(tas, struct tls_auth_standalone, gc); |
6fbf66fa |
|
81d882d5 |
tas->tls_wrap = tls_options->tls_wrap; |
c6e24fa3 |
|
81d882d5 |
/*
* 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; |
6fbf66fa |
|
81d882d5 |
/* get initial frame parms, still need to finalize */
tas->frame = tls_options->frame; |
6fbf66fa |
|
81d882d5 |
return tas; |
6fbf66fa |
}
void |
81d882d5 |
tls_auth_standalone_finalize(struct tls_auth_standalone *tas,
const struct frame *frame) |
6fbf66fa |
{ |
81d882d5 |
tls_init_control_channel_frame_parameters(frame, &tas->frame); |
6fbf66fa |
}
/*
* Set local and remote option compatibility strings.
* Used to verify compatibility of local and remote option
* sets.
*/
void |
81d882d5 |
tls_multi_init_set_options(struct tls_multi *multi,
const char *local,
const char *remote) |
6fbf66fa |
{
#ifdef ENABLE_OCC |
81d882d5 |
/* initialize options string */
multi->opt.local_options = local;
multi->opt.remote_options = remote; |
6fbf66fa |
#endif
}
|
897f8be4 |
/*
* Cleanup a tls_multi structure and free associated memory allocations. |
4c5c5974 |
*/ |
6fbf66fa |
void |
81d882d5 |
tls_multi_free(struct tls_multi *multi, bool clear) |
6fbf66fa |
{ |
81d882d5 |
int i; |
6fbf66fa |
|
81d882d5 |
ASSERT(multi); |
6fbf66fa |
|
5733ef66 |
#ifdef MANAGEMENT_DEF_AUTH |
81d882d5 |
man_def_auth_set_client_reason(multi, NULL); |
aaf72974 |
|
a8be7379 |
#endif |
0a48ae36 |
#if P2MP_SERVER |
81d882d5 |
free(multi->peer_info); |
5733ef66 |
#endif
|
81d882d5 |
if (multi->locked_cn)
{
free(multi->locked_cn);
} |
6fbf66fa |
|
81d882d5 |
if (multi->locked_username)
{
free(multi->locked_username);
} |
71b557ba |
|
81d882d5 |
cert_hash_free(multi->locked_cert_hash_set); |
ec4a500b |
|
81d882d5 |
if (multi->auth_token) |
270dc911 |
{ |
81d882d5 |
secure_memzero(multi->auth_token, AUTH_TOKEN_SIZE);
free(multi->auth_token); |
270dc911 |
}
|
81d882d5 |
free(multi->remote_ciphername); |
6e5ad2fa |
|
81d882d5 |
for (i = 0; i < TM_SIZE; ++i) |
4cd4899e |
{ |
81d882d5 |
tls_session_free(&multi->session[i], false); |
4cd4899e |
} |
6fbf66fa |
|
81d882d5 |
if (clear)
{
secure_memzero(multi, sizeof(*multi));
} |
6fbf66fa |
|
81d882d5 |
free(multi); |
6fbf66fa |
}
|
4c5c5974 |
|
6fbf66fa |
/*
* Move a packet authentication HMAC + related fields to or from the front
* of the buffer so it can be processed by encrypt/decrypt.
*/
/*
* Dependent on hmac size, opcode size, and session_id size.
* Will assert if too small.
*/
#define SWAP_BUF_SIZE 256
static bool |
81d882d5 |
swap_hmac(struct buffer *buf, const struct crypto_options *co, bool incoming) |
6fbf66fa |
{ |
81d882d5 |
const struct key_ctx *ctx; |
6fbf66fa |
|
81d882d5 |
ASSERT(co); |
6fbf66fa |
|
81d882d5 |
ctx = (incoming ? &co->key_ctx_bi.decrypt : &co->key_ctx_bi.encrypt);
ASSERT(ctx->hmac); |
6fbf66fa |
|
81d882d5 |
{
/* hmac + packet_id (8 bytes) */
const int hmac_size = hmac_ctx_size(ctx->hmac) + packet_id_size(true); |
6fbf66fa |
|
81d882d5 |
/* opcode + session_id */
const int osid_size = 1 + SID_SIZE; |
6fbf66fa |
|
81d882d5 |
int e1, e2;
uint8_t *b = BPTR(buf);
uint8_t buf1[SWAP_BUF_SIZE];
uint8_t buf2[SWAP_BUF_SIZE]; |
6fbf66fa |
|
81d882d5 |
if (incoming)
{
e1 = osid_size;
e2 = hmac_size;
}
else
{
e1 = hmac_size;
e2 = osid_size;
}
ASSERT(e1 <= SWAP_BUF_SIZE && e2 <= SWAP_BUF_SIZE);
if (buf->len >= e1 + e2)
{
memcpy(buf1, b, e1);
memcpy(buf2, b + e1, e2);
memcpy(b, buf2, e2);
memcpy(b + e2, buf1, e1);
return true;
}
else
{
return false;
}
} |
6fbf66fa |
}
#undef SWAP_BUF_SIZE
/*
* Write a control channel authentication record.
*/
static void |
81d882d5 |
write_control_auth(struct tls_session *session,
struct key_state *ks,
struct buffer *buf,
struct link_socket_actual **to_link_addr,
int opcode,
int max_ack,
bool prepend_ack) |
6fbf66fa |
{ |
81d882d5 |
uint8_t header = ks->key_id | (opcode << P_OPCODE_SHIFT);
struct buffer null = clear_buf(); |
6fbf66fa |
|
81d882d5 |
ASSERT(link_socket_actual_defined(&ks->remote_addr));
ASSERT(reliable_ack_write
(ks->rec_ack, buf, &ks->session_id_remote, max_ack, prepend_ack)); |
c6e24fa3 |
|
81d882d5 |
if (session->tls_wrap.mode == TLS_WRAP_AUTH
|| session->tls_wrap.mode == TLS_WRAP_NONE) |
c6e24fa3 |
{ |
81d882d5 |
ASSERT(session_id_write_prepend(&session->session_id, buf));
ASSERT(buf_write_prepend(buf, &header, sizeof(header))); |
c6e24fa3 |
} |
81d882d5 |
if (session->tls_wrap.mode == TLS_WRAP_AUTH) |
6fbf66fa |
{ |
81d882d5 |
/* no encryption, only write hmac */
openvpn_encrypt(buf, null, &session->tls_wrap.opt);
ASSERT(swap_hmac(buf, &session->tls_wrap.opt, false)); |
c6e24fa3 |
} |
81d882d5 |
else if (session->tls_wrap.mode == TLS_WRAP_CRYPT) |
c6e24fa3 |
{ |
81d882d5 |
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
{
buf->len = 0;
return;
} |
6fbf66fa |
} |
81d882d5 |
*to_link_addr = &ks->remote_addr; |
6fbf66fa |
}
/*
* Read a control channel authentication record.
*/
static bool |
81d882d5 |
read_control_auth(struct buffer *buf,
struct tls_wrap_ctx *ctx,
const struct link_socket_actual *from) |
6fbf66fa |
{ |
81d882d5 |
struct gc_arena gc = gc_new();
bool ret = false; |
6fbf66fa |
|
81d882d5 |
if (ctx->mode == TLS_WRAP_AUTH) |
6fbf66fa |
{ |
81d882d5 |
struct buffer null = clear_buf(); |
6fbf66fa |
|
81d882d5 |
/* move the hmac record to the front of the packet */
if (!swap_hmac(buf, &ctx->opt, true))
{
msg(D_TLS_ERRORS,
"TLS Error: cannot locate HMAC in incoming packet from %s",
print_link_socket_actual(from, &gc));
gc_free(&gc);
return false;
} |
6fbf66fa |
|
81d882d5 |
/* authenticate only (no decrypt) and remove the hmac record
* from the head of the buffer */
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));
goto cleanup;
} |
6fbf66fa |
} |
81d882d5 |
else if (ctx->mode == TLS_WRAP_CRYPT) |
c6e24fa3 |
{ |
fca89379 |
struct buffer tmp = alloc_buf_gc(buf_forward_capacity_total(buf), &gc); |
81d882d5 |
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)); |
fca89379 |
buf_clear(&tmp); |
c6e24fa3 |
} |
6fbf66fa |
|
81d882d5 |
if (ctx->mode == TLS_WRAP_NONE || ctx->mode == TLS_WRAP_AUTH) |
c6e24fa3 |
{ |
81d882d5 |
/* advance buffer pointer past opcode & session_id since our caller
* already read it */
buf_advance(buf, SID_SIZE + 1); |
c6e24fa3 |
} |
6fbf66fa |
|
81d882d5 |
ret = true; |
c6e24fa3 |
cleanup: |
81d882d5 |
gc_free(&gc);
return ret; |
6fbf66fa |
}
/*
* For debugging, print contents of key_source2 structure.
*/
static void |
81d882d5 |
key_source_print(const struct key_source *k,
const char *prefix) |
6fbf66fa |
{ |
81d882d5 |
struct gc_arena gc = gc_new();
VALGRIND_MAKE_READABLE((void *)k->pre_master, sizeof(k->pre_master));
VALGRIND_MAKE_READABLE((void *)k->random1, sizeof(k->random1));
VALGRIND_MAKE_READABLE((void *)k->random2, sizeof(k->random2));
dmsg(D_SHOW_KEY_SOURCE,
"%s pre_master: %s",
prefix,
format_hex(k->pre_master, sizeof(k->pre_master), 0, &gc));
dmsg(D_SHOW_KEY_SOURCE,
"%s random1: %s",
prefix,
format_hex(k->random1, sizeof(k->random1), 0, &gc));
dmsg(D_SHOW_KEY_SOURCE,
"%s random2: %s",
prefix,
format_hex(k->random2, sizeof(k->random2), 0, &gc));
gc_free(&gc); |
6fbf66fa |
}
static void |
81d882d5 |
key_source2_print(const struct key_source2 *k) |
6fbf66fa |
{ |
81d882d5 |
key_source_print(&k->client, "Client");
key_source_print(&k->server, "Server"); |
6fbf66fa |
}
/* |
eab0cf2d |
* Generate the hash required by for the \c tls1_PRF function. |
6fbf66fa |
* |
81d882d5 |
* @param md_kt Message digest to use
* @param sec Secret to base the hash on
* @param sec_len Length of the secret
* @param seed Seed to hash
* @param seed_len Length of the seed
* @param out Output buffer
* @param olen Length of the output buffer |
6fbf66fa |
*/ |
72bcdfdc |
static void |
eab0cf2d |
tls1_P_hash(const md_kt_t *md_kt, |
81d882d5 |
const uint8_t *sec,
int sec_len,
const uint8_t *seed,
int seed_len,
uint8_t *out,
int olen)
{
struct gc_arena gc = gc_new();
int chunk; |
aba98e90 |
hmac_ctx_t *ctx;
hmac_ctx_t *ctx_tmp; |
81d882d5 |
uint8_t A1[MAX_HMAC_KEY_LENGTH];
unsigned int A1_len; |
6fbf66fa |
#ifdef ENABLE_DEBUG |
81d882d5 |
const int olen_orig = olen;
const uint8_t *out_orig = out; |
6fbf66fa |
#endif |
eab0cf2d |
|
aba98e90 |
ctx = hmac_ctx_new();
ctx_tmp = hmac_ctx_new(); |
eab0cf2d |
|
81d882d5 |
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)); |
6fbf66fa |
|
81d882d5 |
chunk = md_kt_size(md_kt);
A1_len = md_kt_size(md_kt); |
6fbf66fa |
|
aba98e90 |
hmac_ctx_init(ctx, sec, sec_len, md_kt);
hmac_ctx_init(ctx_tmp, sec, sec_len, md_kt); |
eab0cf2d |
|
aba98e90 |
hmac_ctx_update(ctx,seed,seed_len);
hmac_ctx_final(ctx, A1); |
6fbf66fa |
|
81d882d5 |
for (;; ) |
6fbf66fa |
{ |
aba98e90 |
hmac_ctx_reset(ctx);
hmac_ctx_reset(ctx_tmp);
hmac_ctx_update(ctx,A1,A1_len);
hmac_ctx_update(ctx_tmp,A1,A1_len);
hmac_ctx_update(ctx,seed,seed_len); |
6fbf66fa |
|
81d882d5 |
if (olen > chunk)
{ |
aba98e90 |
hmac_ctx_final(ctx, out); |
81d882d5 |
out += chunk;
olen -= chunk; |
aba98e90 |
hmac_ctx_final(ctx_tmp, A1); /* calc the next A1 value */ |
81d882d5 |
}
else /* last one */
{ |
aba98e90 |
hmac_ctx_final(ctx, A1); |
81d882d5 |
memcpy(out,A1,olen);
break;
} |
6fbf66fa |
} |
aba98e90 |
hmac_ctx_cleanup(ctx);
hmac_ctx_free(ctx);
hmac_ctx_cleanup(ctx_tmp);
hmac_ctx_free(ctx_tmp); |
81d882d5 |
secure_memzero(A1, sizeof(A1)); |
6fbf66fa |
|
81d882d5 |
dmsg(D_SHOW_KEY_SOURCE, "tls1_P_hash out: %s", format_hex(out_orig, olen_orig, 0, &gc));
gc_free(&gc); |
6fbf66fa |
}
|
eab0cf2d |
/*
* Use the TLS PRF function for generating data channel keys.
* This code is based on the OpenSSL library.
*
* TLS generates keys as such:
*
* master_secret[48] = PRF(pre_master_secret[48], "master secret",
* ClientHello.random[32] + ServerHello.random[32])
*
* key_block[] = PRF(SecurityParameters.master_secret[48],
* "key expansion",
* SecurityParameters.server_random[32] +
* SecurityParameters.client_random[32]);
*
* Notes:
*
* (1) key_block contains a full set of 4 keys.
* (2) The pre-master secret is generated by the client.
*/ |
6fbf66fa |
static void |
66407e11 |
tls1_PRF(const uint8_t *label, |
81d882d5 |
int label_len,
const uint8_t *sec,
int slen,
uint8_t *out1,
int olen) |
6fbf66fa |
{ |
81d882d5 |
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; |
6fbf66fa |
|
81d882d5 |
out2 = (uint8_t *) gc_malloc(olen, false, &gc); |
6fbf66fa |
|
81d882d5 |
len = slen/2;
S1 = sec;
S2 = &(sec[len]);
len += (slen&1); /* add for odd, make longer */ |
6fbf66fa |
|
81d882d5 |
tls1_P_hash(md5,S1,len,label,label_len,out1,olen);
tls1_P_hash(sha1,S2,len,label,label_len,out2,olen); |
6fbf66fa |
|
81d882d5 |
for (i = 0; i<olen; i++) |
4cd4899e |
{ |
81d882d5 |
out1[i] ^= out2[i]; |
4cd4899e |
} |
6fbf66fa |
|
81d882d5 |
secure_memzero(out2, olen); |
6fbf66fa |
|
81d882d5 |
dmsg(D_SHOW_KEY_SOURCE, "tls1_PRF out[%d]: %s", olen, format_hex(out1, olen, 0, &gc)); |
6fbf66fa |
|
81d882d5 |
gc_free(&gc); |
6fbf66fa |
}
static void |
81d882d5 |
openvpn_PRF(const uint8_t *secret,
int secret_len,
const char *label,
const uint8_t *client_seed,
int client_seed_len,
const uint8_t *server_seed,
int server_seed_len,
const struct session_id *client_sid,
const struct session_id *server_sid,
uint8_t *output,
int output_len) |
6fbf66fa |
{ |
81d882d5 |
/* concatenate seed components */ |
6fbf66fa |
|
81d882d5 |
struct buffer seed = alloc_buf(strlen(label)
+ client_seed_len
+ server_seed_len
+ SID_SIZE * 2); |
6fbf66fa |
|
81d882d5 |
ASSERT(buf_write(&seed, label, strlen(label)));
ASSERT(buf_write(&seed, client_seed, client_seed_len));
ASSERT(buf_write(&seed, server_seed, server_seed_len)); |
6fbf66fa |
|
81d882d5 |
if (client_sid)
{
ASSERT(buf_write(&seed, client_sid->id, SID_SIZE));
}
if (server_sid)
{
ASSERT(buf_write(&seed, server_sid->id, SID_SIZE));
} |
6fbf66fa |
|
81d882d5 |
/* compute PRF */
tls1_PRF(BPTR(&seed), BLEN(&seed), secret, secret_len, output, output_len); |
6fbf66fa |
|
81d882d5 |
buf_clear(&seed);
free_buf(&seed); |
6fbf66fa |
|
81d882d5 |
VALGRIND_MAKE_READABLE((void *)output, output_len); |
6fbf66fa |
}
|
81d882d5 |
/* |
6fbf66fa |
* Using source entropy from local and remote hosts, mix into
* master key.
*/
static bool |
81d882d5 |
generate_key_expansion(struct key_ctx_bi *key,
const struct key_type *key_type,
const struct key_source2 *key_src,
const struct session_id *client_sid,
const struct session_id *server_sid,
bool server)
{
uint8_t master[48] = { 0 };
struct key2 key2 = { 0 };
bool ret = false;
if (key->initialized)
{
msg(D_TLS_ERRORS, "TLS Error: key already initialized");
goto exit;
}
/* debugging print of source key material */
key_source2_print(key_src);
/* compute master secret */
openvpn_PRF(key_src->client.pre_master,
sizeof(key_src->client.pre_master),
KEY_EXPANSION_ID " master secret",
key_src->client.random1,
sizeof(key_src->client.random1),
key_src->server.random1,
sizeof(key_src->server.random1),
NULL,
NULL,
master,
sizeof(master));
/* compute key expansion */
openvpn_PRF(master,
sizeof(master),
KEY_EXPANSION_ID " key expansion",
key_src->client.random2,
sizeof(key_src->client.random2),
key_src->server.random2,
sizeof(key_src->server.random2),
client_sid,
server_sid,
(uint8_t *)key2.keys,
sizeof(key2.keys));
key2.n = 2;
key2_print(&key2, key_type, "Master Encrypt", "Master Decrypt");
/* check for weak keys */
for (int i = 0; i < 2; ++i)
{
fixup_key(&key2.keys[i], key_type);
if (!check_key(&key2.keys[i], key_type))
{
msg(D_TLS_ERRORS, "TLS Error: Bad dynamic key generated");
goto exit;
}
}
/* Initialize OpenSSL key contexts */ |
974513ea |
int key_direction = server ? KEY_DIRECTION_INVERSE : KEY_DIRECTION_NORMAL;
init_key_ctx_bi(key, &key2, key_direction, key_type, "Data Channel"); |
81d882d5 |
/* 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);
ret = true;
exit:
secure_memzero(&master, sizeof(master));
secure_memzero(&key2, sizeof(key2));
return ret; |
6fbf66fa |
}
|
66407e11 |
static void |
4cd4899e |
key_ctx_update_implicit_iv(struct key_ctx *ctx, uint8_t *key, size_t key_len)
{ |
81d882d5 |
const cipher_kt_t *cipher_kt = cipher_ctx_get_cipher_kt(ctx->cipher); |
66407e11 |
|
81d882d5 |
/* Only use implicit IV in AEAD cipher mode, where HMAC key is not used */
if (cipher_kt_mode_aead(cipher_kt)) |
66407e11 |
{ |
81d882d5 |
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; |
66407e11 |
}
}
|
6e5ad2fa |
bool
tls_item_in_cipher_list(const char *item, const char *list) |
d728ebed |
{ |
81d882d5 |
char *tmp_ciphers = string_alloc(list, NULL);
char *tmp_ciphers_orig = tmp_ciphers; |
d728ebed |
|
81d882d5 |
const char *token = strtok(tmp_ciphers, ":");
while (token) |
d728ebed |
{ |
81d882d5 |
if (0 == strcmp(token, item))
{
break;
}
token = strtok(NULL, ":"); |
d728ebed |
} |
81d882d5 |
free(tmp_ciphers_orig); |
d728ebed |
|
81d882d5 |
return token != NULL; |
d728ebed |
}
|
6e5ad2fa |
void
tls_poor_mans_ncp(struct options *o, const char *remote_ciphername)
{ |
81d882d5 |
if (o->ncp_enabled && remote_ciphername
&& 0 != strcmp(o->ciphername, remote_ciphername)) |
6e5ad2fa |
{ |
81d882d5 |
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);
} |
6e5ad2fa |
}
}
|
e2ffdb7c |
/**
* Generate data channel keys for the supplied TLS session.
*
* This erases the source material used to generate the data channel keys, and
* can thus be called only once per session.
*/
static bool
tls_session_generate_data_channel_keys(struct tls_session *session) |
97894360 |
{ |
81d882d5 |
bool ret = false;
struct key_state *ks = &session->key[KS_PRIMARY]; /* primary key */
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;
ASSERT(ks->authenticated);
ks->crypto_options.flags = session->opt->crypto_flags;
if (!generate_key_expansion(&ks->crypto_options.key_ctx_bi,
&session->opt->key_type, ks->key_src, client_sid, server_sid,
session->opt->server)) |
e2ffdb7c |
{ |
81d882d5 |
msg(D_TLS_ERRORS, "TLS Error: generate_key_expansion failed");
goto cleanup; |
e2ffdb7c |
} |
81d882d5 |
tls_limit_reneg_bytes(session->opt->key_type.cipher,
&session->opt->renegotiate_bytes); |
e2ffdb7c |
|
81d882d5 |
ret = true; |
e2ffdb7c |
cleanup: |
81d882d5 |
secure_memzero(ks->key_src, sizeof(*ks->key_src));
return ret; |
e2ffdb7c |
}
bool
tls_session_update_crypto_params(struct tls_session *session, |
3be9a1c1 |
struct options *options, struct frame *frame) |
e2ffdb7c |
{ |
81d882d5 |
if (!session->opt->server
&& 0 != strcmp(options->ciphername, session->opt->config_ciphername)
&& !tls_item_in_cipher_list(options->ciphername, options->ncp_ciphers)) |
d728ebed |
{ |
81d882d5 |
msg(D_TLS_ERRORS, "Error: pushed cipher not allowed - %s not in %s or %s",
options->ciphername, session->opt->config_ciphername,
options->ncp_ciphers); |
3be9a1c1 |
/* undo cipher push, abort connection setup */
options->ciphername = session->opt->config_ciphername; |
81d882d5 |
return false; |
d728ebed |
}
|
d4071dd1 |
if (strcmp(options->ciphername, session->opt->config_ciphername))
{
msg(D_HANDSHAKE, "Data Channel: using negotiated cipher '%s'",
options->ciphername); |
956bb1c3 |
if (options->keysize)
{
msg(D_HANDSHAKE, "NCP: overriding user-set keysize with default");
options->keysize = 0;
} |
d4071dd1 |
}
|
81d882d5 |
init_key_type(&session->opt->key_type, options->ciphername,
options->authname, options->keysize, true, true); |
97894360 |
|
81d882d5 |
bool packet_id_long_form = cipher_kt_mode_ofb_cfb(session->opt->key_type.cipher);
session->opt->crypto_flags &= ~(CO_PACKET_ID_LONG_FORM);
if (packet_id_long_form)
{
session->opt->crypto_flags |= CO_PACKET_ID_LONG_FORM;
} |
97894360 |
|
81d882d5 |
/* 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, |
ef910e3e |
options->replay, packet_id_long_form); |
81d882d5 |
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"); |
97894360 |
|
81d882d5 |
return tls_session_generate_data_channel_keys(session); |
97894360 |
}
|
6fbf66fa |
static bool |
81d882d5 |
random_bytes_to_buf(struct buffer *buf,
uint8_t *out,
int outlen) |
6fbf66fa |
{ |
81d882d5 |
if (!rand_bytes(out, outlen))
{
msg(M_FATAL, "ERROR: Random number generator cannot obtain entropy for key generation [SSL]");
}
if (!buf_write(buf, out, outlen))
{
return false;
}
return true; |
6fbf66fa |
}
static bool |
81d882d5 |
key_source2_randomize_write(struct key_source2 *k2,
struct buffer *buf,
bool server) |
6fbf66fa |
{ |
81d882d5 |
struct key_source *k = &k2->client;
if (server)
{
k = &k2->server;
} |
6fbf66fa |
|
81d882d5 |
CLEAR(*k); |
6fbf66fa |
|
81d882d5 |
if (!server) |
6fbf66fa |
{ |
81d882d5 |
if (!random_bytes_to_buf(buf, k->pre_master, sizeof(k->pre_master)))
{
return false;
} |
6fbf66fa |
}
|
81d882d5 |
if (!random_bytes_to_buf(buf, k->random1, sizeof(k->random1)))
{
return false;
}
if (!random_bytes_to_buf(buf, k->random2, sizeof(k->random2)))
{
return false;
} |
6fbf66fa |
|
81d882d5 |
return true; |
6fbf66fa |
}
static int |
81d882d5 |
key_source2_read(struct key_source2 *k2,
struct buffer *buf,
bool server) |
6fbf66fa |
{ |
81d882d5 |
struct key_source *k = &k2->client; |
6fbf66fa |
|
81d882d5 |
if (!server)
{
k = &k2->server;
} |
6fbf66fa |
|
81d882d5 |
CLEAR(*k); |
6fbf66fa |
|
81d882d5 |
if (server) |
6fbf66fa |
{ |
81d882d5 |
if (!buf_read(buf, k->pre_master, sizeof(k->pre_master)))
{
return 0;
} |
6fbf66fa |
}
|
81d882d5 |
if (!buf_read(buf, k->random1, sizeof(k->random1)))
{
return 0;
}
if (!buf_read(buf, k->random2, sizeof(k->random2)))
{
return 0;
} |
6fbf66fa |
|
81d882d5 |
return 1; |
6fbf66fa |
}
|
dc85dae6 |
static void |
81d882d5 |
flush_payload_buffer(struct key_state *ks) |
dc85dae6 |
{ |
81d882d5 |
struct buffer *b; |
57513aac |
|
81d882d5 |
while ((b = buffer_list_peek(ks->paybuf))) |
dc85dae6 |
{ |
81d882d5 |
key_state_write_plaintext_const(&ks->ks_ssl, b->data, b->len);
buffer_list_pop(ks->paybuf); |
dc85dae6 |
}
}
|
6fbf66fa |
/* true if no in/out acknowledgements pending */
#define FULL_SYNC \ |
81d882d5 |
(reliable_empty(ks->send_reliable) && reliable_ack_empty(ks->rec_ack)) |
6fbf66fa |
/*
* Move the active key to the lame duck key and reinitialize the
* active key.
*/
static void |
81d882d5 |
key_state_soft_reset(struct tls_session *session) |
6fbf66fa |
{ |
81d882d5 |
struct key_state *ks = &session->key[KS_PRIMARY]; /* primary key */
struct key_state *ks_lame = &session->key[KS_LAME_DUCK]; /* retiring key */ |
57513aac |
|
81d882d5 |
ks->must_die = now + session->opt->transition_window; /* remaining lifetime of old key */
key_state_free(ks_lame, false);
*ks_lame = *ks; |
6fbf66fa |
|
81d882d5 |
key_state_init(session, ks);
ks->session_id_remote = ks_lame->session_id_remote;
ks->remote_addr = ks_lame->remote_addr; |
6fbf66fa |
}
/*
* Read/write strings from/to a struct buffer with a u16 length prefix.
*/
static bool |
81d882d5 |
write_empty_string(struct buffer *buf) |
fef565a3 |
{ |
81d882d5 |
if (!buf_write_u16(buf, 0))
{
return false;
}
return true; |
fef565a3 |
}
static bool |
81d882d5 |
write_string(struct buffer *buf, const char *str, const int maxlen) |
6fbf66fa |
{ |
81d882d5 |
const int len = strlen(str) + 1;
if (len < 1 || (maxlen >= 0 && len > maxlen))
{
return false;
}
if (!buf_write_u16(buf, len))
{
return false;
}
if (!buf_write(buf, str, len))
{
return false;
}
return true; |
6fbf66fa |
}
static bool |
81d882d5 |
read_string(struct buffer *buf, char *str, const unsigned int capacity) |
6fbf66fa |
{ |
81d882d5 |
const int len = buf_read_u16(buf);
if (len < 1 || len > (int)capacity)
{
return false;
}
if (!buf_read(buf, str, len))
{
return false;
}
str[len-1] = '\0';
return true; |
6fbf66fa |
}
|
aaf72974 |
static char * |
81d882d5 |
read_string_alloc(struct buffer *buf) |
aaf72974 |
{ |
81d882d5 |
const int len = buf_read_u16(buf);
char *str; |
aaf72974 |
|
81d882d5 |
if (len < 1)
{
return NULL;
}
str = (char *) malloc(len);
check_malloc_return(str);
if (!buf_read(buf, str, len)) |
aaf72974 |
{ |
81d882d5 |
free(str);
return NULL; |
aaf72974 |
} |
81d882d5 |
str[len-1] = '\0';
return str; |
aaf72974 |
}
|
6fbf66fa |
/*
* Handle the reading and writing of key data to and from
* the TLS control channel (cleartext).
*/
static bool |
81d882d5 |
key_method_1_write(struct buffer *buf, struct tls_session *session) |
6fbf66fa |
{ |
81d882d5 |
struct key key;
struct key_state *ks = &session->key[KS_PRIMARY]; /* primary key */ |
6fbf66fa |
|
81d882d5 |
ASSERT(session->opt->key_method == 1);
ASSERT(buf_init(buf, 0)); |
6fbf66fa |
|
81d882d5 |
generate_key_random(&key, &session->opt->key_type);
if (!check_key(&key, &session->opt->key_type)) |
6fbf66fa |
{ |
81d882d5 |
msg(D_TLS_ERRORS, "TLS Error: Bad encrypting key generated");
return false; |
6fbf66fa |
}
|
81d882d5 |
if (!write_key(&key, &session->opt->key_type, buf)) |
6fbf66fa |
{ |
81d882d5 |
msg(D_TLS_ERRORS, "TLS Error: write_key failed");
return false; |
6fbf66fa |
}
|
81d882d5 |
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)); |
6fbf66fa |
|
81d882d5 |
/* 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;
}
} |
6fbf66fa |
|
81d882d5 |
return true; |
6fbf66fa |
}
static bool |
aaf72974 |
push_peer_info(struct buffer *buf, struct tls_session *session)
{ |
81d882d5 |
struct gc_arena gc = gc_new();
bool ret = false; |
aaf72974 |
|
81d882d5 |
if (session->opt->push_peer_info_detail > 0) |
aaf72974 |
{ |
81d882d5 |
struct env_set *es = session->opt->es;
struct env_item *e;
struct buffer out = alloc_buf_gc(512*3, &gc); |
aaf72974 |
|
81d882d5 |
/* push version */
buf_printf(&out, "IV_VER=%s\n", PACKAGE_VERSION); |
aaf72974 |
|
81d882d5 |
/* push platform */ |
aaf72974 |
#if defined(TARGET_LINUX) |
81d882d5 |
buf_printf(&out, "IV_PLAT=linux\n"); |
aaf72974 |
#elif defined(TARGET_SOLARIS) |
81d882d5 |
buf_printf(&out, "IV_PLAT=solaris\n"); |
aaf72974 |
#elif defined(TARGET_OPENBSD) |
81d882d5 |
buf_printf(&out, "IV_PLAT=openbsd\n"); |
aaf72974 |
#elif defined(TARGET_DARWIN) |
81d882d5 |
buf_printf(&out, "IV_PLAT=mac\n"); |
aaf72974 |
#elif defined(TARGET_NETBSD) |
81d882d5 |
buf_printf(&out, "IV_PLAT=netbsd\n"); |
aaf72974 |
#elif defined(TARGET_FREEBSD) |
81d882d5 |
buf_printf(&out, "IV_PLAT=freebsd\n"); |
a55b3cdb |
#elif defined(TARGET_ANDROID) |
81d882d5 |
buf_printf(&out, "IV_PLAT=android\n"); |
445b192a |
#elif defined(_WIN32) |
81d882d5 |
buf_printf(&out, "IV_PLAT=win\n"); |
aaf72974 |
#endif
|
81d882d5 |
/* support for P_DATA_V2 */
buf_printf(&out, "IV_PROTO=2\n"); |
65eedc35 |
|
81d882d5 |
/* 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");
} |
97894360 |
|
81d882d5 |
/* push compression status */ |
38d96bd7 |
#ifdef USE_COMP |
81d882d5 |
comp_generate_peer_info_string(&session->opt->comp_options, &out); |
6c34e74f |
#endif
|
81d882d5 |
if (session->opt->push_peer_info_detail >= 2) |
598e03f0 |
{ |
81d882d5 |
/* push mac addr */
struct route_gateway_info rgi;
get_default_gateway(&rgi);
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() ); |
445b192a |
#if defined(_WIN32) |
81d882d5 |
buf_printf(&out, "IV_PLAT_VER=%s\n", win32_version_string(&gc, false)); |
cdc65ea0 |
#endif |
f3a2cd25 |
} |
598e03f0 |
|
81d882d5 |
/* 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
|| 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);
}
}
}
if (!write_string(buf, BSTR(&out), -1))
{
goto error;
}
}
else |
aaf72974 |
{ |
81d882d5 |
if (!write_empty_string(buf)) /* no peer info */
{
goto error;
} |
aaf72974 |
} |
81d882d5 |
ret = true; |
aaf72974 |
|
81d882d5 |
error:
gc_free(&gc);
return ret; |
aaf72974 |
}
static bool |
81d882d5 |
key_method_2_write(struct buffer *buf, struct tls_session *session) |
6fbf66fa |
{ |
81d882d5 |
struct key_state *ks = &session->key[KS_PRIMARY]; /* primary key */ |
57513aac |
|
81d882d5 |
ASSERT(session->opt->key_method == 2);
ASSERT(buf_init(buf, 0)); |
6fbf66fa |
|
81d882d5 |
/* write a uint32 0 */
if (!buf_write_u32(buf, 0))
{
goto error;
} |
6fbf66fa |
|
81d882d5 |
/* write key_method + flags */
if (!buf_write_u8(buf, (session->opt->key_method & KEY_METHOD_MASK)))
{
goto error;
} |
6fbf66fa |
|
81d882d5 |
/* write key source material */
if (!key_source2_randomize_write(ks->key_src, buf, session->opt->server))
{
goto error;
} |
6fbf66fa |
|
81d882d5 |
/* write options string */
{
if (!write_string(buf, local_options_string(session), TLS_OPTIONS_LEN))
{
goto error;
}
} |
6fbf66fa |
|
81d882d5 |
/* write username/password if specified */
if (auth_user_pass_enabled) |
6fbf66fa |
{ |
eab3e22f |
#ifdef ENABLE_CLIENT_CR |
81d882d5 |
auth_user_pass_setup(session->opt->auth_user_pass_file, session->opt->sci); |
eab3e22f |
#else |
81d882d5 |
auth_user_pass_setup(session->opt->auth_user_pass_file, NULL); |
eab3e22f |
#endif |
81d882d5 |
if (!write_string(buf, auth_user_pass.username, -1))
{
goto error;
}
if (!write_string(buf, auth_user_pass.password, -1))
{
goto error;
} |
57116536 |
/* if auth-nocache was specified, the auth_user_pass object reaches
* a "complete" state only after having received the push-reply
* message.
* This is the case because auth-token statement in a push-reply would
* invert its nocache.
*
* 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)
{
purge_user_pass(&auth_user_pass, false);
} |
6fbf66fa |
} |
81d882d5 |
else |
aaf72974 |
{ |
81d882d5 |
if (!write_empty_string(buf)) /* no username */
{
goto error;
}
if (!write_empty_string(buf)) /* no password */
{
goto error;
} |
aaf72974 |
}
|
81d882d5 |
if (!push_peer_info(buf, session))
{
goto error;
} |
6fbf66fa |
|
81d882d5 |
/* 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 && !(session->opt->ncp_enabled
&& session->opt->mode == MODE_SERVER && ks->key_id <= 0)) |
6fbf66fa |
{ |
81d882d5 |
if (ks->authenticated)
{
if (!tls_session_generate_data_channel_keys(session))
{
msg(D_TLS_ERRORS, "TLS Error: server generate_key_expansion failed");
goto error;
}
} |
6fbf66fa |
}
|
81d882d5 |
return true; |
6fbf66fa |
|
81d882d5 |
error:
msg(D_TLS_ERRORS, "TLS Error: Key Method #2 write failed");
secure_memzero(ks->key_src, sizeof(*ks->key_src));
return false; |
6fbf66fa |
}
static bool |
81d882d5 |
key_method_1_read(struct buffer *buf, struct tls_session *session) |
6fbf66fa |
{ |
81d882d5 |
int status;
struct key key;
struct key_state *ks = &session->key[KS_PRIMARY]; /* primary key */ |
6fbf66fa |
|
81d882d5 |
ASSERT(session->opt->key_method == 1); |
6fbf66fa |
|
81d882d5 |
if (!session->verified) |
6fbf66fa |
{ |
81d882d5 |
msg(D_TLS_ERRORS,
"TLS Error: Certificate verification failed (key-method 1)");
goto error; |
6fbf66fa |
}
|
81d882d5 |
status = read_key(&key, &session->opt->key_type, buf);
if (status != 1) |
6fbf66fa |
{ |
81d882d5 |
msg(D_TLS_ERRORS,
"TLS Error: Error reading data channel key from plaintext buffer");
goto error; |
6fbf66fa |
}
|
81d882d5 |
if (!check_key(&key, &session->opt->key_type)) |
6fbf66fa |
{ |
81d882d5 |
msg(D_TLS_ERRORS, "TLS Error: Bad decrypting key received from peer");
goto error; |
6fbf66fa |
}
|
81d882d5 |
if (buf->len < 1) |
6fbf66fa |
{ |
81d882d5 |
msg(D_TLS_ERRORS, "TLS Error: Missing options string");
goto error; |
6fbf66fa |
}
#ifdef ENABLE_OCC |
81d882d5 |
/* 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)) |
6fbf66fa |
{ |
81d882d5 |
options_warning_safe((char *) BPTR(buf), session->opt->remote_options, buf->len); |
6fbf66fa |
}
#endif
|
81d882d5 |
buf_clear(buf); |
6fbf66fa |
|
81d882d5 |
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; |
6fbf66fa |
|
81d882d5 |
error:
buf_clear(buf);
secure_memzero(&key, sizeof(key));
return false; |
6fbf66fa |
}
static bool |
81d882d5 |
key_method_2_read(struct buffer *buf, struct tls_multi *multi, struct tls_session *session) |
6fbf66fa |
{ |
81d882d5 |
struct key_state *ks = &session->key[KS_PRIMARY]; /* primary key */ |
d0811e64 |
|
81d882d5 |
int key_method_flags;
bool username_status, password_status; |
6fbf66fa |
|
81d882d5 |
struct gc_arena gc = gc_new();
char *options; |
2b60198e |
struct user_pass *up = NULL; |
90efcacb |
|
81d882d5 |
/* allocate temporary objects */
ALLOC_ARRAY_CLEAR_GC(options, char, TLS_OPTIONS_LEN, &gc); |
90efcacb |
|
81d882d5 |
ASSERT(session->opt->key_method == 2); |
6fbf66fa |
|
81d882d5 |
/* discard leading uint32 */
if (!buf_advance(buf, 4))
{
msg(D_TLS_ERRORS, "TLS ERROR: Plaintext buffer too short (%d bytes).",
buf->len);
goto error;
} |
6fbf66fa |
|
81d882d5 |
/* get key method */
key_method_flags = buf_read_u8(buf);
if ((key_method_flags & KEY_METHOD_MASK) != 2) |
6fbf66fa |
{ |
81d882d5 |
msg(D_TLS_ERRORS,
"TLS ERROR: Unknown key_method/flags=%d received from remote host",
key_method_flags);
goto error; |
6fbf66fa |
}
|
81d882d5 |
/* get key source material (not actual keys yet) */
if (!key_source2_read(ks->key_src, buf, session->opt->server)) |
6fbf66fa |
{ |
81d882d5 |
msg(D_TLS_ERRORS, "TLS Error: Error reading remote data channel key source entropy from plaintext buffer");
goto error; |
6fbf66fa |
}
|
81d882d5 |
/* get options */
if (!read_string(buf, options, TLS_OPTIONS_LEN)) |
6fbf66fa |
{ |
81d882d5 |
msg(D_TLS_ERRORS, "TLS Error: Failed to read required OCC options string");
goto error; |
6fbf66fa |
}
|
81d882d5 |
ks->authenticated = false; |
d0811e64 |
|
81d882d5 |
/* 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); |
a8be7379 |
|
1eb9a127 |
#if P2MP_SERVER |
81d882d5 |
/* 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); |
a17aa981 |
} |
a8be7379 |
|
81d882d5 |
free(multi->remote_ciphername);
multi->remote_ciphername =
options_string_extract_option(options, "cipher", NULL);
if (tls_peer_info_ncp_ver(multi->peer_info) < 2) |
6fbf66fa |
{ |
81d882d5 |
/* 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;
}
}
#endif /* if P2MP_SERVER */
if (tls_session_user_pass_enabled(session))
{
/* Perform username/password authentication */
if (!username_status || !password_status)
{
CLEAR(*up);
if (!(session->opt->ssl_flags & SSLF_AUTH_USER_PASS_OPTIONAL))
{
msg(D_TLS_ERRORS, "TLS Error: Auth Username/Password was not provided by peer");
goto error;
}
} |
6fbf66fa |
|
81d882d5 |
verify_user_pass(up, multi, session); |
6fbf66fa |
} |
81d882d5 |
else |
6fbf66fa |
{ |
81d882d5 |
/* Session verification should have occurred during TLS negotiation*/
if (!session->verified)
{
msg(D_TLS_ERRORS,
"TLS Error: Certificate verification failed (key-method 2)");
goto error;
}
ks->authenticated = true; |
6fbf66fa |
}
|
81d882d5 |
/* clear username and password from memory */
secure_memzero(up, sizeof(*up)); |
a8be7379 |
|
81d882d5 |
/* Perform final authentication checks */
if (ks->authenticated) |
6fbf66fa |
{ |
81d882d5 |
verify_final_auth_checks(multi, session); |
6fbf66fa |
}
#ifdef ENABLE_OCC |
81d882d5 |
/* check options consistency */
if (!session->opt->disable_occ
&& !options_cmp_equal(options, session->opt->remote_options)) |
6fbf66fa |
{ |
81d882d5 |
options_warning(options, session->opt->remote_options);
if (session->opt->ssl_flags & SSLF_OPT_VERIFY)
{
msg(D_TLS_ERRORS, "Option inconsistency warnings triggering disconnect due to --opt-verify");
ks->authenticated = false;
} |
6fbf66fa |
}
#endif
|
81d882d5 |
buf_clear(buf); |
6fbf66fa |
|
81d882d5 |
/*
* 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)) |
d92819fa |
{ |
81d882d5 |
key_state_export_keying_material(&ks->ks_ssl, session); |
685e486e |
|
81d882d5 |
if (plugin_call(session->opt->plugins, OPENVPN_PLUGIN_TLS_FINAL, NULL, NULL, session->opt->es) != OPENVPN_PLUGIN_FUNC_SUCCESS)
{
ks->authenticated = false;
} |
685e486e |
|
81d882d5 |
setenv_del(session->opt->es, "exported_keying_material"); |
d92819fa |
}
|
81d882d5 |
/*
* 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 && (!session->opt->pull || ks->key_id > 0)) |
6fbf66fa |
{ |
81d882d5 |
if (!tls_session_generate_data_channel_keys(session))
{
msg(D_TLS_ERRORS, "TLS Error: client generate_key_expansion failed");
goto error;
} |
6fbf66fa |
}
|
81d882d5 |
gc_free(&gc);
return true; |
6fbf66fa |
|
81d882d5 |
error:
secure_memzero(ks->key_src, sizeof(*ks->key_src)); |
2b60198e |
if (up)
{
secure_memzero(up, sizeof(*up));
} |
81d882d5 |
buf_clear(buf);
gc_free(&gc);
return false; |
6fbf66fa |
}
|
1c4af9ea |
static int |
81d882d5 |
auth_deferred_expire_window(const struct tls_options *o) |
1c4af9ea |
{ |
81d882d5 |
int ret = o->handshake_window;
const int r2 = o->renegotiate_seconds / 2; |
112e6704 |
|
81d882d5 |
if (o->renegotiate_seconds && r2 < ret)
{
ret = r2;
}
return ret; |
1c4af9ea |
}
|
6fbf66fa |
/*
* This is the primary routine for processing TLS stuff inside the
* the main event loop. When this routine exits
* with non-error status, it will set *wakeup to the number of seconds
* when it wants to be called again.
*
* Return value is true if we have placed a packet in *to_link which we
* want to send to our peer.
*/
static bool |
81d882d5 |
tls_process(struct tls_multi *multi,
struct tls_session *session,
struct buffer *to_link,
struct link_socket_actual **to_link_addr,
struct link_socket_info *to_link_socket_info,
interval_t *wakeup)
{
struct gc_arena gc = gc_new();
struct buffer *buf;
bool state_change = false;
bool active = false;
struct key_state *ks = &session->key[KS_PRIMARY]; /* primary key */
struct key_state *ks_lame = &session->key[KS_LAME_DUCK]; /* retiring key */
/* 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 trigger a soft reset? -- new key, keeps old key for a while */
if (ks->state >= S_ACTIVE
&& ((session->opt->renegotiate_seconds
&& now >= ks->established + session->opt->renegotiate_seconds)
|| (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->crypto_options.packet_id.send))))
{ |
dd996463 |
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, |
81d882d5 |
ks->n_bytes, session->opt->renegotiate_bytes,
ks->n_packets, session->opt->renegotiate_packets);
key_state_soft_reset(session);
}
/* Kill lame duck key transition_window seconds after primary key negotiation */
if (lame_duck_must_die(session, wakeup))
{
key_state_free(ks_lame, true);
msg(D_TLS_DEBUG_LOW, "TLS: tls_process: killed expiring key");
}
do
{
update_time();
dmsg(D_TLS_DEBUG, "TLS: tls_process: chg=%d ks=%s lame=%s to_link->len=%d wakeup=%d",
state_change,
state_name(ks->state),
state_name(ks_lame->state),
to_link->len,
*wakeup);
state_change = false;
/*
* TLS activity is finished once we get to S_ACTIVE,
* though we will still process acknowledgements.
*
* CHANGED with 2.0 -> now we may send tunnel configuration
* info over the control channel.
*/
/* Initial handshake */
if (ks->state == S_INITIAL)
{
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);
/* 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)); |
6fbf66fa |
#ifdef ENABLE_MANAGEMENT |
81d882d5 |
if (management && ks->initial_opcode != P_CONTROL_SOFT_RESET_V1)
{
management_set_state(management,
OPENVPN_STATE_WAIT,
NULL,
NULL,
NULL,
NULL,
NULL);
} |
c5da6dbf |
#endif |
81d882d5 |
}
}
/* Are we timed out on receive? */
if (now >= ks->must_negotiate)
{
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;
}
}
/* Wait for Initial Handshake ACK */
if (ks->state == S_PRE_START && FULL_SYNC)
{
ks->state = S_START;
state_change = true;
/*
* Attempt CRL reload before TLS negotiation. Won't be performed if
* the file was not modified since the last reload
*/
if (session->opt->crl_file
&& !(session->opt->ssl_flags & SSLF_CRL_VERIFY_DIR))
{
tls_ctx_reload_crl(&session->opt->ssl_ctx,
session->opt->crl_file, session->opt->crl_file_inline);
}
|
fd036181 |
/* New connection, remove any old X509 env variables */
tls_x509_clear_env(session->opt->es);
|
81d882d5 |
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)
{
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);
/* Flush any payload packets that were buffered before our state transitioned to S_ACTIVE */
flush_payload_buffer(ks); |
dc85dae6 |
|
6fbf66fa |
#ifdef MEASURE_TLS_HANDSHAKE_STATS |
81d882d5 |
show_tls_performance_stats(); |
6fbf66fa |
#endif |
81d882d5 |
}
}
/* 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;
}
/* 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)
{
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, "TLS -> Incoming Plaintext");
}
}
/* 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 (!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, "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");
}
}
}
}
while (state_change);
update_time();
/* Send 1 or more ACKs (each received control packet gets one ACK) */
if (!to_link->len && !reliable_ack_empty(ks->rec_ack))
{
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;
active = true;
dmsg(D_TLS_DEBUG, "Dedicated ACK -> TCP/UDP");
}
/* When should we wake up again? */
{
if (ks->state >= S_INITIAL)
{
compute_earliest_wakeup(wakeup,
reliable_send_timeout(ks->send_reliable));
if (ks->must_negotiate)
{
compute_earliest_wakeup(wakeup, ks->must_negotiate - now);
}
}
if (ks->established && session->opt->renegotiate_seconds)
{
compute_earliest_wakeup(wakeup,
ks->established + session->opt->renegotiate_seconds - now);
}
/* prevent event-loop spinning by setting minimum wakeup of 1 second */
if (*wakeup <= 0)
{
*wakeup = 1;
/* if we had something to send to remote, but to_link was busy,
* let caller know we need to be called again soon */
active = true;
}
dmsg(D_TLS_DEBUG, "TLS: tls_process: timeout set to %d", *wakeup);
gc_free(&gc);
return active;
} |
6fbf66fa |
error: |
81d882d5 |
tls_clear_error();
ks->state = S_ERROR;
msg(D_TLS_ERRORS, "TLS Error: TLS handshake failed");
INCR_ERROR;
gc_free(&gc);
return false; |
6fbf66fa |
}
/*
* Called by the top-level event loop.
*
* Basically decides if we should call tls_process for
* the active or untrusted sessions.
*/
|
344ee918 |
int |
81d882d5 |
tls_multi_process(struct tls_multi *multi,
struct buffer *to_link,
struct link_socket_actual **to_link_addr,
struct link_socket_info *to_link_socket_info,
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);
tls_clear_error();
/*
* Process each session object having state of S_INITIAL or greater,
* and which has a defined remote IP addr.
*/
for (i = 0; i < TM_SIZE; ++i)
{
struct tls_session *session = &multi->session[i];
struct key_state *ks = &session->key[KS_PRIMARY];
struct key_state *ks_lame = &session->key[KS_LAME_DUCK];
/* set initial remote address */
if (i == TM_ACTIVE && ks->state == S_INITIAL
&& link_socket_actual_defined(&to_link_socket_info->lsa->actual))
{
ks->remote_addr = to_link_socket_info->lsa->actual;
}
dmsg(D_TLS_DEBUG,
"TLS: tls_multi_process: i=%d state=%s, mysid=%s, stored-sid=%s, stored-ip=%s",
i,
state_name(ks->state),
session_id_print(&session->session_id, &gc),
session_id_print(&ks->session_id_remote, &gc),
print_link_socket_actual(&ks->remote_addr, &gc));
if (ks->state >= S_INITIAL && link_socket_actual_defined(&ks->remote_addr))
{
struct link_socket_actual *tla = NULL;
update_time();
if (tls_process(multi, session, to_link, &tla,
to_link_socket_info, wakeup))
{
active = TLSMP_ACTIVE;
}
/*
* If tls_process produced an outgoing packet,
* return the link_socket_actual object (which
* contains the outgoing address).
*/
if (tla)
{
multi->to_link_addr = *tla;
*to_link_addr = &multi->to_link_addr;
}
/*
* If tls_process hits an error:
* (1) If the session has an unexpired lame duck key, preserve it.
* (2) Reinitialize the session.
* (3) Increment soft error count
*/
if (ks->state == S_ERROR)
{
++multi->n_soft_errors;
if (i == TM_ACTIVE)
{
error = true;
}
if (i == TM_ACTIVE
&& ks_lame->state >= S_ACTIVE
&& !multi->opt.single_session)
{
move_session(multi, TM_LAME_DUCK, TM_ACTIVE, true);
}
else
{
reset_session(multi, session);
}
}
}
}
update_time();
tas = tls_authentication_status(multi, TLS_MULTI_AUTH_STATUS_INTERVAL);
/*
* If lame duck session expires, kill it.
*/
if (lame_duck_must_die(&multi->session[TM_LAME_DUCK], wakeup))
{
tls_session_free(&multi->session[TM_LAME_DUCK], true);
msg(D_TLS_DEBUG_LOW, "TLS: tls_multi_process: killed expiring key");
}
/*
* If untrusted session achieves TLS authentication,
* move it to active session, usurping any prior session.
*
* A semi-trusted session is one in which the certificate authentication
* succeeded (if cert verification is enabled) but the username/password
* verification failed. A semi-trusted session can forward data on the
* TLS control channel but not on the tunnel channel.
*/
if (DECRYPT_KEY_ENABLED(multi, &multi->session[TM_UNTRUSTED].key[KS_PRIMARY]))
{
move_session(multi, TM_ACTIVE, TM_UNTRUSTED, true);
msg(D_TLS_DEBUG_LOW, "TLS: tls_multi_process: untrusted session promoted to %strusted",
tas == TLS_AUTHENTICATION_SUCCEEDED ? "" : "semi-");
}
/*
* A hard error means that TM_ACTIVE hit an S_ERROR state and that no
* other key state objects are S_ACTIVE or higher.
*/
if (error)
{
for (i = 0; i < (int) SIZE(multi->key_scan); ++i)
{
if (multi->key_scan[i]->state >= S_ACTIVE)
{
goto nohard;
}
}
++multi->n_hard_errors;
}
nohard: |
6fbf66fa |
#ifdef ENABLE_DEBUG |
81d882d5 |
/* DEBUGGING -- flood peer with repeating connection attempts */
{
const int throw_level = GREMLIN_CONNECTION_FLOOD_LEVEL(multi->opt.gremlin);
if (throw_level)
{
for (i = 0; i < (int) SIZE(multi->key_scan); ++i)
{
if (multi->key_scan[i]->state >= throw_level)
{
++multi->n_hard_errors;
++multi->n_soft_errors;
}
}
}
} |
6fbf66fa |
#endif
|
81d882d5 |
perf_pop();
gc_free(&gc); |
344ee918 |
|
81d882d5 |
return (tas == TLS_AUTHENTICATION_FAILED) ? TLSMP_KILL : active; |
6fbf66fa |
}
/*
* Pre and post-process the encryption & decryption buffers in order
* to implement a multiplexed TLS channel over the TCP/UDP port.
*/
/*
*
* When we are in TLS mode, this is the first routine which sees
* an incoming packet.
*
* If it's a data packet, we set opt so that our caller can
* decrypt it. We also give our caller the appropriate decryption key.
*
* If it's a control packet, we authenticate it and process it,
* possibly creating a new tls_session if it represents the
* first packet of a new session. For control packets, we will
* also zero the size of *buf so that our caller ignores the
* packet on our return.
*
* Note that openvpn only allows one active session at a time,
* so a new session (once authenticated) will always usurp
* an old session.
*
* Return true if input was an authenticated control channel
* packet.
*
* If we are running in TLS thread mode, all public routines
* below this point must be called with the L_TLS lock held.
*/
bool |
81d882d5 |
tls_pre_decrypt(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();
bool ret = false;
if (buf->len > 0)
{
int i;
int op;
int key_id;
/* get opcode and key ID */
{
uint8_t c = *BPTR(buf);
op = c >> P_OPCODE_SHIFT;
key_id = c & P_KEY_ID_MASK;
}
if ((op == P_DATA_V1) || (op == P_DATA_V2))
{
/* 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 |
47ae8457 |
#ifdef ENABLE_DEF_AUTH |
81d882d5 |
&& !ks->auth_deferred |
47ae8457 |
#endif |
81d882d5 |
&& (floated || link_socket_actual_match(from, &ks->remote_addr)))
{
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;
}
/* 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));
}
++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;
}
}
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;
}
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)
{
msg(D_TLS_ERRORS,
"TLS Error: unknown opcode received from %s op=%d",
print_link_socket_actual(from, &gc), op);
goto error;
}
/* 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));
/* 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: session-id not found in packet from %s",
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)
{
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;
}
}
/*
* 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;
}
/*
* 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;
} |
6fbf66fa |
#ifdef ENABLE_MANAGEMENT |
81d882d5 |
if (management)
{
management_set_state(management,
OPENVPN_STATE_AUTH,
NULL,
NULL,
NULL,
NULL,
NULL);
} |
6fbf66fa |
#endif
|
81d882d5 |
msg(D_TLS_DEBUG_LOW,
"TLS: Initial packet from %s, sid=%s",
print_link_socket_actual(from, &gc),
session_id_print(&sid, &gc));
do_burst = true;
new_link = true;
i = TM_ACTIVE;
session->untrusted_addr = *from;
}
}
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;
}
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;
}
if (!read_control_auth(buf, &session->tls_wrap, from))
{
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));
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];
/*
* 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;
}
/*
* 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;
}
/*
* 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;
}
key_state_soft_reset(session);
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;
}
if (!read_control_auth(buf, &session->tls_wrap, from))
{
goto error;
}
dmsg(D_TLS_DEBUG,
"TLS: received control channel packet s#=%d sid=%s",
i, session_id_print(&sid, &gc));
}
}
/*
* We have an authenticated packet (if --tls-auth was set).
* Now pass to our reliability level which deals with
* packet acknowledgements, retransmits, sequencing, etc.
*/
{
struct tls_session *session = &multi->session[i];
struct key_state *ks = &session->key[KS_PRIMARY];
/* 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));
/* Let our caller know we processed a control channel packet */
ret = true;
/*
* 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;
}
/*
* 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;
}
/* 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;
}
/*
* 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;
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);
}
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); |
5774cf4c |
if(!buf_copy(in, buf))
{
msg(D_MULTI_DROPPED,
"Incoming control channel packet too big, dropping.");
goto error;
} |
81d882d5 |
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);
}
}
}
}
}
}
done:
buf->len = 0;
*opt = NULL;
gc_free(&gc);
return ret;
error:
++multi->n_soft_errors;
error_lite:
tls_clear_error();
goto done; |
6fbf66fa |
}
/*
* This function is similar to tls_pre_decrypt, except it is called
* when we are in server mode and receive an initial incoming
* packet. Note that we don't modify
* any state in our parameter objects. The purpose is solely to
* determine whether we should generate a client instance
* object, in which case true is returned.
*
* This function is essentially the first-line HMAC firewall
* on the UDP port listener in --mode server mode.
*/
bool |
81d882d5 |
tls_pre_decrypt_lite(const struct tls_auth_standalone *tas,
const struct link_socket_actual *from,
const struct buffer *buf)
{
struct gc_arena gc = gc_new();
bool ret = false;
if (buf->len > 0)
{
int op;
int key_id;
/* get opcode and key ID */
{
uint8_t c = *BPTR(buf);
op = c >> P_OPCODE_SHIFT;
key_id = c & P_KEY_ID_MASK;
}
/* 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 (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;
}
{
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.
*/
ret = true;
}
}
gc_free(&gc);
return ret;
error:
tls_clear_error();
gc_free(&gc);
return ret; |
6fbf66fa |
}
/* Choose the key with which to encrypt a data packet */
void |
81d882d5 |
tls_pre_encrypt(struct tls_multi *multi,
struct buffer *buf, struct crypto_options **opt)
{
multi->save_ks = NULL;
if (buf->len > 0)
{
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->crypto_options.key_ctx_bi.initialized |
47ae8457 |
#ifdef ENABLE_DEF_AUTH |
81d882d5 |
&& !ks->auth_deferred |
47ae8457 |
#endif |
81d882d5 |
)
{
if (!ks_select)
{
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);
}
}
buf->len = 0;
*opt = NULL; |
6fbf66fa |
}
void |
81d882d5 |
tls_prepend_opcode_v1(const struct tls_multi *multi, struct buffer *buf) |
6fbf66fa |
{ |
81d882d5 |
struct key_state *ks = multi->save_ks;
uint8_t op; |
66407e11 |
|
81d882d5 |
msg(D_TLS_DEBUG, __func__); |
66407e11 |
|
81d882d5 |
ASSERT(ks); |
66407e11 |
|
81d882d5 |
op = (P_DATA_V1 << P_OPCODE_SHIFT) | ks->key_id;
ASSERT(buf_write_prepend(buf, &op, 1)); |
66407e11 |
}
void |
81d882d5 |
tls_prepend_opcode_v2(const struct tls_multi *multi, struct buffer *buf) |
66407e11 |
{ |
81d882d5 |
struct key_state *ks = multi->save_ks;
uint32_t peer; |
6fbf66fa |
|
81d882d5 |
msg(D_TLS_DEBUG, __func__); |
66407e11 |
|
81d882d5 |
ASSERT(ks); |
66407e11 |
|
81d882d5 |
peer = htonl(((P_DATA_V2 << P_OPCODE_SHIFT) | ks->key_id) << 24
| (multi->peer_id & 0xFFFFFF));
ASSERT(buf_write_prepend(buf, &peer, 4)); |
66407e11 |
}
void |
81d882d5 |
tls_post_encrypt(struct tls_multi *multi, struct buffer *buf) |
66407e11 |
{ |
81d882d5 |
struct key_state *ks = multi->save_ks;
multi->save_ks = NULL; |
66407e11 |
|
81d882d5 |
if (buf->len > 0) |
6fbf66fa |
{ |
81d882d5 |
ASSERT(ks); |
65eedc35 |
|
81d882d5 |
++ks->n_packets;
ks->n_bytes += buf->len; |
6fbf66fa |
}
}
/*
* Send a payload over the TLS control channel.
* Called externally.
*/
bool |
81d882d5 |
tls_send_payload(struct tls_multi *multi,
const uint8_t *data,
int size) |
6fbf66fa |
{ |
81d882d5 |
struct tls_session *session;
struct key_state *ks;
bool ret = false; |
6fbf66fa |
|
81d882d5 |
tls_clear_error(); |
6fbf66fa |
|
81d882d5 |
ASSERT(multi); |
6fbf66fa |
|
81d882d5 |
session = &multi->session[TM_ACTIVE];
ks = &session->key[KS_PRIMARY]; |
6fbf66fa |
|
81d882d5 |
if (ks->state >= S_ACTIVE) |
6fbf66fa |
{ |
81d882d5 |
if (key_state_write_plaintext_const(&ks->ks_ssl, data, size) == 1)
{
ret = true;
} |
6fbf66fa |
} |
81d882d5 |
else |
dc85dae6 |
{ |
81d882d5 |
if (!ks->paybuf)
{
ks->paybuf = buffer_list_new(0);
}
buffer_list_push_data(ks->paybuf, data, (size_t)size);
ret = true; |
dc85dae6 |
} |
6fbf66fa |
|
95993a1d |
|
81d882d5 |
tls_clear_error(); |
6fbf66fa |
|
81d882d5 |
return ret; |
6fbf66fa |
}
bool |
81d882d5 |
tls_rec_payload(struct tls_multi *multi,
struct buffer *buf) |
6fbf66fa |
{ |
81d882d5 |
struct tls_session *session;
struct key_state *ks;
bool ret = false; |
6fbf66fa |
|
81d882d5 |
tls_clear_error(); |
6fbf66fa |
|
81d882d5 |
ASSERT(multi); |
6fbf66fa |
|
81d882d5 |
session = &multi->session[TM_ACTIVE];
ks = &session->key[KS_PRIMARY]; |
6fbf66fa |
|
81d882d5 |
if (ks->state >= S_ACTIVE && BLEN(&ks->plaintext_read_buf)) |
6fbf66fa |
{ |
81d882d5 |
if (buf_copy(buf, &ks->plaintext_read_buf))
{
ret = true;
}
ks->plaintext_read_buf.len = 0; |
6fbf66fa |
}
|
81d882d5 |
tls_clear_error(); |
6fbf66fa |
|
81d882d5 |
return ret; |
6fbf66fa |
}
|
65eedc35 |
void |
81d882d5 |
tls_update_remote_addr(struct tls_multi *multi, const struct link_socket_actual *addr) |
65eedc35 |
{ |
81d882d5 |
struct gc_arena gc = gc_new();
int i, j; |
65eedc35 |
|
81d882d5 |
for (i = 0; i < TM_SIZE; ++i) |
65eedc35 |
{ |
81d882d5 |
struct tls_session *session = &multi->session[i]; |
65eedc35 |
|
81d882d5 |
for (j = 0; j < KS_SIZE; ++j)
{
struct key_state *ks = &session->key[j]; |
65eedc35 |
|
81d882d5 |
if (!link_socket_actual_defined(&ks->remote_addr)
|| link_socket_actual_match(addr, &ks->remote_addr))
{
continue;
} |
65eedc35 |
|
81d882d5 |
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)); |
65eedc35 |
|
81d882d5 |
ks->remote_addr = *addr;
} |
65eedc35 |
} |
81d882d5 |
gc_free(&gc); |
65eedc35 |
}
|
a17aa981 |
int
tls_peer_info_ncp_ver(const char *peer_info)
{ |
81d882d5 |
const char *ncpstr = peer_info ? strstr(peer_info, "IV_NCP=") : NULL;
if (ncpstr) |
a17aa981 |
{ |
81d882d5 |
int ncp = 0;
int r = sscanf(ncpstr, "IV_NCP=%d", &ncp);
if (r == 1)
{
return ncp;
} |
a17aa981 |
} |
81d882d5 |
return 0; |
a17aa981 |
}
|
dc4fa3c4 |
bool |
4cd4899e |
tls_check_ncp_cipher_list(const char *list)
{ |
81d882d5 |
bool unsupported_cipher_found = false; |
dc4fa3c4 |
|
81d882d5 |
ASSERT(list); |
dc4fa3c4 |
|
81d882d5 |
char *const tmp_ciphers = string_alloc(list, NULL);
const char *token = strtok(tmp_ciphers, ":");
while (token) |
dc4fa3c4 |
{ |
81d882d5 |
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, ":"); |
dc4fa3c4 |
} |
81d882d5 |
free(tmp_ciphers); |
dc4fa3c4 |
|
81d882d5 |
return 0 < strlen(list) && !unsupported_cipher_found; |
dc4fa3c4 |
}
|
6fbf66fa |
/*
* Dump a human-readable rendition of an openvpn packet
* into a garbage collectable string which is returned.
*/
const char * |
81d882d5 |
protocol_dump(struct buffer *buffer, unsigned int flags, struct gc_arena *gc) |
6fbf66fa |
{ |
81d882d5 |
struct buffer out = alloc_buf_gc(256, gc);
struct buffer buf = *buffer; |
6fbf66fa |
|
81d882d5 |
uint8_t c;
int op;
int key_id; |
6fbf66fa |
|
81d882d5 |
int tls_auth_hmac_size = (flags & PD_TLS_AUTH_HMAC_SIZE_MASK); |
6fbf66fa |
|
81d882d5 |
if (buf.len <= 0) |
6fbf66fa |
{ |
81d882d5 |
buf_printf(&out, "DATA UNDEF len=%d", buf.len);
goto done; |
6fbf66fa |
}
|
81d882d5 |
if (!(flags & PD_TLS))
{
goto print_data;
} |
6fbf66fa |
|
81d882d5 |
/*
* Initial byte (opcode)
*/
if (!buf_read(&buf, &c, sizeof(c)))
{
goto done;
}
op = (c >> P_OPCODE_SHIFT);
key_id = c & P_KEY_ID_MASK;
buf_printf(&out, "%s kid=%d", packet_opcode_name(op), key_id); |
6fbf66fa |
|
81d882d5 |
if ((op == P_DATA_V1) || (op == P_DATA_V2))
{
goto print_data;
} |
6fbf66fa |
|
81d882d5 |
/*
* Session ID
*/
{
struct session_id sid; |
6fbf66fa |
|
81d882d5 |
if (!session_id_read(&sid, &buf))
{
goto done;
}
if (flags & PD_VERBOSE)
{
buf_printf(&out, " sid=%s", session_id_print(&sid, gc));
}
} |
6fbf66fa |
|
81d882d5 |
/*
* tls-auth hmac + packet_id
*/
if (tls_auth_hmac_size) |
6fbf66fa |
{ |
81d882d5 |
struct packet_id_net pin;
uint8_t tls_auth_hmac[MAX_HMAC_KEY_LENGTH]; |
6fbf66fa |
|
81d882d5 |
ASSERT(tls_auth_hmac_size <= MAX_HMAC_KEY_LENGTH); |
6fbf66fa |
|
81d882d5 |
if (!buf_read(&buf, tls_auth_hmac, tls_auth_hmac_size))
{
goto done;
}
if (flags & PD_VERBOSE)
{
buf_printf(&out, " tls_hmac=%s", format_hex(tls_auth_hmac, tls_auth_hmac_size, 0, gc));
} |
6fbf66fa |
|
81d882d5 |
if (!packet_id_read(&pin, &buf, true))
{
goto done;
}
buf_printf(&out, " pid=%s", packet_id_net_print(&pin, (flags & PD_VERBOSE), gc)); |
6fbf66fa |
}
|
81d882d5 |
/*
* ACK list
*/
buf_printf(&out, " %s", reliable_ack_print(&buf, (flags & PD_VERBOSE), gc)); |
6fbf66fa |
|
81d882d5 |
if (op == P_ACK_V1)
{
goto done;
} |
6fbf66fa |
|
81d882d5 |
/*
* Packet ID
*/
{
packet_id_type l;
if (!buf_read(&buf, &l, sizeof(l)))
{
goto done;
}
l = ntohpid(l);
buf_printf(&out, " pid=" packet_id_format, (packet_id_print_type)l);
} |
6fbf66fa |
print_data: |
81d882d5 |
if (flags & PD_SHOW_DATA)
{
buf_printf(&out, " DATA %s", format_hex(BPTR(&buf), BLEN(&buf), 80, gc));
}
else
{
buf_printf(&out, " DATA len=%d", buf.len);
} |
6fbf66fa |
done: |
81d882d5 |
return BSTR(&out); |
6fbf66fa |
}
|
57116536 |
void
delayed_auth_pass_purge(void)
{
auth_user_pass.wait_for_push = false;
purge_user_pass(&auth_user_pass, false);
} |