From 7c1c8eb3b1d196efdc0c65394c10eb741adf83d1 Mon Sep 17 00:00:00 2001
From: Jeffrey Walton <noloader@gmail.com>
Date: Fri, 22 Feb 2019 12:46:53 +0100
Subject: [PATCH] * src/openssl.c (ssl_init): Trust partial cert chain

---
 src/openssl.c | 29 +++++++++++++++++++++++++++++
 1 file changed, 29 insertions(+)

diff --git a/src/openssl.c b/src/openssl.c
index ec1c82b3..a6fec5b3 100644
--- a/src/openssl.c
+++ b/src/openssl.c
@@ -328,6 +328,35 @@ ssl_init (void)
   SSL_CTX_set_default_verify_paths (ssl_ctx);
   SSL_CTX_load_verify_locations (ssl_ctx, opt.ca_cert, opt.ca_directory);
 
+  /* Set X509_V_FLAG_PARTIAL_CHAIN to allow the client to anchor trust in
+   * a non-self-signed certificate. This defies RFC 4158 (Path Building)
+   * which defines a trust anchor in terms of a self-signed certificate.
+   * However, it substantially reduces attack surface by pruning the tree
+   * of unneeded trust points. For example, the cross-certified
+   * Let's Encrypt X3 CA, which protects gnu.org and appears as an
+   * intermediate CA to clients, can be used as a trust anchor without
+   * the entire IdentTrust PKI.
+   */
+  X509_VERIFY_PARAM *param = X509_VERIFY_PARAM_new();
+  if (param)
+    {
+      /* We only want X509_V_FLAG_PARTIAL_CHAIN, but the OpenSSL docs
+       * say to use X509_V_FLAG_TRUSTED_FIRST also. It looks like
+       * X509_V_FLAG_TRUSTED_FIRST applies to a collection of trust
+       * anchors and not a single trust anchor.
+       */
+      (void) X509_VERIFY_PARAM_set_flags (param, X509_V_FLAG_TRUSTED_FIRST | X509_V_FLAG_PARTIAL_CHAIN);
+      if (SSL_CTX_set1_param (ssl_ctx, param) == 0)
+        logprintf(LOG_NOTQUIET, _("OpenSSL: Failed set trust to partial chain\n"));
+      /* We continue on error */
+      X509_VERIFY_PARAM_free (param);
+    }
+  else
+    {
+      logprintf(LOG_NOTQUIET, _("OpenSSL: Failed to allocate verification param\n"));
+      /* We continue on error */
+    }
+
   if (opt.crl_file)
     {
       X509_STORE *store = SSL_CTX_get_cert_store (ssl_ctx);