summaryrefslogtreecommitdiff
path: root/src/openvpn/ssl_openssl.c
diff options
context:
space:
mode:
authorBernhard Schmidt <berni@debian.org>2020-09-01 16:52:17 +0200
committerBernhard Schmidt <berni@debian.org>2020-09-01 16:52:17 +0200
commit9fc3b98112217f2d92a67977dbde0987cc7a1803 (patch)
tree29fcc8654ee65d9dd89ade797bea2f3d9dfd9cfd /src/openvpn/ssl_openssl.c
parenta8758c0e03eed188dcb9da0e4fd781a67c25bf1e (diff)
parent69b02b1f7fd609d84ace13ab04697158de2418a9 (diff)
Merge branch 'debian/experimental-2.5'
Diffstat (limited to 'src/openvpn/ssl_openssl.c')
-rw-r--r--src/openvpn/ssl_openssl.c707
1 files changed, 474 insertions, 233 deletions
diff --git a/src/openvpn/ssl_openssl.c b/src/openvpn/ssl_openssl.c
index 19509b7..5ba7440 100644
--- a/src/openvpn/ssl_openssl.c
+++ b/src/openvpn/ssl_openssl.c
@@ -34,7 +34,7 @@
#include "syshead.h"
-#if defined(ENABLE_CRYPTO) && defined(ENABLE_CRYPTO_OPENSSL)
+#if defined(ENABLE_CRYPTO_OPENSSL)
#include "errlevel.h"
#include "buffer.h"
@@ -52,10 +52,15 @@
#include "ssl_verify_openssl.h"
+#include <openssl/bn.h>
+#include <openssl/crypto.h>
+#include <openssl/dh.h>
+#include <openssl/dsa.h>
#include <openssl/err.h>
#include <openssl/pkcs12.h>
+#include <openssl/rsa.h>
#include <openssl/x509.h>
-#include <openssl/crypto.h>
+#include <openssl/ssl.h>
#ifndef OPENSSL_NO_EC
#include <openssl/ec.h>
#endif
@@ -110,6 +115,11 @@ tls_ctx_server_new(struct tls_root_ctx *ctx)
{
crypto_msg(M_FATAL, "SSL_CTX_new SSLv23_server_method");
}
+ if (ERR_peek_error() != 0)
+ {
+ crypto_msg(M_WARN, "Warning: TLS server context initialisation "
+ "has warnings.");
+ }
}
void
@@ -123,6 +133,11 @@ tls_ctx_client_new(struct tls_root_ctx *ctx)
{
crypto_msg(M_FATAL, "SSL_CTX_new SSLv23_client_method");
}
+ if (ERR_peek_error() != 0)
+ {
+ crypto_msg(M_WARN, "Warning: TLS client context initialisation "
+ "has warnings.");
+ }
}
void
@@ -149,13 +164,14 @@ key_state_export_keying_material(struct key_state_ssl *ssl,
{
if (session->opt->ekm_size > 0)
{
-#if (OPENSSL_VERSION_NUMBER >= 0x10001000)
unsigned int size = session->opt->ekm_size;
struct gc_arena gc = gc_new();
unsigned char *ekm = (unsigned char *) gc_malloc(size, true, &gc);
if (SSL_export_keying_material(ssl->ssl, ekm, size,
- session->opt->ekm_label, session->opt->ekm_label_size, NULL, 0, 0))
+ session->opt->ekm_label,
+ session->opt->ekm_label_size,
+ NULL, 0, 0))
{
unsigned int len = (size * 2) + 2;
@@ -171,7 +187,6 @@ key_state_export_keying_material(struct key_state_ssl *ssl,
setenv_del(session->opt->es, "exported_keying_material");
}
gc_free(&gc);
-#endif /* if (OPENSSL_VERSION_NUMBER >= 0x10001000) */
}
}
@@ -209,13 +224,34 @@ info_callback(INFO_CALLBACK_SSL_CONST SSL *s, int where, int ret)
int
tls_version_max(void)
{
-#if defined(TLS1_3_VERSION) && !defined(OPENSSL_NO_TLS1_3)
+#if defined(TLS1_3_VERSION)
+ /* If this is defined we can safely assume TLS 1.3 support */
return TLS_VER_1_3;
+#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
+ * 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)
+ */
+ if (OpenSSL_version_num() >= 0x1010100fL)
+ {
+ return TLS_VER_1_3;
+ }
+ else
+ {
+ return TLS_VER_1_2;
+ }
#elif defined(TLS1_2_VERSION) || defined(SSL_OP_NO_TLSv1_2)
return TLS_VER_1_2;
#elif defined(TLS1_1_VERSION) || defined(SSL_OP_NO_TLSv1_1)
return TLS_VER_1_1;
-#else
+#else /* if defined(TLS1_3_VERSION) */
return TLS_VER_1_0;
#endif
}
@@ -236,12 +272,25 @@ openssl_tls_version(int ver)
{
return TLS1_2_VERSION;
}
-#if defined(TLS1_3_VERSION) && !defined(OPENSSL_NO_TLS1_3)
else if (ver == TLS_VER_1_3)
{
+ /*
+ * 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
return TLS1_3_VERSION;
- }
#endif
+ }
return 0;
}
@@ -280,18 +329,12 @@ tls_ctx_set_options(struct tls_root_ctx *ctx, unsigned int ssl_flags)
{
ASSERT(NULL != ctx);
- /* default certificate verification flags */
- int flags = SSL_VERIFY_PEER | SSL_VERIFY_FAIL_IF_NO_PEER_CERT;
-
/* process SSL options */
long sslopt = SSL_OP_SINGLE_DH_USE | SSL_OP_NO_TICKET;
#ifdef SSL_OP_CIPHER_SERVER_PREFERENCE
sslopt |= SSL_OP_CIPHER_SERVER_PREFERENCE;
#endif
-#ifdef SSL_OP_NO_COMPRESSION
- /* Disable compression - flag not available in OpenSSL 0.9.8 */
sslopt |= SSL_OP_NO_COMPRESSION;
-#endif
SSL_CTX_set_options(ctx->ctx, sslopt);
@@ -307,17 +350,16 @@ tls_ctx_set_options(struct tls_root_ctx *ctx, unsigned int ssl_flags)
SSL_CTX_set_default_passwd_cb(ctx->ctx, pem_password_callback);
/* Require peer certificate verification */
-#if P2MP_SERVER
+ int verify_flags = SSL_VERIFY_PEER | SSL_VERIFY_FAIL_IF_NO_PEER_CERT;
if (ssl_flags & SSLF_CLIENT_CERT_NOT_REQUIRED)
{
- flags = 0;
+ verify_flags = 0;
}
else if (ssl_flags & SSLF_CLIENT_CERT_OPTIONAL)
{
- flags = SSL_VERIFY_PEER;
+ verify_flags = SSL_VERIFY_PEER;
}
-#endif
- SSL_CTX_set_verify(ctx->ctx, flags, verify_callback);
+ SSL_CTX_set_verify(ctx->ctx, verify_flags, verify_callback);
SSL_CTX_set_info_callback(ctx->ctx, info_callback);
@@ -325,28 +367,8 @@ tls_ctx_set_options(struct tls_root_ctx *ctx, unsigned int ssl_flags)
}
void
-tls_ctx_restrict_ciphers(struct tls_root_ctx *ctx, const char *ciphers)
+convert_tls_list_to_openssl(char *openssl_ciphers, size_t len,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;
- }
-
/* Parse supplied cipher list and pass on to OpenSSL */
size_t begin_of_cipher, end_of_cipher;
@@ -355,12 +377,9 @@ tls_ctx_restrict_ciphers(struct tls_root_ctx *ctx, const char *ciphers)
const tls_cipher_name_pair *cipher_pair;
- char openssl_ciphers[4096];
size_t openssl_ciphers_len = 0;
openssl_ciphers[0] = '\0';
- ASSERT(NULL != ctx);
-
/* Translate IANA cipher suite names to OpenSSL names */
begin_of_cipher = end_of_cipher = 0;
for (; begin_of_cipher < strlen(ciphers); begin_of_cipher = end_of_cipher)
@@ -397,11 +416,11 @@ tls_ctx_restrict_ciphers(struct tls_root_ctx *ctx, const char *ciphers)
/* Make sure new cipher name fits in cipher string */
if ((SIZE_MAX - openssl_ciphers_len) < current_cipher_len
- || ((sizeof(openssl_ciphers)-1) < openssl_ciphers_len + current_cipher_len))
+ || (len - 1) < (openssl_ciphers_len + current_cipher_len))
{
msg(M_FATAL,
"Failed to set restricted TLS cipher list, too long (>%d).",
- (int)sizeof(openssl_ciphers)-1);
+ (int)(len - 1));
}
/* Concatenate cipher name to OpenSSL cipher string */
@@ -417,6 +436,35 @@ tls_ctx_restrict_ciphers(struct tls_root_ctx *ctx, const char *ciphers)
{
openssl_ciphers[openssl_ciphers_len-1] = '\0';
}
+}
+
+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);
/* Set OpenSSL cipher list */
if (!SSL_CTX_set_cipher_list(ctx->ctx, openssl_ciphers))
@@ -462,10 +510,10 @@ tls_ctx_restrict_ciphers_tls13(struct tls_root_ctx *ctx, const char *ciphers)
return;
}
-#if (OPENSSL_VERSION_NUMBER < 0x1010100fL) || !defined(TLS1_3_VERSION) || defined(OPENSSL_NO_TLS1_3)
- crypto_msg(M_WARN, "Not compiled with OpenSSL 1.1.1 or higher, or without TLS 1.3 support. "
- "Ignoring TLS 1.3 only tls-ciphersuites '%s' setting.",
- ciphers);
+#if !defined(TLS1_3_VERSION)
+ crypto_msg(M_WARN, "Not compiled with OpenSSL 1.1.1 or higher. "
+ "Ignoring TLS 1.3 only tls-ciphersuites '%s' setting.",
+ ciphers);
#else
ASSERT(NULL != ctx);
@@ -506,13 +554,64 @@ tls_ctx_set_cert_profile(struct tls_root_ctx *ctx, const char *profile)
{
msg(M_FATAL, "ERROR: Invalid cert profile: %s", profile);
}
-#else
+#else /* ifdef HAVE_SSL_CTX_SET_SECURITY_LEVEL */
if (profile)
{
- msg(M_WARN, "WARNING: OpenSSL 1.0.1 does not support --tls-cert-profile"
+ msg(M_WARN, "WARNING: OpenSSL 1.0.2 does not support --tls-cert-profile"
", ignoring user-set profile: '%s'", profile);
}
-#endif
+#endif /* ifdef HAVE_SSL_CTX_SET_SECURITY_LEVEL */
+}
+
+void
+tls_ctx_set_tls_groups(struct tls_root_ctx *ctx, const char *groups)
+{
+ ASSERT(ctx);
+ struct gc_arena gc = gc_new();
+ /* This method could be as easy as
+ * SSL_CTX_set1_groups_list(ctx->ctx, groups)
+ * but OpenSSL does not like the name secp256r1 for prime256v1
+ * This is one of the important curves.
+ * To support the same name for OpenSSL and mbedTLS, we do
+ * this dance.
+ */
+
+ 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);
}
void
@@ -523,18 +622,11 @@ tls_ctx_check_cert_time(const struct tls_root_ctx *ctx)
ASSERT(ctx);
-#if OPENSSL_VERSION_NUMBER >= 0x10002000L && !defined(LIBRESSL_VERSION_NUMBER)
- /* OpenSSL 1.0.2 and up */
cert = SSL_CTX_get0_certificate(ctx->ctx);
-#else
- /* OpenSSL 1.0.1 and earlier need an SSL object to get at the certificate */
- SSL *ssl = SSL_new(ctx->ctx);
- cert = SSL_get_certificate(ssl);
-#endif
if (cert == NULL)
{
- goto cleanup; /* Nothing to check if there is no certificate */
+ return; /* Nothing to check if there is no certificate */
}
ret = X509_cmp_time(X509_get0_notBefore(cert), NULL);
@@ -556,27 +648,20 @@ tls_ctx_check_cert_time(const struct tls_root_ctx *ctx)
{
msg(M_WARN, "WARNING: Your certificate has expired!");
}
-
-cleanup:
-#if OPENSSL_VERSION_NUMBER < 0x10002000L || defined(LIBRESSL_VERSION_NUMBER)
- SSL_free(ssl);
-#endif
- return;
}
void
tls_ctx_load_dh_params(struct tls_root_ctx *ctx, const char *dh_file,
- const char *dh_file_inline
- )
+ bool dh_file_inline)
{
DH *dh;
BIO *bio;
ASSERT(NULL != ctx);
- if (!strcmp(dh_file, INLINE_FILE_TAG) && dh_file_inline)
+ if (dh_file_inline)
{
- if (!(bio = BIO_new_mem_buf((char *)dh_file_inline, -1)))
+ if (!(bio = BIO_new_mem_buf((char *)dh_file, -1)))
{
crypto_msg(M_FATAL, "Cannot open memory BIO for inline DH parameters");
}
@@ -595,7 +680,8 @@ tls_ctx_load_dh_params(struct tls_root_ctx *ctx, const char *dh_file,
if (!dh)
{
- crypto_msg(M_FATAL, "Cannot load DH parameters from %s", dh_file);
+ crypto_msg(M_FATAL, "Cannot load DH parameters from %s",
+ print_key_filename(dh_file, dh_file_inline));
}
if (!SSL_CTX_set_tmp_dh(ctx->ctx, dh))
{
@@ -628,7 +714,6 @@ tls_ctx_load_ecdh_params(struct tls_root_ctx *ctx, const char *curve_name
}
else
{
-#if OPENSSL_VERSION_NUMBER >= 0x10002000L
#if (OPENSSL_VERSION_NUMBER < 0x10100000L && !defined(LIBRESSL_VERSION_NUMBER))
/* OpenSSL 1.0.2 and newer can automatically handle ECDH parameter
@@ -639,29 +724,6 @@ tls_ctx_load_ecdh_params(struct tls_root_ctx *ctx, const char *curve_name
* so do nothing */
#endif
return;
-#else
- /* For older OpenSSL we have to extract the curve from key on our own */
- EC_KEY *eckey = NULL;
- const EC_GROUP *ecgrp = NULL;
- EVP_PKEY *pkey = NULL;
-
- /* Little hack to get private key ref from SSL_CTX, yay OpenSSL... */
- SSL *ssl = SSL_new(ctx->ctx);
- if (!ssl)
- {
- crypto_msg(M_FATAL, "SSL_new failed");
- }
- pkey = SSL_get_privatekey(ssl);
- SSL_free(ssl);
-
- msg(D_TLS_DEBUG, "Extracting ECDH curve from private key");
-
- if (pkey != NULL && (eckey = EVP_PKEY_get1_EC_KEY(pkey)) != NULL
- && (ecgrp = EC_KEY_get0_group(eckey)) != NULL)
- {
- nid = EC_GROUP_get_curve_name(ecgrp);
- }
-#endif
}
/* Translate NID back to name , just for kicks */
@@ -699,9 +761,7 @@ tls_ctx_load_ecdh_params(struct tls_root_ctx *ctx, const char *curve_name
int
tls_ctx_load_pkcs12(struct tls_root_ctx *ctx, const char *pkcs12_file,
- const char *pkcs12_file_inline,
- bool load_ca_file
- )
+ bool pkcs12_file_inline, bool load_ca_file)
{
FILE *fp;
EVP_PKEY *pkey;
@@ -713,11 +773,11 @@ tls_ctx_load_pkcs12(struct tls_root_ctx *ctx, const char *pkcs12_file,
ASSERT(NULL != ctx);
- if (!strcmp(pkcs12_file, INLINE_FILE_TAG) && pkcs12_file_inline)
+ if (pkcs12_file_inline)
{
BIO *b64 = BIO_new(BIO_f_base64());
- BIO *bio = BIO_new_mem_buf((void *) pkcs12_file_inline,
- (int) strlen(pkcs12_file_inline));
+ BIO *bio = BIO_new_mem_buf((void *) pkcs12_file,
+ (int) strlen(pkcs12_file));
ASSERT(b64 && bio);
BIO_push(b64, bio);
p12 = d2i_PKCS12_bio(b64, NULL);
@@ -873,28 +933,19 @@ tls_ctx_add_extra_certs(struct tls_root_ctx *ctx, BIO *bio, bool optional)
}
}
-/* Like tls_ctx_load_cert, but returns a copy of the certificate in **X509 */
-static void
-tls_ctx_load_cert_file_and_copy(struct tls_root_ctx *ctx,
- const char *cert_file, const char *cert_file_inline, X509 **x509
- )
+void
+tls_ctx_load_cert_file(struct tls_root_ctx *ctx, const char *cert_file,
+ bool cert_file_inline)
{
BIO *in = NULL;
X509 *x = NULL;
int ret = 0;
- bool inline_file = false;
ASSERT(NULL != ctx);
- if (NULL != x509)
- {
- ASSERT(NULL == *x509);
- }
-
- inline_file = (strcmp(cert_file, INLINE_FILE_TAG) == 0);
- if (inline_file && cert_file_inline)
+ if (cert_file_inline)
{
- in = BIO_new_mem_buf((char *)cert_file_inline, -1);
+ in = BIO_new_mem_buf((char *) cert_file, -1);
}
else
{
@@ -925,7 +976,7 @@ tls_ctx_load_cert_file_and_copy(struct tls_root_ctx *ctx,
end:
if (!ret)
{
- if (inline_file)
+ if (cert_file_inline)
{
crypto_msg(M_FATAL, "Cannot load inline certificate file");
}
@@ -943,27 +994,15 @@ end:
{
BIO_free(in);
}
- if (x509)
- {
- *x509 = x;
- }
- else if (x)
+ if (x)
{
X509_free(x);
}
}
-void
-tls_ctx_load_cert_file(struct tls_root_ctx *ctx, const char *cert_file,
- const char *cert_file_inline)
-{
- tls_ctx_load_cert_file_and_copy(ctx, cert_file, cert_file_inline, NULL);
-}
-
int
tls_ctx_load_priv_file(struct tls_root_ctx *ctx, const char *priv_key_file,
- const char *priv_key_file_inline
- )
+ bool priv_key_file_inline)
{
SSL_CTX *ssl_ctx = NULL;
BIO *in = NULL;
@@ -974,9 +1013,9 @@ tls_ctx_load_priv_file(struct tls_root_ctx *ctx, const char *priv_key_file,
ssl_ctx = ctx->ctx;
- if (!strcmp(priv_key_file, INLINE_FILE_TAG) && priv_key_file_inline)
+ if (priv_key_file_inline)
{
- in = BIO_new_mem_buf((char *)priv_key_file_inline, -1);
+ in = BIO_new_mem_buf((char *) priv_key_file, -1);
}
else
{
@@ -991,6 +1030,11 @@ tls_ctx_load_priv_file(struct tls_root_ctx *ctx, const char *priv_key_file,
pkey = PEM_read_bio_PrivateKey(in, NULL,
SSL_CTX_get_default_passwd_cb(ctx->ctx),
SSL_CTX_get_default_passwd_cb_userdata(ctx->ctx));
+ if (!pkey)
+ {
+ pkey = engine_load_key(priv_key_file, ctx->ctx);
+ }
+
if (!pkey || !SSL_CTX_use_PrivateKey(ssl_ctx, pkey))
{
#ifdef ENABLE_MANAGEMENT
@@ -999,7 +1043,8 @@ tls_ctx_load_priv_file(struct tls_root_ctx *ctx, const char *priv_key_file,
management_auth_failure(management, UP_TYPE_PRIVATE_KEY, NULL);
}
#endif
- crypto_msg(M_WARN, "Cannot load private key file %s", priv_key_file);
+ crypto_msg(M_WARN, "Cannot load private key file %s",
+ print_key_filename(priv_key_file, priv_key_file_inline));
goto end;
}
@@ -1024,7 +1069,7 @@ end:
void
backend_tls_ctx_reload_crl(struct tls_root_ctx *ssl_ctx, const char *crl_file,
- const char *crl_inline)
+ bool crl_inline)
{
BIO *in = NULL;
@@ -1051,9 +1096,9 @@ backend_tls_ctx_reload_crl(struct tls_root_ctx *ssl_ctx, const char *crl_file,
X509_STORE_set_flags(store, X509_V_FLAG_CRL_CHECK | X509_V_FLAG_CRL_CHECK_ALL);
- if (!strcmp(crl_file, INLINE_FILE_TAG) && crl_inline)
+ if (crl_inline)
{
- in = BIO_new_mem_buf((char *)crl_inline, -1);
+ in = BIO_new_mem_buf((char *) crl_file, -1);
}
else
{
@@ -1062,7 +1107,8 @@ backend_tls_ctx_reload_crl(struct tls_root_ctx *ssl_ctx, const char *crl_file,
if (in == NULL)
{
- msg(M_WARN, "CRL: cannot read: %s", crl_file);
+ msg(M_WARN, "CRL: cannot read: %s",
+ print_key_filename(crl_file, crl_inline));
goto end;
}
@@ -1084,14 +1130,16 @@ backend_tls_ctx_reload_crl(struct tls_root_ctx *ssl_ctx, const char *crl_file,
break;
}
- crypto_msg(M_WARN, "CRL: cannot read CRL from file %s", crl_file);
+ crypto_msg(M_WARN, "CRL: cannot read CRL from file %s",
+ print_key_filename(crl_file, crl_inline));
break;
}
if (!X509_STORE_add_crl(store, crl))
{
X509_CRL_free(crl);
- crypto_msg(M_WARN, "CRL: cannot add %s to store", crl_file);
+ crypto_msg(M_WARN, "CRL: cannot add %s to store",
+ print_key_filename(crl_file, crl_inline));
break;
}
X509_CRL_free(crl);
@@ -1103,7 +1151,7 @@ end:
}
-#ifdef MANAGMENT_EXTERNAL_KEY
+#ifdef ENABLE_MANAGEMENT
/* encrypt */
static int
@@ -1133,7 +1181,7 @@ rsa_priv_dec(int flen, const unsigned char *from, unsigned char *to, RSA *rsa, i
static int
openvpn_extkey_rsa_finish(RSA *rsa)
{
- /* meth was allocated in tls_ctx_use_external_private_key() ; since
+ /* meth was allocated in tls_ctx_use_management_external_key() ; since
* 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);
@@ -1141,74 +1189,93 @@ openvpn_extkey_rsa_finish(RSA *rsa)
return 1;
}
-/* sign arbitrary data */
+/*
+ * Convert OpenSSL's constant to the strings used in the management
+ * interface query
+ */
+const char *
+get_rsa_padding_name(const int padding)
+{
+ 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.
+ *
+ * @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.
+ */
static int
-rsa_priv_enc(int flen, const unsigned char *from, unsigned char *to, RSA *rsa, int padding)
+get_sig_from_man(const unsigned char *dgst, unsigned int dgstlen,
+ unsigned char *sig, unsigned int siglen,
+ const char *algorithm)
{
- /* optional app data in rsa->meth->app_data; */
char *in_b64 = NULL;
char *out_b64 = NULL;
- int ret = -1;
- int len;
+ int len = -1;
- if (padding != RSA_PKCS1_PADDING)
- {
- RSAerr(RSA_F_RSA_OSSL_PRIVATE_ENCRYPT, RSA_R_UNKNOWN_PADDING_TYPE);
- goto done;
- }
+ int bencret = openvpn_base64_encode(dgst, dgstlen, &in_b64);
- /* convert 'from' to base64 */
- if (openvpn_base64_encode(from, flen, &in_b64) <= 0)
+ if (management && bencret > 0)
{
- goto done;
- }
+ out_b64 = management_query_pk_sig(management, in_b64, algorithm);
- /* call MI for signature */
- if (management)
- {
- out_b64 = management_query_rsa_sig(management, in_b64);
}
- if (!out_b64)
+ if (out_b64)
{
- goto done;
+ len = openvpn_base64_decode(out_b64, sig, siglen);
}
- /* decode base64 signature to binary */
- len = RSA_size(rsa);
- ret = openvpn_base64_decode(out_b64, to, len);
+ free(in_b64);
+ free(out_b64);
+ return len;
+}
- /* verify length */
- if (ret != len)
- {
- ret = -1;
- }
+/* sign arbitrary data */
+static int
+rsa_priv_enc(int flen, const unsigned char *from, unsigned char *to, RSA *rsa,
+ int padding)
+{
+ unsigned int len = RSA_size(rsa);
+ int ret = -1;
-done:
- if (in_b64)
+ if (padding != RSA_PKCS1_PADDING && padding != RSA_NO_PADDING)
{
- free(in_b64);
- }
- if (out_b64)
- {
- free(out_b64);
+ RSAerr(RSA_F_RSA_OSSL_PRIVATE_ENCRYPT, RSA_R_UNKNOWN_PADDING_TYPE);
+ return -1;
}
- return ret;
+
+ ret = get_sig_from_man(from, flen, to, len, get_rsa_padding_name(padding));
+
+ return (ret == len) ? ret : -1;
}
-int
-tls_ctx_use_external_private_key(struct tls_root_ctx *ctx,
- const char *cert_file, const char *cert_file_inline)
+static int
+tls_ctx_use_external_rsa_key(struct tls_root_ctx *ctx, EVP_PKEY *pkey)
{
RSA *rsa = NULL;
RSA *pub_rsa;
RSA_METHOD *rsa_meth;
- X509 *cert = NULL;
ASSERT(NULL != ctx);
- tls_ctx_load_cert_file_and_copy(ctx, cert_file, cert_file_inline, &cert);
-
- ASSERT(NULL != cert);
+ pub_rsa = EVP_PKEY_get0_RSA(pkey);
+ ASSERT(NULL != pub_rsa);
/* allocate custom RSA method object */
rsa_meth = RSA_meth_new("OpenVPN external private key RSA Method",
@@ -1230,18 +1297,6 @@ tls_ctx_use_external_private_key(struct tls_root_ctx *ctx,
goto err;
}
- /* get the public key */
- EVP_PKEY *pkey = X509_get0_pubkey(cert);
- ASSERT(pkey); /* NULL before SSL_CTX_use_certificate() is called */
- pub_rsa = EVP_PKEY_get0_RSA(pkey);
-
- /* Certificate might not be RSA but DSA or EC */
- if (!pub_rsa)
- {
- crypto_msg(M_WARN, "management-external-key requires a RSA certificate");
- goto err;
- }
-
/* initialize RSA object */
const BIGNUM *n = NULL;
const BIGNUM *e = NULL;
@@ -1250,8 +1305,10 @@ tls_ctx_use_external_private_key(struct tls_root_ctx *ctx,
RSA_set_flags(rsa, RSA_flags(rsa) | RSA_FLAG_EXT_PKEY);
if (!RSA_set_method(rsa, rsa_meth))
{
+ RSA_meth_free(rsa_meth);
goto err;
}
+ /* from this point rsa_meth will get freed with rsa */
/* bind our custom RSA object to ssl_ctx */
if (!SSL_CTX_use_RSAPrivateKey(ctx->ctx, rsa))
@@ -1259,15 +1316,10 @@ tls_ctx_use_external_private_key(struct tls_root_ctx *ctx,
goto err;
}
- X509_free(cert);
RSA_free(rsa); /* doesn't necessarily free, just decrements refcount */
- return 0;
+ return 1;
err:
- if (cert)
- {
- X509_free(cert);
- }
if (rsa)
{
RSA_free(rsa);
@@ -1279,11 +1331,195 @@ err:
RSA_meth_free(rsa_meth);
}
}
- crypto_msg(M_FATAL, "Cannot enable SSL external private key capability");
+ return 0;
+}
+
+#if ((OPENSSL_VERSION_NUMBER > 0x10100000L && !defined(LIBRESSL_VERSION_NUMBER)) \
+ || LIBRESSL_VERSION_NUMBER > 0x2090000fL) \
+ && !defined(OPENSSL_NO_EC)
+
+/* 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);
+ /*
+ * 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");
+
+ 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;
}
-#endif /* ifdef MANAGMENT_EXTERNAL_KEY */
+/* 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 */
+ if (privkey)
+ {
+ EVP_PKEY_free(privkey);
+ }
+ if (ec)
+ {
+ EC_KEY_free(ec);
+ }
+ return 0;
+}
+#endif /* OPENSSL_VERSION_NUMBER > 1.1.0 dev && !defined(OPENSSL_NO_EC) */
+
+int
+tls_ctx_use_management_external_key(struct tls_root_ctx *ctx)
+{
+ int ret = 1;
+
+ ASSERT(NULL != ctx);
+
+ X509 *cert = SSL_CTX_get0_certificate(ctx->ctx);
+
+ ASSERT(NULL != cert);
+
+ /* get the public key */
+ EVP_PKEY *pkey = X509_get0_pubkey(cert);
+ ASSERT(pkey); /* NULL before SSL_CTX_use_certificate() is called */
+
+ if (EVP_PKEY_id(pkey) == EVP_PKEY_RSA)
+ {
+ if (!tls_ctx_use_external_rsa_key(ctx, pkey))
+ {
+ goto cleanup;
+ }
+ }
+#if ((OPENSSL_VERSION_NUMBER > 0x10100000L && !defined(LIBRESSL_VERSION_NUMBER)) \
+ || LIBRESSL_VERSION_NUMBER > 0x2090000fL) \
+ && !defined(OPENSSL_NO_EC)
+ else if (EVP_PKEY_id(pkey) == EVP_PKEY_EC)
+ {
+ if (!tls_ctx_use_external_ec_key(ctx, pkey))
+ {
+ goto cleanup;
+ }
+ }
+ else
+ {
+ crypto_msg(M_WARN, "management-external-key requires an RSA or EC certificate");
+ goto cleanup;
+ }
+#else /* OPENSSL_VERSION_NUMBER > 1.1.0 dev && !defined(OPENSSL_NO_EC) */
+ else
+ {
+ crypto_msg(M_WARN, "management-external-key requires an RSA certificate");
+ goto cleanup;
+ }
+#endif /* OPENSSL_VERSION_NUMBER > 1.1.0 dev && !defined(OPENSSL_NO_EC) */
+
+ ret = 0;
+cleanup:
+ if (ret)
+ {
+ crypto_msg(M_FATAL, "Cannot enable SSL external private key capability");
+ }
+ return ret;
+}
+
+#endif /* ifdef ENABLE_MANAGEMENT */
static int
sk_x509_name_cmp(const X509_NAME *const *a, const X509_NAME *const *b)
@@ -1293,9 +1529,7 @@ sk_x509_name_cmp(const X509_NAME *const *a, const X509_NAME *const *b)
void
tls_ctx_load_ca(struct tls_root_ctx *ctx, const char *ca_file,
- const char *ca_file_inline,
- const char *ca_path, bool tls_server
- )
+ bool ca_file_inline, const char *ca_path, bool tls_server)
{
STACK_OF(X509_INFO) *info_stack = NULL;
STACK_OF(X509_NAME) *cert_names = NULL;
@@ -1316,9 +1550,9 @@ tls_ctx_load_ca(struct tls_root_ctx *ctx, const char *ca_file,
/* Try to add certificates and CRLs from ca_file */
if (ca_file)
{
- if (!strcmp(ca_file, INLINE_FILE_TAG) && ca_file_inline)
+ if (ca_file_inline)
{
- in = BIO_new_mem_buf((char *)ca_file_inline, -1);
+ in = BIO_new_mem_buf((char *)ca_file, -1);
}
else
{
@@ -1390,11 +1624,11 @@ tls_ctx_load_ca(struct tls_root_ctx *ctx, const char *ca_file,
{
crypto_msg(M_WARN,
"Cannot load CA certificate file %s (entry %d did not validate)",
- np(ca_file), added);
+ print_key_filename(ca_file, ca_file_inline),
+ added);
}
prev = cnum;
}
-
}
sk_X509_INFO_pop_free(info_stack, X509_INFO_free);
}
@@ -1408,7 +1642,7 @@ tls_ctx_load_ca(struct tls_root_ctx *ctx, const char *ca_file,
{
crypto_msg(M_FATAL,
"Cannot load CA certificate file %s (no entries were read)",
- np(ca_file));
+ print_key_filename(ca_file, ca_file_inline));
}
if (tls_server)
@@ -1418,7 +1652,8 @@ tls_ctx_load_ca(struct tls_root_ctx *ctx, const char *ca_file,
{
crypto_msg(M_FATAL, "Cannot load CA certificate file %s (only %d "
"of %d entries were valid X509 names)",
- np(ca_file), cnum, added);
+ print_key_filename(ca_file, ca_file_inline), cnum,
+ added);
}
}
@@ -1446,13 +1681,12 @@ tls_ctx_load_ca(struct tls_root_ctx *ctx, const char *ca_file,
void
tls_ctx_load_extra_certs(struct tls_root_ctx *ctx, const char *extra_certs_file,
- const char *extra_certs_file_inline
- )
+ bool extra_certs_file_inline)
{
BIO *in;
- if (!strcmp(extra_certs_file, INLINE_FILE_TAG) && extra_certs_file_inline)
+ if (extra_certs_file_inline)
{
- in = BIO_new_mem_buf((char *)extra_certs_file_inline, -1);
+ in = BIO_new_mem_buf((char *)extra_certs_file, -1);
}
else
{
@@ -1461,7 +1695,10 @@ tls_ctx_load_extra_certs(struct tls_root_ctx *ctx, const char *extra_certs_file,
if (in == NULL)
{
- crypto_msg(M_FATAL, "Cannot load extra-certs file: %s", extra_certs_file);
+ crypto_msg(M_FATAL, "Cannot load extra-certs file: %s",
+ print_key_filename(extra_certs_file,
+ extra_certs_file_inline));
+
}
else
{
@@ -1529,8 +1766,8 @@ bio_debug_data(const char *mode, BIO *bio, const uint8_t *buf, int len, const ch
if (len > 0)
{
open_biofp();
- fprintf(biofp, "BIO_%s %s time=" time_format " bio=" ptr_format " len=%d data=%s\n",
- mode, desc, time(NULL), (ptr_type)bio, len, format_hex(buf, len, 0, &gc));
+ fprintf(biofp, "BIO_%s %s time=%" PRIi64 " bio=" ptr_format " len=%d data=%s\n",
+ mode, desc, (int64_t)time(NULL), (ptr_type)bio, len, format_hex(buf, len, 0, &gc));
fflush(biofp);
}
gc_free(&gc);
@@ -1540,8 +1777,8 @@ static void
bio_debug_oc(const char *mode, BIO *bio)
{
open_biofp();
- fprintf(biofp, "BIO %s time=" time_format " bio=" ptr_format "\n",
- mode, time(NULL), (ptr_type)bio);
+ fprintf(biofp, "BIO %s time=%" PRIi64 " bio=" ptr_format "\n",
+ mode, (int64_t)time(NULL), (ptr_type)bio);
fflush(biofp);
}
@@ -1848,7 +2085,7 @@ print_details(struct key_state_ssl *ks_ssl, const char *prefix)
{
EC_KEY *ec = EVP_PKEY_get0_EC_KEY(pkey);
const EC_GROUP *group = EC_KEY_get0_group(ec);
- const char* curve;
+ const char *curve;
int nid = EC_GROUP_get_curve_name(group);
if (nid == 0 || (curve = OBJ_nid2sn(nid)) == NULL)
@@ -1873,7 +2110,7 @@ print_details(struct key_state_ssl *ks_ssl, const char *prefix)
void
show_available_tls_ciphers_list(const char *cipher_list,
const char *tls_cert_profile,
- const bool tls13)
+ bool tls13)
{
struct tls_root_ctx tls_ctx;
@@ -1883,10 +2120,11 @@ show_available_tls_ciphers_list(const char *cipher_list,
crypto_msg(M_FATAL, "Cannot create SSL_CTX object");
}
-#if (OPENSSL_VERSION_NUMBER >= 0x1010100fL) && defined(TLS1_3_VERSION) && !defined(OPENSSL_NO_TLS1_3)
+#if defined(TLS1_3_VERSION)
if (tls13)
{
- SSL_CTX_set_min_proto_version(tls_ctx.ctx, TLS1_3_VERSION);
+ SSL_CTX_set_min_proto_version(tls_ctx.ctx,
+ openssl_tls_version(TLS_VER_1_3));
tls_ctx_restrict_ciphers_tls13(&tls_ctx, cipher_list);
}
else
@@ -1904,12 +2142,13 @@ show_available_tls_ciphers_list(const char *cipher_list,
crypto_msg(M_FATAL, "Cannot create SSL object");
}
-#if (OPENSSL_VERSION_NUMBER < 0x1010000fL)
+#if (OPENSSL_VERSION_NUMBER < 0x1010000fL) \
+ || (defined(LIBRESSL_VERSION_NUMBER) && LIBRESSL_VERSION_NUMBER <= 0x2090000fL)
STACK_OF(SSL_CIPHER) *sk = SSL_get_ciphers(ssl);
#else
STACK_OF(SSL_CIPHER) *sk = SSL_get1_supported_ciphers(ssl);
#endif
- for (int i=0;i < sk_SSL_CIPHER_num(sk);i++)
+ for (int i = 0; i < sk_SSL_CIPHER_num(sk); i++)
{
const SSL_CIPHER *c = sk_SSL_CIPHER_value(sk, i);
@@ -1920,7 +2159,7 @@ show_available_tls_ciphers_list(const char *cipher_list,
if (tls13)
{
- printf("%s\n", cipher_name);
+ printf("%s\n", cipher_name);
}
else if (NULL == pair)
{
@@ -1947,6 +2186,8 @@ show_available_tls_ciphers_list(const char *cipher_list,
void
show_available_curves(void)
{
+ printf("Consider using openssl 'ecparam -list_curves' as\n"
+ "alternative to running this command.\n");
#ifndef OPENSSL_NO_EC
EC_builtin_curve *curves = NULL;
size_t crv_len = 0;
@@ -1956,7 +2197,7 @@ show_available_curves(void)
ALLOC_ARRAY(curves, EC_builtin_curve, crv_len);
if (EC_get_builtin_curves(curves, crv_len))
{
- printf("Available Elliptic curves:\n");
+ printf("\nAvailable Elliptic curves/groups:\n");
for (n = 0; n < crv_len; n++)
{
const char *sname;
@@ -2008,7 +2249,7 @@ get_highest_preference_tls_cipher(char *buf, int size)
const char *
get_ssl_library_version(void)
{
- return SSLeay_version(SSLEAY_VERSION);
+ return OpenSSL_version(OPENSSL_VERSION);
}
-#endif /* defined(ENABLE_CRYPTO) && defined(ENABLE_CRYPTO_OPENSSL) */
+#endif /* defined(ENABLE_CRYPTO_OPENSSL) */