static char ssl_errstring[256];
-static int ssl_session_timeout = 3600;
+static int ssl_session_timeout = 7200; /* Two hours */
static BOOL client_verify_optional = FALSE;
static BOOL server_verify_optional = FALSE;
}
DEBUG(D_tls) debug_printf("Event-action verify failure overridden "
"(host in tls_try_verify_hosts)\n");
+ tlsp->verify_override = TRUE;
}
X509_free(tlsp->peercert);
tlsp->peercert = old_cert;
}
dn[sizeof(dn)-1] = '\0';
+tlsp->verify_override = FALSE;
if (preverify_ok == 0)
{
uschar * extra = verify_mode ? string_sprintf(" (during %c-verify for [%s])",
}
DEBUG(D_tls) debug_printf("SSL verify failure overridden (host in "
"tls_try_verify_hosts)\n");
+ tlsp->verify_override = TRUE;
}
else if (depth != 0)
tlsp->peercert = X509_dup(cert); /* record failing cert */
return 0; /* reject */
}
- DEBUG(D_tls) debug_printf("SSL verify failure overridden (host in "
+ DEBUG(D_tls) debug_printf("SSL verify name failure overridden (host in "
"tls_try_verify_hosts)\n");
+ tlsp->verify_override = TRUE;
}
}
DEBUG(D_tls) debug_printf("SSL%s verify ok: depth=0 SN=%s\n",
*calledp ? "" : " authenticated", dn);
- if (!*calledp) tlsp->certificate_verified = TRUE;
*calledp = TRUE;
}
if (preverify_ok == 1)
{
- tls_out.dane_verified = tls_out.certificate_verified = TRUE;
+ tls_out.dane_verified = TRUE;
#ifndef DISABLE_OCSP
if (client_static_cbinfo->u_ocsp.client.verify_store)
{ /* client, wanting stapling */
EVP_DecryptInit_ex(ctx, key->aes_cipher, NULL, key->aes_key, iv);
DEBUG(D_tls) debug_printf("ticket usable, STEK expire %ld\n", key->expire - now);
+
+ /* The ticket lifetime and renewal are the same as the STEK lifetime and
+ renewal, which is overenthusiastic. A factor of, say, 3x longer STEK would
+ be better. To do that we'd have to encode ticket lifetime in the name as
+ we don't yet see the restored session. Could check posthandshake for TLS1.3
+ and trigger a new ticket then, but cannot do that for TLS1.2 */
return key->renew < now ? 2 : 1;
}
}
return cbinfo->u_ocsp.client.verify_required ? 0 : 1;
}
-if(!(rsp = d2i_OCSP_RESPONSE(NULL, &p, len)))
- {
- tls_out.ocsp = OCSP_FAILED;
+if (!(rsp = d2i_OCSP_RESPONSE(NULL, &p, len)))
+ {
+ tls_out.ocsp = OCSP_FAILED; /*XXX should use tlsp-> to permit concurrent outbound */
if (LOGGING(tls_cipher))
log_write(0, LOG_MAIN, "Received TLS cert status response, parse error");
else
DEBUG(D_tls) debug_printf(" parse error\n");
return 0;
- }
+ }
-if(!(bs = OCSP_response_get1_basic(rsp)))
+if (!(bs = OCSP_response_get1_basic(rsp)))
{
tls_out.ocsp = OCSP_FAILED;
if (LOGGING(tls_cipher))
{ DEBUG(D_tls) debug_printf("X509_NAME_oneline() error\n"); }
else
{
- peerdn[siz-1] = '\0';
- tlsp->peerdn = peerdn; /*XXX a static buffer... */
+ int oldpool = store_pool;
+
+ peerdn[siz-1] = '\0'; /* paranoia */
+ store_pool = POOL_PERM;
+ tlsp->peerdn = string_copy(peerdn);
+ store_pool = oldpool;
+
+ /* We used to set CV in the cert-verify callbacks (either plain or dane)
+ but they don't get called on session-resumption. So use the official
+ interface, which uses the resumed value. Unfortunately this claims verified
+ when it actually failed but we're in try-verify mode, due to us wanting the
+ knowlege that it failed so needing to have the callback and forcing a
+ permissive return. If we don't force it, the TLS startup is failed.
+ The extra bit of information is set in verify_override in the cb, stashed
+ for resumption next to the TLS session, and used here. */
+
+ if (!tlsp->verify_override)
+ tlsp->certificate_verified = SSL_get_verify_result(ssl) == X509_V_OK;
}
}
#ifdef EXIM_HAVE_SESSION_TICKET
{
SSL_SESSION * ss = SSL_get_session(server_ssl);
- if (SSL_SESSION_has_ticket(ss))
+ if (SSL_SESSION_has_ticket(ss)) /* 1.1.0 */
debug_printf("The session has a ticket, life %lu seconds\n",
SSL_SESSION_get_ticket_lifetime_hint(ss));
}
debug_printf("decoding session: %s\n", ssl_errstring);
}
}
+#ifdef EXIM_HAVE_SESSION_TICKET
+ else if ( SSL_SESSION_get_ticket_lifetime_hint(ss) + dt->time_stamp
+ < time(NULL))
+ {
+ DEBUG(D_tls) debug_printf("session expired\n");
+ dbfn_delete(dbm_file, key);
+ }
+#endif
else if (!SSL_set_session(ssl, ss))
{
DEBUG(D_tls)
{
DEBUG(D_tls) debug_printf("good session\n");
tlsp->resumption |= RESUME_CLIENT_SUGGESTED;
+ tlsp->verify_override = dt->verify_override;
+ tlsp->ocsp = dt->ocsp;
}
}
else
if (!cbinfo || !(tlsp = cbinfo->tlsp)->host_resumable) return 0;
-# ifdef EXIM_HAVE_SESSION_TICKET
-
-if (SSL_SESSION_is_resumable(ss))
+# ifdef OPENSSL_HAVE_NUM_TICKETS
+if (SSL_SESSION_is_resumable(ss)) /* 1.1.1 */
+# endif
{
int len = i2d_SSL_SESSION(ss, NULL);
int dlen = sizeof(dbdata_tls_session) + len;
DEBUG(D_tls) debug_printf("session is resumable\n");
tlsp->resumption |= RESUME_SERVER_TICKET; /* server gave us a ticket */
- len = i2d_SSL_SESSION(ss, &s); /* s gets bumped to end */
+ dt->verify_override = tlsp->verify_override;
+ dt->ocsp = tlsp->ocsp;
+ (void) i2d_SSL_SESSION(ss, &s); /* s gets bumped to end */
if ((dbm_file = dbfn_open(US"tls", O_RDWR, &dbblock, FALSE, FALSE)))
{
(unsigned)dlen);
}
}
-# endif
return 1;
}
}
SSL_set_session_id_context(exim_client_ctx->ssl, sid_ctx, Ustrlen(sid_ctx));
-#ifdef EXPERIMENTAL_TLS_RESUME
-if (!tls_client_ssl_resume_prehandshake(exim_client_ctx->ssl, tlsp, host,
- errstr))
- return FALSE;
-#endif
-
SSL_set_fd(exim_client_ctx->ssl, cctx->sock);
SSL_set_connect_state(exim_client_ctx->ssl);
}
#endif
+#ifdef EXPERIMENTAL_TLS_RESUME
+if (!tls_client_ssl_resume_prehandshake(exim_client_ctx->ssl, tlsp, host,
+ errstr))
+ return FALSE;
+#endif
+
#ifndef DISABLE_EVENT
client_static_cbinfo->event_action = tb ? tb->event_action : NULL;
#endif
if ((more || corked))
{
-#ifdef EXPERIMENTAL_PIPE_CONNECT
+#ifdef SUPPORT_PIPE_CONNECT
int save_pool = store_pool;
store_pool = POOL_PERM;
#endif
corked = string_catn(corked, buff, len);
-#ifdef EXPERIMENTAL_PIPE_CONNECT
+#ifdef SUPPORT_PIPE_CONNECT
store_pool = save_pool;
#endif