#if GNUTLS_VERSION_NUMBER >= 0x030109
# define SUPPORT_CORK
#endif
+#if GNUTLS_VERSION_NUMBER >= 0x03010a
+# define SUPPORT_GNUTLS_SESS_DESC
+#endif
+#if GNUTLS_VERSION_NUMBER >= 0x030500
+# define SUPPORT_GNUTLS_KEYLOG
+#endif
#if GNUTLS_VERSION_NUMBER >= 0x030506 && !defined(DISABLE_OCSP)
# define SUPPORT_SRV_OCSP_STACK
#endif
#ifdef HAVE_GNUTLS_SESSION_CHANNEL_BINDING
channel.data = NULL;
channel.size = 0;
-rc = gnutls_session_channel_binding(state->session, GNUTLS_CB_TLS_UNIQUE, &channel);
-if (rc) {
- DEBUG(D_tls) debug_printf("Channel binding error: %s\n", gnutls_strerror(rc));
-} else {
+if ((rc = gnutls_session_channel_binding(state->session, GNUTLS_CB_TLS_UNIQUE, &channel)))
+ { DEBUG(D_tls) debug_printf("Channel binding error: %s\n", gnutls_strerror(rc)); }
+else
+ {
old_pool = store_pool;
store_pool = POOL_PERM;
- tls_channelbinding_b64 = b64encode(channel.data, (int)channel.size);
+ tls_channelbinding_b64 = b64encode(CUS channel.data, (int)channel.size);
store_pool = old_pool;
DEBUG(D_tls) debug_printf("Have channel bindings cached for possible auth usage.\n");
-}
+ }
#endif
/* peercert is set in peer_status() */
where = US"generating pkey";
if ((rc = gnutls_x509_privkey_generate(pkey, GNUTLS_PK_RSA,
#ifdef SUPPORT_PARAM_TO_PK_BITS
- gnutls_sec_param_to_pk_bits(GNUTLS_PK_RSA, GNUTLS_SEC_PARAM_LOW),
+# ifndef GNUTLS_SEC_PARAM_MEDIUM
+# define GNUTLS_SEC_PARAM_MEDIUM GNUTLS_SEC_PARAM_HIGH
+# endif
+ gnutls_sec_param_to_pk_bits(GNUTLS_PK_RSA, GNUTLS_SEC_PARAM_MEDIUM),
#else
- 1024,
+ 2048,
#endif
0)))
goto err;
gnutls_mac_algorithm_t mac;
gnutls_certificate_type_t ct;
gnutls_x509_crt_t crt;
-uschar *p, *dn_buf;
+uschar *dn_buf;
size_t sz;
if (state->have_set_peerdn)
/* I don't see a way that spaces could occur, in the current GnuTLS
code base, but it was a concern in the old code and perhaps older GnuTLS
releases did return "TLS 1.0"; play it safe, just in case. */
-for (p = cipherbuf; *p != '\0'; ++p)
+for (uschar * p = cipherbuf; *p != '\0'; ++p)
if (isspace(*p))
*p = '-';
old_pool = store_pool;
#endif
+static gstring *
+ddump(gnutls_datum_t * d)
+{
+gstring * g = string_get((d->size+1) * 2);
+uschar * s = d->data;
+for (unsigned i = d->size; i > 0; i--, s++)
+ {
+ g = string_catn(g, US "0123456789abcdef" + (*s >> 4), 1);
+ g = string_catn(g, US "0123456789abcdef" + (*s & 0xf), 1);
+ }
+return g;
+}
/* ------------------------------------------------------------------------ */
/* Exported functions */
gnutls_certificate_free_credentials(state->x509_cred);
millisleep(500);
shutdown(state->fd_out, SHUT_WR);
- for (rc = 1024; fgetc(smtp_in) != EOF && rc > 0; ) rc--; /* drain skt */
+ for (int i = 1024; fgetc(smtp_in) != EOF && i > 0; ) i--; /* drain skt */
(void)fclose(smtp_out);
(void)fclose(smtp_in);
smtp_out = smtp_in = NULL;
return FAIL;
}
-DEBUG(D_tls) debug_printf("gnutls_handshake was successful\n");
+DEBUG(D_tls)
+ {
+ debug_printf("gnutls_handshake was successful\n");
+#ifdef SUPPORT_GNUTLS_SESS_DESC
+ debug_printf("%s\n", gnutls_session_get_desc(state->session));
+#endif
+#ifdef SUPPORT_GNUTLS_KEYLOG
+ {
+ gnutls_datum_t c, s;
+ gstring * gc, * gs;
+ gnutls_session_get_random(state->session, &c, &s);
+ gnutls_session_get_master_secret(state->session, &s);
+ gc = ddump(&c);
+ gs = ddump(&s);
+ debug_printf("CLIENT_RANDOM %.*s %.*s\n", (int)gc->ptr, gc->s, (int)gs->ptr, gs->s);
+ }
+#endif
+ }
/* Verify after the fact */
static BOOL
dane_tlsa_load(exim_gnutls_state_st * state, dns_answer * dnsa)
{
-dns_record * rr;
dns_scan dnss;
int i;
const char ** dane_data;
int * dane_data_len;
-for (rr = dns_next_rr(dnsa, &dnss, RESET_ANSWERS), i = 1;
- rr;
+i = 1;
+for (dns_record * rr = dns_next_rr(dnsa, &dnss, RESET_ANSWERS); rr;
rr = dns_next_rr(dnsa, &dnss, RESET_NEXT)
) if (rr->type == T_TLSA) i++;
dane_data = store_get(i * sizeof(uschar *));
dane_data_len = store_get(i * sizeof(int));
-for (rr = dns_next_rr(dnsa, &dnss, RESET_ANSWERS), i = 0;
- rr;
+i = 0;
+for (dns_record * rr = dns_next_rr(dnsa, &dnss, RESET_ANSWERS); rr;
rr = dns_next_rr(dnsa, &dnss, RESET_NEXT)
) if (rr->type == T_TLSA && rr->size > 3)
{
return NULL;
}
-DEBUG(D_tls) debug_printf("gnutls_handshake was successful\n");
+DEBUG(D_tls)
+ {
+ debug_printf("gnutls_handshake was successful\n");
+#ifdef SUPPORT_GNUTLS_SESS_DESC
+ debug_printf("%s\n", gnutls_session_get_desc(state->session));
+#endif
+#ifdef SUPPORT_GNUTLS_KEYLOG
+ {
+ gnutls_datum_t c, s;
+ gstring * gc, * gs;
+ gnutls_session_get_random(state->session, &c, &s);
+ gnutls_session_get_master_secret(state->session, &s);
+ gc = ddump(&c);
+ gs = ddump(&s);
+ debug_printf("CLIENT_RANDOM %.*s %.*s\n", (int)gc->ptr, gc->s, (int)gs->ptr, gs->s);
+ }
+#endif
+ }
/* Verify late */
sigalrm_seen = FALSE;
if (smtp_receive_timeout > 0) ALARM(smtp_receive_timeout);
-inbytes = gnutls_record_recv(state->session, state->xfer_buffer,
- MIN(ssl_xfer_buffer_size, lim));
+
+do
+ inbytes = gnutls_record_recv(state->session, state->xfer_buffer,
+ MIN(ssl_xfer_buffer_size, lim));
+while (inbytes == GNUTLS_E_AGAIN);
+
if (smtp_receive_timeout > 0) ALARM_CLR(0);
if (had_command_timeout) /* set by signal handler */
else if (inbytes < 0)
{
-debug_printf("%s: err from gnutls_record_recv(\n", __FUNCTION__);
+ DEBUG(D_tls) debug_printf("%s: err from gnutls_record_recv(\n", __FUNCTION__);
record_io_error(state, (int) inbytes, US"recv", NULL);
state->xfer_error = TRUE;
return FALSE;
debug_printf("Calling gnutls_record_recv(%p, %p, " SIZE_T_FMT ")\n",
state->session, buff, len);
-inbytes = gnutls_record_recv(state->session, buff, len);
+do
+ inbytes = gnutls_record_recv(state->session, buff, len);
+while (inbytes == GNUTLS_E_AGAIN);
+
if (inbytes > 0) return inbytes;
if (inbytes == 0)
{
DEBUG(D_tls) debug_printf("Got TLS_EOF\n");
}
else
-{
-debug_printf("%s: err from gnutls_record_recv(\n", __FUNCTION__);
-record_io_error(state, (int)inbytes, US"recv", NULL);
-}
+ {
+ DEBUG(D_tls) debug_printf("%s: err from gnutls_record_recv(\n", __FUNCTION__);
+ record_io_error(state, (int)inbytes, US"recv", NULL);
+ }
return -1;
}
{
DEBUG(D_tls) debug_printf("gnutls_record_send(SSL, %p, " SIZE_T_FMT ")\n",
buff, left);
- outbytes = gnutls_record_send(state->session, buff, left);
+
+ do
+ outbytes = gnutls_record_send(state->session, buff, left);
+ while (outbytes == GNUTLS_E_AGAIN);
DEBUG(D_tls) debug_printf("outbytes=" SSIZE_T_FMT "\n", outbytes);
if (outbytes < 0)
{
unsigned int r;
int i, needed_len;
-uschar *p;
uschar smallbuf[sizeof(r)];
if (max <= 1)
needed_len = sizeof(r);
/* Don't take 8 times more entropy than needed if int is 8 octets and we were
- * asked for a number less than 10. */
+asked for a number less than 10. */
+
for (r = max, i = 0; r; ++i)
r >>= 1;
i = (i + 7) / 8;
return vaguely_random_number_fallback(max);
}
r = 0;
-for (p = smallbuf; needed_len; --needed_len, ++p)
- {
- r *= 256;
- r += *p;
- }
+for (uschar * p = smallbuf; needed_len; --needed_len, ++p)
+ r = r * 256 + *p;
/* We don't particularly care about weighted results; if someone wants
* smooth distribution and cares enough then they should submit a patch then. */