summaryrefslogtreecommitdiff
path: root/src/openvpn
diff options
context:
space:
mode:
Diffstat (limited to 'src/openvpn')
-rw-r--r--src/openvpn/Makefile.am4
-rw-r--r--src/openvpn/Makefile.in8
-rw-r--r--src/openvpn/cryptoapi.c52
-rw-r--r--src/openvpn/forward.c3
-rw-r--r--src/openvpn/init.c14
-rw-r--r--src/openvpn/misc.c77
-rw-r--r--src/openvpn/multi.c27
-rw-r--r--src/openvpn/openvpn.h1
-rw-r--r--src/openvpn/push.c13
-rw-r--r--src/openvpn/socks.c2
-rw-r--r--src/openvpn/ssl.c25
-rw-r--r--src/openvpn/ssl.h18
-rw-r--r--src/openvpn/ssl_mbedtls.c55
-rw-r--r--src/openvpn/ssl_mbedtls.h4
-rw-r--r--src/openvpn/ssl_openssl.c87
15 files changed, 281 insertions, 109 deletions
diff --git a/src/openvpn/Makefile.am b/src/openvpn/Makefile.am
index f3bf52f..0ff23ba 100644
--- a/src/openvpn/Makefile.am
+++ b/src/openvpn/Makefile.am
@@ -28,6 +28,7 @@ AM_CFLAGS = \
$(OPTIONAL_LZO_CFLAGS) \
$(OPTIONAL_LZ4_CFLAGS) \
$(OPTIONAL_PKCS11_HELPER_CFLAGS) \
+ $(OPTIONAL_INOTIFY_CFLAGS) \
-DPLUGIN_LIBDIR=\"${plugindir}\"
if WIN32
@@ -129,7 +130,8 @@ openvpn_LDADD = \
$(OPTIONAL_CRYPTO_LIBS) \
$(OPTIONAL_SELINUX_LIBS) \
$(OPTIONAL_SYSTEMD_LIBS) \
- $(OPTIONAL_DL_LIBS)
+ $(OPTIONAL_DL_LIBS) \
+ $(OPTIONAL_INOTIFY_LIBS)
if WIN32
openvpn_SOURCES += openvpn_win32_resources.rc block_dns.c block_dns.h
openvpn_LDADD += -lgdi32 -lws2_32 -lwininet -lcrypt32 -liphlpapi -lwinmm -lfwpuclnt -lrpcrt4 -lncrypt
diff --git a/src/openvpn/Makefile.in b/src/openvpn/Makefile.in
index 3db2849..963f6ab 100644
--- a/src/openvpn/Makefile.in
+++ b/src/openvpn/Makefile.in
@@ -198,7 +198,7 @@ openvpn_DEPENDENCIES = $(top_builddir)/src/compat/libcompat.la \
$(am__DEPENDENCIES_1) $(am__DEPENDENCIES_1) \
$(am__DEPENDENCIES_1) $(am__DEPENDENCIES_1) \
$(am__DEPENDENCIES_1) $(am__DEPENDENCIES_1) \
- $(am__DEPENDENCIES_1)
+ $(am__DEPENDENCIES_1) $(am__DEPENDENCIES_1)
AM_V_lt = $(am__v_lt_@AM_V@)
am__v_lt_ = $(am__v_lt_@AM_DEFAULT_V@)
am__v_lt_0 = --silent
@@ -371,6 +371,8 @@ OPENVPN_VERSION_PATCH = @OPENVPN_VERSION_PATCH@
OPTIONAL_CRYPTO_CFLAGS = @OPTIONAL_CRYPTO_CFLAGS@
OPTIONAL_CRYPTO_LIBS = @OPTIONAL_CRYPTO_LIBS@
OPTIONAL_DL_LIBS = @OPTIONAL_DL_LIBS@
+OPTIONAL_INOTIFY_CFLAGS = @OPTIONAL_INOTIFY_CFLAGS@
+OPTIONAL_INOTIFY_LIBS = @OPTIONAL_INOTIFY_LIBS@
OPTIONAL_LZ4_CFLAGS = @OPTIONAL_LZ4_CFLAGS@
OPTIONAL_LZ4_LIBS = @OPTIONAL_LZ4_LIBS@
OPTIONAL_LZO_CFLAGS = @OPTIONAL_LZO_CFLAGS@
@@ -493,7 +495,7 @@ AM_CPPFLAGS = \
AM_CFLAGS = $(TAP_CFLAGS) $(OPTIONAL_CRYPTO_CFLAGS) \
$(OPTIONAL_LZO_CFLAGS) $(OPTIONAL_LZ4_CFLAGS) \
- $(OPTIONAL_PKCS11_HELPER_CFLAGS) \
+ $(OPTIONAL_PKCS11_HELPER_CFLAGS) $(OPTIONAL_INOTIFY_CFLAGS) \
-DPLUGIN_LIBDIR=\"${plugindir}\" $(am__append_1)
openvpn_SOURCES = argv.c argv.h base64.c base64.h basic.h buffer.c \
buffer.h circ_list.h clinat.c clinat.h common.h comp.c comp.h \
@@ -528,7 +530,7 @@ openvpn_LDADD = $(top_builddir)/src/compat/libcompat.la \
$(SOCKETS_LIBS) $(OPTIONAL_LZO_LIBS) $(OPTIONAL_LZ4_LIBS) \
$(OPTIONAL_PKCS11_HELPER_LIBS) $(OPTIONAL_CRYPTO_LIBS) \
$(OPTIONAL_SELINUX_LIBS) $(OPTIONAL_SYSTEMD_LIBS) \
- $(OPTIONAL_DL_LIBS) $(am__append_3)
+ $(OPTIONAL_DL_LIBS) $(OPTIONAL_INOTIFY_LIBS) $(am__append_3)
all: all-am
.SUFFIXES:
diff --git a/src/openvpn/cryptoapi.c b/src/openvpn/cryptoapi.c
index 7f2c3c0..0f95d00 100644
--- a/src/openvpn/cryptoapi.c
+++ b/src/openvpn/cryptoapi.c
@@ -50,6 +50,7 @@
#include "buffer.h"
#include "openssl_compat.h"
+#include "win32.h"
/* MinGW w32api 3.17 is still incomplete when it comes to CryptoAPI while
* MinGW32-w64 defines all macros used. This is a hack around that problem.
@@ -529,27 +530,32 @@ find_certificate_in_store(const char *cert_prop, HCERTSTORE cert_store)
* SUBJ:<certificate substring to match>
* THUMB:<certificate thumbprint hex value>, e.g.
* THUMB:f6 49 24 41 01 b4 fb 44 0c ce f4 36 ae d0 c4 c9 df 7a b6 28
+ * The first matching certificate that has not expired is returned.
*/
const CERT_CONTEXT *rv = NULL;
+ DWORD find_type;
+ const void *find_param;
+ unsigned char hash[255];
+ CRYPT_HASH_BLOB blob = {.cbData = 0, .pbData = hash};
+ struct gc_arena gc = gc_new();
if (!strncmp(cert_prop, "SUBJ:", 5))
{
/* skip the tag */
- cert_prop += 5;
- rv = CertFindCertificateInStore(cert_store, X509_ASN_ENCODING | PKCS_7_ASN_ENCODING,
- 0, CERT_FIND_SUBJECT_STR_A, cert_prop, NULL);
-
+ find_param = wide_string(cert_prop + 5, &gc);
+ find_type = CERT_FIND_SUBJECT_STR_W;
}
else if (!strncmp(cert_prop, "THUMB:", 6))
{
- unsigned char hash[255];
- char *p;
+ const char *p;
int i, x = 0;
- CRYPT_HASH_BLOB blob;
+ find_type = CERT_FIND_HASH;
+ find_param = &blob;
/* skip the tag */
cert_prop += 6;
- for (p = (char *) cert_prop, i = 0; *p && i < sizeof(hash); i++) {
+ for (p = cert_prop, i = 0; *p && i < sizeof(hash); i++)
+ {
if (*p >= '0' && *p <= '9')
{
x = (*p - '0') << 4;
@@ -564,7 +570,8 @@ find_certificate_in_store(const char *cert_prop, HCERTSTORE cert_store)
}
if (!*++p) /* unexpected end of string */
{
- break;
+ msg(M_WARN, "WARNING: cryptoapicert: error parsing <THUMB:%s>.", cert_prop);
+ goto out;
}
if (*p >= '0' && *p <= '9')
{
@@ -585,12 +592,33 @@ find_certificate_in_store(const char *cert_prop, HCERTSTORE cert_store)
}
}
blob.cbData = i;
- blob.pbData = (unsigned char *) &hash;
- rv = CertFindCertificateInStore(cert_store, X509_ASN_ENCODING | PKCS_7_ASN_ENCODING,
- 0, CERT_FIND_HASH, &blob, NULL);
+ }
+ else
+ {
+ msg(M_WARN, "WARNING: cryptoapicert: unsupported certificate specification <%s>", cert_prop);
+ goto out;
+ }
+ while(true)
+ {
+ int validity = 1;
+ /* this frees previous rv, if not NULL */
+ rv = CertFindCertificateInStore(cert_store, X509_ASN_ENCODING | PKCS_7_ASN_ENCODING,
+ 0, find_type, find_param, rv);
+ if (rv)
+ {
+ validity = CertVerifyTimeValidity(NULL, rv->pCertInfo);
+ }
+ if (!rv || validity == 0)
+ {
+ break;
+ }
+ msg(M_WARN, "WARNING: cryptoapicert: ignoring certificate in store %s.",
+ validity < 0 ? "not yet valid" : "that has expired");
}
+out:
+ gc_free(&gc);
return rv;
}
diff --git a/src/openvpn/forward.c b/src/openvpn/forward.c
index 65f790f..84bb584 100644
--- a/src/openvpn/forward.c
+++ b/src/openvpn/forward.c
@@ -873,6 +873,9 @@ process_incoming_link_part1(struct context *c, struct link_socket_info *lsi, boo
if (is_hard_reset(opcode, c->options.key_method))
{
c->c2.frame = c->c2.frame_initial;
+#ifdef ENABLE_FRAGMENT
+ c->c2.frame_fragment = c->c2.frame_fragment_initial;
+#endif
}
interval_action(&c->c2.tmp_int);
diff --git a/src/openvpn/init.c b/src/openvpn/init.c
index d3785ca..8bac74f 100644
--- a/src/openvpn/init.c
+++ b/src/openvpn/init.c
@@ -2294,9 +2294,16 @@ do_deferred_options(struct context *c, const unsigned int found)
{
tls_poor_mans_ncp(&c->options, c->c2.tls_multi->remote_ciphername);
}
- /* Do not regenerate keys if server sends an extra push reply */
- if (!session->key[KS_PRIMARY].crypto_options.key_ctx_bi.initialized
- && !tls_session_update_crypto_params(session, &c->options, &c->c2.frame))
+ struct frame *frame_fragment = NULL;
+#ifdef ENABLE_FRAGMENT
+ if (c->options.ce.fragment)
+ {
+ frame_fragment = &c->c2.frame_fragment;
+ }
+#endif
+
+ if (!tls_session_update_crypto_params(session, &c->options, &c->c2.frame,
+ frame_fragment))
{
msg(D_TLS_ERRORS, "OPTIONS ERROR: failed to import crypto options");
return false;
@@ -3035,6 +3042,7 @@ do_init_frame(struct context *c)
*/
c->c2.frame_fragment = c->c2.frame;
frame_subtract_extra(&c->c2.frame_fragment, &c->c2.frame_fragment_omit);
+ c->c2.frame_fragment_initial = c->c2.frame_fragment;
#endif
#if defined(ENABLE_FRAGMENT) && defined(ENABLE_OCC)
diff --git a/src/openvpn/misc.c b/src/openvpn/misc.c
index f44c65f..9c5e96e 100644
--- a/src/openvpn/misc.c
+++ b/src/openvpn/misc.c
@@ -880,6 +880,43 @@ absolute_pathname(const char *pathname)
}
}
+#ifdef ENABLE_MANAGEMENT
+
+/* Get username/password from the management interface */
+static bool
+auth_user_pass_mgmt(struct user_pass *up, const char *prefix, const unsigned int flags,
+ const char *auth_challenge)
+{
+ const char *sc = NULL;
+
+ if (flags & GET_USER_PASS_PREVIOUS_CREDS_FAILED)
+ {
+ management_auth_failure(management, prefix, "previous auth credentials failed");
+ }
+
+#ifdef ENABLE_CLIENT_CR
+ if (auth_challenge && (flags & GET_USER_PASS_STATIC_CHALLENGE))
+ {
+ sc = auth_challenge;
+ }
+#endif
+
+ if (!management_query_user_pass(management, up, prefix, flags, sc))
+ {
+ if ((flags & GET_USER_PASS_NOFATAL) != 0)
+ {
+ return false;
+ }
+ else
+ {
+ msg(M_FATAL, "ERROR: could not read %s username/password/ok/string from management interface", prefix);
+ }
+ }
+ return true;
+}
+
+#endif /* ifdef ENABLE_MANAGEMENT */
+
/*
* Get and store a username/password
*/
@@ -913,30 +950,10 @@ get_user_pass_cr(struct user_pass *up,
&& (!from_authfile && (flags & GET_USER_PASS_MANAGEMENT))
&& management_query_user_pass_enabled(management))
{
- const char *sc = NULL;
response_from_stdin = false;
-
- if (flags & GET_USER_PASS_PREVIOUS_CREDS_FAILED)
- {
- management_auth_failure(management, prefix, "previous auth credentials failed");
- }
-
-#ifdef ENABLE_CLIENT_CR
- if (auth_challenge && (flags & GET_USER_PASS_STATIC_CHALLENGE))
+ if (!auth_user_pass_mgmt(up, prefix, flags, auth_challenge))
{
- sc = auth_challenge;
- }
-#endif
- if (!management_query_user_pass(management, up, prefix, flags, sc))
- {
- if ((flags & GET_USER_PASS_NOFATAL) != 0)
- {
- return false;
- }
- else
- {
- msg(M_FATAL, "ERROR: could not read %s username/password/ok/string from management interface", prefix);
- }
+ return false;
}
}
else
@@ -1013,6 +1030,22 @@ get_user_pass_cr(struct user_pass *up,
{
strncpy(up->password, password_buf, USER_PASS_LEN);
}
+ /* The auth-file does not have the password: get both username
+ * and password from the management interface if possible.
+ * Otherwise set to read password from console.
+ */
+#if defined(ENABLE_MANAGEMENT)
+ else if (management
+ && (flags & GET_USER_PASS_MANAGEMENT)
+ && management_query_user_pass_enabled(management))
+ {
+ msg(D_LOW, "No password found in %s authfile '%s'. Querying the management interface", prefix, auth_file);
+ if (!auth_user_pass_mgmt(up, prefix, flags, auth_challenge))
+ {
+ return false;
+ }
+ }
+#endif
else
{
password_from_stdin = 1;
diff --git a/src/openvpn/multi.c b/src/openvpn/multi.c
index baffd74..c8c9a40 100644
--- a/src/openvpn/multi.c
+++ b/src/openvpn/multi.c
@@ -2132,8 +2132,30 @@ multi_process_file_closed(struct multi_context *m, const unsigned int mpp_flags)
{
if (mi)
{
- /* continue authentication and send push_reply */
+ /* continue authentication, perform NCP negotiation and send push_reply */
multi_process_post(m, mi, mpp_flags);
+
+ /* With NCP and deferred authentication, we perform cipher negotiation and
+ * data channel keys generation on incoming push request, assuming that auth
+ * succeeded. When auth succeeds in between push requests and async push is used,
+ * we send push reply immediately. Above multi_process_post() call performs
+ * NCP negotiation and here we do keys generation. */
+
+ struct context *c = &mi->context;
+ struct frame *frame_fragment = NULL;
+#ifdef ENABLE_FRAGMENT
+ if (c->options.ce.fragment)
+ {
+ frame_fragment = &c->c2.frame_fragment;
+ }
+#endif
+ struct tls_session *session = &c->c2.tls_multi->session[TM_ACTIVE];
+ if (!tls_session_update_crypto_params(session, &c->options,
+ &c->c2.frame, frame_fragment))
+ {
+ msg(D_TLS_ERRORS, "TLS Error: initializing data channel failed");
+ register_signal(c, SIGUSR1, "init-data-channel-failed");
+ }
}
else
{
@@ -2540,7 +2562,8 @@ multi_process_incoming_link(struct multi_context *m, struct multi_instance *inst
orig_buf = c->c2.buf.data;
if (process_incoming_link_part1(c, lsi, floated))
{
- if (floated)
+ /* nonzero length means that we have a valid, decrypted packed */
+ if (floated && c->c2.buf.len > 0)
{
multi_process_float(m, m->pending);
}
diff --git a/src/openvpn/openvpn.h b/src/openvpn/openvpn.h
index 7736183..ed7975c 100644
--- a/src/openvpn/openvpn.h
+++ b/src/openvpn/openvpn.h
@@ -269,6 +269,7 @@ struct context_2
/* Object to handle advanced MTU negotiation and datagram fragmentation */
struct fragment_master *fragment;
struct frame frame_fragment;
+ struct frame frame_fragment_initial;
struct frame frame_fragment_omit;
#endif
diff --git a/src/openvpn/push.c b/src/openvpn/push.c
index dd5bd41..002be23 100644
--- a/src/openvpn/push.c
+++ b/src/openvpn/push.c
@@ -287,11 +287,16 @@ incoming_push_message(struct context *c, const struct buffer *buffer)
{
if (c->options.mode == MODE_SERVER)
{
+ struct frame *frame_fragment = NULL;
+#ifdef ENABLE_FRAGMENT
+ if (c->options.ce.fragment)
+ {
+ frame_fragment = &c->c2.frame_fragment;
+ }
+#endif
struct tls_session *session = &c->c2.tls_multi->session[TM_ACTIVE];
- /* Do not regenerate keys if client send a second push request */
- if (!session->key[KS_PRIMARY].crypto_options.key_ctx_bi.initialized
- && !tls_session_update_crypto_params(session, &c->options,
- &c->c2.frame))
+ if (!tls_session_update_crypto_params(session, &c->options,
+ &c->c2.frame, frame_fragment))
{
msg(D_TLS_ERRORS, "TLS Error: initializing data channel failed");
goto error;
diff --git a/src/openvpn/socks.c b/src/openvpn/socks.c
index ad3a70b..57f0cee 100644
--- a/src/openvpn/socks.c
+++ b/src/openvpn/socks.c
@@ -416,7 +416,7 @@ recv_socks_reply(socket_descriptor_t sd,
memcpy(&addr->addr.in4.sin_port, buf + 8, sizeof(addr->addr.in4.sin_port));
struct gc_arena gc = gc_new();
msg(M_INFO, "SOCKS proxy wants us to send UDP to %s",
- print_sockaddr(addr, &gc));
+ print_openvpn_sockaddr(addr, &gc));
gc_free(&gc);
}
diff --git a/src/openvpn/ssl.c b/src/openvpn/ssl.c
index 9696e9b..cf66899 100644
--- a/src/openvpn/ssl.c
+++ b/src/openvpn/ssl.c
@@ -1962,8 +1962,15 @@ cleanup:
bool
tls_session_update_crypto_params(struct tls_session *session,
- struct options *options, struct frame *frame)
+ struct options *options, struct frame *frame,
+ struct frame *frame_fragment)
{
+ if (session->key[KS_PRIMARY].crypto_options.key_ctx_bi.initialized)
+ {
+ /* keys already generated, nothing to do */
+ return true;
+ }
+
if (!session->opt->server
&& 0 != strcmp(options->ciphername, session->opt->config_ciphername)
&& !tls_item_in_cipher_list(options->ciphername, options->ncp_ciphers))
@@ -2006,6 +2013,22 @@ tls_session_update_crypto_params(struct tls_session *session,
frame_init_mssfix(frame, options);
frame_print(frame, D_MTU_INFO, "Data Channel MTU parms");
+ /*
+ * mssfix uses data channel framing, which at this point contains
+ * actual overhead. Fragmentation logic uses frame_fragment, which
+ * still contains worst case overhead. Replace it with actual overhead
+ * to prevent unneeded fragmentation.
+ */
+
+ if (frame_fragment)
+ {
+ frame_remove_from_extra_frame(frame_fragment, crypto_max_overhead());
+ crypto_adjust_frame_parameters(frame_fragment, &session->opt->key_type,
+ options->use_iv, options->replay, packet_id_long_form);
+ frame_set_mtu_dynamic(frame_fragment, options->ce.fragment, SET_MTU_UPPER_BOUND);
+ frame_print(frame_fragment, D_MTU_INFO, "Fragmentation MTU parms");
+ }
+
return tls_session_generate_data_channel_keys(session);
}
diff --git a/src/openvpn/ssl.h b/src/openvpn/ssl.h
index 8066789..3266f38 100644
--- a/src/openvpn/ssl.h
+++ b/src/openvpn/ssl.h
@@ -473,17 +473,21 @@ void tls_update_remote_addr(struct tls_multi *multi,
/**
* Update TLS session crypto parameters (cipher and auth) and derive data
- * channel keys based on the supplied options.
+ * channel keys based on the supplied options. Does nothing if keys are already
+ * generated.
*
- * @param session The TLS session to update.
- * @param options The options to use when updating session.
- * @param frame The frame options for this session (frame overhead is
- * adjusted based on the selected cipher/auth).
+ * @param session The TLS session to update.
+ * @param options The options to use when updating session.
+ * @param frame The frame options for this session (frame overhead is
+ * adjusted based on the selected cipher/auth).
+ * @param frame_fragment The fragment frame options.
*
- * @return true if updating succeeded, false otherwise.
+ * @return true if updating succeeded or keys are already generated, false otherwise.
*/
bool tls_session_update_crypto_params(struct tls_session *session,
- struct options *options, struct frame *frame);
+ struct options *options,
+ struct frame *frame,
+ struct frame *frame_fragment);
/**
* "Poor man's NCP": Use peer cipher if it is an allowed (NCP) cipher.
diff --git a/src/openvpn/ssl_mbedtls.c b/src/openvpn/ssl_mbedtls.c
index 89b1b67..4746261 100644
--- a/src/openvpn/ssl_mbedtls.c
+++ b/src/openvpn/ssl_mbedtls.c
@@ -974,21 +974,22 @@ key_state_ssl_init(struct key_state_ssl *ks_ssl,
CLEAR(*ks_ssl);
/* Initialise SSL config */
- mbedtls_ssl_config_init(&ks_ssl->ssl_config);
- mbedtls_ssl_config_defaults(&ks_ssl->ssl_config, ssl_ctx->endpoint,
+ ALLOC_OBJ_CLEAR(ks_ssl->ssl_config, mbedtls_ssl_config);
+ mbedtls_ssl_config_init(ks_ssl->ssl_config);
+ mbedtls_ssl_config_defaults(ks_ssl->ssl_config, ssl_ctx->endpoint,
MBEDTLS_SSL_TRANSPORT_STREAM, MBEDTLS_SSL_PRESET_DEFAULT);
#ifdef MBEDTLS_DEBUG_C
mbedtls_debug_set_threshold(3);
#endif
- mbedtls_ssl_conf_dbg(&ks_ssl->ssl_config, my_debug, NULL);
- mbedtls_ssl_conf_rng(&ks_ssl->ssl_config, mbedtls_ctr_drbg_random,
+ mbedtls_ssl_conf_dbg(ks_ssl->ssl_config, my_debug, NULL);
+ mbedtls_ssl_conf_rng(ks_ssl->ssl_config, mbedtls_ctr_drbg_random,
rand_ctx_get());
- mbedtls_ssl_conf_cert_profile(&ks_ssl->ssl_config, &ssl_ctx->cert_profile);
+ mbedtls_ssl_conf_cert_profile(ks_ssl->ssl_config, &ssl_ctx->cert_profile);
if (ssl_ctx->allowed_ciphers)
{
- mbedtls_ssl_conf_ciphersuites(&ks_ssl->ssl_config, ssl_ctx->allowed_ciphers);
+ mbedtls_ssl_conf_ciphersuites(ks_ssl->ssl_config, ssl_ctx->allowed_ciphers);
}
/* Disable record splitting (for now). OpenVPN assumes records are sent
@@ -996,35 +997,35 @@ key_state_ssl_init(struct key_state_ssl *ks_ssl,
* testing. Since OpenVPN is not susceptible to BEAST, we can just
* disable record splitting as a quick fix. */
#if defined(MBEDTLS_SSL_CBC_RECORD_SPLITTING)
- mbedtls_ssl_conf_cbc_record_splitting(&ks_ssl->ssl_config,
+ mbedtls_ssl_conf_cbc_record_splitting(ks_ssl->ssl_config,
MBEDTLS_SSL_CBC_RECORD_SPLITTING_DISABLED);
#endif /* MBEDTLS_SSL_CBC_RECORD_SPLITTING */
/* Initialise authentication information */
if (is_server)
{
- mbed_ok(mbedtls_ssl_conf_dh_param_ctx(&ks_ssl->ssl_config,
+ mbed_ok(mbedtls_ssl_conf_dh_param_ctx(ks_ssl->ssl_config,
ssl_ctx->dhm_ctx));
}
- mbed_ok(mbedtls_ssl_conf_own_cert(&ks_ssl->ssl_config, ssl_ctx->crt_chain,
+ mbed_ok(mbedtls_ssl_conf_own_cert(ks_ssl->ssl_config, ssl_ctx->crt_chain,
ssl_ctx->priv_key));
/* Initialise SSL verification */
#if P2MP_SERVER
if (session->opt->ssl_flags & SSLF_CLIENT_CERT_OPTIONAL)
{
- mbedtls_ssl_conf_authmode(&ks_ssl->ssl_config, MBEDTLS_SSL_VERIFY_OPTIONAL);
+ mbedtls_ssl_conf_authmode(ks_ssl->ssl_config, MBEDTLS_SSL_VERIFY_OPTIONAL);
}
else if (!(session->opt->ssl_flags & SSLF_CLIENT_CERT_NOT_REQUIRED))
#endif
{
- mbedtls_ssl_conf_authmode(&ks_ssl->ssl_config, MBEDTLS_SSL_VERIFY_REQUIRED);
+ mbedtls_ssl_conf_authmode(ks_ssl->ssl_config, MBEDTLS_SSL_VERIFY_REQUIRED);
}
- mbedtls_ssl_conf_verify(&ks_ssl->ssl_config, verify_callback, session);
+ mbedtls_ssl_conf_verify(ks_ssl->ssl_config, verify_callback, session);
/* TODO: mbed TLS does not currently support sending the CA chain to the client */
- mbedtls_ssl_conf_ca_chain(&ks_ssl->ssl_config, ssl_ctx->ca_chain, ssl_ctx->crl);
+ mbedtls_ssl_conf_ca_chain(ks_ssl->ssl_config, ssl_ctx->ca_chain, ssl_ctx->crl);
/* Initialize minimum TLS version */
{
@@ -1041,7 +1042,7 @@ key_state_ssl_init(struct key_state_ssl *ks_ssl,
tls_version_to_major_minor(tls_version_min, &major, &minor);
}
- mbedtls_ssl_conf_min_version(&ks_ssl->ssl_config, major, minor);
+ mbedtls_ssl_conf_min_version(ks_ssl->ssl_config, major, minor);
}
/* Initialize maximum TLS version */
@@ -1054,18 +1055,18 @@ key_state_ssl_init(struct key_state_ssl *ks_ssl,
{
int major, minor;
tls_version_to_major_minor(tls_version_max, &major, &minor);
- mbedtls_ssl_conf_max_version(&ks_ssl->ssl_config, major, minor);
+ mbedtls_ssl_conf_max_version(ks_ssl->ssl_config, major, minor);
}
}
/* Initialise SSL context */
ALLOC_OBJ_CLEAR(ks_ssl->ctx, mbedtls_ssl_context);
mbedtls_ssl_init(ks_ssl->ctx);
- mbedtls_ssl_setup(ks_ssl->ctx, &ks_ssl->ssl_config);
+ mbedtls_ssl_setup(ks_ssl->ctx, ks_ssl->ssl_config);
/* Initialise BIOs */
- CLEAR(ks_ssl->bio_ctx);
- mbedtls_ssl_set_bio(ks_ssl->ctx, &ks_ssl->bio_ctx, ssl_bio_write,
+ ALLOC_OBJ_CLEAR(ks_ssl->bio_ctx, bio_ctx);
+ mbedtls_ssl_set_bio(ks_ssl->ctx, ks_ssl->bio_ctx, ssl_bio_write,
ssl_bio_read, NULL);
}
@@ -1079,9 +1080,17 @@ key_state_ssl_free(struct key_state_ssl *ks_ssl)
mbedtls_ssl_free(ks_ssl->ctx);
free(ks_ssl->ctx);
}
- mbedtls_ssl_config_free(&ks_ssl->ssl_config);
- buf_free_entries(&ks_ssl->bio_ctx.in);
- buf_free_entries(&ks_ssl->bio_ctx.out);
+ if (ks_ssl->ssl_config)
+ {
+ mbedtls_ssl_config_free(ks_ssl->ssl_config);
+ free(ks_ssl->ssl_config);
+ }
+ if (ks_ssl->bio_ctx)
+ {
+ buf_free_entries(&ks_ssl->bio_ctx->in);
+ buf_free_entries(&ks_ssl->bio_ctx->out);
+ free(ks_ssl->bio_ctx);
+ }
CLEAR(*ks_ssl);
}
}
@@ -1176,7 +1185,7 @@ key_state_read_ciphertext(struct key_state_ssl *ks, struct buffer *buf,
len = maxlen;
}
- retval = endless_buf_read(&ks->bio_ctx.out, BPTR(buf), len);
+ retval = endless_buf_read(&ks->bio_ctx->out, BPTR(buf), len);
/* Error during read, check for retry error */
if (retval < 0)
@@ -1221,7 +1230,7 @@ key_state_write_ciphertext(struct key_state_ssl *ks, struct buffer *buf)
return 0;
}
- retval = endless_buf_write(&ks->bio_ctx.in, BPTR(buf), buf->len);
+ retval = endless_buf_write(&ks->bio_ctx->in, BPTR(buf), buf->len);
if (retval < 0)
{
diff --git a/src/openvpn/ssl_mbedtls.h b/src/openvpn/ssl_mbedtls.h
index dd8ca75..f99aba1 100644
--- a/src/openvpn/ssl_mbedtls.h
+++ b/src/openvpn/ssl_mbedtls.h
@@ -86,9 +86,9 @@ struct tls_root_ctx {
};
struct key_state_ssl {
- mbedtls_ssl_config ssl_config; /**< mbedTLS global ssl config */
+ mbedtls_ssl_config *ssl_config; /**< mbedTLS global ssl config */
mbedtls_ssl_context *ctx; /**< mbedTLS connection context */
- bio_ctx bio_ctx;
+ bio_ctx *bio_ctx;
};
diff --git a/src/openvpn/ssl_openssl.c b/src/openvpn/ssl_openssl.c
index 6aa3ac3..19509b7 100644
--- a/src/openvpn/ssl_openssl.c
+++ b/src/openvpn/ssl_openssl.c
@@ -634,8 +634,11 @@ tls_ctx_load_ecdh_params(struct tls_root_ctx *ctx, const char *curve_name
/* OpenSSL 1.0.2 and newer can automatically handle ECDH parameter
* loading */
SSL_CTX_set_ecdh_auto(ctx->ctx, 1);
- return;
+
+ /* OpenSSL 1.1.0 and newer have always ecdh auto loading enabled,
+ * so do nothing */
#endif
+ return;
#else
/* For older OpenSSL we have to extract the curve from key on our own */
EC_KEY *eckey = NULL;
@@ -837,24 +840,36 @@ tls_ctx_load_cryptoapi(struct tls_root_ctx *ctx, const char *cryptoapi_cert)
#endif /* ENABLE_CRYPTOAPI */
static void
-tls_ctx_add_extra_certs(struct tls_root_ctx *ctx, BIO *bio)
+tls_ctx_add_extra_certs(struct tls_root_ctx *ctx, BIO *bio, bool optional)
{
X509 *cert;
- for (;; )
+ while (true)
{
cert = NULL;
- if (!PEM_read_bio_X509(bio, &cert, NULL, NULL)) /* takes ownership of cert */
- {
- break;
- }
- if (!cert)
+ if (!PEM_read_bio_X509(bio, &cert, NULL, NULL))
{
+ /* 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 */
crypto_msg(M_FATAL, "Error reading extra certificate");
}
+ /* takes ownership of cert like a set1 method */
if (SSL_CTX_add_extra_chain_cert(ctx->ctx, cert) != 1)
{
crypto_msg(M_FATAL, "Error adding extra certificate");
}
+ /* We loaded at least one certificate, so loading more is optional */
+ optional = true;
}
}
@@ -904,7 +919,7 @@ tls_ctx_load_cert_file_and_copy(struct tls_root_ctx *ctx,
ret = SSL_CTX_use_certificate(ctx->ctx, x);
if (ret)
{
- tls_ctx_add_extra_certs(ctx, in);
+ tls_ctx_add_extra_certs(ctx, in, true);
}
end:
@@ -919,6 +934,10 @@ end:
crypto_msg(M_FATAL, "Cannot load certificate file %s", cert_file);
}
}
+ else
+ {
+ crypto_print_openssl_errors(M_DEBUG);
+ }
if (in != NULL)
{
@@ -972,12 +991,7 @@ 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)
- {
- goto end;
- }
-
- if (!SSL_CTX_use_PrivateKey(ssl_ctx, pkey))
+ if (!pkey || !SSL_CTX_use_PrivateKey(ssl_ctx, pkey))
{
#ifdef ENABLE_MANAGEMENT
if (management && (ERR_GET_REASON(ERR_peek_error()) == EVP_R_BAD_DECRYPT))
@@ -1012,7 +1026,6 @@ void
backend_tls_ctx_reload_crl(struct tls_root_ctx *ssl_ctx, const char *crl_file,
const char *crl_inline)
{
- X509_CRL *crl = NULL;
BIO *in = NULL;
X509_STORE *store = SSL_CTX_get_cert_store(ssl_ctx->ctx);
@@ -1053,21 +1066,39 @@ backend_tls_ctx_reload_crl(struct tls_root_ctx *ssl_ctx, const char *crl_file,
goto end;
}
- crl = PEM_read_bio_X509_CRL(in, NULL, NULL, NULL);
- if (crl == NULL)
+ int num_crls_loaded = 0;
+ while (true)
{
- msg(M_WARN, "CRL: cannot read CRL from file %s", crl_file);
- goto end;
- }
+ 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;
+ }
- if (!X509_STORE_add_crl(store, crl))
- {
- msg(M_WARN, "CRL: cannot add %s to store", crl_file);
- goto end;
- }
+ crypto_msg(M_WARN, "CRL: cannot read CRL from file %s", crl_file);
+ break;
+ }
+ if (!X509_STORE_add_crl(store, crl))
+ {
+ X509_CRL_free(crl);
+ crypto_msg(M_WARN, "CRL: cannot add %s to store", crl_file);
+ break;
+ }
+ X509_CRL_free(crl);
+ num_crls_loaded++;
+ }
+ msg(M_INFO, "CRL: loaded %d CRLs from file %s", num_crls_loaded, crl_file);
end:
- X509_CRL_free(crl);
BIO_free(in);
}
@@ -1434,7 +1465,7 @@ tls_ctx_load_extra_certs(struct tls_root_ctx *ctx, const char *extra_certs_file,
}
else
{
- tls_ctx_add_extra_certs(ctx, in);
+ tls_ctx_add_extra_certs(ctx, in, false);
}
BIO_free(in);