* Exim - an Internet mail transport agent *
*************************************************/
-/* Copyright (c) The Exim Maintainers 2020 - 2022 */
+/* Copyright (c) The Exim Maintainers 2020 - 2024 */
/* Copyright (c) University of Cambridge 1995 - 2018 */
/* Copyright (c) Phil Pennock 2012 */
/* See the file NOTICE for conditions of use and distribution. */
const uschar * msg;
uschar * errstr;
+if (rc == GNUTLS_E_INVALID_SESSION && errno == 0)
+ {
+ DEBUG(D_tls) debug_printf("- INVALID_SESSION with zero errno\n");
+ return;
+ }
+
msg = rc == GNUTLS_E_FATAL_ALERT_RECEIVED
? string_sprintf("A TLS fatal alert has been received: %s",
US gnutls_alert_get_name(gnutls_alert_get(state->session)))
# ifdef notdef_crashes
/*XXX crashes */
return gnutls_ext_raw_parse(NULL, tls_server_servercerts_ext, msg, 0);
+# else
+return GNUTLS_E_SUCCESS;
# endif
}
#endif /*SUPPORT_GNUTLS_EXT_RAW_PARSE*/
return tls_server_ticket_cb(sess, htype, when, incoming, msg);
# endif
default:
- return 0;
+ return GNUTLS_E_SUCCESS;
}
}
#endif
static void
tls_client_creds_init(transport_instance * t, BOOL watch)
{
-smtp_transport_options_block * ob = t->options_block;
+smtp_transport_options_block * ob = t->drinst.options_block;
+const uschar * trname = t->drinst.name;
exim_gnutls_state_st tpt_dummy_state;
host_item * dummy_host = (host_item *)1;
uschar * dummy_errstr;
const uschar * pkey = ob->tls_privatekey;
DEBUG(D_tls)
- debug_printf("TLS: preloading client certs for transport '%s'\n", t->name);
+ debug_printf("TLS: preloading client certs for transport '%s'\n", trname);
/* The state->lib_state.x509_cred is used for the certs load, and is the sole
structure element used. So we can set up a dummy. The hoat arg only
}
else
DEBUG(D_tls)
- debug_printf("TLS: not preloading client certs, for transport '%s'\n", t->name);
+ debug_printf("TLS: not preloading client certs, for transport '%s'\n", trname);
/* If tls_verify_certificates is non-empty and has no $, load CAs.
If none was configured and we can't handle "system", treat as empty. */
if (!watch || tls_set_watch(ob->tls_verify_certificates, FALSE))
{
DEBUG(D_tls)
- debug_printf("TLS: preloading CA bundle for transport '%s'\n", t->name);
+ debug_printf("TLS: preloading CA bundle for transport '%s'\n", trname);
if (creds_load_cabundle(&tpt_dummy_state, ob->tls_verify_certificates,
dummy_host, &dummy_errstr) != OK)
return;
{
if (!watch || tls_set_watch(ob->tls_crl, FALSE))
{
- DEBUG(D_tls) debug_printf("TLS: preloading CRL for transport '%s'\n", t->name);
+ DEBUG(D_tls) debug_printf("TLS: preloading CRL for transport '%s'\n", trname);
if (creds_load_crl(&tpt_dummy_state, ob->tls_crl, &dummy_errstr) != OK)
return;
ob->tls_preload.crl = TRUE;
}
}
else
- DEBUG(D_tls) debug_printf("TLS: not preloading CRL, for transport '%s'\n", t->name);
+ DEBUG(D_tls) debug_printf("TLS: not preloading CRL, for transport '%s'\n", trname);
}
}
else
DEBUG(D_tls)
- debug_printf("TLS: not preloading CA bundle, for transport '%s'\n", t->name);
+ debug_printf("TLS: not preloading CA bundle, for transport '%s'\n", trname);
/* We do not preload tls_require_ciphers to to the transport as it implicitly
depends on DANE or plain usage. */
static void
tls_client_creds_invalidate(transport_instance * t)
{
-smtp_transport_options_block * ob = t->options_block;
+smtp_transport_options_block * ob = t->drinst.options_block;
if (ob->tls_preload.x509_cred)
gnutls_certificate_free_credentials(ob->tls_preload.x509_cred);
ob->tls_preload = null_tls_preload;
if (*s) s++; /* now on _ between groups */
while ((c = *s))
{
- for (*++s && ++s; (c = *s) && c != ')'; s++)
- g = string_catn(g, c == '-' ? US"_" : s, 1);
+ if (*++s)
+ for (++s; (c = *s) && c != ')'; s++)
+ g = string_catn(g, c == '-' ? US"_" : s, 1);
/* now on ) closing group */
if ((c = *s) && *++s == '-') g = string_catn(g, US"__", 2);
/* now on _ between groups */
tls_server_ticket_cb(gnutls_session_t sess, u_int htype, unsigned when,
unsigned incoming, const gnutls_datum_t * msg)
{
-DEBUG(D_tls) debug_printf("newticket cb\n");
+DEBUG(D_tls) debug_printf("newticket cb (on server)\n");
tls_in.resumption |= RESUME_CLIENT_REQUESTED;
return 0;
}
{
if (gnutls_session_resumption_requested(state->session))
{
- /* This tells us the client sent a full ticket. We use a
+ /* This tells us the client sent a full (?) ticket. We use a
callback on session-ticket request, elsewhere, to tell
- if a client asked for a ticket. */
+ if a client asked for a ticket.
+ XXX As of GnuTLS 3.0.1 it seems to be returning true even for
+ a pure ticket-req (a zero-length Session Ticket extension
+ in the Client Hello, for 1.2) which mucks up our logic. */
tls_in.resumption |= RESUME_CLIENT_SUGGESTED;
DEBUG(D_tls) debug_printf("client requested resumption\n");
if (tls_in.active.sock >= 0)
{
tls_error(US"STARTTLS received after TLS started", US "", NULL, errstr);
- smtp_printf("554 Already in TLS\r\n", FALSE);
+ smtp_printf("554 Already in TLS\r\n", SP_NO_MORE);
return FAIL;
}
if (!state->tlsp->on_connect)
{
- smtp_printf("220 TLS go ahead\r\n", FALSE);
+ smtp_printf("220 TLS go ahead\r\n", SP_NO_MORE);
fflush(smtp_out);
}
tlsp->resumption = RESUME_SUPPORTED;
if (!conn_args->have_lbserver)
- { DEBUG(D_tls) debug_printf("resumption not supported on continued-connection\n"); }
+ { DEBUG(D_tls) debug_printf(
+ "resumption not supported: no LB detection done (continued-conn?)\n"); }
else if (verify_check_given_host(CUSS &ob->tls_resumption_hosts, conn_args->host) == OK)
{
dbdata_tls_session * dt;
dbfn_close(dbm_file);
}
}
+else DEBUG(D_tls) debug_printf("no resumption for this host\n");
}
int dlen = sizeof(dbdata_tls_session) + tkt.size;
dbdata_tls_session * dt = store_get(dlen, GET_TAINTED);
- DEBUG(D_tls) debug_printf("session data size %u\n", (unsigned)tkt.size);
+ DEBUG(D_tls) debug_printf(" session data size %u\n", (unsigned)tkt.size);
memcpy(dt->session, tkt.data, tkt.size);
gnutls_free(tkt.data);
- if ((dbm_file = dbfn_open(US"tls", O_RDWR, &dbblock, FALSE, FALSE)))
+ if ((dbm_file = dbfn_open(US"tls", O_RDWR|O_CREAT, &dbblock, FALSE, FALSE)))
{
/* key for the db is the IP */
dbfn_write(dbm_file, tlsp->resume_index, dt, dlen);
dbfn_close(dbm_file);
DEBUG(D_tls)
- debug_printf("wrote session db (len %u)\n", (unsigned)dlen);
+ debug_printf(" wrote session db (len %u)\n", (unsigned)dlen);
}
}
- else DEBUG(D_tls)
- debug_printf("extract session data: %s\n", US gnutls_strerror(rc));
+ else
+ { DEBUG(D_tls)
+ debug_printf(" extract session data: %s\n", US gnutls_strerror(rc));
+ }
+ else DEBUG(D_tls)
+ debug_printf(" host not resmable; not saving ticket\n");
}
}
exim_gnutls_state_st * state = gnutls_session_get_ptr(sess);
tls_support * tlsp = state->tlsp;
-DEBUG(D_tls) debug_printf("newticket cb\n");
+DEBUG(D_tls) debug_printf("newticket cb (on client)\n");
if (!tlsp->ticket_received)
tls_save_session(tlsp, sess, state->host);
host_item * host = conn_args->host; /* for msgs and option-tests */
transport_instance * tb = conn_args->tblock; /* always smtp or NULL */
smtp_transport_options_block * ob = tb
- ? (smtp_transport_options_block *)tb->options_block
+ ? tb->drinst.options_block
: &smtp_transport_option_defaults;
int rc;
exim_gnutls_state_st * state = NULL;
return FALSE;
}
#ifndef DISABLE_DKIM
-dkim_exim_verify_feed(state->xfer_buffer, inbytes);
+smtp_verify_feed(state->xfer_buffer, inbytes);
#endif
state->xfer_buffer_hwm = (int) inbytes;
state->xfer_buffer_lwm = 0;
if (n > lim)
n = lim;
if (n > 0)
- dkim_exim_verify_feed(state->xfer_buffer+state->xfer_buffer_lwm, n);
+ smtp_verify_feed(state->xfer_buffer+state->xfer_buffer_lwm, n);
#endif
}
}
+/* For ATRN provider: transfer the tls_in context to tls_out */
+
+void
+tls_state_in_to_out(int newfd, const uschar * ipaddr, int port)
+{
+exim_gnutls_state_st * state;
+host_item * h;
+int old_pool = store_pool;
+
+store_pool = POOL_PERM;
+state = store_get(sizeof(exim_gnutls_state_st), GET_UNTAINTED);
+h = store_get(sizeof(host_item), GET_UNTAINTED);
+
+memset(h, 0, sizeof(host_item));
+h->name = h->address = string_copy(ipaddr);
+h->port = port;
+
+*state = state_server;
+
+state->fd_in = newfd;
+state->fd_out = newfd;
+state->tlsp = &tls_out;
+state->host = h;
+
+tls_out = tls_in;
+tls_out.active.sock = newfd;
+tls_out.active.tls_ctx = state;
+
+memset(&tls_in, 0, sizeof(tls_in));
+
+gnutls_transport_set_ptr2(state->session,
+ (gnutls_transport_ptr_t)(long) newfd,
+ (gnutls_transport_ptr_t)(long) newfd);
+store_pool = old_pool;
+}
+
+
+
+/* For ATRN customer: transfer the tls_out context to tls_in */
+
+void
+tls_state_out_to_in(int newfd, const uschar * ipaddr, int port)
+{
+host_item * h;
+int old_pool = store_pool;
+
+store_pool = POOL_PERM;
+h = store_get(sizeof(host_item), GET_UNTAINTED);
+store_pool = old_pool;
+memset(h, 0, sizeof(host_item));
+h->name = h->address = string_copy(ipaddr);
+h->port = port;
+
+state_server = *(exim_gnutls_state_st *)tls_out.active.tls_ctx;
+state_server.fd_in = newfd;
+state_server.fd_out = newfd;
+state_server.tlsp = &tls_in;
+state_server.host = h;
+state_server.xfer_buffer = store_malloc(ssl_xfer_buffer_size);
+
+tls_in = tls_out;
+tls_in.on_connect = FALSE;
+tls_in.active.sock = newfd;
+tls_in.active.tls_ctx = &state_server;
+
+memset(&tls_out, 0, sizeof(tls_out));
+
+gnutls_transport_set_ptr2(state_server.session,
+ (gnutls_transport_ptr_t)(long) newfd,
+ (gnutls_transport_ptr_t)(long) newfd);
+}
+
+
/*************************************************