Previously, client certificate expiry warnings would only visible in the
server log, and server certificate expiry warnings in the client log.
Both after a (failed) connection attempt.  This patch adds a warning to
log when a users own certificate has expired (or is not yet valid) to ease
problem diagnosis / error reporting.

Note that this is just a warning, since on some systems (notably embedded
devices) there might be no correct time available.

The SSL_CTX_get0_certificate() function is available in OpenSSL 1.0.2+
only.  Older versions seem to not have a useful alternative, and the
certificate reference we need is hidden in an opaque struct.  The
remaining option would then be to add extra workaround code for the select
group of people that do use an up-to-date openvpn, but do not update their
openssl.  I don't think that's worth it.  So just disable the code for
older openssl versions.

(This is a combination of commits 091edd8e and 644f2cdd from the master
branch, adjusted to apply to the release/2.3 branch cleanly)

Signed-off-by: Steffan Karger <stef...@karger.me>
---
 src/openvpn/ssl.c          |  3 +++
 src/openvpn/ssl_backend.h  |  9 +++++++++
 src/openvpn/ssl_openssl.c  | 29 +++++++++++++++++++++++++++++
 src/openvpn/ssl_polarssl.c | 14 ++++++++++++++
 4 files changed, 55 insertions(+)

diff --git a/src/openvpn/ssl.c b/src/openvpn/ssl.c
index 202a03f..f728ffb 100644
--- a/src/openvpn/ssl.c
+++ b/src/openvpn/ssl.c
@@ -556,6 +556,9 @@ init_ssl (const struct options *options, struct 
tls_root_ctx *new_ctx)
       tls_ctx_load_extra_certs(new_ctx, options->extra_certs_file, 
options->extra_certs_file_inline);
     }

+  /* Check certificate notBefore and notAfter */
+  tls_ctx_check_cert_time(new_ctx);
+
   /* Allowable ciphers */
   if (options->cipher_list)
     {
diff --git a/src/openvpn/ssl_backend.h b/src/openvpn/ssl_backend.h
index 6d47bd0..4b35e51 100644
--- a/src/openvpn/ssl_backend.h
+++ b/src/openvpn/ssl_backend.h
@@ -176,6 +176,15 @@ void 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);

 /**
+ * Check our certificate notBefore and notAfter fields, and warn if the cert is
+ * either not yet valid or has expired.  Note that this is a non-fatal error,
+ * since we compare against the system time, which might be incorrect.
+ *
+ * @param ctx          TLS context to get our certificate from.
+ */
+void tls_ctx_check_cert_time (const struct tls_root_ctx *ctx);
+
+/**
  * Load Diffie Hellman Parameters, and load them into the library-specific
  * TLS context.
  *
diff --git a/src/openvpn/ssl_openssl.c b/src/openvpn/ssl_openssl.c
index be33caa..13cce5e 100644
--- a/src/openvpn/ssl_openssl.c
+++ b/src/openvpn/ssl_openssl.c
@@ -335,6 +335,35 @@ tls_ctx_restrict_ciphers(struct tls_root_ctx *ctx, const 
char *ciphers)
 }

 void
+tls_ctx_check_cert_time (const struct tls_root_ctx *ctx)
+{
+#if OPENSSL_VERSION_NUMBER >= 0x10002000L
+  int ret;
+  const X509 *cert = SSL_CTX_get0_certificate(ctx->ctx);
+
+  ret = X509_cmp_time (X509_get_notBefore (cert), NULL);
+  if (ret == 0)
+    {
+      msg (D_TLS_DEBUG_MED, "Failed to read certificate notBefore field.");
+    }
+  if (ret > 0)
+    {
+      msg (M_WARN, "WARNING: Your certificate is not yet valid!");
+    }
+
+  ret = X509_cmp_time (X509_get_notAfter (cert), NULL);
+  if (ret == 0)
+    {
+      msg (D_TLS_DEBUG_MED, "Failed to read certificate notAfter field.");
+    }
+  if (ret < 0)
+    {
+      msg (M_WARN, "WARNING: Your certificate has expired!");
+    }
+#endif
+}
+
+void
 tls_ctx_load_dh_params (struct tls_root_ctx *ctx, const char *dh_file,
     const char *dh_file_inline
     )
diff --git a/src/openvpn/ssl_polarssl.c b/src/openvpn/ssl_polarssl.c
index 8d9d219..def397d 100644
--- a/src/openvpn/ssl_polarssl.c
+++ b/src/openvpn/ssl_polarssl.c
@@ -205,6 +205,20 @@ tls_ctx_restrict_ciphers(struct tls_root_ctx *ctx, const 
char *ciphers)
 }

 void
+tls_ctx_check_cert_time (const struct tls_root_ctx *ctx)
+{
+  if (x509_time_future (&ctx->crt_chain->valid_from))
+    {
+      msg (M_WARN, "WARNING: Your certificate is not yet valid!");
+    }
+
+  if (x509_time_expired (&ctx->crt_chain->valid_to))
+    {
+      msg (M_WARN, "WARNING: Your certificate has expired!");
+    }
+}
+
+void
 tls_ctx_load_dh_params (struct tls_root_ctx *ctx, const char *dh_file,
     const char *dh_inline
     )
-- 
2.5.0


Reply via email to