9a160b79 |
/*
* 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.
* |
b25c6d7e |
* Copyright (C) 2002-2024 OpenVPN Inc <sales@openvpn.net> |
ccee09d1 |
* Copyright (C) 2010-2021 Fox Crypto B.V. <openvpn@foxcrypto.com> |
9a160b79 |
*
* 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. |
9a160b79 |
*/
/**
* @file Control Channel OpenSSL Backend
*/
|
c110b289 |
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
|
9a160b79 |
#include "syshead.h" |
31ea2ee4 |
|
c7ca9133 |
#if defined(ENABLE_CRYPTO_OPENSSL) |
31ea2ee4 |
|
9a160b79 |
#include "errlevel.h"
#include "buffer.h"
#include "misc.h"
#include "manage.h"
#include "memdbg.h"
#include "ssl_backend.h"
#include "ssl_common.h" |
be960aad |
#include "base64.h" |
6554ac9f |
#include "openssl_compat.h" |
4b85c488 |
#include "xkey_common.h" |
9a160b79 |
|
9009aa46 |
#ifdef ENABLE_CRYPTOAPI
#include "cryptoapi.h"
#endif
|
9a160b79 |
#include "ssl_verify_openssl.h" |
3094d8fb |
#include "ssl_util.h" |
9a160b79 |
|
19874982 |
#include <openssl/bn.h>
#include <openssl/crypto.h>
#include <openssl/dh.h>
#include <openssl/dsa.h> |
9a160b79 |
#include <openssl/err.h>
#include <openssl/pkcs12.h> |
19874982 |
#include <openssl/rsa.h> |
9a160b79 |
#include <openssl/x509.h> |
7aeabadd |
#include <openssl/ssl.h> |
609e8131 |
#ifndef OPENSSL_NO_EC
#include <openssl/ec.h> |
af5de933 |
#endif
#if defined(_MSC_VER) && !defined(_M_ARM64)
#include <openssl/applink.c> |
609e8131 |
#endif |
95993a1d |
|
6121001e |
OSSL_LIB_CTX *tls_libctx; /* Global */ |
4b85c488 |
static void unload_xkey_provider(void);
|
95993a1d |
/*
* Allocate space in SSL objects in which to store a struct tls_session
* pointer back to parent.
*
*/
int mydata_index; /* GLOBAL */
void |
e2a0cad4 |
tls_init_lib(void) |
95993a1d |
{ |
2c0ebe0f |
#if OPENSSL_VERSION_NUMBER < 0x10100000L |
81d882d5 |
SSL_library_init(); |
39b54baa |
#ifndef ENABLE_SMALL |
81d882d5 |
SSL_load_error_strings(); |
39b54baa |
#endif |
81d882d5 |
OpenSSL_add_all_algorithms(); |
8a01147f |
#endif |
81d882d5 |
mydata_index = SSL_get_ex_new_index(0, "struct session *", NULL, NULL, NULL);
ASSERT(mydata_index >= 0); |
95993a1d |
}
void |
e2a0cad4 |
tls_free_lib(void) |
95993a1d |
{ |
2c0ebe0f |
#if OPENSSL_VERSION_NUMBER < 0x10100000L |
81d882d5 |
EVP_cleanup(); |
39b54baa |
#ifndef ENABLE_SMALL |
81d882d5 |
ERR_free_strings(); |
39b54baa |
#endif |
8a01147f |
#endif |
95993a1d |
}
void |
62451786 |
tls_ctx_server_new(struct tls_root_ctx *ctx)
{ |
81d882d5 |
ASSERT(NULL != ctx); |
62451786 |
|
4b85c488 |
ctx->ctx = SSL_CTX_new_ex(tls_libctx, NULL, SSLv23_server_method()); |
62451786 |
|
81d882d5 |
if (ctx->ctx == NULL)
{
crypto_msg(M_FATAL, "SSL_CTX_new SSLv23_server_method");
} |
75aa88af |
if (ERR_peek_error() != 0)
{
crypto_msg(M_WARN, "Warning: TLS server context initialisation "
"has warnings.");
} |
62451786 |
}
void
tls_ctx_client_new(struct tls_root_ctx *ctx)
{ |
81d882d5 |
ASSERT(NULL != ctx); |
62451786 |
|
4b85c488 |
ctx->ctx = SSL_CTX_new_ex(tls_libctx, NULL, SSLv23_client_method()); |
62451786 |
|
81d882d5 |
if (ctx->ctx == NULL)
{
crypto_msg(M_FATAL, "SSL_CTX_new SSLv23_client_method");
} |
75aa88af |
if (ERR_peek_error() != 0)
{
crypto_msg(M_WARN, "Warning: TLS client context initialisation "
"has warnings.");
} |
62451786 |
}
void
tls_ctx_free(struct tls_root_ctx *ctx)
{ |
81d882d5 |
ASSERT(NULL != ctx); |
cb70cf51 |
SSL_CTX_free(ctx->ctx); |
81d882d5 |
ctx->ctx = NULL; |
4b85c488 |
unload_xkey_provider(); /* in case it is loaded */ |
62451786 |
}
|
81d882d5 |
bool
tls_ctx_initialised(struct tls_root_ctx *ctx) |
62451786 |
{ |
81d882d5 |
ASSERT(NULL != ctx);
return NULL != ctx->ctx; |
62451786 |
}
|
f0734e49 |
bool |
10abd656 |
key_state_export_keying_material(struct tls_session *session, |
abe49856 |
const char *label, size_t label_size, |
f0734e49 |
void *ekm, size_t ekm_size) |
10abd656 |
|
685e486e |
{ |
abe49856 |
SSL *ssl = session->key[KS_PRIMARY].ks_ssl.ssl; |
10abd656 |
if (SSL_export_keying_material(ssl, ekm, ekm_size, label,
label_size, NULL, 0, 0) == 1)
{ |
f0734e49 |
return true; |
10abd656 |
}
else |
685e486e |
{ |
10abd656 |
secure_memzero(ekm, ekm_size); |
f0734e49 |
return false; |
685e486e |
}
}
|
b5563f11 |
/*
* Print debugging information on SSL/TLS session negotiation.
*/
#ifndef INFO_CALLBACK_SSL_CONST
#define INFO_CALLBACK_SSL_CONST const
#endif
static void |
81d882d5 |
info_callback(INFO_CALLBACK_SSL_CONST SSL *s, int where, int ret) |
b5563f11 |
{ |
81d882d5 |
if (where & SSL_CB_LOOP) |
b5563f11 |
{ |
81d882d5 |
dmsg(D_HANDSHAKE_VERBOSE, "SSL state (%s): %s",
where & SSL_ST_CONNECT ? "connect" :
where &SSL_ST_ACCEPT ? "accept" :
"undefined", SSL_state_string_long(s)); |
b5563f11 |
} |
81d882d5 |
else if (where & SSL_CB_ALERT) |
b5563f11 |
{ |
a1cb1b47 |
dmsg(D_TLS_DEBUG_LOW, "%s %s SSL alert: %s",
where & SSL_CB_READ ? "Received" : "Sent", |
81d882d5 |
SSL_alert_type_string_long(ret),
SSL_alert_desc_string_long(ret)); |
b5563f11 |
}
}
|
4b67f984 |
/*
* Return maximum TLS version supported by local OpenSSL library.
* Assume that presence of SSL_OP_NO_TLSvX macro indicates that
* TLSvX is supported.
*/
int
tls_version_max(void)
{ |
8ca9eda1 |
#if defined(TLS1_3_VERSION) |
6328aef9 |
/* If this is defined we can safely assume TLS 1.3 support */ |
8ca9eda1 |
return TLS_VER_1_3; |
6328aef9 |
#elif OPENSSL_VERSION_NUMBER >= 0x10100000L
/*
* If TLS_VER_1_3 is not defined, we were compiled against a version that
* did not support TLS 1.3.
*
* However, the library we are *linked* against might be OpenSSL 1.1.1
* and therefore supports TLS 1.3. This needs to be checked at runtime
* since we can be compiled against 1.1.0 and then the library can be |
8be444df |
* upgraded to 1.1.1.
* We only need to check this for OpenSSL versions that can be
* upgraded to 1.1.1 without recompile (>= 1.1.0) |
6328aef9 |
*/
if (OpenSSL_version_num() >= 0x1010100fL)
{
return TLS_VER_1_3;
}
else
{
return TLS_VER_1_2;
} |
8ca9eda1 |
#elif defined(TLS1_2_VERSION) || defined(SSL_OP_NO_TLSv1_2) |
81d882d5 |
return TLS_VER_1_2; |
0e8a30c0 |
#elif defined(TLS1_1_VERSION) || defined(SSL_OP_NO_TLSv1_1) |
81d882d5 |
return TLS_VER_1_1; |
f57431cd |
#else /* if defined(TLS1_3_VERSION) */ |
81d882d5 |
return TLS_VER_1_0; |
4b67f984 |
#endif
}
|
0e8a30c0 |
/** Convert internal version number to openssl version number */
static int
openssl_tls_version(int ver)
{
if (ver == TLS_VER_1_0)
{
return TLS1_VERSION;
}
else if (ver == TLS_VER_1_1)
{
return TLS1_1_VERSION;
}
else if (ver == TLS_VER_1_2)
{
return TLS1_2_VERSION;
} |
8ca9eda1 |
else if (ver == TLS_VER_1_3)
{ |
6328aef9 |
/*
* Supporting the library upgraded to TLS1.3 without recompile
* is enough to support here with a simple constant that the same
* as in the TLS 1.3, so spec it is very unlikely that OpenSSL
* will change this constant
*/
#ifndef TLS1_3_VERSION
/*
* We do not want to define TLS_VER_1_3 if not defined
* since other parts of the code use the existance of this macro
* as proxy for TLS 1.3 support
*/
return 0x0304;
#else |
8ca9eda1 |
return TLS1_3_VERSION;
#endif |
6328aef9 |
} |
0e8a30c0 |
return 0;
}
static bool
tls_ctx_set_tls_versions(struct tls_root_ctx *ctx, unsigned int ssl_flags)
{
int tls_ver_min = openssl_tls_version(
(ssl_flags >> SSLF_TLS_VERSION_MIN_SHIFT) & SSLF_TLS_VERSION_MIN_MASK);
int tls_ver_max = openssl_tls_version(
(ssl_flags >> SSLF_TLS_VERSION_MAX_SHIFT) & SSLF_TLS_VERSION_MAX_MASK);
if (!tls_ver_min)
{
/* Enforce at least TLS 1.0 */
int cur_min = SSL_CTX_get_min_proto_version(ctx->ctx);
tls_ver_min = cur_min < TLS1_VERSION ? TLS1_VERSION : cur_min;
}
if (!SSL_CTX_set_min_proto_version(ctx->ctx, tls_ver_min))
{
msg(D_TLS_ERRORS, "%s: failed to set minimum TLS version", __func__);
return false;
}
if (tls_ver_max && !SSL_CTX_set_max_proto_version(ctx->ctx, tls_ver_max))
{
msg(D_TLS_ERRORS, "%s: failed to set maximum TLS version", __func__);
return false;
}
return true;
}
bool |
81d882d5 |
tls_ctx_set_options(struct tls_root_ctx *ctx, unsigned int ssl_flags) |
b5563f11 |
{ |
81d882d5 |
ASSERT(NULL != ctx); |
b8cdb213 |
|
0e8a30c0 |
/* process SSL options */
long sslopt = SSL_OP_SINGLE_DH_USE | SSL_OP_NO_TICKET; |
5fd8e94d |
#ifdef SSL_OP_CIPHER_SERVER_PREFERENCE |
0e8a30c0 |
sslopt |= SSL_OP_CIPHER_SERVER_PREFERENCE; |
5fd8e94d |
#endif |
0e8a30c0 |
sslopt |= SSL_OP_NO_COMPRESSION; |
9e702a5d |
/* Disable TLS renegotiations. OpenVPN's renegotiation creates new SSL
* session and does not depend on this feature. And TLS renegotiations have
* been problematic in the past */
#ifdef SSL_OP_NO_RENEGOTIATION
sslopt |= SSL_OP_NO_RENEGOTIATION;
#endif |
0e8a30c0 |
SSL_CTX_set_options(ctx->ctx, sslopt);
if (!tls_ctx_set_tls_versions(ctx, ssl_flags))
{
return false; |
81d882d5 |
} |
4b67f984 |
|
a6c573d2 |
#ifdef SSL_MODE_RELEASE_BUFFERS |
81d882d5 |
SSL_CTX_set_mode(ctx->ctx, SSL_MODE_RELEASE_BUFFERS); |
a6c573d2 |
#endif |
81d882d5 |
SSL_CTX_set_session_cache_mode(ctx->ctx, SSL_SESS_CACHE_OFF);
SSL_CTX_set_default_passwd_cb(ctx->ctx, pem_password_callback); |
b5563f11 |
|
81d882d5 |
/* Require peer certificate verification */ |
e05aca45 |
int verify_flags = SSL_VERIFY_PEER | SSL_VERIFY_FAIL_IF_NO_PEER_CERT; |
81d882d5 |
if (ssl_flags & SSLF_CLIENT_CERT_NOT_REQUIRED) |
b5563f11 |
{ |
e05aca45 |
verify_flags = 0; |
b5563f11 |
} |
81d882d5 |
else if (ssl_flags & SSLF_CLIENT_CERT_OPTIONAL) |
f107c620 |
{ |
e05aca45 |
verify_flags = SSL_VERIFY_PEER; |
f107c620 |
} |
e05aca45 |
SSL_CTX_set_verify(ctx->ctx, verify_flags, verify_callback); |
b5563f11 |
|
81d882d5 |
SSL_CTX_set_info_callback(ctx->ctx, info_callback); |
0e8a30c0 |
return true; |
b5563f11 |
}
|
397c0a35 |
void |
e51d9a73 |
convert_tls_list_to_openssl(char *openssl_ciphers, size_t len, const char *ciphers) |
2e74a9d0 |
{ |
81d882d5 |
/* Parse supplied cipher list and pass on to OpenSSL */
size_t begin_of_cipher, end_of_cipher;
const char *current_cipher;
size_t current_cipher_len; |
3b23b18d |
|
81d882d5 |
const tls_cipher_name_pair *cipher_pair; |
3b23b18d |
|
81d882d5 |
size_t openssl_ciphers_len = 0;
openssl_ciphers[0] = '\0'; |
3b23b18d |
|
81d882d5 |
/* Translate IANA cipher suite names to OpenSSL names */
begin_of_cipher = end_of_cipher = 0; |
4cd4899e |
for (; begin_of_cipher < strlen(ciphers); begin_of_cipher = end_of_cipher)
{ |
81d882d5 |
end_of_cipher += strcspn(&ciphers[begin_of_cipher], ":");
cipher_pair = tls_get_cipher_name_pair(&ciphers[begin_of_cipher], end_of_cipher - begin_of_cipher);
if (NULL == cipher_pair)
{
/* No translation found, use original */
current_cipher = &ciphers[begin_of_cipher];
current_cipher_len = end_of_cipher - begin_of_cipher;
/* Issue warning on missing translation */
/* %.*s format specifier expects length of type int, so guarantee */
/* that length is small enough and cast to int. */
msg(D_LOW, "No valid translation found for TLS cipher '%.*s'",
constrain_int(current_cipher_len, 0, 256), current_cipher);
}
else
{
/* Use OpenSSL name */
current_cipher = cipher_pair->openssl_name;
current_cipher_len = strlen(current_cipher); |
2e74a9d0 |
|
81d882d5 |
if (end_of_cipher - begin_of_cipher == current_cipher_len
&& 0 != memcmp(&ciphers[begin_of_cipher], cipher_pair->iana_name,
end_of_cipher - begin_of_cipher))
{
/* Non-IANA name used, show warning */
msg(M_WARN, "Deprecated TLS cipher name '%s', please use IANA name '%s'", cipher_pair->openssl_name, cipher_pair->iana_name);
}
} |
3b23b18d |
|
81d882d5 |
/* Make sure new cipher name fits in cipher string */ |
e6bf7e03 |
if ((SIZE_MAX - openssl_ciphers_len) < current_cipher_len |
3b9d4d2a |
|| (len - 1) < (openssl_ciphers_len + current_cipher_len)) |
3b23b18d |
{ |
81d882d5 |
msg(M_FATAL,
"Failed to set restricted TLS cipher list, too long (>%d).", |
3b9d4d2a |
(int)(len - 1)); |
3b23b18d |
} |
81d882d5 |
/* Concatenate cipher name to OpenSSL cipher string */
memcpy(&openssl_ciphers[openssl_ciphers_len], current_cipher, current_cipher_len);
openssl_ciphers_len += current_cipher_len;
openssl_ciphers[openssl_ciphers_len] = ':';
openssl_ciphers_len++;
end_of_cipher++;
}
if (openssl_ciphers_len > 0)
{
openssl_ciphers[openssl_ciphers_len-1] = '\0';
} |
3b9d4d2a |
} |
ea4ee313 |
|
3b9d4d2a |
void
tls_ctx_restrict_ciphers(struct tls_root_ctx *ctx, const char *ciphers)
{
if (ciphers == NULL)
{
/* Use sane default TLS cipher list */
if (!SSL_CTX_set_cipher_list(ctx->ctx,
/* Use openssl's default list as a basis */
"DEFAULT"
/* Disable export ciphers and openssl's 'low' and 'medium' ciphers */
":!EXP:!LOW:!MEDIUM"
/* Disable static (EC)DH keys (no forward secrecy) */
":!kDH:!kECDH"
/* Disable DSA private keys */
":!DSS"
/* Disable unsupported TLS modes */
":!PSK:!SRP:!kRSA"))
{
crypto_msg(M_FATAL, "Failed to set default TLS cipher list.");
}
return;
}
char openssl_ciphers[4096];
convert_tls_list_to_openssl(openssl_ciphers, sizeof(openssl_ciphers), ciphers);
ASSERT(NULL != ctx); |
81d882d5 |
/* Set OpenSSL cipher list */
if (!SSL_CTX_set_cipher_list(ctx->ctx, openssl_ciphers))
{
crypto_msg(M_FATAL, "Failed to set restricted TLS cipher list: %s", openssl_ciphers);
} |
2e74a9d0 |
}
void |
7aeabadd |
convert_tls13_list_to_openssl(char *openssl_ciphers, size_t len,
const char *ciphers) |
ea4ee313 |
{
/*
* OpenSSL (and official IANA) cipher names have _ in them. We
* historically used names with - in them. Silently convert names
* with - to names with _ to support both
*/
if (strlen(ciphers) >= (len - 1))
{
msg(M_FATAL,
"Failed to set restricted TLS 1.3 cipher list, too long (>%d).",
(int) (len - 1));
}
strncpy(openssl_ciphers, ciphers, len);
for (size_t i = 0; i < strlen(openssl_ciphers); i++)
{
if (openssl_ciphers[i] == '-')
{
openssl_ciphers[i] = '_';
}
}
}
void
tls_ctx_restrict_ciphers_tls13(struct tls_root_ctx *ctx, const char *ciphers)
{
if (ciphers == NULL)
{
/* default cipher list of OpenSSL 1.1.1 is sane, do not set own
* default as we do with tls-cipher */
return;
}
|
a4750860 |
#if !defined(TLS1_3_VERSION) |
f57431cd |
crypto_msg(M_WARN, "Not compiled with OpenSSL 1.1.1 or higher. "
"Ignoring TLS 1.3 only tls-ciphersuites '%s' setting.",
ciphers); |
ea4ee313 |
#else
ASSERT(NULL != ctx);
char openssl_ciphers[4096];
convert_tls13_list_to_openssl(openssl_ciphers, sizeof(openssl_ciphers),
ciphers);
if (!SSL_CTX_set_ciphersuites(ctx->ctx, openssl_ciphers))
{
crypto_msg(M_FATAL, "Failed to set restricted TLS 1.3 cipher list: %s",
openssl_ciphers);
}
#endif
}
void |
aba75874 |
tls_ctx_set_cert_profile(struct tls_root_ctx *ctx, const char *profile)
{ |
b66701e5 |
#if OPENSSL_VERSION_NUMBER > 0x10100000L && !defined(LIBRESSL_VERSION_NUMBER) |
aba75874 |
/* OpenSSL does not have certificate profiles, but a complex set of
* callbacks that we could try to implement to achieve something similar.
* For now, use OpenSSL's security levels to achieve similar (but not equal)
* behaviour. */
if (!profile || 0 == strcmp(profile, "legacy"))
{
SSL_CTX_set_security_level(ctx->ctx, 1);
} |
23efeb7a |
else if (0 == strcmp(profile, "insecure"))
{
SSL_CTX_set_security_level(ctx->ctx, 0);
} |
aba75874 |
else if (0 == strcmp(profile, "preferred"))
{
SSL_CTX_set_security_level(ctx->ctx, 2);
}
else if (0 == strcmp(profile, "suiteb"))
{
SSL_CTX_set_security_level(ctx->ctx, 3);
SSL_CTX_set_cipher_list(ctx->ctx, "SUITEB128");
}
else
{
msg(M_FATAL, "ERROR: Invalid cert profile: %s", profile);
} |
b66701e5 |
#else /* if OPENSSL_VERSION_NUMBER > 0x10100000L */ |
aba75874 |
if (profile)
{ |
b66701e5 |
msg(M_WARN, "WARNING: OpenSSL 1.0.2 and LibreSSL do not support "
"--tls-cert-profile, ignoring user-set profile: '%s'", profile); |
aba75874 |
} |
b66701e5 |
#endif /* if OPENSSL_VERSION_NUMBER > 0x10100000L */ |
aba75874 |
}
void |
8353ae80 |
tls_ctx_set_tls_groups(struct tls_root_ctx *ctx, const char *groups)
{
ASSERT(ctx); |
711a4044 |
#if OPENSSL_VERSION_NUMBER < 0x30000000L |
8353ae80 |
struct gc_arena gc = gc_new();
/* This method could be as easy as
* SSL_CTX_set1_groups_list(ctx->ctx, groups) |
711a4044 |
* but OpenSSL (< 3.0) does not like the name secp256r1 for prime256v1 |
8353ae80 |
* This is one of the important curves.
* To support the same name for OpenSSL and mbedTLS, we do
* this dance. |
711a4044 |
* Also note that the code is wrong in the presence of OpenSSL3 providers. |
8353ae80 |
*/
int groups_count = get_num_elements(groups, ':');
int *glist;
/* Allocate an array for them */
ALLOC_ARRAY_CLEAR_GC(glist, int, groups_count, &gc);
/* Parse allowed ciphers, getting IDs */
int glistlen = 0;
char *tmp_groups = string_alloc(groups, &gc);
const char *token;
while ((token = strsep(&tmp_groups, ":")))
{
if (streq(token, "secp256r1"))
{
token = "prime256v1";
}
int nid = OBJ_sn2nid(token);
if (nid == 0)
{
msg(M_WARN, "Warning unknown curve/group specified: %s", token);
}
else
{
glist[glistlen] = nid;
glistlen++;
}
}
if (!SSL_CTX_set1_groups(ctx->ctx, glist, glistlen))
{
crypto_msg(M_FATAL, "Failed to set allowed TLS group list: %s",
groups);
}
gc_free(&gc); |
abe49856 |
#else /* if OPENSSL_VERSION_NUMBER < 0x30000000L */ |
711a4044 |
if (!SSL_CTX_set1_groups_list(ctx->ctx, groups))
{
crypto_msg(M_FATAL, "Failed to set allowed TLS group list: %s",
groups);
} |
abe49856 |
#endif /* if OPENSSL_VERSION_NUMBER < 0x30000000L */ |
8353ae80 |
}
void |
81d882d5 |
tls_ctx_check_cert_time(const struct tls_root_ctx *ctx) |
091edd8e |
{ |
81d882d5 |
int ret;
const X509 *cert; |
0e591a2f |
|
81d882d5 |
ASSERT(ctx); |
868d9d01 |
|
81d882d5 |
cert = SSL_CTX_get0_certificate(ctx->ctx); |
091edd8e |
|
81d882d5 |
if (cert == NULL) |
868d9d01 |
{ |
ec7d0e8e |
return; /* Nothing to check if there is no certificate */ |
868d9d01 |
}
|
8a01147f |
ret = X509_cmp_time(X509_get0_notBefore(cert), NULL); |
81d882d5 |
if (ret == 0) |
091edd8e |
{ |
81d882d5 |
msg(D_TLS_DEBUG_MED, "Failed to read certificate notBefore field."); |
091edd8e |
} |
81d882d5 |
if (ret > 0) |
091edd8e |
{ |
81d882d5 |
msg(M_WARN, "WARNING: Your certificate is not yet valid!"); |
091edd8e |
}
|
8a01147f |
ret = X509_cmp_time(X509_get0_notAfter(cert), NULL); |
81d882d5 |
if (ret == 0) |
091edd8e |
{ |
81d882d5 |
msg(D_TLS_DEBUG_MED, "Failed to read certificate notAfter field."); |
091edd8e |
} |
81d882d5 |
if (ret < 0) |
091edd8e |
{ |
81d882d5 |
msg(M_WARN, "WARNING: Your certificate has expired!"); |
091edd8e |
}
}
void |
81d882d5 |
tls_ctx_load_dh_params(struct tls_root_ctx *ctx, const char *dh_file, |
cb2e9218 |
bool dh_file_inline) |
ac3e8d62 |
{ |
81d882d5 |
BIO *bio; |
ac3e8d62 |
|
81d882d5 |
ASSERT(NULL != ctx); |
ac3e8d62 |
|
cb2e9218 |
if (dh_file_inline) |
ac3e8d62 |
{ |
cb2e9218 |
if (!(bio = BIO_new_mem_buf((char *)dh_file, -1))) |
81d882d5 |
{
crypto_msg(M_FATAL, "Cannot open memory BIO for inline DH parameters");
} |
ac3e8d62 |
} |
81d882d5 |
else |
ac3e8d62 |
{ |
81d882d5 |
/* Get Diffie Hellman Parameters */
if (!(bio = BIO_new_file(dh_file, "r")))
{
crypto_msg(M_FATAL, "Cannot open %s for DH parameters", dh_file);
} |
ac3e8d62 |
}
|
658c72e6 |
#if OPENSSL_VERSION_NUMBER >= 0x30000000L
EVP_PKEY *dh = PEM_read_bio_Parameters(bio, NULL);
BIO_free(bio);
if (!dh)
{
crypto_msg(M_FATAL, "Cannot load DH parameters from %s",
print_key_filename(dh_file, dh_file_inline));
}
if (!SSL_CTX_set0_tmp_dh_pkey(ctx->ctx, dh))
{ |
f1dd638c |
crypto_msg(M_FATAL, "SSL_CTX_set0_tmp_dh_pkey"); |
658c72e6 |
}
msg(D_TLS_DEBUG_LOW, "Diffie-Hellman initialized with %d bit key",
8 * EVP_PKEY_get_size(dh)); |
abe49856 |
#else /* if OPENSSL_VERSION_NUMBER >= 0x30000000L */ |
658c72e6 |
DH *dh = PEM_read_bio_DHparams(bio, NULL, NULL, NULL); |
81d882d5 |
BIO_free(bio); |
ac3e8d62 |
|
81d882d5 |
if (!dh)
{ |
cb2e9218 |
crypto_msg(M_FATAL, "Cannot load DH parameters from %s",
print_key_filename(dh_file, dh_file_inline)); |
81d882d5 |
}
if (!SSL_CTX_set_tmp_dh(ctx->ctx, dh))
{
crypto_msg(M_FATAL, "SSL_CTX_set_tmp_dh");
} |
ac3e8d62 |
|
81d882d5 |
msg(D_TLS_DEBUG_LOW, "Diffie-Hellman initialized with %d bit key",
8 * DH_size(dh)); |
ac3e8d62 |
|
81d882d5 |
DH_free(dh); |
abe49856 |
#endif /* if OPENSSL_VERSION_NUMBER >= 0x30000000L */ |
ac3e8d62 |
}
|
609e8131 |
void |
39eb3125 |
tls_ctx_load_ecdh_params(struct tls_root_ctx *ctx, const char *curve_name) |
609e8131 |
{ |
39eb3125 |
#if OPENSSL_VERSION_NUMBER >= 0x30000000L
if (curve_name != NULL)
{
msg(M_WARN, "WARNING: OpenSSL 3.0+ builds do not support specifying an " |
abe49856 |
"ECDH curve with --ecdh-curve, using default curves. Use "
"--tls-groups to specify groups."); |
39eb3125 |
}
#elif !defined(OPENSSL_NO_EC) |
81d882d5 |
int nid = NID_undef;
EC_KEY *ecdh = NULL;
const char *sname = NULL; |
609e8131 |
|
81d882d5 |
/* Generate a new ECDH key for each SSL session (for non-ephemeral ECDH) */
SSL_CTX_set_options(ctx->ctx, SSL_OP_SINGLE_ECDH_USE); |
5b004f99 |
|
81d882d5 |
if (curve_name != NULL) |
609e8131 |
{ |
81d882d5 |
/* Use user supplied curve if given */
msg(D_TLS_DEBUG, "Using user specified ECDH curve (%s)", curve_name);
nid = OBJ_sn2nid(curve_name); |
609e8131 |
} |
81d882d5 |
else |
609e8131 |
{ |
2c0ebe0f |
#if OPENSSL_VERSION_NUMBER < 0x10100000L |
8a01147f |
|
5b004f99 |
/* OpenSSL 1.0.2 and newer can automatically handle ECDH parameter
* loading */
SSL_CTX_set_ecdh_auto(ctx->ctx, 1); |
d8ac887c |
/* OpenSSL 1.1.0 and newer have always ecdh auto loading enabled,
* so do nothing */ |
8a01147f |
#endif |
d8ac887c |
return; |
609e8131 |
}
|
81d882d5 |
/* Translate NID back to name , just for kicks */
sname = OBJ_nid2sn(nid);
if (sname == NULL)
{
sname = "(Unknown)";
} |
609e8131 |
|
81d882d5 |
/* Create new EC key and set as ECDH key */
if (NID_undef == nid || NULL == (ecdh = EC_KEY_new_by_curve_name(nid))) |
609e8131 |
{ |
81d882d5 |
/* Creating key failed, fall back on sane default */
ecdh = EC_KEY_new_by_curve_name(NID_secp384r1);
const char *source = (NULL == curve_name) ?
"extract curve from certificate" : "use supplied curve";
msg(D_TLS_DEBUG_LOW,
"Failed to %s (%s), using secp384r1 instead.", source, sname);
sname = OBJ_nid2sn(NID_secp384r1); |
609e8131 |
}
|
81d882d5 |
if (!SSL_CTX_set_tmp_ecdh(ctx->ctx, ecdh))
{
crypto_msg(M_FATAL, "SSL_CTX_set_tmp_ecdh: cannot add curve");
} |
609e8131 |
|
81d882d5 |
msg(D_TLS_DEBUG_LOW, "ECDH curve %s added", sname); |
609e8131 |
|
81d882d5 |
EC_KEY_free(ecdh);
#else /* ifndef OPENSSL_NO_EC */ |
68441882 |
msg(D_LOW, "Your OpenSSL library was built without elliptic curve support." |
81d882d5 |
" Skipping ECDH parameter loading."); |
609e8131 |
#endif /* OPENSSL_NO_EC */
}
|
289a8bb8 |
int
tls_ctx_load_pkcs12(struct tls_root_ctx *ctx, const char *pkcs12_file, |
cb2e9218 |
bool pkcs12_file_inline, bool load_ca_file) |
289a8bb8 |
{ |
81d882d5 |
FILE *fp;
EVP_PKEY *pkey;
X509 *cert;
STACK_OF(X509) *ca = NULL;
PKCS12 *p12;
int i;
char password[256];
ASSERT(NULL != ctx);
|
cb2e9218 |
if (pkcs12_file_inline) |
81d882d5 |
{
BIO *b64 = BIO_new(BIO_f_base64()); |
cb2e9218 |
BIO *bio = BIO_new_mem_buf((void *) pkcs12_file,
(int) strlen(pkcs12_file)); |
81d882d5 |
ASSERT(b64 && bio);
BIO_push(b64, bio);
p12 = d2i_PKCS12_bio(b64, NULL);
if (!p12)
{
crypto_msg(M_FATAL, "Error reading inline PKCS#12 file");
}
BIO_free(b64);
BIO_free(bio);
}
else
{
/* Load the PKCS #12 file */
if (!(fp = platform_fopen(pkcs12_file, "rb")))
{
crypto_msg(M_FATAL, "Error opening file %s", pkcs12_file);
}
p12 = d2i_PKCS12_fp(fp, NULL);
fclose(fp);
if (!p12)
{
crypto_msg(M_FATAL, "Error reading PKCS#12 file %s", pkcs12_file);
}
}
/* Parse the PKCS #12 file */
if (!PKCS12_parse(p12, "", &pkey, &cert, &ca))
{
pem_password_callback(password, sizeof(password) - 1, 0, NULL);
/* Reparse the PKCS #12 file with password */
ca = NULL;
if (!PKCS12_parse(p12, password, &pkey, &cert, &ca))
{ |
6ac4e63c |
crypto_msg(M_WARN, "Decoding PKCS12 failed. Probably wrong password " |
abe49856 |
"or unsupported/legacy encryption"); |
289a8bb8 |
#ifdef ENABLE_MANAGEMENT |
81d882d5 |
if (management && (ERR_GET_REASON(ERR_peek_error()) == PKCS12_R_MAC_VERIFY_FAILURE))
{
management_auth_failure(management, UP_TYPE_PRIVATE_KEY, NULL);
} |
289a8bb8 |
#endif |
81d882d5 |
PKCS12_free(p12);
return 1;
}
}
PKCS12_free(p12);
/* Load Certificate */
if (!SSL_CTX_use_certificate(ctx->ctx, cert))
{ |
2671dcb6 |
crypto_print_openssl_errors(M_WARN); |
81d882d5 |
crypto_msg(M_FATAL, "Cannot use certificate");
}
/* Load Private Key */
if (!SSL_CTX_use_PrivateKey(ctx->ctx, pkey))
{
crypto_msg(M_FATAL, "Cannot use private key");
}
/* Check Private Key */
if (!SSL_CTX_check_private_key(ctx->ctx))
{
crypto_msg(M_FATAL, "Private key does not match the certificate");
}
/* Set Certificate Verification chain */
if (load_ca_file)
{
/* Add CAs from PKCS12 to the cert store and mark them as trusted.
* They're also used to fill in the chain of intermediate certs as
* necessary.
*/
if (ca && sk_X509_num(ca))
{
for (i = 0; i < sk_X509_num(ca); i++)
{ |
6554ac9f |
X509_STORE *cert_store = SSL_CTX_get_cert_store(ctx->ctx); |
e51d9a73 |
if (!X509_STORE_add_cert(cert_store, sk_X509_value(ca, i))) |
81d882d5 |
{ |
e51d9a73 |
crypto_msg(M_FATAL, "Cannot add certificate to certificate chain (X509_STORE_add_cert)"); |
81d882d5 |
}
if (!SSL_CTX_add_client_CA(ctx->ctx, sk_X509_value(ca, i)))
{ |
e51d9a73 |
crypto_msg(M_FATAL, "Cannot add certificate to client CA list (SSL_CTX_add_client_CA)"); |
81d882d5 |
}
}
}
}
else
{
/* If trusted CA certs were loaded from a PEM file, and we ignore the
* ones in PKCS12, do load PKCS12-provided certs to the client extra
* certs chain just in case they include intermediate CAs needed to
* prove my identity to the other end. This does not make them trusted.
*/
if (ca && sk_X509_num(ca))
{
for (i = 0; i < sk_X509_num(ca); i++)
{ |
e51d9a73 |
if (!SSL_CTX_add_extra_chain_cert(ctx->ctx, sk_X509_value(ca, i))) |
81d882d5 |
{
crypto_msg(M_FATAL, "Cannot add extra certificate to chain (SSL_CTX_add_extra_chain_cert)");
}
}
}
}
return 0; |
289a8bb8 |
}
|
93c22ecc |
#ifdef ENABLE_CRYPTOAPI |
d494c315 |
void
tls_ctx_load_cryptoapi(struct tls_root_ctx *ctx, const char *cryptoapi_cert)
{ |
81d882d5 |
ASSERT(NULL != ctx); |
d494c315 |
|
81d882d5 |
/* Load Certificate and Private Key */
if (!SSL_CTX_use_CryptoAPI_certificate(ctx->ctx, cryptoapi_cert))
{
crypto_msg(M_FATAL, "Cannot load certificate \"%s\" from Microsoft Certificate Store", cryptoapi_cert);
} |
d494c315 |
} |
445b192a |
#endif /* ENABLE_CRYPTOAPI */ |
d494c315 |
|
71bbbd76 |
static void |
3608d890 |
tls_ctx_add_extra_certs(struct tls_root_ctx *ctx, BIO *bio, bool optional) |
f4047d74 |
{ |
81d882d5 |
X509 *cert; |
3608d890 |
while (true) |
f4047d74 |
{ |
81d882d5 |
cert = NULL; |
3608d890 |
if (!PEM_read_bio_X509(bio, &cert, NULL, NULL)) |
81d882d5 |
{ |
3608d890 |
/* a PEM_R_NO_START_LINE "Error" indicates that no certificate
* is found in the buffer. If loading more certificates is
* optional, break without raising an error
*/
if (optional
&& ERR_GET_REASON(ERR_peek_error()) == PEM_R_NO_START_LINE)
{
/* remove that error from error stack */
(void)ERR_get_error();
break;
}
/* Otherwise, bail out with error */ |
81d882d5 |
crypto_msg(M_FATAL, "Error reading extra certificate");
} |
3608d890 |
/* takes ownership of cert like a set1 method */ |
81d882d5 |
if (SSL_CTX_add_extra_chain_cert(ctx->ctx, cert) != 1)
{
crypto_msg(M_FATAL, "Error adding extra certificate");
} |
3608d890 |
/* We loaded at least one certificate, so loading more is optional */
optional = true; |
f4047d74 |
}
}
|
98bfeeb4 |
void
tls_ctx_load_cert_file(struct tls_root_ctx *ctx, const char *cert_file, |
cb2e9218 |
bool cert_file_inline) |
f4047d74 |
{ |
81d882d5 |
BIO *in = NULL;
X509 *x = NULL;
int ret = 0; |
71bbbd76 |
|
81d882d5 |
ASSERT(NULL != ctx); |
f4047d74 |
|
cb2e9218 |
if (cert_file_inline) |
81d882d5 |
{ |
cb2e9218 |
in = BIO_new_mem_buf((char *) cert_file, -1); |
81d882d5 |
}
else
{
in = BIO_new_file(cert_file, "r");
} |
71bbbd76 |
|
81d882d5 |
if (in == NULL) |
71bbbd76 |
{ |
81d882d5 |
SSLerr(SSL_F_SSL_CTX_USE_CERTIFICATE_FILE, ERR_R_SYS_LIB);
goto end; |
71bbbd76 |
}
|
6554ac9f |
x = PEM_read_bio_X509(in, NULL,
SSL_CTX_get_default_passwd_cb(ctx->ctx),
SSL_CTX_get_default_passwd_cb_userdata(ctx->ctx)); |
81d882d5 |
if (x == NULL) |
f4047d74 |
{ |
81d882d5 |
SSLerr(SSL_F_SSL_CTX_USE_CERTIFICATE_FILE, ERR_R_PEM_LIB);
goto end; |
71bbbd76 |
}
|
81d882d5 |
ret = SSL_CTX_use_certificate(ctx->ctx, x);
if (ret)
{ |
3608d890 |
tls_ctx_add_extra_certs(ctx, in, true); |
81d882d5 |
} |
71bbbd76 |
end: |
81d882d5 |
if (!ret) |
71bbbd76 |
{ |
2671dcb6 |
crypto_print_openssl_errors(M_WARN); |
cb2e9218 |
if (cert_file_inline) |
81d882d5 |
{
crypto_msg(M_FATAL, "Cannot load inline certificate file");
}
else
{
crypto_msg(M_FATAL, "Cannot load certificate file %s", cert_file);
} |
f4047d74 |
} |
f67efa94 |
else
{
crypto_print_openssl_errors(M_DEBUG);
} |
71bbbd76 |
|
cb70cf51 |
BIO_free(in);
X509_free(x); |
f4047d74 |
}
|
d67c3147 |
int |
81d882d5 |
tls_ctx_load_priv_file(struct tls_root_ctx *ctx, const char *priv_key_file, |
cb2e9218 |
bool priv_key_file_inline) |
d67c3147 |
{ |
81d882d5 |
SSL_CTX *ssl_ctx = NULL;
BIO *in = NULL;
EVP_PKEY *pkey = NULL;
int ret = 1; |
d67c3147 |
|
81d882d5 |
ASSERT(NULL != ctx); |
be960aad |
|
81d882d5 |
ssl_ctx = ctx->ctx; |
71bbbd76 |
|
cb2e9218 |
if (priv_key_file_inline) |
81d882d5 |
{ |
cb2e9218 |
in = BIO_new_mem_buf((char *) priv_key_file, -1); |
81d882d5 |
}
else
{
in = BIO_new_file(priv_key_file, "r");
} |
71bbbd76 |
|
81d882d5 |
if (!in)
{
goto end;
} |
71bbbd76 |
|
81d882d5 |
pkey = PEM_read_bio_PrivateKey(in, NULL, |
6554ac9f |
SSL_CTX_get_default_passwd_cb(ctx->ctx),
SSL_CTX_get_default_passwd_cb_userdata(ctx->ctx)); |
8155f8aa |
|
f67efa94 |
if (!pkey || !SSL_CTX_use_PrivateKey(ssl_ctx, pkey)) |
d67c3147 |
{
#ifdef ENABLE_MANAGEMENT |
81d882d5 |
if (management && (ERR_GET_REASON(ERR_peek_error()) == EVP_R_BAD_DECRYPT))
{
management_auth_failure(management, UP_TYPE_PRIVATE_KEY, NULL);
} |
d67c3147 |
#endif |
cb2e9218 |
crypto_msg(M_WARN, "Cannot load private key file %s",
print_key_filename(priv_key_file, priv_key_file_inline)); |
81d882d5 |
goto end; |
d67c3147 |
}
|
81d882d5 |
/* Check Private Key */
if (!SSL_CTX_check_private_key(ssl_ctx))
{
crypto_msg(M_FATAL, "Private key does not match the certificate");
}
ret = 0; |
d67c3147 |
|
71bbbd76 |
end: |
cb70cf51 |
EVP_PKEY_free(pkey);
BIO_free(in); |
81d882d5 |
return ret; |
d67c3147 |
}
|
160504a2 |
void |
ce91c187 |
backend_tls_ctx_reload_crl(struct tls_root_ctx *ssl_ctx, const char *crl_file, |
cb2e9218 |
bool crl_inline) |
160504a2 |
{ |
81d882d5 |
BIO *in = NULL; |
160504a2 |
|
81d882d5 |
X509_STORE *store = SSL_CTX_get_cert_store(ssl_ctx->ctx);
if (!store)
{
crypto_msg(M_FATAL, "Cannot get certificate store");
} |
160504a2 |
|
81d882d5 |
/* Always start with a cleared CRL list, for that we
* we need to manually find the CRL object from the stack
* and remove it */ |
f05665df |
STACK_OF(X509_OBJECT) *objs = X509_STORE_get0_objects(store);
for (int i = 0; i < sk_X509_OBJECT_num(objs); i++) |
160504a2 |
{ |
f05665df |
X509_OBJECT *obj = sk_X509_OBJECT_value(objs, i); |
81d882d5 |
ASSERT(obj); |
47191f49 |
if (X509_OBJECT_get_type(obj) == X509_LU_CRL) |
81d882d5 |
{ |
f05665df |
sk_X509_OBJECT_delete(objs, i); |
47191f49 |
X509_OBJECT_free(obj); |
81d882d5 |
} |
160504a2 |
}
|
81d882d5 |
X509_STORE_set_flags(store, X509_V_FLAG_CRL_CHECK | X509_V_FLAG_CRL_CHECK_ALL); |
160504a2 |
|
cb2e9218 |
if (crl_inline) |
81d882d5 |
{ |
cb2e9218 |
in = BIO_new_mem_buf((char *) crl_file, -1); |
81d882d5 |
}
else
{
in = BIO_new_file(crl_file, "r");
} |
160504a2 |
|
81d882d5 |
if (in == NULL) |
160504a2 |
{ |
cb2e9218 |
msg(M_WARN, "CRL: cannot read: %s",
print_key_filename(crl_file, crl_inline)); |
81d882d5 |
goto end; |
160504a2 |
}
|
05229fb5 |
int num_crls_loaded = 0;
while (true) |
160504a2 |
{ |
05229fb5 |
X509_CRL *crl = PEM_read_bio_X509_CRL(in, NULL, NULL, NULL);
if (crl == NULL)
{
/*
* PEM_R_NO_START_LINE can be considered equivalent to EOF.
*/
bool eof = ERR_GET_REASON(ERR_peek_error()) == PEM_R_NO_START_LINE;
/* but warn if no CRLs have been loaded */
if (num_crls_loaded > 0 && eof)
{
/* remove that error from error stack */
(void)ERR_get_error();
break;
} |
160504a2 |
|
cb2e9218 |
crypto_msg(M_WARN, "CRL: cannot read CRL from file %s",
print_key_filename(crl_file, crl_inline)); |
05229fb5 |
break;
} |
160504a2 |
|
05229fb5 |
if (!X509_STORE_add_crl(store, crl))
{
X509_CRL_free(crl); |
cb2e9218 |
crypto_msg(M_WARN, "CRL: cannot add %s to store",
print_key_filename(crl_file, crl_inline)); |
05229fb5 |
break;
}
X509_CRL_free(crl);
num_crls_loaded++;
}
msg(M_INFO, "CRL: loaded %d CRLs from file %s", num_crls_loaded, crl_file); |
160504a2 |
end: |
81d882d5 |
BIO_free(in); |
160504a2 |
}
|
199df03b |
#if defined(ENABLE_MANAGEMENT) && !defined(HAVE_XKEY_PROVIDER) |
5f4eb537 |
/* encrypt */
static int
rsa_pub_enc(int flen, const unsigned char *from, unsigned char *to, RSA *rsa, int padding)
{ |
81d882d5 |
ASSERT(0);
return -1; |
5f4eb537 |
}
/* verify arbitrary data */
static int
rsa_pub_dec(int flen, const unsigned char *from, unsigned char *to, RSA *rsa, int padding)
{ |
81d882d5 |
ASSERT(0);
return -1; |
5f4eb537 |
}
/* decrypt */
static int
rsa_priv_dec(int flen, const unsigned char *from, unsigned char *to, RSA *rsa, int padding)
{ |
81d882d5 |
ASSERT(0);
return -1; |
5f4eb537 |
}
/* called at RSA_free */
static int |
f7780af6 |
openvpn_extkey_rsa_finish(RSA *rsa) |
5f4eb537 |
{ |
98bfeeb4 |
/* meth was allocated in tls_ctx_use_management_external_key() ; since |
f7780af6 |
* this function is called when the parent RSA object is destroyed,
* it is no longer used after this point so kill it. */
const RSA_METHOD *meth = RSA_get_method(rsa);
RSA_meth_free((RSA_METHOD *)meth); |
81d882d5 |
return 1; |
5f4eb537 |
}
|
8be444df |
/*
* Convert OpenSSL's constant to the strings used in the management
* interface query
*/
const char * |
9cf7b492 |
get_rsa_padding_name(const int padding) |
8be444df |
{
switch (padding)
{
case RSA_PKCS1_PADDING:
return "RSA_PKCS1_PADDING";
case RSA_NO_PADDING:
return "RSA_NO_PADDING";
default:
return "UNKNOWN";
}
}
/**
* Pass the input hash in 'dgst' to management and get the signature back.
* |
9cf7b492 |
* @param dgst hash to be signed
* @param dgstlen len of data in dgst
* @param sig On successful return signature is in sig.
* @param siglen length of buffer sig
* @param algorithm padding/hashing algorithm for the signature
*
* @return signature length or -1 on error. |
7eca140c |
*/ |
5f4eb537 |
static int |
7eca140c |
get_sig_from_man(const unsigned char *dgst, unsigned int dgstlen, |
8be444df |
unsigned char *sig, unsigned int siglen,
const char *algorithm) |
5f4eb537 |
{ |
81d882d5 |
char *in_b64 = NULL;
char *out_b64 = NULL; |
7eca140c |
int len = -1; |
5f4eb537 |
|
8be444df |
int bencret = openvpn_base64_encode(dgst, dgstlen, &in_b64);
if (management && bencret > 0) |
81d882d5 |
{ |
8be444df |
out_b64 = management_query_pk_sig(management, in_b64, algorithm);
|
81d882d5 |
} |
7eca140c |
if (out_b64) |
81d882d5 |
{ |
7eca140c |
len = openvpn_base64_decode(out_b64, sig, siglen); |
81d882d5 |
} |
c3b2d487 |
|
7eca140c |
free(in_b64);
free(out_b64);
return len;
} |
68793f40 |
|
7eca140c |
/* sign arbitrary data */
static int |
8be444df |
rsa_priv_enc(int flen, const unsigned char *from, unsigned char *to, RSA *rsa,
int padding) |
7eca140c |
{
unsigned int len = RSA_size(rsa);
int ret = -1; |
5f4eb537 |
|
8be444df |
if (padding != RSA_PKCS1_PADDING && padding != RSA_NO_PADDING) |
81d882d5 |
{ |
7eca140c |
RSAerr(RSA_F_RSA_OSSL_PRIVATE_ENCRYPT, RSA_R_UNKNOWN_PADDING_TYPE);
return -1; |
81d882d5 |
} |
7eca140c |
|
9cf7b492 |
ret = get_sig_from_man(from, flen, to, len, get_rsa_padding_name(padding)); |
7eca140c |
|
f57431cd |
return (ret == len) ? ret : -1; |
81d882d5 |
} |
5f4eb537 |
|
d59a1c2f |
static int
tls_ctx_use_external_rsa_key(struct tls_root_ctx *ctx, EVP_PKEY *pkey) |
81d882d5 |
{
RSA *rsa = NULL;
RSA_METHOD *rsa_meth;
ASSERT(NULL != ctx);
|
6fc292d2 |
const RSA *pub_rsa = EVP_PKEY_get0_RSA(pkey); |
d59a1c2f |
ASSERT(NULL != pub_rsa); |
81d882d5 |
/* allocate custom RSA method object */ |
09776c5b |
rsa_meth = RSA_meth_new("OpenVPN external private key RSA Method",
RSA_METHOD_FLAG_NO_CHECK);
check_malloc_return(rsa_meth);
RSA_meth_set_pub_enc(rsa_meth, rsa_pub_enc);
RSA_meth_set_pub_dec(rsa_meth, rsa_pub_dec);
RSA_meth_set_priv_enc(rsa_meth, rsa_priv_enc);
RSA_meth_set_priv_dec(rsa_meth, rsa_priv_dec);
RSA_meth_set_init(rsa_meth, NULL); |
f7780af6 |
RSA_meth_set_finish(rsa_meth, openvpn_extkey_rsa_finish); |
09776c5b |
RSA_meth_set0_app_data(rsa_meth, NULL); |
81d882d5 |
/* allocate RSA object */
rsa = RSA_new();
if (rsa == NULL)
{
SSLerr(SSL_F_SSL_USE_PRIVATEKEY, ERR_R_MALLOC_FAILURE);
goto err;
} |
5f4eb537 |
|
81d882d5 |
/* initialize RSA object */ |
f7780af6 |
const BIGNUM *n = NULL;
const BIGNUM *e = NULL;
RSA_get0_key(pub_rsa, &n, &e, NULL);
RSA_set0_key(rsa, BN_dup(n), BN_dup(e), NULL);
RSA_set_flags(rsa, RSA_flags(rsa) | RSA_FLAG_EXT_PKEY); |
81d882d5 |
if (!RSA_set_method(rsa, rsa_meth))
{ |
d59a1c2f |
RSA_meth_free(rsa_meth); |
81d882d5 |
goto err;
} |
d59a1c2f |
/* from this point rsa_meth will get freed with rsa */ |
5f4eb537 |
|
81d882d5 |
/* bind our custom RSA object to ssl_ctx */
if (!SSL_CTX_use_RSAPrivateKey(ctx->ctx, rsa))
{
goto err;
} |
5f4eb537 |
|
81d882d5 |
RSA_free(rsa); /* doesn't necessarily free, just decrements refcount */
return 1;
err:
if (rsa)
{
RSA_free(rsa);
} |
cb70cf51 |
else if (rsa_meth) |
5f4eb537 |
{ |
cb70cf51 |
RSA_meth_free(rsa_meth); |
5f4eb537 |
} |
d59a1c2f |
return 0;
}
|
2c0ebe0f |
#if OPENSSL_VERSION_NUMBER > 0x10100000L && !defined(OPENSSL_NO_EC) |
7eca140c |
/* called when EC_KEY is destroyed */
static void
openvpn_extkey_ec_finish(EC_KEY *ec)
{
/* release the method structure */
const EC_KEY_METHOD *ec_meth = EC_KEY_get_method(ec);
EC_KEY_METHOD_free((EC_KEY_METHOD *) ec_meth);
}
/* EC_KEY_METHOD callback: sign().
* Sign the hash using EC key and return DER encoded signature in sig,
* its length in siglen. Return value is 1 on success, 0 on error.
*/
static int
ecdsa_sign(int type, const unsigned char *dgst, int dgstlen, unsigned char *sig,
unsigned int *siglen, const BIGNUM *kinv, const BIGNUM *r, EC_KEY *ec)
{
int capacity = ECDSA_size(ec); |
8be444df |
/*
* ECDSA does not seem to have proper constants for paddings since
* there are only signatures without padding at the moment, use
* a generic ECDSA for the moment
*/
int len = get_sig_from_man(dgst, dgstlen, sig, capacity, "ECDSA"); |
7eca140c |
if (len > 0)
{
*siglen = len;
return 1;
}
return 0;
}
/* EC_KEY_METHOD callback: sign_setup(). We do no precomputations */
static int
ecdsa_sign_setup(EC_KEY *ec, BN_CTX *ctx_in, BIGNUM **kinvp, BIGNUM **rp)
{
return 1;
}
/* EC_KEY_METHOD callback: sign_sig().
* Sign the hash and return the result as a newly allocated ECDS_SIG
* struct or NULL on error.
*/
static ECDSA_SIG *
ecdsa_sign_sig(const unsigned char *dgst, int dgstlen, const BIGNUM *in_kinv,
const BIGNUM *in_r, EC_KEY *ec)
{
ECDSA_SIG *ecsig = NULL;
unsigned int len = ECDSA_size(ec);
struct gc_arena gc = gc_new();
unsigned char *buf = gc_malloc(len, false, &gc);
if (ecdsa_sign(0, dgst, dgstlen, buf, &len, NULL, NULL, ec) != 1)
{
goto out;
}
/* const char ** should be avoided: not up to us, so we cast our way through */
ecsig = d2i_ECDSA_SIG(NULL, (const unsigned char **)&buf, len);
out:
gc_free(&gc);
return ecsig;
}
static int
tls_ctx_use_external_ec_key(struct tls_root_ctx *ctx, EVP_PKEY *pkey)
{
EC_KEY *ec = NULL;
EVP_PKEY *privkey = NULL;
EC_KEY_METHOD *ec_method;
ASSERT(ctx);
ec_method = EC_KEY_METHOD_new(EC_KEY_OpenSSL());
if (!ec_method)
{
goto err;
}
/* Among init methods, we only need the finish method */
EC_KEY_METHOD_set_init(ec_method, NULL, openvpn_extkey_ec_finish, NULL, NULL, NULL, NULL);
EC_KEY_METHOD_set_sign(ec_method, ecdsa_sign, ecdsa_sign_setup, ecdsa_sign_sig);
ec = EC_KEY_dup(EVP_PKEY_get0_EC_KEY(pkey));
if (!ec)
{
EC_KEY_METHOD_free(ec_method);
goto err;
}
if (!EC_KEY_set_method(ec, ec_method))
{
EC_KEY_METHOD_free(ec_method);
goto err;
}
/* from this point ec_method will get freed when ec is freed */
privkey = EVP_PKEY_new();
if (!EVP_PKEY_assign_EC_KEY(privkey, ec))
{
goto err;
}
/* from this point ec will get freed when privkey is freed */
if (!SSL_CTX_use_PrivateKey(ctx->ctx, privkey))
{
ec = NULL; /* avoid double freeing it below */
goto err;
}
EVP_PKEY_free(privkey); /* this will down ref privkey and ec */
return 1;
err:
/* Reach here only when ec and privkey can be independenly freed */ |
cb70cf51 |
EVP_PKEY_free(privkey);
EC_KEY_free(ec); |
7eca140c |
return 0;
} |
a4750860 |
#endif /* OPENSSL_VERSION_NUMBER > 1.1.0 dev && !defined(OPENSSL_NO_EC) */ |
199df03b |
#endif /* ENABLE_MANAGEMENT && !HAVE_XKEY_PROVIDER */ |
7eca140c |
|
199df03b |
#ifdef ENABLE_MANAGEMENT |
d59a1c2f |
int |
98bfeeb4 |
tls_ctx_use_management_external_key(struct tls_root_ctx *ctx) |
d59a1c2f |
{ |
98bfeeb4 |
int ret = 1; |
d59a1c2f |
ASSERT(NULL != ctx);
|
98bfeeb4 |
X509 *cert = SSL_CTX_get0_certificate(ctx->ctx); |
d59a1c2f |
ASSERT(NULL != cert);
/* get the public key */
EVP_PKEY *pkey = X509_get0_pubkey(cert);
ASSERT(pkey); /* NULL before SSL_CTX_use_certificate() is called */
|
c279986b |
#ifdef HAVE_XKEY_PROVIDER
EVP_PKEY *privkey = xkey_load_management_key(tls_libctx, pkey);
if (!privkey
|| !SSL_CTX_use_PrivateKey(ctx->ctx, privkey))
{ |
0f7cd474 |
EVP_PKEY_free(privkey); |
c279986b |
goto cleanup;
}
EVP_PKEY_free(privkey); |
abe49856 |
#else /* ifdef HAVE_XKEY_PROVIDER */ |
6c111be9 |
#if OPENSSL_VERSION_NUMBER < 0x30000000L |
7eca140c |
if (EVP_PKEY_id(pkey) == EVP_PKEY_RSA) |
6c111be9 |
#else /* OPENSSL_VERSION_NUMBER < 0x30000000L */
if (EVP_PKEY_is_a(pkey, "RSA"))
#endif /* OPENSSL_VERSION_NUMBER < 0x30000000L */ |
d59a1c2f |
{
if (!tls_ctx_use_external_rsa_key(ctx, pkey))
{ |
98bfeeb4 |
goto cleanup; |
d59a1c2f |
}
} |
2c0ebe0f |
#if (OPENSSL_VERSION_NUMBER > 0x10100000L) && !defined(OPENSSL_NO_EC) |
6c111be9 |
#if OPENSSL_VERSION_NUMBER < 0x30000000L |
7eca140c |
else if (EVP_PKEY_id(pkey) == EVP_PKEY_EC) |
6c111be9 |
#else /* OPENSSL_VERSION_NUMBER < 0x30000000L */
else if (EVP_PKEY_is_a(pkey, "EC"))
#endif /* OPENSSL_VERSION_NUMBER < 0x30000000L */ |
7eca140c |
{
if (!tls_ctx_use_external_ec_key(ctx, pkey))
{ |
98bfeeb4 |
goto cleanup; |
7eca140c |
}
}
else
{
crypto_msg(M_WARN, "management-external-key requires an RSA or EC certificate"); |
98bfeeb4 |
goto cleanup; |
7eca140c |
} |
a4750860 |
#else /* OPENSSL_VERSION_NUMBER > 1.1.0 dev && !defined(OPENSSL_NO_EC) */ |
d59a1c2f |
else
{ |
7eca140c |
crypto_msg(M_WARN, "management-external-key requires an RSA certificate"); |
98bfeeb4 |
goto cleanup; |
d59a1c2f |
} |
a4750860 |
#endif /* OPENSSL_VERSION_NUMBER > 1.1.0 dev && !defined(OPENSSL_NO_EC) */ |
d59a1c2f |
|
c279986b |
#endif /* HAVE_XKEY_PROVIDER */
|
98bfeeb4 |
ret = 0;
cleanup:
if (ret)
{
crypto_msg(M_FATAL, "Cannot enable SSL external private key capability");
}
return ret; |
5f4eb537 |
}
|
66b9409b |
#endif /* ifdef ENABLE_MANAGEMENT */ |
5f4eb537 |
|
244da317 |
static int |
81d882d5 |
sk_x509_name_cmp(const X509_NAME *const *a, const X509_NAME *const *b) |
244da317 |
{ |
81d882d5 |
return X509_NAME_cmp(*a, *b); |
244da317 |
}
void |
81d882d5 |
tls_ctx_load_ca(struct tls_root_ctx *ctx, const char *ca_file, |
cb2e9218 |
bool ca_file_inline, const char *ca_path, bool tls_server) |
244da317 |
{ |
81d882d5 |
STACK_OF(X509_INFO) *info_stack = NULL;
STACK_OF(X509_NAME) *cert_names = NULL;
X509_LOOKUP *lookup = NULL;
X509_STORE *store = NULL;
X509_NAME *xn = NULL;
BIO *in = NULL;
int i, added = 0, prev = 0;
ASSERT(NULL != ctx);
store = SSL_CTX_get_cert_store(ctx->ctx);
if (!store)
{
crypto_msg(M_FATAL, "Cannot get certificate store");
} |
71bbbd76 |
|
81d882d5 |
/* Try to add certificates and CRLs from ca_file */
if (ca_file) |
71bbbd76 |
{ |
cb2e9218 |
if (ca_file_inline) |
81d882d5 |
{ |
cb2e9218 |
in = BIO_new_mem_buf((char *)ca_file, -1); |
81d882d5 |
}
else
{
in = BIO_new_file(ca_file, "r");
} |
244da317 |
|
81d882d5 |
if (in)
{
info_stack = PEM_X509_INFO_read_bio(in, NULL, NULL, NULL);
} |
71bbbd76 |
|
81d882d5 |
if (info_stack) |
71bbbd76 |
{ |
81d882d5 |
for (i = 0; i < sk_X509_INFO_num(info_stack); i++) |
71bbbd76 |
{ |
81d882d5 |
X509_INFO *info = sk_X509_INFO_value(info_stack, i);
if (info->crl) |
9927cdbd |
{ |
81d882d5 |
X509_STORE_add_crl(store, info->crl); |
9927cdbd |
}
|
81d882d5 |
if (tls_server && !info->x509) |
71bbbd76 |
{ |
81d882d5 |
crypto_msg(M_FATAL, "X509 name was missing in TLS mode");
} |
71bbbd76 |
|
81d882d5 |
if (info->x509)
{
X509_STORE_add_cert(store, info->x509);
added++; |
71bbbd76 |
|
81d882d5 |
if (!tls_server) |
71bbbd76 |
{
continue;
}
|
81d882d5 |
/* Use names of CAs as a client CA list */
if (cert_names == NULL)
{
cert_names = sk_X509_NAME_new(sk_x509_name_cmp);
if (!cert_names)
{
continue;
}
} |
71bbbd76 |
|
81d882d5 |
xn = X509_get_subject_name(info->x509);
if (!xn) |
71bbbd76 |
{
continue; |
81d882d5 |
}
/* Don't add duplicate CA names */
if (sk_X509_NAME_find(cert_names, xn) == -1)
{
xn = X509_NAME_dup(xn);
if (!xn)
{
continue;
}
sk_X509_NAME_push(cert_names, xn); |
71bbbd76 |
}
} |
9927cdbd |
|
81d882d5 |
if (tls_server)
{
int cnum = sk_X509_NAME_num(cert_names);
if (cnum != (prev + 1))
{
crypto_msg(M_WARN,
"Cannot load CA certificate file %s (entry %d did not validate)", |
cb2e9218 |
print_key_filename(ca_file, ca_file_inline),
added); |
81d882d5 |
}
prev = cnum;
} |
71bbbd76 |
} |
81d882d5 |
sk_X509_INFO_pop_free(info_stack, X509_INFO_free); |
71bbbd76 |
}
|
81d882d5 |
if (tls_server)
{
SSL_CTX_set_client_CA_list(ctx->ctx, cert_names);
} |
71bbbd76 |
|
81d882d5 |
if (!added)
{
crypto_msg(M_FATAL,
"Cannot load CA certificate file %s (no entries were read)", |
cb2e9218 |
print_key_filename(ca_file, ca_file_inline)); |
81d882d5 |
} |
9927cdbd |
|
81d882d5 |
if (tls_server)
{
int cnum = sk_X509_NAME_num(cert_names);
if (cnum != added)
{
crypto_msg(M_FATAL, "Cannot load CA certificate file %s (only %d "
"of %d entries were valid X509 names)", |
cb2e9218 |
print_key_filename(ca_file, ca_file_inline), cnum,
added); |
81d882d5 |
}
} |
9927cdbd |
|
cb70cf51 |
BIO_free(in); |
71bbbd76 |
} |
244da317 |
|
81d882d5 |
/* Set a store for certs (CA & CRL) with a lookup on the "capath" hash directory */
if (ca_path) |
71bbbd76 |
{ |
81d882d5 |
lookup = X509_STORE_add_lookup(store, X509_LOOKUP_hash_dir());
if (lookup && X509_LOOKUP_add_dir(lookup, ca_path, X509_FILETYPE_PEM))
{
msg(M_WARN, "WARNING: experimental option --capath %s", ca_path);
}
else
{
crypto_msg(M_FATAL, "Cannot add lookup at --capath %s", ca_path);
}
X509_STORE_set_flags(store, X509_V_FLAG_CRL_CHECK | X509_V_FLAG_CRL_CHECK_ALL); |
71bbbd76 |
} |
fceecbab |
}
void |
81d882d5 |
tls_ctx_load_extra_certs(struct tls_root_ctx *ctx, const char *extra_certs_file, |
cb2e9218 |
bool extra_certs_file_inline) |
fceecbab |
{ |
81d882d5 |
BIO *in; |
cb2e9218 |
if (extra_certs_file_inline) |
81d882d5 |
{ |
cb2e9218 |
in = BIO_new_mem_buf((char *)extra_certs_file, -1); |
81d882d5 |
}
else
{
in = BIO_new_file(extra_certs_file, "r");
}
if (in == NULL)
{ |
cb2e9218 |
crypto_msg(M_FATAL, "Cannot load extra-certs file: %s",
print_key_filename(extra_certs_file,
extra_certs_file_inline));
|
81d882d5 |
}
else
{ |
3608d890 |
tls_ctx_add_extra_certs(ctx, in, false); |
81d882d5 |
}
BIO_free(in); |
244da317 |
}
|
d7efe640 |
/* **************************************
*
* Key-state specific functions
*
***************************************/
/*
*
* BIO functions
*
*/
|
dea110e0 |
#ifdef BIO_DEBUG
#warning BIO_DEBUG defined
static FILE *biofp; /* GLOBAL */
static bool biofp_toggle; /* GLOBAL */
static time_t biofp_last_open; /* GLOBAL */
static const int biofp_reopen_interval = 600; /* GLOBAL */
static void |
e2a0cad4 |
close_biofp(void) |
dea110e0 |
{ |
81d882d5 |
if (biofp) |
dea110e0 |
{ |
81d882d5 |
ASSERT(!fclose(biofp));
biofp = NULL; |
dea110e0 |
}
}
static void |
e2a0cad4 |
open_biofp(void) |
dea110e0 |
{ |
81d882d5 |
const time_t current = time(NULL);
const pid_t pid = getpid(); |
dea110e0 |
|
81d882d5 |
if (biofp_last_open + biofp_reopen_interval < current)
{
close_biofp();
}
if (!biofp) |
dea110e0 |
{ |
81d882d5 |
char fn[256]; |
130548fe |
snprintf(fn, sizeof(fn), "bio/%d-%d.log", pid, biofp_toggle); |
81d882d5 |
biofp = fopen(fn, "w");
ASSERT(biofp);
biofp_last_open = time(NULL);
biofp_toggle ^= 1; |
dea110e0 |
}
}
static void |
81d882d5 |
bio_debug_data(const char *mode, BIO *bio, const uint8_t *buf, int len, const char *desc) |
dea110e0 |
{ |
81d882d5 |
struct gc_arena gc = gc_new();
if (len > 0) |
dea110e0 |
{ |
81d882d5 |
open_biofp(); |
f57431cd |
fprintf(biofp, "BIO_%s %s time=%" PRIi64 " bio=" ptr_format " len=%d data=%s\n", |
06ad53e0 |
mode, desc, (int64_t)time(NULL), (ptr_type)bio, len, format_hex(buf, len, 0, &gc)); |
81d882d5 |
fflush(biofp); |
dea110e0 |
} |
81d882d5 |
gc_free(&gc); |
dea110e0 |
}
static void |
81d882d5 |
bio_debug_oc(const char *mode, BIO *bio) |
dea110e0 |
{ |
81d882d5 |
open_biofp(); |
f57431cd |
fprintf(biofp, "BIO %s time=%" PRIi64 " bio=" ptr_format "\n", |
06ad53e0 |
mode, (int64_t)time(NULL), (ptr_type)bio); |
81d882d5 |
fflush(biofp); |
dea110e0 |
}
|
81d882d5 |
#endif /* ifdef BIO_DEBUG */ |
dea110e0 |
|
d7efe640 |
/* |
bf707bd2 |
* Write to an OpenSSL BIO in non-blocking mode.
*/
static int |
81d882d5 |
bio_write(BIO *bio, const uint8_t *data, int size, const char *desc) |
bf707bd2 |
{ |
81d882d5 |
int i;
int ret = 0;
ASSERT(size >= 0);
if (size)
{
/*
* Free the L_TLS lock prior to calling BIO routines
* so that foreground thread can still call
* tls_pre_decrypt or tls_pre_encrypt,
* allowing tunnel packet forwarding to continue.
*/ |
bf707bd2 |
#ifdef BIO_DEBUG |
81d882d5 |
bio_debug_data("write", bio, data, size, desc); |
bf707bd2 |
#endif |
81d882d5 |
i = BIO_write(bio, data, size);
if (i < 0)
{ |
f2454ec6 |
if (!BIO_should_retry(bio)) |
81d882d5 |
{
crypto_msg(D_TLS_ERRORS, "TLS ERROR: BIO write %s error", desc);
ret = -1;
ERR_clear_error();
}
}
else if (i != size)
{
crypto_msg(D_TLS_ERRORS, "TLS ERROR: BIO write %s incomplete %d/%d",
desc, i, size);
ret = -1;
ERR_clear_error();
}
else
{ /* successful write */
dmsg(D_HANDSHAKE_VERBOSE, "BIO write %s %d bytes", desc, i);
ret = 1;
}
}
return ret; |
bf707bd2 |
}
/*
* Inline functions for reading from and writing
* to BIOs.
*/
static void |
81d882d5 |
bio_write_post(const int status, struct buffer *buf) |
bf707bd2 |
{ |
81d882d5 |
if (status == 1) /* success status return from bio_write? */ |
bf707bd2 |
{ |
81d882d5 |
memset(BPTR(buf), 0, BLEN(buf)); /* erase data just written */
buf->len = 0; |
bf707bd2 |
}
}
/* |
dd5e1102 |
* Read from an OpenSSL BIO in non-blocking mode.
*/
static int |
4e9e25a9 |
bio_read(BIO *bio, struct buffer *buf, const char *desc) |
dd5e1102 |
{ |
81d882d5 |
ASSERT(buf->len >= 0);
if (buf->len) |
dd5e1102 |
{ |
f2454ec6 |
/* we only want to write empty buffers, ignore read request
* if the buffer is not empty */
return 0; |
dd5e1102 |
} |
f2454ec6 |
int len = buf_forward_capacity(buf); |
dd5e1102 |
|
f2454ec6 |
/*
* BIO_read brackets most of the serious RSA
* key negotiation number crunching.
*/
int i = BIO_read(bio, BPTR(buf), len); |
dd5e1102 |
|
f2454ec6 |
VALGRIND_MAKE_READABLE((void *) &i, sizeof(i)); |
dd5e1102 |
#ifdef BIO_DEBUG |
f2454ec6 |
bio_debug_data("read", bio, BPTR(buf), i, desc); |
dd5e1102 |
#endif |
f2454ec6 |
int ret = 0;
if (i < 0)
{
if (!BIO_should_retry(bio)) |
81d882d5 |
{ |
f2454ec6 |
crypto_msg(D_TLS_ERRORS, "TLS_ERROR: BIO read %s error", desc); |
81d882d5 |
buf->len = 0; |
f2454ec6 |
ret = -1;
ERR_clear_error(); |
81d882d5 |
} |
f2454ec6 |
}
else if (!i)
{
buf->len = 0;
}
else
{ /* successful read */
dmsg(D_HANDSHAKE_VERBOSE, "BIO read %s %d bytes", desc, i);
buf->len = i;
ret = 1;
VALGRIND_MAKE_READABLE((void *) BPTR(buf), BLEN(buf)); |
81d882d5 |
}
return ret; |
dd5e1102 |
}
|
d7efe640 |
void |
b97e2c3c |
key_state_ssl_init(struct key_state_ssl *ks_ssl, const struct tls_root_ctx *ssl_ctx, bool is_server, struct tls_session *session) |
d7efe640 |
{ |
81d882d5 |
ASSERT(NULL != ssl_ctx);
ASSERT(ks_ssl);
CLEAR(*ks_ssl); |
d7efe640 |
|
81d882d5 |
ks_ssl->ssl = SSL_new(ssl_ctx->ctx);
if (!ks_ssl->ssl)
{
crypto_msg(M_FATAL, "SSL_new failed");
} |
d7efe640 |
|
81d882d5 |
/* put session * in ssl object so we can access it
* from verify callback*/
SSL_set_ex_data(ks_ssl->ssl, mydata_index, session); |
d7efe640 |
|
006d6a57 |
ASSERT((ks_ssl->ssl_bio = BIO_new(BIO_f_ssl())));
ASSERT((ks_ssl->ct_in = BIO_new(BIO_s_mem())));
ASSERT((ks_ssl->ct_out = BIO_new(BIO_s_mem()))); |
d7efe640 |
#ifdef BIO_DEBUG |
81d882d5 |
bio_debug_oc("open ssl_bio", ks_ssl->ssl_bio);
bio_debug_oc("open ct_in", ks_ssl->ct_in);
bio_debug_oc("open ct_out", ks_ssl->ct_out); |
d7efe640 |
#endif
|
81d882d5 |
if (is_server)
{
SSL_set_accept_state(ks_ssl->ssl);
}
else
{
SSL_set_connect_state(ks_ssl->ssl);
} |
d7efe640 |
|
81d882d5 |
SSL_set_bio(ks_ssl->ssl, ks_ssl->ct_in, ks_ssl->ct_out);
BIO_set_ssl(ks_ssl->ssl_bio, ks_ssl->ssl, BIO_NOCLOSE); |
d7efe640 |
}
|
81d882d5 |
void
key_state_ssl_free(struct key_state_ssl *ks_ssl) |
214fc873 |
{ |
81d882d5 |
if (ks_ssl->ssl)
{ |
214fc873 |
#ifdef BIO_DEBUG |
81d882d5 |
bio_debug_oc("close ssl_bio", ks_ssl->ssl_bio);
bio_debug_oc("close ct_in", ks_ssl->ct_in);
bio_debug_oc("close ct_out", ks_ssl->ct_out); |
214fc873 |
#endif |
81d882d5 |
BIO_free_all(ks_ssl->ssl_bio);
SSL_free(ks_ssl->ssl);
} |
214fc873 |
}
|
dd5e1102 |
int |
81d882d5 |
key_state_write_plaintext(struct key_state_ssl *ks_ssl, struct buffer *buf) |
bf707bd2 |
{ |
81d882d5 |
int ret = 0;
perf_push(PERF_BIO_WRITE_PLAINTEXT); |
bf707bd2 |
|
81d882d5 |
ASSERT(NULL != ks_ssl); |
bf707bd2 |
|
81d882d5 |
ret = bio_write(ks_ssl->ssl_bio, BPTR(buf), BLEN(buf),
"tls_write_plaintext");
bio_write_post(ret, buf); |
bf707bd2 |
|
81d882d5 |
perf_pop();
return ret; |
bf707bd2 |
}
int |
81d882d5 |
key_state_write_plaintext_const(struct key_state_ssl *ks_ssl, const uint8_t *data, int len) |
bf707bd2 |
{ |
81d882d5 |
int ret = 0;
perf_push(PERF_BIO_WRITE_PLAINTEXT); |
bf707bd2 |
|
81d882d5 |
ASSERT(NULL != ks_ssl); |
bf707bd2 |
|
81d882d5 |
ret = bio_write(ks_ssl->ssl_bio, data, len, "tls_write_plaintext_const"); |
bf707bd2 |
|
81d882d5 |
perf_pop();
return ret; |
bf707bd2 |
}
int |
4e9e25a9 |
key_state_read_ciphertext(struct key_state_ssl *ks_ssl, struct buffer *buf) |
dd5e1102 |
{ |
81d882d5 |
int ret = 0;
perf_push(PERF_BIO_READ_CIPHERTEXT); |
dd5e1102 |
|
81d882d5 |
ASSERT(NULL != ks_ssl); |
dd5e1102 |
|
4e9e25a9 |
ret = bio_read(ks_ssl->ct_out, buf, "tls_read_ciphertext"); |
dd5e1102 |
|
81d882d5 |
perf_pop();
return ret; |
dd5e1102 |
}
int |
81d882d5 |
key_state_write_ciphertext(struct key_state_ssl *ks_ssl, struct buffer *buf) |
bf707bd2 |
{ |
81d882d5 |
int ret = 0;
perf_push(PERF_BIO_WRITE_CIPHERTEXT); |
bf707bd2 |
|
81d882d5 |
ASSERT(NULL != ks_ssl); |
bf707bd2 |
|
81d882d5 |
ret = bio_write(ks_ssl->ct_in, BPTR(buf), BLEN(buf), "tls_write_ciphertext");
bio_write_post(ret, buf); |
bf707bd2 |
|
81d882d5 |
perf_pop();
return ret; |
bf707bd2 |
}
int |
4e9e25a9 |
key_state_read_plaintext(struct key_state_ssl *ks_ssl, struct buffer *buf) |
dd5e1102 |
{ |
81d882d5 |
int ret = 0;
perf_push(PERF_BIO_READ_PLAINTEXT); |
dd5e1102 |
|
81d882d5 |
ASSERT(NULL != ks_ssl); |
dd5e1102 |
|
4e9e25a9 |
ret = bio_read(ks_ssl->ssl_bio, buf, "tls_read_plaintext"); |
dd5e1102 |
|
81d882d5 |
perf_pop();
return ret; |
dd5e1102 |
}
|
ca570706 |
static void |
4e80aac4 |
print_pkey_details(EVP_PKEY *pkey, char *buf, size_t buflen) |
ca570706 |
{
const char *curve = "";
const char *type = "(error getting type)";
if (pkey == NULL)
{
buf[0] = 0;
return;
}
int typeid = EVP_PKEY_id(pkey); |
6c111be9 |
#if OPENSSL_VERSION_NUMBER < 0x30000000L
bool is_ec = typeid == EVP_PKEY_EC;
#else
bool is_ec = EVP_PKEY_is_a(pkey, "EC");
#endif |
ca570706 |
#ifndef OPENSSL_NO_EC |
6889d9e2 |
char groupname[64]; |
6c111be9 |
if (is_ec) |
ca570706 |
{ |
4b3c1e76 |
size_t len; |
abe49856 |
if (EVP_PKEY_get_group_name(pkey, groupname, sizeof(groupname), &len)) |
4b3c1e76 |
{ |
abe49856 |
curve = groupname; |
4b3c1e76 |
}
else |
ca570706 |
{
curve = "(error getting curve name)";
}
}
#endif |
6c111be9 |
if (typeid != 0) |
ca570706 |
{ |
6c111be9 |
#if OPENSSL_VERSION_NUMBER < 0x30000000L |
ca570706 |
type = OBJ_nid2sn(typeid);
/* OpenSSL reports rsaEncryption, dsaEncryption and
* id-ecPublicKey, map these values to nicer ones */
if (typeid == EVP_PKEY_RSA)
{
type = "RSA";
}
else if (typeid == EVP_PKEY_DSA)
{
type = "DSA";
}
else if (typeid == EVP_PKEY_EC)
{
/* EC gets the curve appended after the type */
type = "EC, curve ";
}
else if (type == NULL)
{
type = "unknown type";
} |
6c111be9 |
#else /* OpenSSL >= 3 */
type = EVP_PKEY_get0_type_name(pkey);
if (type == NULL)
{
type = "(error getting public key type)";
}
#endif /* if OPENSSL_VERSION_NUMBER < 0x30000000L */ |
ca570706 |
}
|
130548fe |
snprintf(buf, buflen, "%d bits %s%s",
EVP_PKEY_bits(pkey), type, curve); |
4e80aac4 |
}
/**
* Print human readable information about the certificate into buf
* @param cert the certificate being used
* @param buf output buffer
* @param buflen output buffer length
*/
static void
print_cert_details(X509 *cert, char *buf, size_t buflen)
{
EVP_PKEY *pkey = X509_get_pubkey(cert); |
6889d9e2 |
char pkeybuf[64] = { 0 }; |
4e80aac4 |
print_pkey_details(pkey, pkeybuf, sizeof(pkeybuf));
|
ca570706 |
char sig[128] = { 0 };
int signature_nid = X509_get_signature_nid(cert);
if (signature_nid != 0)
{ |
130548fe |
snprintf(sig, sizeof(sig), ", signature: %s",
OBJ_nid2sn(signature_nid)); |
ca570706 |
}
|
130548fe |
snprintf(buf, buflen, ", peer certificate: %s%s",
pkeybuf, sig); |
4e80aac4 |
EVP_PKEY_free(pkey);
}
static void
print_server_tempkey(SSL *ssl, char *buf, size_t buflen)
{
EVP_PKEY *pkey = NULL;
SSL_get_peer_tmp_key(ssl, &pkey);
if (!pkey)
{
return;
}
char pkeybuf[128] = { 0 };
print_pkey_details(pkey, pkeybuf, sizeof(pkeybuf));
|
130548fe |
snprintf(buf, buflen, ", peer temporary key: %s",
pkeybuf); |
ca570706 |
EVP_PKEY_free(pkey);
}
|
ff402c7c |
#if (!defined(LIBRESSL_VERSION_NUMBER) && OPENSSL_VERSION_NUMBER >= 0x1010000fL) \
|| (defined(LIBRESSL_VERSION_NUMBER) && LIBRESSL_VERSION_NUMBER >= 0x3090000fL) |
b431721e |
/**
* Translate an OpenSSL NID into a more human readable name
* @param nid
* @return
*/
static const char *
get_sigtype(int nid)
{
/* Fix a few OpenSSL names to be better understandable */
switch (nid)
{
case EVP_PKEY_RSA:
/* will otherwise say rsaEncryption */
return "RSA";
case EVP_PKEY_DSA:
/* dsaEncryption otherwise */
return "DSA";
case EVP_PKEY_EC:
/* will say id-ecPublicKey */
return "ECDSA";
case -1:
return "(error getting name)";
default:
return OBJ_nid2sn(nid);
}
}
#endif /* ifndef LIBRESSL_VERSION_NUMBER */
/**
* Get the type of the signature that is used by the peer during the
* TLS handshake
*/
static void
print_peer_signature(SSL *ssl, char *buf, size_t buflen)
{
int peer_sig_nid = NID_undef, peer_sig_type_nid = NID_undef;
const char *peer_sig = "unknown";
const char *peer_sig_type = "unknown type";
/* Even though these methods use the deprecated NIDs instead of using
* string as new OpenSSL APIs do, there seem to be no API that replaces
* it yet */
#if !defined(LIBRESSL_VERSION_NUMBER) || LIBRESSL_VERSION_NUMBER > 0x3050400fL
if (SSL_get_peer_signature_nid(ssl, &peer_sig_nid)
&& peer_sig_nid != NID_undef)
{
peer_sig = OBJ_nid2sn(peer_sig_nid);
}
#endif
#if (!defined(LIBRESSL_VERSION_NUMBER) && OPENSSL_VERSION_NUMBER >= 0x1010000fL) \
|| (defined(LIBRESSL_VERSION_NUMBER) && LIBRESSL_VERSION_NUMBER >= 0x3090000fL)
/* LibreSSL 3.7.x and 3.8.x implement this function but do not export it
* and fail linking with an unresolved symbol */
if (SSL_get_peer_signature_type_nid(ssl, &peer_sig_type_nid)
&& peer_sig_type_nid != NID_undef)
{
peer_sig_type = get_sigtype(peer_sig_type_nid);
}
#endif
if (peer_sig_nid == NID_undef && peer_sig_type_nid == NID_undef)
{
return;
}
|
130548fe |
snprintf(buf, buflen, ", peer signing digest/type: %s %s",
peer_sig, peer_sig_type); |
b431721e |
}
|
963ad54e |
/* **************************************
*
* Information functions
*
* Print information for the end user.
*
***************************************/
void |
81d882d5 |
print_details(struct key_state_ssl *ks_ssl, const char *prefix) |
963ad54e |
{ |
81d882d5 |
const SSL_CIPHER *ciph;
char s1[256];
char s2[256]; |
4e80aac4 |
char s3[256]; |
b431721e |
char s4[256]; |
81d882d5 |
|
b431721e |
s1[0] = s2[0] = s3[0] = s4[0] = 0; |
81d882d5 |
ciph = SSL_get_current_cipher(ks_ssl->ssl); |
130548fe |
snprintf(s1, sizeof(s1), "%s %s, cipher %s %s",
prefix,
SSL_get_version(ks_ssl->ssl),
SSL_CIPHER_get_version(ciph),
SSL_CIPHER_get_name(ciph)); |
ca570706 |
X509 *cert = SSL_get_peer_certificate(ks_ssl->ssl); |
bb23eca8 |
|
ca570706 |
if (cert)
{
print_cert_details(cert, s2, sizeof(s2)); |
81d882d5 |
X509_free(cert);
} |
4e80aac4 |
print_server_tempkey(ks_ssl->ssl, s3, sizeof(s3)); |
b431721e |
print_peer_signature(ks_ssl->ssl, s4, sizeof(s4)); |
4e80aac4 |
|
b431721e |
msg(D_HANDSHAKE, "%s%s%s%s", s1, s2, s3, s4); |
963ad54e |
}
|
244da317 |
void |
7aeabadd |
show_available_tls_ciphers_list(const char *cipher_list,
const char *tls_cert_profile, |
2569902c |
bool tls13) |
397c0a35 |
{ |
81d882d5 |
struct tls_root_ctx tls_ctx;
tls_ctx.ctx = SSL_CTX_new(SSLv23_method());
if (!tls_ctx.ctx)
{
crypto_msg(M_FATAL, "Cannot create SSL_CTX object");
} |
397c0a35 |
|
a4750860 |
#if defined(TLS1_3_VERSION) |
7aeabadd |
if (tls13) |
81d882d5 |
{ |
6328aef9 |
SSL_CTX_set_min_proto_version(tls_ctx.ctx,
openssl_tls_version(TLS_VER_1_3)); |
68011752 |
tls_ctx_restrict_ciphers_tls13(&tls_ctx, cipher_list); |
7aeabadd |
}
else
#endif
{
SSL_CTX_set_max_proto_version(tls_ctx.ctx, TLS1_2_VERSION); |
68011752 |
tls_ctx_restrict_ciphers(&tls_ctx, cipher_list); |
81d882d5 |
} |
397c0a35 |
|
aba75874 |
tls_ctx_set_cert_profile(&tls_ctx, tls_cert_profile); |
cb03dca8 |
|
7aeabadd |
SSL *ssl = SSL_new(tls_ctx.ctx);
if (!ssl)
{
crypto_msg(M_FATAL, "Cannot create SSL object");
}
|
2c0ebe0f |
#if OPENSSL_VERSION_NUMBER < 0x1010000fL |
7aeabadd |
STACK_OF(SSL_CIPHER) *sk = SSL_get_ciphers(ssl);
#else
STACK_OF(SSL_CIPHER) *sk = SSL_get1_supported_ciphers(ssl);
#endif |
f57431cd |
for (int i = 0; i < sk_SSL_CIPHER_num(sk); i++) |
3b23b18d |
{ |
7aeabadd |
const SSL_CIPHER *c = sk_SSL_CIPHER_value(sk, i);
const char *cipher_name = SSL_CIPHER_get_name(c);
const tls_cipher_name_pair *pair =
tls_get_cipher_name_pair(cipher_name, strlen(cipher_name)); |
3b23b18d |
|
7aeabadd |
if (tls13)
{ |
f57431cd |
printf("%s\n", cipher_name); |
7aeabadd |
}
else if (NULL == pair) |
81d882d5 |
{
/* No translation found, print warning */ |
68011752 |
printf("%s (No IANA name known to OpenVPN, use OpenSSL name.)\n",
cipher_name); |
81d882d5 |
}
else
{
printf("%s\n", pair->iana_name);
} |
3b23b18d |
} |
7aeabadd |
#if (OPENSSL_VERSION_NUMBER >= 0x1010000fL)
sk_SSL_CIPHER_free(sk);
#endif |
81d882d5 |
SSL_free(ssl);
SSL_CTX_free(tls_ctx.ctx); |
397c0a35 |
} |
b64ffdcf |
|
609e8131 |
/*
* Show the Elliptic curves that are available for us to use
* in the OpenSSL library.
*/
void |
e2a0cad4 |
show_available_curves(void) |
609e8131 |
{ |
a840d509 |
printf("Consider using 'openssl ecparam -list_curves' as alternative to running\n"
"this command.\n"
"Note this output does only list curves/groups that OpenSSL considers as\n"
"builtin EC curves. It does not list additional curves nor X448 or X25519\n"); |
609e8131 |
#ifndef OPENSSL_NO_EC |
81d882d5 |
EC_builtin_curve *curves = NULL;
size_t crv_len = 0;
size_t n = 0;
crv_len = EC_get_builtin_curves(NULL, 0);
ALLOC_ARRAY(curves, EC_builtin_curve, crv_len);
if (EC_get_builtin_curves(curves, crv_len))
{ |
8353ae80 |
printf("\nAvailable Elliptic curves/groups:\n"); |
81d882d5 |
for (n = 0; n < crv_len; n++)
{
const char *sname;
sname = OBJ_nid2sn(curves[n].nid);
if (sname == NULL)
{
sname = "";
}
printf("%s\n", sname);
}
}
else
{
crypto_msg(M_FATAL, "Cannot get list of builtin curves");
}
free(curves);
#else /* ifndef OPENSSL_NO_EC */
msg(M_WARN, "Your OpenSSL library was built without elliptic curve support. "
"No curves available.");
#endif /* ifndef OPENSSL_NO_EC */ |
609e8131 |
}
|
b64ffdcf |
void |
81d882d5 |
get_highest_preference_tls_cipher(char *buf, int size) |
b64ffdcf |
{ |
81d882d5 |
SSL_CTX *ctx;
SSL *ssl;
const char *cipher_name;
ctx = SSL_CTX_new(SSLv23_method());
if (!ctx)
{
crypto_msg(M_FATAL, "Cannot create SSL_CTX object");
}
ssl = SSL_new(ctx);
if (!ssl)
{
crypto_msg(M_FATAL, "Cannot create SSL object");
}
cipher_name = SSL_get_cipher_list(ssl, 0);
strncpynt(buf, cipher_name, size);
SSL_free(ssl);
SSL_CTX_free(ctx); |
b64ffdcf |
} |
31ea2ee4 |
|
5b17803e |
const char * |
1ec984b1 |
get_ssl_library_version(void)
{ |
17a476fd |
return OpenSSL_version(OPENSSL_VERSION); |
1ec984b1 |
}
|
4b85c488 |
/** Some helper routines for provider load/unload */
#ifdef HAVE_XKEY_PROVIDER
static int
provider_load(OSSL_PROVIDER *prov, void *dest_libctx)
{
const char *name = OSSL_PROVIDER_get0_name(prov);
OSSL_PROVIDER_load(dest_libctx, name);
return 1;
}
static int
provider_unload(OSSL_PROVIDER *prov, void *unused)
{
(void) unused;
OSSL_PROVIDER_unload(prov);
return 1;
}
#endif /* HAVE_XKEY_PROVIDER */
/**
* Setup ovpn.xey provider for signing with external keys.
* It is loaded into a custom library context so as not to pollute
* the default context. Alternatively we could override any
* system-wide property query set on the default context. But we
* want to avoid that.
*/
void
load_xkey_provider(void)
{
#ifdef HAVE_XKEY_PROVIDER
/* Make a new library context for use in TLS context */
if (!tls_libctx)
{
tls_libctx = OSSL_LIB_CTX_new();
check_malloc_return(tls_libctx);
/* Load all providers in default LIBCTX into this libctx.
* OpenSSL has a child libctx functionality to automate this,
* but currently that is usable only from within providers.
* So we do something close to it manually here.
*/
OSSL_PROVIDER_do_all(NULL, provider_load, tls_libctx);
}
if (!OSSL_PROVIDER_available(tls_libctx, "ovpn.xkey"))
{
OSSL_PROVIDER_add_builtin(tls_libctx, "ovpn.xkey", xkey_provider_init);
if (!OSSL_PROVIDER_load(tls_libctx, "ovpn.xkey"))
{
msg(M_NONFATAL, "ERROR: failed loading external key provider: " |
abe49856 |
"Signing with external keys will not work."); |
4b85c488 |
}
}
/* We only implement minimal functionality in ovpn.xkey, so we do not want
* methods in xkey to be picked unless absolutely required (i.e, when the key
* is external). Ensure this by setting a default propquery for the custom
* libctx that unprefers, but does not forbid, ovpn.xkey. See also man page
* of "property" in OpenSSL 3.0.
*/
EVP_set_default_properties(tls_libctx, "?provider!=ovpn.xkey");
#endif /* HAVE_XKEY_PROVIDER */
}
/**
* Undo steps in load_xkey_provider
*/
static void
unload_xkey_provider(void)
{
#ifdef HAVE_XKEY_PROVIDER
if (tls_libctx)
{
OSSL_PROVIDER_do_all(tls_libctx, provider_unload, NULL);
OSSL_LIB_CTX_free(tls_libctx);
}
#endif /* HAVE_XKEY_PROVIDER */
tls_libctx = NULL;
}
|
c7ca9133 |
#endif /* defined(ENABLE_CRYPTO_OPENSSL) */ |