[exim-cvs] OpenSSL: full-chain OCSP stapling. Bug 1466

Top Page
Delete this message
Reply to this message
Author: Exim Git Commits Mailing List
Date:  
To: exim-cvs
Subject: [exim-cvs] OpenSSL: full-chain OCSP stapling. Bug 1466
Gitweb: https://git.exim.org/exim.git/commitdiff/86ede124f0ce622b4f73e05504abc11fece021e3
Commit:     86ede124f0ce622b4f73e05504abc11fece021e3
Parent:     6f47da8d2d526953e8e6403f448d1598c9140df1
Author:     Jeremy Harris <jgh146exb@???>
AuthorDate: Thu Oct 17 21:45:32 2019 +0100
Committer:  Jeremy Harris <jgh146exb@???>
CommitDate: Thu Oct 17 21:45:32 2019 +0100


    OpenSSL: full-chain OCSP stapling.  Bug 1466
---
 doc/doc-docbook/spec.xfpt                          |  20 ++-
 doc/doc-txt/NewStuff                               |   2 +-
 src/src/environment.c                              |   1 -
 src/src/tls-gnu.c                                  |  11 +-
 src/src/tls-openssl.c                              | 150 ++++++++++++++-------
 src/src/tls.c                                      |   2 +-
 .../server1.example.com/fullchain.ocsp.resp.pem    |  52 +++++++
 test/aux-fixed/exim-ca/genall                      |  27 ++--
 test/confs/5615                                    |   1 +
 test/confs/5655                                    |  35 +++--
 test/log/{5655 => 5615}                            |  17 +--
 test/log/5655                                      |   3 -
 test/scripts/5615-OCSP-OpenSSL-1.3/5615            |  54 ++++++++
 test/scripts/5615-OCSP-OpenSSL-1.3/REQUIRES        |   4 +
 test/scripts/5655-OCSP-GnuTLS-1.3/5655             |   4 +-
 test/src/server.c                                  |   3 +-
 16 files changed, 270 insertions(+), 116 deletions(-)


diff --git a/doc/doc-docbook/spec.xfpt b/doc/doc-docbook/spec.xfpt
index bb19e39..6cfe0bf 100644
--- a/doc/doc-docbook/spec.xfpt
+++ b/doc/doc-docbook/spec.xfpt
@@ -16459,6 +16459,8 @@ and from which pipeline early-connection (before MAIL) SMTP
commands are acceptable.
When used, the pipelining saves on roundtrip times.

+See also the &%hosts_pipe_connect%& smtp transport option.
+
Currently the option name &"X_PIPE_CONNECT"& is used.
.wen

@@ -17848,12 +17850,20 @@ The ordering of the two lists must match.

.new
The file(s) should be in DER format,
-except for GnuTLS 3.6.3 or later when an optional filetype prefix
-can be used. The prefix must be one of "DER" or "PEM", followed by
+except for GnuTLS 3.6.3 or later
+or for OpenSSL,
+when an optional filetype prefix can be used.
+The prefix must be one of "DER" or "PEM", followed by
a single space. If one is used it sets the format for subsequent
files in the list; the initial format is DER.
-When a PEM format file is used it may contain multiple proofs,
-for multiple certificate chain element proofs under TLS1.3.
+If multiple proofs are wanted, for multiple chain elements
+(this only works under TLS1.3)
+they must be coded as a combined OCSP response.
+
+Although GnuTLS will accept PEM files with multiple separate
+PEM blobs (ie. separate OCSP responses), it sends them in the
+TLS Certificate record interleaved with the certificates of the chain;
+although a GnuTLS client is happy with that, an OpenSSL client is not.
.wen

.option tls_on_connect_ports main "string list" unset
@@ -24740,6 +24750,8 @@ When used, the pipelining saves on roundtrip times.
It also turns SMTP into a client-first protocol
so combines well with TCP Fast Open.

+See also the &%pipelining_connect_advertise_hosts%& main option.
+
Note:
When the facility is used, the transport &%helo_data%& option
will be expanded before the &$sending_ip_address$& variable
diff --git a/doc/doc-txt/NewStuff b/doc/doc-txt/NewStuff
index 4ca28bb..7317696 100644
--- a/doc/doc-txt/NewStuff
+++ b/doc/doc-txt/NewStuff
@@ -35,7 +35,7 @@ Version 4.93

11. Main options for DKIM verify to filter hash and key types.

-12. Under GnuTLS, with TLS1.3, support for full-chain OCSP stapling.
+12. With TLS1.3, support for full-chain OCSP stapling.

13. Dual-certificate stacks on servers now support OCSP stapling, under OpenSSL.

diff --git a/src/src/environment.c b/src/src/environment.c
index cef82df..9cb90c8 100644
--- a/src/src/environment.c
+++ b/src/src/environment.c
@@ -67,7 +67,6 @@ if (add_environment)
uschar * p;
int sep = 0;
const uschar * envlist = add_environment;
- int old_pool = store_pool;

   while ((p = string_nextinlist(&envlist, &sep, NULL, 0)))
     {
diff --git a/src/src/tls-gnu.c b/src/src/tls-gnu.c
index deeb042..03e704e 100644
--- a/src/src/tls-gnu.c
+++ b/src/src/tls-gnu.c
@@ -2258,17 +2258,17 @@ post_handshake_debug(exim_gnutls_state_st * state)
 #ifdef SUPPORT_GNUTLS_SESS_DESC
 debug_printf("%s\n", gnutls_session_get_desc(state->session));
 #endif
-#ifdef SUPPORT_GNUTLS_KEYLOG


+#ifdef SUPPORT_GNUTLS_KEYLOG
 # ifdef EXIM_HAVE_TLS1_3
 if (gnutls_protocol_get_version(state->session) < GNUTLS_TLS1_3)
-#else
+# else
 if (TRUE)
-#endif
+# endif
   {
   gnutls_datum_t c, s;
   gstring * gc, * gs;
-  /* we only want the client random and the master secret */
+  /* For TLS1.2 we only want the client random and the master secret */
   gnutls_session_get_random(state->session, &c, &s);
   gnutls_session_get_master_secret(state->session, &s);
   gc = ddump(&c);
@@ -2281,7 +2281,8 @@ else
     " add SSLKEYLOGFILE to keep_environment in the exim config\n"
     " run exim as root\n"
     " if using sudo, add SSLKEYLOGFILE to env_keep in /etc/sudoers\n"
-    " (works for TLS1.2 also, and saves cut-paste into file)\n");
+    " (works for TLS1.2 also, and saves cut-paste into file)"
+    " Trying to use add_environment for this will not work\n");
 #endif
 }


diff --git a/src/src/tls-openssl.c b/src/src/tls-openssl.c
index 67a35d4..7a625a8 100644
--- a/src/src/tls-openssl.c
+++ b/src/src/tls-openssl.c
@@ -1206,12 +1206,13 @@ Arguments:
   sctx            the SSL_CTX* to update
   cbinfo          various parts of session state
   filename        the filename putatively holding an OCSP response
+  is_pem      file is PEM format; otherwise is DER


*/

static void
ocsp_load_response(SSL_CTX * sctx, tls_ext_ctx_cb * cbinfo,
- const uschar * filename)
+ const uschar * filename, BOOL is_pem)
{
BIO * bio;
OCSP_RESPONSE * resp;
@@ -1222,7 +1223,8 @@ STACK_OF(X509) * sk;
unsigned long verify_flags;
int status, reason, i;

-DEBUG(D_tls) debug_printf("tls_ocsp_file        '%s'\n", filename);
+DEBUG(D_tls)
+  debug_printf("tls_ocsp_file (%s)  '%s'\n", is_pem ? "PEM" : "DER", filename);


if (!(bio = BIO_new_file(CS filename, "rb")))
{
@@ -1231,8 +1233,26 @@ if (!(bio = BIO_new_file(CS filename, "rb")))
return;
}

-resp = d2i_OCSP_RESPONSE_bio(bio, NULL);
+if (is_pem)
+  {
+  uschar * data, * freep;
+  char * dummy;
+  long len;
+  if (!PEM_read_bio(bio, &dummy, &dummy, &data, &len))
+    {
+    DEBUG(D_tls) debug_printf("Failed to read PEM file \"%s\"\n",
+    filename);
+    return;
+    }
+debug_printf("read pem file\n");
+  freep = data;
+  resp = d2i_OCSP_RESPONSE(NULL, CUSS &data, len);
+  OPENSSL_free(freep);
+  }
+else
+  resp = d2i_OCSP_RESPONSE_bio(bio, NULL);
 BIO_free(bio);
+
 if (!resp)
   {
   DEBUG(D_tls) debug_printf("Error reading OCSP response.\n");
@@ -1518,6 +1538,7 @@ else
       const uschar * olist = cbinfo->u_ocsp.server.file;
       int osep = 0;
       uschar * ofile;
+      BOOL fmt_pem = FALSE;


       if (olist)
     if (!expand_check(olist, US"tls_ocsp_file", USS &olist, errstr))
@@ -1546,7 +1567,19 @@ else
 #ifndef DISABLE_OCSP
     if (olist)
       if ((ofile = string_nextinlist(&olist, &osep, NULL, 0)))
-        ocsp_load_response(sctx, cbinfo, ofile);
+        {
+        if (Ustrncmp(ofile, US"PEM ", 4) == 0)
+          {
+          fmt_pem = TRUE;
+          ofile += 4;
+          }
+        else if (Ustrncmp(ofile, US"DER ", 4) == 0)
+          {
+          fmt_pem = FALSE;
+          ofile += 4;
+          }
+        ocsp_load_response(sctx, cbinfo, ofile, fmt_pem);
+        }
       else
         DEBUG(D_tls) debug_printf("ran out of ocsp file list\n");
 #endif
@@ -1808,7 +1841,7 @@ OCSP_RESPONSE * rsp;
 OCSP_BASICRESP * bs;
 int i;


-DEBUG(D_tls) debug_printf("Received TLS status response (OCSP stapling):");
+DEBUG(D_tls) debug_printf("Received TLS status response (OCSP stapling):\n");
 len = SSL_get_tlsext_status_ocsp_resp(s, &p);
 if(!p)
  {
@@ -1850,8 +1883,9 @@ if (!(bs = OCSP_response_get1_basic(rsp)))
 */
   {
     BIO * bp = NULL;
-    int status, reason;
-    ASN1_GENERALIZEDTIME *rev, *thisupd, *nextupd;
+#ifndef EXIM_HAVE_OCSP_RESP_COUNT
+    STACK_OF(OCSP_SINGLERESP) * sresp = bs->tbsResponseData->responses;
+#endif


     DEBUG(D_tls) bp = BIO_new_fp(debug_file, BIO_NOCLOSE);


@@ -1861,19 +1895,23 @@ if (!(bs = OCSP_response_get1_basic(rsp)))
     /* DEBUG(D_tls) x509_store_dump_cert_s_names(cbinfo->u_ocsp.client.verify_store); */


     if ((i = OCSP_basic_verify(bs, cbinfo->verify_stack,
-          cbinfo->u_ocsp.client.verify_store, 0)) <= 0)
-      {
-      tls_out.ocsp = OCSP_FAILED;
-      if (LOGGING(tls_cipher)) log_write(0, LOG_MAIN,
-          "Received TLS cert status response, itself unverifiable: %s",
-          ERR_reason_error_string(ERR_peek_error()));
-      BIO_printf(bp, "OCSP response verify failure\n");
-      ERR_print_errors(bp);
-      OCSP_RESPONSE_print(bp, rsp, 0);
-      goto failed;
-      }
+          cbinfo->u_ocsp.client.verify_store, OCSP_NOEXPLICIT)) <= 0)
+      if (ERR_peek_error())
+    {
+    tls_out.ocsp = OCSP_FAILED;
+    if (LOGGING(tls_cipher)) log_write(0, LOG_MAIN,
+        "Received TLS cert status response, itself unverifiable: %s",
+        ERR_reason_error_string(ERR_peek_error()));
+    BIO_printf(bp, "OCSP response verify failure\n");
+    ERR_print_errors(bp);
+    OCSP_RESPONSE_print(bp, rsp, 0);
+    goto failed;
+    }
+      else
+    DEBUG(D_tls) debug_printf("no explicit trust for OCSP signing"
+      " in the root CA certificate; ignoring\n");


-    BIO_printf(bp, "OCSP response well-formed and signed OK\n");
+    DEBUG(D_tls) debug_printf("OCSP response well-formed and signed OK\n");


     /*XXX So we have a good stapled OCSP status.  How do we know
     it is for the cert of interest?  OpenSSL 1.1.0 has a routine
@@ -1883,60 +1921,65 @@ if (!(bs = OCSP_response_get1_basic(rsp)))


     For now, carry on blindly accepting the resp. */


-      {
-      OCSP_SINGLERESP * single;
-
+    for (int idx =
 #ifdef EXIM_HAVE_OCSP_RESP_COUNT
-      if (OCSP_resp_count(bs) != 1)
+        OCSP_resp_count(bs) - 1;
 #else
-      STACK_OF(OCSP_SINGLERESP) * sresp = bs->tbsResponseData->responses;
-      if (sk_OCSP_SINGLERESP_num(sresp) != 1)
+        sk_OCSP_SINGLERESP_num(sresp) - 1;
 #endif
-        {
-    tls_out.ocsp = OCSP_FAILED;
-        log_write(0, LOG_MAIN, "OCSP stapling "
-        "with multiple responses not handled");
-        goto failed;
-        }
-      single = OCSP_resp_get0(bs, 0);
+     idx >= 0; idx--)
+      {
+      OCSP_SINGLERESP * single = OCSP_resp_get0(bs, idx);
+      int status, reason;
+      ASN1_GENERALIZEDTIME * rev, * thisupd, * nextupd;
+
+  /*XXX so I can see putting a loop in here to handle a rsp with >1 singleresp
+  - but what happens with a GnuTLS-style input?
+
+  we could do with a debug label for each singleresp
+  - it has a certID with a serialNumber, but I see no API to get that
+  */
       status = OCSP_single_get0_status(single, &reason, &rev,
           &thisupd, &nextupd);
-      }


-    DEBUG(D_tls) time_print(bp, "This OCSP Update", thisupd);
-    DEBUG(D_tls) if(nextupd) time_print(bp, "Next OCSP Update", nextupd);
-    if (!OCSP_check_validity(thisupd, nextupd,
-      EXIM_OCSP_SKEW_SECONDS, EXIM_OCSP_MAX_AGE))
-      {
-      tls_out.ocsp = OCSP_FAILED;
-      DEBUG(D_tls) ERR_print_errors(bp);
-      log_write(0, LOG_MAIN, "Server OSCP dates invalid");
-      }
-    else
-      {
+      DEBUG(D_tls) time_print(bp, "This OCSP Update", thisupd);
+      DEBUG(D_tls) if(nextupd) time_print(bp, "Next OCSP Update", nextupd);
+      if (!OCSP_check_validity(thisupd, nextupd,
+        EXIM_OCSP_SKEW_SECONDS, EXIM_OCSP_MAX_AGE))
+    {
+    tls_out.ocsp = OCSP_FAILED;
+    DEBUG(D_tls) ERR_print_errors(bp);
+    log_write(0, LOG_MAIN, "Server OSCP dates invalid");
+    goto failed;
+    }
+
       DEBUG(D_tls) BIO_printf(bp, "Certificate status: %s\n",
             OCSP_cert_status_str(status));
       switch(status)
     {
     case V_OCSP_CERTSTATUS_GOOD:
-      tls_out.ocsp = OCSP_VFIED;
-      i = 1;
-      goto good;
+      continue;    /* the idx loop */
     case V_OCSP_CERTSTATUS_REVOKED:
-      tls_out.ocsp = OCSP_FAILED;
       log_write(0, LOG_MAIN, "Server certificate revoked%s%s",
           reason != -1 ? "; reason: " : "",
           reason != -1 ? OCSP_crl_reason_str(reason) : "");
       DEBUG(D_tls) time_print(bp, "Revocation Time", rev);
       break;
     default:
-      tls_out.ocsp = OCSP_FAILED;
       log_write(0, LOG_MAIN,
           "Server certificate status unknown, in OCSP stapling");
       break;
     }
+
+      goto failed;
       }
+
+    i = 1;
+    tls_out.ocsp = OCSP_VFIED;
+    goto good;
+
   failed:
+    tls_out.ocsp = OCSP_FAILED;
     i = cbinfo->u_ocsp.client.verify_required ? 0 : 1;
   good:
     BIO_free(bp);
@@ -3904,7 +3947,7 @@ BOOL
 tls_openssl_options_parse(uschar *option_spec, long *results)
 {
 long result, item;
-uschar *end;
+uschar * exp, * end;
 uschar keep_c;
 BOOL adding, item_parsed;


@@ -3912,7 +3955,7 @@ BOOL adding, item_parsed;
result = SSL_OP_NO_TICKET;

/* Prior to 4.80 we or'd in SSL_OP_DONT_INSERT_EMPTY_FRAGMENTS; removed
- * from default because it increases BEAST susceptibility. */
+from default because it increases BEAST susceptibility. */
#ifdef SSL_OP_NO_SSLv2
result |= SSL_OP_NO_SSLv2;
#endif
@@ -3929,7 +3972,10 @@ if (!option_spec)
return TRUE;
}

-for (uschar * s = option_spec; *s; /**/)
+if (!expand_check(option_spec, US"openssl_options", &exp, &end))
+  return FALSE;
+
+for (uschar * s = exp; *s; /**/)
   {
   while (isspace(*s)) ++s;
   if (*s == '\0')
diff --git a/src/src/tls.c b/src/src/tls.c
index 9c587e5..a541a3c 100644
--- a/src/src/tls.c
+++ b/src/src/tls.c
@@ -399,7 +399,7 @@ if (path)
   else if (Ustrncmp(path, spool_directory, Ustrlen(spool_directory)) != 0)
     {
     DEBUG(D_tls)
-      debug_printf("removing env SSLKEYLOGFILE: not under spooldir\n");
+      debug_printf("removing env SSLKEYLOGFILE=%s: not under spooldir\n", path);
     unsetenv("SSLKEYLOGFILE");
     }
 }
diff --git a/test/aux-fixed/exim-ca/example.com/server1.example.com/fullchain.ocsp.resp.pem b/test/aux-fixed/exim-ca/example.com/server1.example.com/fullchain.ocsp.resp.pem
new file mode 100644
index 0000000..9667e06
--- /dev/null
+++ b/test/aux-fixed/exim-ca/example.com/server1.example.com/fullchain.ocsp.resp.pem
@@ -0,0 +1,52 @@
+OCSP Response Information:
+    Response Status: Successful
+    Response Type: Basic OCSP Response
+    Version: 1
+    Responder ID: CN=clica CA rsa,O=example.com
+    Produced At: Thu Oct 10 20:08:22 UTC 2019
+    Responses:
+        Certificate ID:
+            Hash Algorithm: SHA256
+            Issuer Name Hash: 5af082e51d62fe01fd706baebeb878db64e68f76e74a36f36d914297ddee24b8
+            Issuer Key Hash: 333db14364b98e78a33dd8a4fae8d8378ea9b0f5fbca97b25685aa0d32116091
+            Serial Number: 65
+        Certificate Status: good
+        This Update: Thu Oct 10 20:08:22 UTC 2019
+        Next Update: Tue Oct 09 20:08:22 UTC 2029
+        Certificate ID:
+            Hash Algorithm: SHA256
+            Issuer Name Hash: bfa7275a566efd4be2df82dbd9d1290d470186f6ff2acd8c16659f342ab56109
+            Issuer Key Hash: 208f9d28c7c0bc914144dfa8c0be3d5b3bfcebb622c8a8dc27e865fc06ca0e12
+            Serial Number: 42
+        Certificate Status: good
+        This Update: Thu Oct 10 20:08:22 UTC 2019
+        Next Update: Tue Oct 09 20:08:22 UTC 2029
+        Certificate ID:
+            Hash Algorithm: SHA256
+            Issuer Name Hash: bfa7275a566efd4be2df82dbd9d1290d470186f6ff2acd8c16659f342ab56109
+            Issuer Key Hash: 208f9d28c7c0bc914144dfa8c0be3d5b3bfcebb622c8a8dc27e865fc06ca0e12
+            Serial Number: 41
+        Certificate Status: good
+        This Update: Thu Oct 10 20:08:22 UTC 2019
+        Next Update: Tue Oct 09 20:08:22 UTC 2029
+    Extensions:
+    Signature Algorithm: RSA-SHA256
+
+-----BEGIN OCSP RESPONSE-----
+MIIC/AoBAKCCAvUwggLxBgkrBgEFBQcwAQEEggLiMIIC3jCCAcahLzAtMRQwEgYD
+VQQKEwtleGFtcGxlLmNvbTEVMBMGA1UEAxMMY2xpY2EgQ0EgcnNhGA8yMDE5MTAx
+MDIwMDgyMlowggGAMH4wVjANBglghkgBZQMEAgEFAAQgWvCC5R1i/gH9cGuuvrh4
+22Tmj3bnSjbzbZFCl93uJLgEIDM9sUNkuY54oz3YpPro2DeOqbD1+8qXslaFqg0y
+EWCRAgFlgAAYDzIwMTkxMDEwMjAwODIyWqARGA8yMDI5MTAwOTIwMDgyMlowfjBW
+MA0GCWCGSAFlAwQCAQUABCC/pydaVm79S+LfgtvZ0SkNRwGG9v8qzYwWZZ80KrVh
+CQQgII+dKMfAvJFBRN+owL49Wzv867YiyKjcJ+hl/AbKDhICAUKAABgPMjAxOTEw
+MTAyMDA4MjJaoBEYDzIwMjkxMDA5MjAwODIyWjB+MFYwDQYJYIZIAWUDBAIBBQAE
+IL+nJ1pWbv1L4t+C29nRKQ1HAYb2/yrNjBZlnzQqtWEJBCAgj50ox8C8kUFE36jA
+vj1bO/zrtiLIqNwn6GX8BsoOEgIBQYAAGA8yMDE5MTAxMDIwMDgyMlqgERgPMjAy
+OTEwMDkyMDA4MjJaMA0GCSqGSIb3DQEBCwUAA4IBAQBm8uLIawRny88oLSzr7sxj
+IgGjhC+S2OXWjAlTxErHoEsJ0JPKkQAt/s5YLy4IKiPbCg6CIm9KotgE4vnpMFjg
+297pSrdYKdtb2iBPKq5afB2Iv6ET78L/j2HhBFyJaxlt6lhI0Ly6JE75IbUrdP24
+c5uIh+KpJaC60bTZehgcRnrw9fR7HJ5W9ln9mbOZDggNQeM9hmFLUmQYPQWxav2x
+IjCYAZOfIp8ficETnLhuDuILsohFRnQnFAaf1YTgvW2zoKLMeLUWzMm8a6IoBpXQ
+0ecpPJs2FFiaYL78EcRNN47YbClcfDQRAjTvlSZupk59YuxedlwiH6uc7Cwa3RnN
+-----END OCSP RESPONSE-----
diff --git a/test/aux-fixed/exim-ca/genall b/test/aux-fixed/exim-ca/genall
index 8efda88..6998108 100755
--- a/test/aux-fixed/exim-ca/genall
+++ b/test/aux-fixed/exim-ca/genall
@@ -75,12 +75,6 @@ do


####

- # so, for full-chain OCSP we sill want an OCSP resp for the Signer cert and also (?) one for the
- # CA cert itself.  The existing bits below only create for the leaf certs, next layer down.
- #
- # First test will be just adding OCSP for the Signer cert. Presumably we could use the CA cert
- # to sign that.
-
     # create OCSP reqs & resps
     CADIR=$idir/CA


@@ -160,11 +154,11 @@ EOF
     done


     # convert one good leaf-resp to PEM
-    $server=server1
+    server=server1
     RESP=$idir/$server.$iname/$server.$iname.ocsp.signernocert.good.resp
     ocsptool -S $RESP -j > $RESP.pem


-    # Then, ocsp request and responses for the signer cert
+    # Then, ocsp request and (valid, revoked) responses for the signer cert
     REQ=$CADIR/Signer.ocsp.req
     RESP=$CADIR/Signer.ocsp.signernocert.good.resp
     openssl ocsp -issuer $CADIR/CA.pem -sha256 -cert $CADIR/Signer.pem -no_nonce -reqout $REQ
@@ -177,11 +171,18 @@ EOF
     -ndays 3652 -reqin $REQ -respout $RESP
     ocsptool -S $RESP -j > $RESP.pem


-    # Then, ocsp request and response for the CA cert
-    REQ=$CADIR/CA.ocsp.req
-    RESP=$CADIR/CA.ocsp.signernocert.good.resp
-    openssl ocsp -issuer $CADIR/CA.pem -sha256 -cert $CADIR/CA.pem -no_nonce -reqout $REQ
-    openssl ocsp $IVALID -rsigner $CADIR/CA.pem -rkey $CADIR/CA.key -CA $CADIR/CA.pem -resp_no_certs -noverify \
+    # Finally, a full-chain all-good request and response
+    REQ=$idir/$server.$iname/fullchain.ocsp.req
+    leafcert=$idir/$server.$iname/$server.$iname.pem
+    signercert=$CADIR/Signer.pem
+    cacert=$CADIR/CA.pem
+    openssl ocsp -sha256 -no_nonce -reqout $REQ \
+        -issuer $signercert -cert $leafcert \
+        -issuer $cacert     -cert $CADIR/Signer.pem -cert $CADIR/CA.pem
+
+    RESP=$idir/$server.$iname/fullchain.ocsp.resp
+    authorities=$idir/$server.$iname/ca_chain.pem
+    openssl ocsp $IVALID -rsigner $CADIR/CA.pem -rkey $CADIR/CA.key -CA $authorities -resp_no_certs -noverify \
     -ndays 3652 -reqin $REQ -respout $RESP
     ocsptool -S $RESP -j > $RESP.pem


diff --git a/test/confs/5615 b/test/confs/5615
new file mode 120000
index 0000000..36c91e7
--- /dev/null
+++ b/test/confs/5615
@@ -0,0 +1 @@
+5655
\ No newline at end of file
diff --git a/test/confs/5655 b/test/confs/5655
index 0f6fe1b..6fbd7c1 100644
--- a/test/confs/5655
+++ b/test/confs/5655
@@ -1,5 +1,5 @@
# Exim test configuration 5655
-# OCSP stapling, server, multiple chain-element OCSP
+# OCSP stapling, server, multiple chain-element OCSP. Both GnuTLS and OpenSSL.

.include DIR/aux-var/tls_conf_prefix

@@ -7,7 +7,6 @@ primary_hostname = server1.example.com

# ----- Main settings -----

-acl_smtp_connect = accept logwrite = ${env {SSLKEYLOGFILE}}
acl_smtp_mail = check_mail
acl_smtp_rcpt = check_recipient

@@ -22,23 +21,24 @@ CADIR = DIR/aux-fixed/exim-ca
DRSA = CADIR/example.com
DECDSA = CADIR/example_ec.com

-tls_certificate = DRSA/server1.example.com/fullchain.pem \
-          : DECDSA/server1.example_ec.com/server1.example_ec.com.pem
-tls_privatekey =  DRSA/server1.example.com/server1.example.com.unlocked.key \
-          : DECDSA/server1.example_ec.com/server1.example_ec.com.unlocked.key
+tls_certificate = DRSA/server1.example.com/fullchain.pem
+tls_privatekey =  DRSA/server1.example.com/server1.example.com.unlocked.key


 .ifndef CONTROL
-tls_ocsp_file =   PEM DIR/tmp/ocsp/triple.ocsp.pem \
-          : DER DECDSA/server1.example_ec.com/server1.example_ec.com.ocsp.good.resp
+tls_ocsp_file =   PEM DRSA/server1.example.com/fullchain.ocsp.resp.pem
 .else
-tls_ocsp_file =   PEM DIR/tmp/ocsp/double_r.ocsp.pem \
-          : DER DECDSA/server1.example_ec.com/server1.example_ec.com.ocsp.good.resp
+tls_ocsp_file =   PEM DIR/tmp/ocsp/double_r.ocsp.pem
 .endif



.ifdef _HAVE_GNUTLS
tls_require_ciphers = ${if eq {LIMIT}{TLS1.2} {NORMAL:!VERS-ALL:+VERS-TLS1.2} {}}
.endif
+.ifdef _HAVE_OPENSSL
+.ifdef LIMIT
+openssl_options = ${if eq {LIMIT}{TLS1.2} {+no_tlsv1_3} {}}
+.endif
+.endif

# ------ ACL ------

@@ -79,21 +79,18 @@ remote_delivery:
   driver =            smtp
   port =            PORT_D
   hosts_require_tls =        *
-.ifdef _HAVE_GNUTLS


+.ifdef _HAVE_GNUTLS
   tls_require_ciphers =        ${if eq {LIMIT}{TLS1.2} \
                   {NONE:\
-                    ${if eq {OPT}{rsa} \
-                      {+SIGN-RSA-SHA256:+VERS-TLS-ALL:+ECDHE-RSA:+DHE-RSA:+RSA} \
-                      {+SIGN-ECDSA-SHA512:+VERS-TLS-ALL:+KX-ALL}}\
+                      +SIGN-RSA-SHA256:+VERS-TLS-ALL:+ECDHE-RSA:+DHE-RSA:+RSA\
                   :+CIPHER-ALL:+MAC-ALL:+COMP-NULL:+CURVE-ALL:+CTYPE-X509} \
                   {}}
-  tls_verify_certificates =    CADIR/\
-                  ${if eq {OPT}{rsa} \
-                    {example.com/server1.example.com} \
-                    {example_ec.com/server1.example_ec.com}}\
-                /ca_chain.pem
 .endif
+.ifdef _HAVE_OPENSSL
+  tls_require_ciphers =        RSA
+.endif
+  tls_verify_certificates =    CADIR/example.com/server1.example.com/ca_chain.pem
   hosts_require_ocsp =        *
   tls_verify_cert_hostnames =    :


diff --git a/test/log/5655 b/test/log/5615
similarity index 55%
copy from test/log/5655
copy to test/log/5615
index 9275ad1..314fd91 100644
--- a/test/log/5655
+++ b/test/log/5615
@@ -1,27 +1,16 @@
1999-03-02 09:44:33 1: TLS1.2 Server sends good leaf-staple on request, to client requiring RSA auth
1999-03-02 09:44:33 10HmaX-0005vi-00 <= CALLER@??? U=CALLER P=local S=sss
-1999-03-02 09:44:33 10HmaX-0005vi-00 => rsa.auth@??? R=client T=remote_delivery H=127.0.0.1 [127.0.0.1] X=TLS1.x:ke-RSA-AES256-SHAnnn:xxx CV=yes DN="CN=server1.example.com" C="250 OK id=10HmaY-0005vi-00"
+1999-03-02 09:44:33 10HmaX-0005vi-00 => rsa.auth@??? R=client T=remote_delivery H=127.0.0.1 [127.0.0.1] X=TLS1.x:ke-RSA-AES256-SHAnnn:xxx CV=yes DN="/CN=server1.example.com" C="250 OK id=10HmaY-0005vi-00"
1999-03-02 09:44:33 10HmaX-0005vi-00 Completed
1999-03-02 09:44:33 2: TLS1.3 Server sends good 3-element staple on request, to client requiring RSA auth
1999-03-02 09:44:33 10HmaZ-0005vi-00 <= CALLER@??? U=CALLER P=local S=sss
-1999-03-02 09:44:33 10HmaZ-0005vi-00 => rsa.auth@??? R=client T=remote_delivery H=127.0.0.1 [127.0.0.1] X=TLS1.x:ke-RSA-AES256-SHAnnn:xxx CV=yes DN="CN=server1.example.com" C="250 OK id=10HmbA-0005vi-00"
+1999-03-02 09:44:33 10HmaZ-0005vi-00 => rsa.auth@??? R=client T=remote_delivery H=127.0.0.1 [127.0.0.1] X=TLS1.x:ke-RSA-AES256-SHAnnn:xxx CV=yes DN="/CN=server1.example.com" C="250 OK id=10HmbA-0005vi-00"
1999-03-02 09:44:33 10HmaZ-0005vi-00 Completed
-1999-03-02 09:44:33 3: TLS1.3 Server sends bad nonleaf staple, client detects it
-1999-03-02 09:44:33 10HmbB-0005vi-00 <= CALLER@??? U=CALLER P=local S=sss
-1999-03-02 09:44:33 10HmbB-0005vi-00 == rsa.auth@??? R=client T=remote_delivery defer (-37) H=127.0.0.1 [127.0.0.1]: TLS session: (certificate status check failed)
-1999-03-02 09:44:33 10HmbB-0005vi-00 ** rsa.auth@???: retry timeout exceeded
-1999-03-02 09:44:33 10HmbB-0005vi-00 rsa.auth@???: error ignored
-1999-03-02 09:44:33 10HmbB-0005vi-00 Completed

******** SERVER ********
1999-03-02 09:44:33 exim x.yz daemon started: pid=pppp, no queue runs, listening for SMTP on port PORT_D
-1999-03-02 09:44:33 TESTSUITE/spool/sslkeys
1999-03-02 09:44:33 acl_mail: ocsp in status: 4 (verified)
1999-03-02 09:44:33 10HmaY-0005vi-00 <= <> H=localhost (server1.example.com) [127.0.0.1] P=esmtps X=TLS1.x:ke-RSA-AES256-SHAnnn:xxx CV=no S=sss id=E10HmaX-0005vi-00@???
1999-03-02 09:44:33 exim x.yz daemon started: pid=pppp, no queue runs, listening for SMTP on port PORT_D
-1999-03-02 09:44:33 TESTSUITE/spool/sslkeys
-1999-03-02 09:44:33 acl_mail: ocsp in status: 1 (notresp)
+1999-03-02 09:44:33 acl_mail: ocsp in status: 4 (verified)
1999-03-02 09:44:33 10HmbA-0005vi-00 <= <> H=localhost (server1.example.com) [127.0.0.1] P=esmtps X=TLS1.x:ke-RSA-AES256-SHAnnn:xxx CV=no S=sss id=E10HmaZ-0005vi-00@???
-1999-03-02 09:44:33 exim x.yz daemon started: pid=pppp, no queue runs, listening for SMTP on port PORT_D
-1999-03-02 09:44:33 TESTSUITE/spool/sslkeys
-1999-03-02 09:44:33 TLS error on connection from localhost [127.0.0.1] (recv): The TLS connection was non-properly terminated.
diff --git a/test/log/5655 b/test/log/5655
index 9275ad1..9936c85 100644
--- a/test/log/5655
+++ b/test/log/5655
@@ -15,13 +15,10 @@

 ******** SERVER ********
 1999-03-02 09:44:33 exim x.yz daemon started: pid=pppp, no queue runs, listening for SMTP on port PORT_D
-1999-03-02 09:44:33 TESTSUITE/spool/sslkeys
 1999-03-02 09:44:33 acl_mail: ocsp in status: 4 (verified)
 1999-03-02 09:44:33 10HmaY-0005vi-00 <= <> H=localhost (server1.example.com) [127.0.0.1] P=esmtps X=TLS1.x:ke-RSA-AES256-SHAnnn:xxx CV=no S=sss id=E10HmaX-0005vi-00@???
 1999-03-02 09:44:33 exim x.yz daemon started: pid=pppp, no queue runs, listening for SMTP on port PORT_D
-1999-03-02 09:44:33 TESTSUITE/spool/sslkeys
 1999-03-02 09:44:33 acl_mail: ocsp in status: 1 (notresp)
 1999-03-02 09:44:33 10HmbA-0005vi-00 <= <> H=localhost (server1.example.com) [127.0.0.1] P=esmtps X=TLS1.x:ke-RSA-AES256-SHAnnn:xxx CV=no S=sss id=E10HmaZ-0005vi-00@???
 1999-03-02 09:44:33 exim x.yz daemon started: pid=pppp, no queue runs, listening for SMTP on port PORT_D
-1999-03-02 09:44:33 TESTSUITE/spool/sslkeys
 1999-03-02 09:44:33 TLS error on connection from localhost [127.0.0.1] (recv): The TLS connection was non-properly terminated.
diff --git a/test/scripts/5615-OCSP-OpenSSL-1.3/5615 b/test/scripts/5615-OCSP-OpenSSL-1.3/5615
new file mode 100644
index 0000000..17d5f7a
--- /dev/null
+++ b/test/scripts/5615-OCSP-OpenSSL-1.3/5615
@@ -0,0 +1,54 @@
+# OCSP stapling, server, multiple chain-element OCSP
+#
+#
+#
+#
+exim -z '1: TLS1.2 Server sends good leaf-staple on request, to client requiring RSA auth'
+****
+#
+exim -bd -oX PORT_D -DSERVER=server -DLIMIT=TLS1.2
+****
+#
+exim -odf -DOPT=rsa -DLIMIT=TLS1.2 rsa.auth@???
+Subject: test
+
+.
+****
+killdaemon
+#
+#
+exim -z '2: TLS1.3 Server sends good 3-element staple on request, to client requiring RSA auth'
+****
+#
+# Works when the (single) proof file has an ocsp-response with 3 statusses.
+# Contrast with with GnuTLS which can do either that or have 3 proof files
+# each with one status.
+#
+exim -bd -oX PORT_D -DSERVER=server -DLIMIT=TLS1.3
+****
+exim -odf -DOPT=rsa rsa.auth@???
+Subject: test
+
+.
+****
+killdaemon
+#
+##
+##
+#exim -z '3: TLS1.3 Server sends bad nonleaf staple, client detects it'
+#****
+##
+#EXIM_TESTHARNESS_DISABLE_OCSPVALIDITYCHECK=y exim -bd -oX PORT_D -DSERVER=server -DLIMIT=TLS1.3 -DCONTROL=bad
+#****
+#exim -odf -DOPT=rsa rsa.auth@???
+#Subject: test
+#
+#.
+#****
+#killdaemon
+##
+##
+#
+#
+sudo rm -fr tmp/
+no_msglog_check
diff --git a/test/scripts/5615-OCSP-OpenSSL-1.3/REQUIRES b/test/scripts/5615-OCSP-OpenSSL-1.3/REQUIRES
new file mode 100644
index 0000000..7df03fb
--- /dev/null
+++ b/test/scripts/5615-OCSP-OpenSSL-1.3/REQUIRES
@@ -0,0 +1,4 @@
+support OpenSSL
+support OCSP
+running IPv4
+feature _HAVE_TLS1_3
diff --git a/test/scripts/5655-OCSP-GnuTLS-1.3/5655 b/test/scripts/5655-OCSP-GnuTLS-1.3/5655
index 25ebdfd..1df75fb 100644
--- a/test/scripts/5655-OCSP-GnuTLS-1.3/5655
+++ b/test/scripts/5655-OCSP-GnuTLS-1.3/5655
@@ -7,7 +7,6 @@ sudo chown -R EXIMUSER:EXIMGROUP tmp
 sudo chmod -R a+rwx DIR/tmp/ocsp
 perl
 chdir 'aux-fixed/exim-ca/example.com';
-system 'cat server1.example.com/server1.example.com.ocsp.signernocert.good.resp.pem CA/Signer.ocsp.signernocert.good.resp.pem CA/CA.ocsp.signernocert.good.resp.pem > DIR/tmp/ocsp/triple.ocsp.pem';
 system 'cat server1.example.com/server1.example.com.ocsp.signernocert.good.resp.pem CA/Signer.ocsp.signernocert.revoked.resp.pem > DIR/tmp/ocsp/double_r.ocsp.pem';
 ****
 #
@@ -15,7 +14,7 @@ system 'cat server1.example.com/server1.example.com.ocsp.signernocert.good.resp.
 exim -z '1: TLS1.2 Server sends good leaf-staple on request, to client requiring RSA auth'
 ****
 #
-exim -bd -oX PORT_D -DSERVER=server -DLIMIT=TLS1.2
+sudo exim -bd -oX PORT_D -DSERVER=server -DLIMIT=TLS1.2
 ****
 #
 exim -odf -DOPT=rsa -DLIMIT=TLS1.2 rsa.auth@???
@@ -29,6 +28,7 @@ killdaemon
 exim -z '2: TLS1.3 Server sends good 3-element staple on request, to client requiring RSA auth'
 ****
 #
+# Prefix with sudo to get SSLKEYLOGFILE to work.  Only works on the server.
 exim -bd -oX PORT_D -DSERVER=server -DLIMIT=TLS1.3
 ****
 exim -odf -DOPT=rsa rsa.auth@???
diff --git a/test/src/server.c b/test/src/server.c
index 4cf1260..c1f1ecf 100644
--- a/test/src/server.c
+++ b/test/src/server.c
@@ -159,7 +159,8 @@ putchar('\n');
 #define udn 2    /* Unix domain socket number */
 #define skn 2    /* Potential number of sockets */


-int main(int argc, char **argv)
+int
+main(int argc, char **argv)
{
int i;
int port = 0;