Testsuite: fix problem with parsing retry records spanning midnight.
[exim.git] / src / src / tls-gnu.c
CommitLineData
059ec3d9
PH
1/*************************************************
2* Exim - an Internet mail transport agent *
3*************************************************/
4
0a49a7a4 5/* Copyright (c) University of Cambridge 1995 - 2009 */
059ec3d9
PH
6/* See the file NOTICE for conditions of use and distribution. */
7
8/* This module provides TLS (aka SSL) support for Exim using the GnuTLS
9library. It is #included into tls.c when that library is used. The code herein
10is based on a patch that was contributed by Nikos Mavroyanopoulos.
11
12No cryptographic code is included in Exim. All this module does is to call
13functions from the GnuTLS library. */
14
c566dd90
PP
15/* Note: This appears to be using an old API from compat.h; it is likely that
16someone familiary with GnuTLS programming could rework a lot of this to a
17modern API and perhaps remove the explicit knowledge of crypto algorithms from
18Exim. Such a re-work would be most welcome and we'd sacrifice support for
19older GnuTLS releases without too many qualms -- maturity and experience
20in crypto libraries tends to improve their robustness against attack.
21Frankly, if you maintain it, you decide what's supported and what isn't. */
059ec3d9
PH
22
23/* Heading stuff for GnuTLS */
24
25#include <gnutls/gnutls.h>
26#include <gnutls/x509.h>
27
28
29#define UNKNOWN_NAME "unknown"
87054a31 30#define DH_BITS 1024
b5aea5e1
PH
31#define PARAM_SIZE 2*1024
32
059ec3d9 33
7199e1ee 34/* Values for verify_requirment */
059ec3d9
PH
35
36enum { VERIFY_NONE, VERIFY_OPTIONAL, VERIFY_REQUIRED };
059ec3d9
PH
37
38/* Local static variables for GNUTLS */
39
059ec3d9
PH
40static host_item *client_host;
41
059ec3d9
PH
42static gnutls_dh_params dh_params = NULL;
43
44static gnutls_certificate_server_credentials x509_cred = NULL;
45static gnutls_session tls_session = NULL;
46
47static char ssl_errstring[256];
48
49static int ssl_session_timeout = 200;
50static int verify_requirement;
51
83da1223
PH
52/* Priorities for TLS algorithms to use. In each case there's a default table,
53and space into which it can be copied and altered. */
059ec3d9 54
83da1223 55static const int default_proto_priority[16] = {
c566dd90
PP
56 /* These are gnutls_protocol_t enum values */
57#if GNUTLS_VERSION_MAJOR > 1 || GNUTLS_VERSION_MINOR >= 7
58 GNUTLS_TLS1_2,
59#endif
60#if GNUTLS_VERSION_MAJOR > 1 || GNUTLS_VERSION_MINOR >= 2
61 GNUTLS_TLS1_1,
62#endif
83da1223
PH
63 GNUTLS_TLS1,
64 GNUTLS_SSL3,
65 0 };
66
67static int proto_priority[16];
059ec3d9 68
83da1223 69static const int default_kx_priority[16] = {
059ec3d9
PH
70 GNUTLS_KX_RSA,
71 GNUTLS_KX_DHE_DSS,
72 GNUTLS_KX_DHE_RSA,
059ec3d9
PH
73 0 };
74
83da1223
PH
75static int kx_priority[16];
76
059ec3d9 77static int default_cipher_priority[16] = {
26dd5a95 78 GNUTLS_CIPHER_AES_256_CBC,
059ec3d9
PH
79 GNUTLS_CIPHER_AES_128_CBC,
80 GNUTLS_CIPHER_3DES_CBC,
26dd5a95 81 GNUTLS_CIPHER_ARCFOUR_128,
059ec3d9
PH
82 0 };
83
84static int cipher_priority[16];
85
83da1223 86static const int default_mac_priority[16] = {
059ec3d9
PH
87 GNUTLS_MAC_SHA,
88 GNUTLS_MAC_MD5,
89 0 };
90
83da1223
PH
91static int mac_priority[16];
92
93/* These two are currently not changeable. */
94
059ec3d9
PH
95static const int comp_priority[16] = { GNUTLS_COMP_NULL, 0 };
96static const int cert_type_priority[16] = { GNUTLS_CRT_X509, 0 };
97
83da1223 98/* Tables of priority names and equivalent numbers */
059ec3d9
PH
99
100typedef struct pri_item {
101 uschar *name;
102 int *values;
103} pri_item;
104
83da1223 105
c566dd90
PP
106#if GNUTLS_VERSION_MAJOR > 1 || GNUTLS_VERSION_MINOR >= 7
107static int tls1_2_codes[] = { GNUTLS_TLS1_2, 0 };
108#endif
109#if GNUTLS_VERSION_MAJOR > 1 || GNUTLS_VERSION_MINOR >= 2
110static int tls1_1_codes[] = { GNUTLS_TLS1_1, 0 };
111#endif
112/* more recent libraries define this as an equivalent value to the
113canonical GNUTLS_TLS1_0; since they're the same, we stick to the
114older name. */
115static int tls1_0_codes[] = { GNUTLS_TLS1, 0 };
83da1223
PH
116static int ssl3_codes[] = { GNUTLS_SSL3, 0 };
117
118static pri_item proto_index[] = {
c566dd90
PP
119#if GNUTLS_VERSION_MAJOR > 1 || GNUTLS_VERSION_MINOR >= 7
120 { US"TLS1.2", tls1_2_codes },
121#endif
122#if GNUTLS_VERSION_MAJOR > 1 || GNUTLS_VERSION_MINOR >= 2
123 { US"TLS1.1", tls1_1_codes },
124#endif
125 { US"TLS1.0", tls1_0_codes },
126 { US"TLS1", tls1_0_codes },
83da1223
PH
127 { US"SSL3", ssl3_codes }
128};
129
130
131static int kx_rsa_codes[] = { GNUTLS_KX_RSA,
132 GNUTLS_KX_DHE_RSA, 0 };
133static int kx_dhe_codes[] = { GNUTLS_KX_DHE_DSS,
134 GNUTLS_KX_DHE_RSA, 0 };
135static int kx_dhe_dss_codes[] = { GNUTLS_KX_DHE_DSS, 0 };
136static int kx_dhe_rsa_codes[] = { GNUTLS_KX_DHE_RSA, 0 };
137
138static pri_item kx_index[] = {
139 { US"DHE_DSS", kx_dhe_dss_codes },
140 { US"DHE_RSA", kx_dhe_rsa_codes },
141 { US"RSA", kx_rsa_codes },
142 { US"DHE", kx_dhe_codes }
143};
144
145
059ec3d9
PH
146static int arcfour_128_codes[] = { GNUTLS_CIPHER_ARCFOUR_128, 0 };
147static int arcfour_40_codes[] = { GNUTLS_CIPHER_ARCFOUR_40, 0 };
148static int arcfour_codes[] = { GNUTLS_CIPHER_ARCFOUR_128,
149 GNUTLS_CIPHER_ARCFOUR_40, 0 };
150static int aes_256_codes[] = { GNUTLS_CIPHER_AES_256_CBC, 0 };
151static int aes_128_codes[] = { GNUTLS_CIPHER_AES_128_CBC, 0 };
152static int aes_codes[] = { GNUTLS_CIPHER_AES_256_CBC,
153 GNUTLS_CIPHER_AES_128_CBC, 0 };
154static int des3_codes[] = { GNUTLS_CIPHER_3DES_CBC, 0 };
155
156static pri_item cipher_index[] = {
157 { US"ARCFOUR_128", arcfour_128_codes },
158 { US"ARCFOUR_40", arcfour_40_codes },
159 { US"ARCFOUR", arcfour_codes },
160 { US"AES_256", aes_256_codes },
161 { US"AES_128", aes_128_codes },
162 { US"AES", aes_codes },
163 { US"3DES", des3_codes }
164};
165
166
83da1223
PH
167static int mac_sha_codes[] = { GNUTLS_MAC_SHA, 0 };
168static int mac_md5_codes[] = { GNUTLS_MAC_MD5, 0 };
169
170static pri_item mac_index[] = {
171 { US"SHA", mac_sha_codes },
172 { US"SHA1", mac_sha_codes },
173 { US"MD5", mac_md5_codes }
174};
175
176
059ec3d9
PH
177
178/*************************************************
179* Handle TLS error *
180*************************************************/
181
182/* Called from lots of places when errors occur before actually starting to do
183the TLS handshake, that is, while the session is still in clear. Always returns
184DEFER for a server and FAIL for a client so that most calls can use "return
185tls_error(...)" to do this processing and then give an appropriate return. A
186single function is used for both server and client, because it is called from
187some shared functions.
188
189Argument:
190 prefix text to include in the logged error
191 host NULL if setting up a server;
192 the connected host if setting up a client
7199e1ee
TF
193 msg additional error string (may be NULL)
194 usually obtained from gnutls_strerror()
059ec3d9
PH
195
196Returns: OK/DEFER/FAIL
197*/
198
199static int
7199e1ee 200tls_error(uschar *prefix, host_item *host, const char *msg)
059ec3d9 201{
059ec3d9
PH
202if (host == NULL)
203 {
7199e1ee
TF
204 uschar *conn_info = smtp_get_connection_info();
205 if (strncmp(conn_info, "SMTP ", 5) == 0)
206 conn_info += 5;
207 log_write(0, LOG_MAIN, "TLS error on %s (%s)%s%s",
208 conn_info, prefix, msg ? ": " : "", msg ? msg : "");
059ec3d9
PH
209 return DEFER;
210 }
211else
212 {
7199e1ee
TF
213 log_write(0, LOG_MAIN, "TLS error on connection to %s [%s] (%s)%s%s",
214 host->name, host->address, prefix, msg ? ": " : "", msg ? msg : "");
059ec3d9
PH
215 return FAIL;
216 }
217}
218
219
220
221/*************************************************
222* Verify certificate *
223*************************************************/
224
225/* Called after a successful handshake, when certificate verification is
226required or optional, for both server and client.
227
228Arguments:
229 session GNUTLS session
230 error where to put text giving a reason for failure
231
232Returns: TRUE/FALSE
233*/
234
235static BOOL
7199e1ee 236verify_certificate(gnutls_session session, const char **error)
059ec3d9 237{
d641a340 238int rc = -1;
059ec3d9
PH
239uschar *dn_string = US"";
240const gnutls_datum *cert;
89f897c3 241unsigned int verify, cert_size = 0;
059ec3d9
PH
242
243*error = NULL;
244
245/* Get the peer's certificate. If it sent one, extract it's DN, and then
246attempt to verify the certificate. If no certificate is supplied, verification
247is forced to fail. */
248
249cert = gnutls_certificate_get_peers(session, &cert_size);
250if (cert != NULL)
251 {
252 uschar buff[1024];
253 gnutls_x509_crt gcert;
254
255 gnutls_x509_crt_init(&gcert);
256 dn_string = US"unknown";
257
258 if (gnutls_x509_crt_import(gcert, cert, GNUTLS_X509_FMT_DER) == 0)
259 {
260 size_t bufsize = sizeof(buff);
261 if (gnutls_x509_crt_get_dn(gcert, CS buff, &bufsize) >= 0)
262 dn_string = string_copy_malloc(buff);
263 }
264
89f897c3 265 rc = gnutls_certificate_verify_peers2(session, &verify);
059ec3d9
PH
266 }
267else
268 {
269 DEBUG(D_tls) debug_printf("no peer certificate supplied\n");
270 verify = GNUTLS_CERT_INVALID;
7199e1ee 271 *error = "not supplied";
059ec3d9
PH
272 }
273
274/* Handle the result of verification. INVALID seems to be set as well
275as REVOKED, but leave the test for both. */
276
89f897c3 277if ((rc < 0) || (verify & (GNUTLS_CERT_INVALID|GNUTLS_CERT_REVOKED)) != 0)
059ec3d9
PH
278 {
279 tls_certificate_verified = FALSE;
280 if (*error == NULL) *error = ((verify & GNUTLS_CERT_REVOKED) != 0)?
7199e1ee 281 "revoked" : "invalid";
059ec3d9
PH
282 if (verify_requirement == VERIFY_REQUIRED)
283 {
284 DEBUG(D_tls) debug_printf("TLS certificate verification failed (%s): "
285 "peerdn=%s\n", *error, dn_string);
286 gnutls_alert_send(session, GNUTLS_AL_FATAL, GNUTLS_A_BAD_CERTIFICATE);
287 return FALSE; /* reject */
288 }
289 DEBUG(D_tls) debug_printf("TLS certificate verify failure (%s) overridden "
290 "(host in tls_try_verify_hosts): peerdn=%s\n", *error, dn_string);
291 }
292else
293 {
294 tls_certificate_verified = TRUE;
295 DEBUG(D_tls) debug_printf("TLS certificate verified: peerdn=%s\n",
296 dn_string);
297 }
298
299tls_peerdn = dn_string;
300return TRUE; /* accept */
301}
302
303
304
059ec3d9 305/*************************************************
575643cd 306* Setup up DH parameters *
059ec3d9
PH
307*************************************************/
308
575643cd 309/* Generating the D-H parameters may take a long time. They only need to
059ec3d9
PH
310be re-generated every so often, depending on security policy. What we do is to
311keep these parameters in a file in the spool directory. If the file does not
312exist, we generate them. This means that it is easy to cause a regeneration.
313
314The new file is written as a temporary file and renamed, so that an incomplete
315file is never present. If two processes both compute some new parameters, you
316waste a bit of effort, but it doesn't seem worth messing around with locking to
317prevent this.
318
319Argument:
320 host NULL for server, server for client (for error handling)
321
322Returns: OK/DEFER/FAIL
323*/
324
325static int
575643cd 326init_dh(host_item *host)
059ec3d9 327{
b5aea5e1 328int fd;
182ad5cf 329int ret;
b5aea5e1 330gnutls_datum m;
059ec3d9
PH
331uschar filename[200];
332
333/* Initialize the data structures for holding the parameters */
334
059ec3d9 335ret = gnutls_dh_params_init(&dh_params);
7199e1ee 336if (ret < 0) return tls_error(US"init dh_params", host, gnutls_strerror(ret));
059ec3d9
PH
337
338/* Set up the name of the cache file */
339
340if (!string_format(filename, sizeof(filename), "%s/gnutls-params",
341 spool_directory))
7199e1ee 342 return tls_error(US"overlong filename", host, NULL);
059ec3d9 343
b5aea5e1 344/* Open the cache file for reading and if successful, read it and set up the
575643cd 345parameters. */
059ec3d9
PH
346
347fd = Uopen(filename, O_RDONLY, 0);
b5aea5e1 348if (fd >= 0)
059ec3d9 349 {
b5aea5e1
PH
350 struct stat statbuf;
351 if (fstat(fd, &statbuf) < 0)
352 {
353 (void)close(fd);
7199e1ee 354 return tls_error(US"TLS cache stat failed", host, strerror(errno));
b5aea5e1 355 }
059ec3d9 356
b5aea5e1
PH
357 m.size = statbuf.st_size;
358 m.data = malloc(m.size);
359 if (m.data == NULL)
7199e1ee
TF
360 return tls_error(US"memory allocation failed", host, strerror(errno));
361 errno = 0;
b5aea5e1 362 if (read(fd, m.data, m.size) != m.size)
7199e1ee 363 return tls_error(US"TLS cache read failed", host, strerror(errno));
b5aea5e1
PH
364 (void)close(fd);
365
411ef850 366 ret = gnutls_dh_params_import_pkcs3(dh_params, &m, GNUTLS_X509_FMT_PEM);
7199e1ee
TF
367 if (ret < 0)
368 return tls_error(US"DH params import", host, gnutls_strerror(ret));
575643cd 369 DEBUG(D_tls) debug_printf("read D-H parameters from file\n");
b5aea5e1
PH
370
371 free(m.data);
372 }
373
374/* If the file does not exist, fall through to compute new data and cache it.
375If there was any other opening error, it is serious. */
376
182ad5cf
PH
377else if (errno == ENOENT)
378 {
379 ret = -1;
380 DEBUG(D_tls)
381 debug_printf("parameter cache file %s does not exist\n", filename);
382 }
383else
b5aea5e1 384 return tls_error(string_open_failed(errno, "%s for reading", filename),
7199e1ee 385 host, NULL);
b5aea5e1
PH
386
387/* If ret < 0, either the cache file does not exist, or the data it contains
388is not useful. One particular case of this is when upgrading from an older
389release of Exim in which the data was stored in a different format. We don't
390try to be clever and support both formats; we just regenerate new data in this
391case. */
392
393if (ret < 0)
394 {
395 uschar tempfilename[sizeof(filename) + 10];
059ec3d9 396
059ec3d9
PH
397 DEBUG(D_tls) debug_printf("generating %d bit Diffie-Hellman key...\n",
398 DH_BITS);
399 ret = gnutls_dh_params_generate2(dh_params, DH_BITS);
7199e1ee 400 if (ret < 0) return tls_error(US"D-H key generation", host, gnutls_strerror(ret));
059ec3d9
PH
401
402 /* Write the parameters to a file in the spool directory so that we
403 can use them from other Exim processes. */
404
405 sprintf(CS tempfilename, "%s-%d", filename, (int)getpid());
406 fd = Uopen(tempfilename, O_WRONLY|O_CREAT, 0400);
407 if (fd < 0)
408 return tls_error(string_open_failed(errno, "%s for writing", filename),
7199e1ee 409 host, NULL);
059ec3d9
PH
410 (void)fchown(fd, exim_uid, exim_gid); /* Probably not necessary */
411
b5aea5e1
PH
412 /* export the parameters in a format that can be generated using GNUTLS'
413 * certtool or other programs.
414 *
415 * The commands for certtool are:
411ef850 416 * $ certtool --generate-dh-params --bits 1024 > params
b5aea5e1
PH
417 */
418
419 m.size = PARAM_SIZE;
420 m.data = malloc(m.size);
421 if (m.data == NULL)
7199e1ee 422 return tls_error(US"memory allocation failed", host, strerror(errno));
b5aea5e1 423
b5aea5e1
PH
424 m.size = PARAM_SIZE;
425 ret = gnutls_dh_params_export_pkcs3(dh_params, GNUTLS_X509_FMT_PEM, m.data,
426 &m.size);
7199e1ee
TF
427 if (ret < 0)
428 return tls_error(US"DH params export", host, gnutls_strerror(ret));
059ec3d9 429
b5aea5e1 430 m.size = Ustrlen(m.data);
7199e1ee 431 errno = 0;
b5aea5e1 432 if (write(fd, m.data, m.size) != m.size || write(fd, "\n", 1) != 1)
7199e1ee 433 return tls_error(US"TLS cache write failed", host, strerror(errno));
059ec3d9 434
b5aea5e1 435 free(m.data);
059ec3d9
PH
436 (void)close(fd);
437
438 if (rename(CS tempfilename, CS filename) < 0)
7199e1ee
TF
439 return tls_error(string_sprintf("failed to rename %s as %s",
440 tempfilename, filename), host, strerror(errno));
059ec3d9 441
411ef850 442 DEBUG(D_tls) debug_printf("wrote D-H parameters to file %s\n", filename);
059ec3d9
PH
443 }
444
411ef850 445DEBUG(D_tls) debug_printf("initialized D-H parameters\n");
059ec3d9
PH
446return OK;
447}
448
449
450
451
452/*************************************************
453* Initialize for GnuTLS *
454*************************************************/
455
456/* Called from both server and client code. In the case of a server, errors
457before actual TLS negotiation return DEFER.
458
459Arguments:
460 host connected host, if client; NULL if server
461 certificate certificate file
462 privatekey private key file
463 cas CA certs file
464 crl CRL file
465
466Returns: OK/DEFER/FAIL
467*/
468
469static int
470tls_init(host_item *host, uschar *certificate, uschar *privatekey, uschar *cas,
471 uschar *crl)
472{
473int rc;
474uschar *cert_expanded, *key_expanded, *cas_expanded, *crl_expanded;
475
7199e1ee 476client_host = host;
059ec3d9
PH
477
478rc = gnutls_global_init();
7199e1ee 479if (rc < 0) return tls_error(US"tls-init", host, gnutls_strerror(rc));
059ec3d9 480
575643cd
PH
481/* Create D-H parameters, or read them from the cache file. This function does
482its own SMTP error messaging. */
059ec3d9 483
575643cd 484rc = init_dh(host);
059ec3d9
PH
485if (rc != OK) return rc;
486
487/* Create the credentials structure */
488
489rc = gnutls_certificate_allocate_credentials(&x509_cred);
7199e1ee
TF
490if (rc < 0)
491 return tls_error(US"certificate_allocate_credentials",
492 host, gnutls_strerror(rc));
059ec3d9
PH
493
494/* This stuff must be done for each session, because different certificates
495may be required for different sessions. */
496
497if (!expand_check(certificate, US"tls_certificate", &cert_expanded))
498 return DEFER;
499
c91535f3 500key_expanded = NULL;
059ec3d9
PH
501if (privatekey != NULL)
502 {
503 if (!expand_check(privatekey, US"tls_privatekey", &key_expanded))
504 return DEFER;
505 }
c91535f3
PH
506
507/* If expansion was forced to fail, key_expanded will be NULL. If the result of
508the expansion is an empty string, ignore it also, and assume that the private
509key is in the same file as the certificate. */
510
511if (key_expanded == NULL || *key_expanded == 0)
512 key_expanded = cert_expanded;
059ec3d9
PH
513
514/* Set the certificate and private keys */
515
516if (cert_expanded != NULL)
517 {
518 DEBUG(D_tls) debug_printf("certificate file = %s\nkey file = %s\n",
519 cert_expanded, key_expanded);
520 rc = gnutls_certificate_set_x509_key_file(x509_cred, CS cert_expanded,
521 CS key_expanded, GNUTLS_X509_FMT_PEM);
8e669ac1 522 if (rc < 0)
de365ded
PH
523 {
524 uschar *msg = string_sprintf("cert/key setup: cert=%s key=%s",
8e669ac1 525 cert_expanded, key_expanded);
7199e1ee 526 return tls_error(msg, host, gnutls_strerror(rc));
8e669ac1 527 }
059ec3d9
PH
528 }
529
530/* A certificate is mandatory in a server, but not in a client */
531
532else
533 {
534 if (host == NULL)
7199e1ee 535 return tls_error(US"no TLS server certificate is specified", NULL, NULL);
059ec3d9
PH
536 DEBUG(D_tls) debug_printf("no TLS client certificate is specified\n");
537 }
538
539/* Set the trusted CAs file if one is provided, and then add the CRL if one is
540provided. Experiment shows that, if the certificate file is empty, an unhelpful
541error message is provided. However, if we just refrain from setting anything up
542in that case, certificate verification fails, which seems to be the correct
543behaviour. */
544
545if (cas != NULL)
546 {
547 struct stat statbuf;
548
549 if (!expand_check(cas, US"tls_verify_certificates", &cas_expanded))
550 return DEFER;
551
552 if (stat(CS cas_expanded, &statbuf) < 0)
553 {
554 log_write(0, LOG_MAIN|LOG_PANIC, "could not stat %s "
555 "(tls_verify_certificates): %s", cas_expanded, strerror(errno));
556 return DEFER;
557 }
558
b1c749bb
PH
559 DEBUG(D_tls) debug_printf("verify certificates = %s size=" OFF_T_FMT "\n",
560 cas_expanded, statbuf.st_size);
059ec3d9
PH
561
562 /* If the cert file is empty, there's no point in loading the CRL file. */
563
564 if (statbuf.st_size > 0)
565 {
566 rc = gnutls_certificate_set_x509_trust_file(x509_cred, CS cas_expanded,
567 GNUTLS_X509_FMT_PEM);
7199e1ee 568 if (rc < 0) return tls_error(US"setup_certs", host, gnutls_strerror(rc));
059ec3d9
PH
569
570 if (crl != NULL && *crl != 0)
571 {
572 if (!expand_check(crl, US"tls_crl", &crl_expanded))
573 return DEFER;
574 DEBUG(D_tls) debug_printf("loading CRL file = %s\n", crl_expanded);
575 rc = gnutls_certificate_set_x509_crl_file(x509_cred, CS crl_expanded,
576 GNUTLS_X509_FMT_PEM);
7199e1ee 577 if (rc < 0) return tls_error(US"CRL setup", host, gnutls_strerror(rc));
059ec3d9
PH
578 }
579 }
580 }
581
582/* Associate the parameters with the x509 credentials structure. */
583
584gnutls_certificate_set_dh_params(x509_cred, dh_params);
059ec3d9
PH
585
586DEBUG(D_tls) debug_printf("initialized certificate stuff\n");
587return OK;
588}
589
590
591
592
593/*************************************************
83da1223 594* Remove from a priority list *
059ec3d9
PH
595*************************************************/
596
597/* Cautiously written so that it will remove duplicates if present.
598
599Arguments:
600 list a zero-terminated list
601 remove_list a zero-terminated list to be removed
602
603Returns: nothing
604*/
605
606static void
83da1223 607remove_priority(int *list, int *remove_list)
059ec3d9
PH
608{
609for (; *remove_list != 0; remove_list++)
610 {
611 int *p = list;
612 while (*p != 0)
613 {
614 if (*p == *remove_list)
615 {
616 int *pp = p;
617 do { pp[0] = pp[1]; pp++; } while (*pp != 0);
618 }
619 else p++;
620 }
621 }
622}
623
624
625
626/*************************************************
83da1223 627* Add to a priority list *
059ec3d9
PH
628*************************************************/
629
630/* Cautiously written to check the list size
631
632Arguments:
633 list a zero-terminated list
634 list_max maximum offset in the list
635 add_list a zero-terminated list to be added
636
637Returns: TRUE if OK; FALSE if list overflows
638*/
639
640static BOOL
83da1223 641add_priority(int *list, int list_max, int *add_list)
059ec3d9
PH
642{
643int next = 0;
644while (list[next] != 0) next++;
645while (*add_list != 0)
646 {
647 if (next >= list_max) return FALSE;
648 list[next++] = *add_list++;
649 }
650list[next] = 0;
651return TRUE;
652}
653
654
655
656/*************************************************
83da1223
PH
657* Adjust a priority list *
658*************************************************/
659
660/* This function is called to adjust the lists of cipher algorithms, MAC
661algorithms, key-exchange methods, and protocols.
662
663Arguments:
664 plist the appropriate priority list
665 psize the length of the list
666 s the configuation string
667 index the index of recognized strings
668 isize the length of the index
669
670
671 which text for an error message
672
673Returns: FALSE if the table overflows, else TRUE
674*/
675
676static BOOL
677set_priority(int *plist, int psize, uschar *s, pri_item *index, int isize,
678 uschar *which)
679{
680int sep = 0;
681BOOL first = TRUE;
682uschar *t;
683
684while ((t = string_nextinlist(&s, &sep, big_buffer, big_buffer_size)) != NULL)
685 {
686 int i;
687 BOOL exclude = t[0] == '!';
688 if (first && !exclude) plist[0] = 0;
689 first = FALSE;
690 for (i = 0; i < isize; i++)
691 {
692 uschar *ss = strstric(t, index[i].name, FALSE);
693 if (ss != NULL)
694 {
695 uschar *endss = ss + Ustrlen(index[i].name);
696 if ((ss == t || !isalnum(ss[-1])) && !isalnum(*endss))
697 {
698 if (exclude)
699 remove_priority(plist, index[i].values);
700 else
701 {
702 if (!add_priority(plist, psize, index[i].values))
703 {
704 log_write(0, LOG_MAIN|LOG_PANIC, "GnuTLS init failed: %s "
705 "priority table overflow", which);
706 return FALSE;
707 }
708 }
709 }
710 }
711 }
712 }
713
714DEBUG(D_tls)
715 {
716 int *ptr = plist;
717 debug_printf("adjusted %s priorities:", which);
718 while (*ptr != 0) debug_printf(" %d", *ptr++);
719 debug_printf("\n");
720 }
721
722return TRUE;
723}
724
725
726
727
728/*************************************************
059ec3d9
PH
729* Initialize a single GNUTLS session *
730*************************************************/
731
732/* Set the algorithm, the db backend, whether to request certificates etc.
733
734TLS in Exim was first implemented using OpenSSL. This has a function to which
735you pass a list of cipher suites that are permitted/not permitted. GnuTLS works
736differently. It operates using priority lists for the different components of
737cipher suites.
738
739For compatibility of configuration, we scan a list of cipher suites and set
740priorities therefrom. However, at the moment, we pay attention only to the bulk
741cipher.
742
743Arguments:
744 side one of GNUTLS_SERVER, GNUTLS_CLIENT
83da1223
PH
745 expciphers expanded ciphers list or NULL
746 expmac expanded MAC list or NULL
747 expkx expanded key-exchange list or NULL
748 expproto expanded protocol list or NULL
059ec3d9
PH
749
750Returns: a gnutls_session, or NULL if there is a problem
751*/
752
753static gnutls_session
83da1223
PH
754tls_session_init(int side, uschar *expciphers, uschar *expmac, uschar *expkx,
755 uschar *expproto)
059ec3d9
PH
756{
757gnutls_session session;
758
759gnutls_init(&session, side);
760
83da1223
PH
761/* Initialize the lists of permitted protocols, key-exchange methods, ciphers,
762and MACs. */
059ec3d9
PH
763
764memcpy(cipher_priority, default_cipher_priority, sizeof(cipher_priority));
83da1223
PH
765memcpy(mac_priority, default_mac_priority, sizeof(mac_priority));
766memcpy(kx_priority, default_kx_priority, sizeof(kx_priority));
767memcpy(proto_priority, default_proto_priority, sizeof(proto_priority));
768
769/* The names OpenSSL uses in tls_require_ciphers are of the form DES-CBC3-SHA,
770using hyphen separators. GnuTLS uses underscore separators. So that I can use
771either form for tls_require_ciphers in my tests, and also for general
772convenience, we turn hyphens into underscores before scanning the list. */
059ec3d9
PH
773
774if (expciphers != NULL)
775 {
059ec3d9
PH
776 uschar *s = expciphers;
777 while (*s != 0) { if (*s == '-') *s = '_'; s++; }
83da1223 778 }
059ec3d9 779
83da1223
PH
780if ((expciphers != NULL &&
781 !set_priority(cipher_priority, sizeof(cipher_priority)/sizeof(int),
782 expciphers, cipher_index, sizeof(cipher_index)/sizeof(pri_item),
783 US"cipher")) ||
784 (expmac != NULL &&
785 !set_priority(mac_priority, sizeof(mac_priority)/sizeof(int),
786 expmac, mac_index, sizeof(mac_index)/sizeof(pri_item),
787 US"MAC")) ||
788 (expkx != NULL &&
789 !set_priority(kx_priority, sizeof(kx_priority)/sizeof(int),
790 expkx, kx_index, sizeof(kx_index)/sizeof(pri_item),
791 US"key-exchange")) ||
792 (expproto != NULL &&
793 !set_priority(proto_priority, sizeof(proto_priority)/sizeof(int),
794 expproto, proto_index, sizeof(proto_index)/sizeof(pri_item),
795 US"protocol")))
796 {
797 gnutls_deinit(session);
798 return NULL;
059ec3d9
PH
799 }
800
801/* Define the various priorities */
802
803gnutls_cipher_set_priority(session, cipher_priority);
804gnutls_compression_set_priority(session, comp_priority);
805gnutls_kx_set_priority(session, kx_priority);
83da1223 806gnutls_protocol_set_priority(session, proto_priority);
059ec3d9
PH
807gnutls_mac_set_priority(session, mac_priority);
808
809gnutls_cred_set(session, GNUTLS_CRD_CERTIFICATE, x509_cred);
810
811gnutls_dh_set_prime_bits(session, DH_BITS);
812
813/* Request or demand a certificate of the peer, as configured. This will
814happen only in a server. */
815
816if (verify_requirement != VERIFY_NONE)
817 gnutls_certificate_server_set_request(session,
818 (verify_requirement == VERIFY_OPTIONAL)?
819 GNUTLS_CERT_REQUEST : GNUTLS_CERT_REQUIRE);
820
821gnutls_db_set_cache_expiration(session, ssl_session_timeout);
822
e6060e2c
NM
823/* Reduce security in favour of increased compatibility, if the admin
824decides to make that trade-off. */
825if (gnutls_compat_mode)
826 {
827#if LIBGNUTLS_VERSION_NUMBER >= 0x020104
828 DEBUG(D_tls) debug_printf("lowering GnuTLS security, compatibility mode\n");
829 gnutls_session_enable_compatibility_mode(session);
830#else
831 DEBUG(D_tls) debug_printf("Unable to set gnutls_compat_mode - GnuTLS version too old\n");
832#endif
833 }
834
059ec3d9
PH
835DEBUG(D_tls) debug_printf("initialized GnuTLS session\n");
836return session;
837}
838
839
840
841/*************************************************
842* Get name of cipher in use *
843*************************************************/
844
845/* The answer is left in a static buffer, and tls_cipher is set to point
846to it.
847
848Argument: pointer to a GnuTLS session
849Returns: nothing
850*/
851
852static void
853construct_cipher_name(gnutls_session session)
854{
855static uschar cipherbuf[256];
856uschar *ver;
edc33b5f 857int c, kx, mac;
44bbabb5 858#ifdef GNUTLS_CB_TLS_UNIQUE
f1e05cc7 859int rc;
44bbabb5
PP
860gnutls_datum_t channel;
861#endif
059ec3d9
PH
862
863ver = string_copy(
864 US gnutls_protocol_get_name(gnutls_protocol_get_version(session)));
865if (Ustrncmp(ver, "TLS ", 4) == 0) ver[3] = '-'; /* Don't want space */
866
867c = gnutls_cipher_get(session);
edc33b5f
PP
868/* returns size in "bytes" */
869tls_bits = gnutls_cipher_get_key_size(c) * 8;
059ec3d9
PH
870
871mac = gnutls_mac_get(session);
872kx = gnutls_kx_get(session);
873
874string_format(cipherbuf, sizeof(cipherbuf), "%s:%s:%u", ver,
edc33b5f 875 gnutls_cipher_suite_get_name(kx, c, mac), tls_bits);
059ec3d9
PH
876tls_cipher = cipherbuf;
877
878DEBUG(D_tls) debug_printf("cipher: %s\n", cipherbuf);
44bbabb5
PP
879
880if (tls_channelbinding_b64)
881 free(tls_channelbinding_b64);
882tls_channelbinding_b64 = NULL;
883
884#ifdef GNUTLS_CB_TLS_UNIQUE
885channel = { NULL, 0 };
886rc = gnutls_session_channel_binding(session, GNUTLS_CB_TLS_UNIQUE, &channel);
887if (rc) {
888 DEBUG(D_tls) debug_printf("Channel binding error: %s\n", gnutls_strerror(rc));
889} else {
890 tls_channelbinding_b64 = auth_b64encode(channel.data, (int)channel.size);
891 DEBUG(D_tls) debug_printf("Have channel bindings cached for possible auth usage.\n");
892}
893#endif
059ec3d9
PH
894}
895
896
897
898/*************************************************
899* Start a TLS session in a server *
900*************************************************/
901
902/* This is called when Exim is running as a server, after having received
903the STARTTLS command. It must respond to that command, and then negotiate
904a TLS session.
905
906Arguments:
83da1223
PH
907 require_ciphers list of allowed ciphers or NULL
908 require_mac list of allowed MACs or NULL
909 require_kx list of allowed key_exchange methods or NULL
910 require_proto list of allowed protocols or NULL
059ec3d9
PH
911
912Returns: OK on success
913 DEFER for errors before the start of the negotiation
914 FAIL for errors during the negotation; the server can't
915 continue running.
916*/
917
918int
83da1223
PH
919tls_server_start(uschar *require_ciphers, uschar *require_mac,
920 uschar *require_kx, uschar *require_proto)
059ec3d9
PH
921{
922int rc;
7199e1ee 923const char *error;
059ec3d9 924uschar *expciphers = NULL;
83da1223
PH
925uschar *expmac = NULL;
926uschar *expkx = NULL;
927uschar *expproto = NULL;
059ec3d9
PH
928
929/* Check for previous activation */
930
931if (tls_active >= 0)
932 {
7199e1ee 933 tls_error("STARTTLS received after TLS started", NULL, "");
059ec3d9
PH
934 smtp_printf("554 Already in TLS\r\n");
935 return FAIL;
936 }
937
938/* Initialize the library. If it fails, it will already have logged the error
939and sent an SMTP response. */
940
941DEBUG(D_tls) debug_printf("initializing GnuTLS as a server\n");
942
943rc = tls_init(NULL, tls_certificate, tls_privatekey, tls_verify_certificates,
944 tls_crl);
945if (rc != OK) return rc;
946
83da1223
PH
947if (!expand_check(require_ciphers, US"tls_require_ciphers", &expciphers) ||
948 !expand_check(require_mac, US"gnutls_require_mac", &expmac) ||
949 !expand_check(require_kx, US"gnutls_require_kx", &expkx) ||
950 !expand_check(require_proto, US"gnutls_require_proto", &expproto))
059ec3d9
PH
951 return FAIL;
952
953/* If this is a host for which certificate verification is mandatory or
954optional, set up appropriately. */
955
956tls_certificate_verified = FALSE;
957verify_requirement = VERIFY_NONE;
958
959if (verify_check_host(&tls_verify_hosts) == OK)
960 verify_requirement = VERIFY_REQUIRED;
961else if (verify_check_host(&tls_try_verify_hosts) == OK)
962 verify_requirement = VERIFY_OPTIONAL;
963
964/* Prepare for new connection */
965
83da1223
PH
966tls_session = tls_session_init(GNUTLS_SERVER, expciphers, expmac, expkx,
967 expproto);
059ec3d9 968if (tls_session == NULL)
7199e1ee
TF
969 return tls_error(US"tls_session_init", NULL,
970 gnutls_strerror(GNUTLS_E_MEMORY_ERROR));
059ec3d9
PH
971
972/* Set context and tell client to go ahead, except in the case of TLS startup
973on connection, where outputting anything now upsets the clients and tends to
974make them disconnect. We need to have an explicit fflush() here, to force out
975the response. Other smtp_printf() calls do not need it, because in non-TLS
976mode, the fflush() happens when smtp_getc() is called. */
977
978if (!tls_on_connect)
979 {
980 smtp_printf("220 TLS go ahead\r\n");
981 fflush(smtp_out);
982 }
983
984/* Now negotiate the TLS session. We put our own timer on it, since it seems
985that the GnuTLS library doesn't. */
986
56f5d9bd
PH
987gnutls_transport_set_ptr2(tls_session, (gnutls_transport_ptr)fileno(smtp_in),
988 (gnutls_transport_ptr)fileno(smtp_out));
059ec3d9
PH
989
990sigalrm_seen = FALSE;
991if (smtp_receive_timeout > 0) alarm(smtp_receive_timeout);
992rc = gnutls_handshake(tls_session);
993alarm(0);
994
995if (rc < 0)
996 {
7199e1ee
TF
997 tls_error(US"gnutls_handshake", NULL,
998 sigalrm_seen ? "timed out" : gnutls_strerror(rc));
059ec3d9
PH
999
1000 /* It seems that, except in the case of a timeout, we have to close the
1001 connection right here; otherwise if the other end is running OpenSSL it hangs
1002 until the server times out. */
1003
1004 if (!sigalrm_seen)
1005 {
f1e894f3
PH
1006 (void)fclose(smtp_out);
1007 (void)fclose(smtp_in);
059ec3d9
PH
1008 }
1009
1010 return FAIL;
1011 }
1012
1013DEBUG(D_tls) debug_printf("gnutls_handshake was successful\n");
1014
1015if (verify_requirement != VERIFY_NONE &&
1016 !verify_certificate(tls_session, &error))
1017 {
7199e1ee 1018 tls_error(US"certificate verification failed", NULL, error);
059ec3d9
PH
1019 return FAIL;
1020 }
1021
1022construct_cipher_name(tls_session);
1023
1024/* TLS has been set up. Adjust the input functions to read via TLS,
1025and initialize appropriately. */
1026
1027ssl_xfer_buffer = store_malloc(ssl_xfer_buffer_size);
1028ssl_xfer_buffer_lwm = ssl_xfer_buffer_hwm = 0;
1029ssl_xfer_eof = ssl_xfer_error = 0;
1030
1031receive_getc = tls_getc;
1032receive_ungetc = tls_ungetc;
1033receive_feof = tls_feof;
1034receive_ferror = tls_ferror;
58eb016e 1035receive_smtp_buffered = tls_smtp_buffered;
059ec3d9
PH
1036
1037tls_active = fileno(smtp_out);
1038
1039return OK;
1040}
1041
1042
1043
1044
1045/*************************************************
1046* Start a TLS session in a client *
1047*************************************************/
1048
1049/* Called from the smtp transport after STARTTLS has been accepted.
1050
1051Arguments:
1052 fd the fd of the connection
1053 host connected host (for messages)
83da1223 1054 addr the first address (not used)
059ec3d9
PH
1055 dhparam DH parameter file
1056 certificate certificate file
1057 privatekey private key file
3f0945ff 1058 sni TLS SNI to send to remote host
059ec3d9
PH
1059 verify_certs file for certificate verify
1060 verify_crl CRL for verify
83da1223
PH
1061 require_ciphers list of allowed ciphers or NULL
1062 require_mac list of allowed MACs or NULL
1063 require_kx list of allowed key_exchange methods or NULL
1064 require_proto list of allowed protocols or NULL
059ec3d9
PH
1065 timeout startup timeout
1066
1067Returns: OK/DEFER/FAIL (because using common functions),
1068 but for a client, DEFER and FAIL have the same meaning
1069*/
1070
1071int
1072tls_client_start(int fd, host_item *host, address_item *addr, uschar *dhparam,
3f0945ff
PP
1073 uschar *certificate, uschar *privatekey, uschar *sni ARG_UNUSED,
1074 uschar *verify_certs, uschar *verify_crl,
1075 uschar *require_ciphers, uschar *require_mac,
83da1223 1076 uschar *require_kx, uschar *require_proto, int timeout)
059ec3d9
PH
1077{
1078const gnutls_datum *server_certs;
1079uschar *expciphers = NULL;
83da1223
PH
1080uschar *expmac = NULL;
1081uschar *expkx = NULL;
1082uschar *expproto = NULL;
7199e1ee 1083const char *error;
059ec3d9
PH
1084unsigned int server_certs_size;
1085int rc;
1086
1087DEBUG(D_tls) debug_printf("initializing GnuTLS as a client\n");
1088
059ec3d9
PH
1089verify_requirement = (verify_certs == NULL)? VERIFY_NONE : VERIFY_REQUIRED;
1090rc = tls_init(host, certificate, privatekey, verify_certs, verify_crl);
1091if (rc != OK) return rc;
1092
83da1223
PH
1093if (!expand_check(require_ciphers, US"tls_require_ciphers", &expciphers) ||
1094 !expand_check(require_mac, US"gnutls_require_mac", &expmac) ||
1095 !expand_check(require_kx, US"gnutls_require_kx", &expkx) ||
1096 !expand_check(require_proto, US"gnutls_require_proto", &expproto))
059ec3d9
PH
1097 return FAIL;
1098
83da1223
PH
1099tls_session = tls_session_init(GNUTLS_CLIENT, expciphers, expmac, expkx,
1100 expproto);
1101
059ec3d9 1102if (tls_session == NULL)
7199e1ee
TF
1103 return tls_error(US "tls_session_init", host,
1104 gnutls_strerror(GNUTLS_E_MEMORY_ERROR));
059ec3d9
PH
1105
1106gnutls_transport_set_ptr(tls_session, (gnutls_transport_ptr)fd);
1107
1108/* There doesn't seem to be a built-in timeout on connection. */
1109
1110sigalrm_seen = FALSE;
1111alarm(timeout);
1112rc = gnutls_handshake(tls_session);
1113alarm(0);
1114
1115if (rc < 0)
7199e1ee
TF
1116 return tls_error(US "gnutls_handshake", host,
1117 sigalrm_seen ? "timed out" : gnutls_strerror(rc));
059ec3d9
PH
1118
1119server_certs = gnutls_certificate_get_peers(tls_session, &server_certs_size);
1120
1121if (server_certs != NULL)
1122 {
1123 uschar buff[1024];
1124 gnutls_x509_crt gcert;
1125
1126 gnutls_x509_crt_init(&gcert);
1127 tls_peerdn = US"unknown";
1128
1129 if (gnutls_x509_crt_import(gcert, server_certs, GNUTLS_X509_FMT_DER) == 0)
1130 {
1131 size_t bufsize = sizeof(buff);
1132 if (gnutls_x509_crt_get_dn(gcert, CS buff, &bufsize) >= 0)
1133 tls_peerdn = string_copy_malloc(buff);
1134 }
1135 }
1136
1137/* Should we also verify the hostname here? */
1138
1139if (verify_requirement != VERIFY_NONE &&
1140 !verify_certificate(tls_session, &error))
7199e1ee 1141 return tls_error(US"certificate verification failed", host, error);
059ec3d9
PH
1142
1143construct_cipher_name(tls_session); /* Sets tls_cipher */
1144tls_active = fd;
1145return OK;
1146}
1147
1148
1149
1150/*************************************************
1151* Deal with logging errors during I/O *
1152*************************************************/
1153
1154/* We have to get the identity of the peer from saved data.
1155
1156Argument:
1157 ec the GnuTLS error code, or 0 if it's a local error
1158 when text identifying read or write
1159 text local error text when ec is 0
1160
1161Returns: nothing
1162*/
1163
1164static void
1165record_io_error(int ec, uschar *when, uschar *text)
1166{
7199e1ee 1167const char *msg;
059ec3d9
PH
1168
1169if (ec == GNUTLS_E_FATAL_ALERT_RECEIVED)
7199e1ee 1170 msg = string_sprintf("%s: %s", gnutls_strerror(ec),
059ec3d9 1171 gnutls_alert_get_name(gnutls_alert_get(tls_session)));
059ec3d9 1172else
7199e1ee
TF
1173 msg = gnutls_strerror(ec);
1174
1175tls_error(when, client_host, msg);
059ec3d9
PH
1176}
1177
1178
1179
1180/*************************************************
1181* TLS version of getc *
1182*************************************************/
1183
1184/* This gets the next byte from the TLS input buffer. If the buffer is empty,
1185it refills the buffer via the GnuTLS reading function.
1186
1187Arguments: none
1188Returns: the next character or EOF
1189*/
1190
1191int
1192tls_getc(void)
1193{
1194if (ssl_xfer_buffer_lwm >= ssl_xfer_buffer_hwm)
1195 {
1196 int inbytes;
1197
1198 DEBUG(D_tls) debug_printf("Calling gnutls_record_recv(%lx, %lx, %u)\n",
1199 (long) tls_session, (long) ssl_xfer_buffer, ssl_xfer_buffer_size);
1200
1201 if (smtp_receive_timeout > 0) alarm(smtp_receive_timeout);
1202 inbytes = gnutls_record_recv(tls_session, CS ssl_xfer_buffer,
1203 ssl_xfer_buffer_size);
1204 alarm(0);
1205
1206 /* A zero-byte return appears to mean that the TLS session has been
1207 closed down, not that the socket itself has been closed down. Revert to
1208 non-TLS handling. */
1209
1210 if (inbytes == 0)
1211 {
1212 DEBUG(D_tls) debug_printf("Got TLS_EOF\n");
1213
1214 receive_getc = smtp_getc;
1215 receive_ungetc = smtp_ungetc;
1216 receive_feof = smtp_feof;
1217 receive_ferror = smtp_ferror;
58eb016e 1218 receive_smtp_buffered = smtp_buffered;
059ec3d9
PH
1219
1220 gnutls_deinit(tls_session);
1221 tls_session = NULL;
1222 tls_active = -1;
1223 tls_cipher = NULL;
1224 tls_peerdn = NULL;
1225
1226 return smtp_getc();
1227 }
1228
1229 /* Handle genuine errors */
1230
1231 else if (inbytes < 0)
1232 {
1233 record_io_error(inbytes, US"recv", NULL);
1234 ssl_xfer_error = 1;
1235 return EOF;
1236 }
80a47a2c
TK
1237#ifndef DISABLE_DKIM
1238 dkim_exim_verify_feed(ssl_xfer_buffer, inbytes);
1239#endif
059ec3d9
PH
1240 ssl_xfer_buffer_hwm = inbytes;
1241 ssl_xfer_buffer_lwm = 0;
1242 }
1243
1244
1245/* Something in the buffer; return next uschar */
1246
1247return ssl_xfer_buffer[ssl_xfer_buffer_lwm++];
1248}
1249
1250
1251
1252/*************************************************
1253* Read bytes from TLS channel *
1254*************************************************/
1255
1256/*
1257Arguments:
1258 buff buffer of data
1259 len size of buffer
1260
1261Returns: the number of bytes read
1262 -1 after a failed read
1263*/
1264
1265int
1266tls_read(uschar *buff, size_t len)
1267{
1268int inbytes;
1269
1270DEBUG(D_tls) debug_printf("Calling gnutls_record_recv(%lx, %lx, %u)\n",
1271 (long) tls_session, (long) buff, len);
1272
1273inbytes = gnutls_record_recv(tls_session, CS buff, len);
1274if (inbytes > 0) return inbytes;
1275if (inbytes == 0)
1276 {
1277 DEBUG(D_tls) debug_printf("Got TLS_EOF\n");
1278 }
1279else record_io_error(inbytes, US"recv", NULL);
1280
1281return -1;
1282}
1283
1284
1285
1286/*************************************************
1287* Write bytes down TLS channel *
1288*************************************************/
1289
1290/*
1291Arguments:
1292 buff buffer of data
1293 len number of bytes
1294
1295Returns: the number of bytes after a successful write,
1296 -1 after a failed write
1297*/
1298
1299int
1300tls_write(const uschar *buff, size_t len)
1301{
1302int outbytes;
1303int left = len;
1304
1305DEBUG(D_tls) debug_printf("tls_do_write(%lx, %d)\n", (long) buff, left);
1306while (left > 0)
1307 {
1308 DEBUG(D_tls) debug_printf("gnutls_record_send(SSL, %lx, %d)\n", (long)buff,
1309 left);
1310 outbytes = gnutls_record_send(tls_session, CS buff, left);
1311
1312 DEBUG(D_tls) debug_printf("outbytes=%d\n", outbytes);
1313 if (outbytes < 0)
1314 {
1315 record_io_error(outbytes, US"send", NULL);
1316 return -1;
1317 }
1318 if (outbytes == 0)
1319 {
1320 record_io_error(0, US"send", US"TLS channel closed on write");
1321 return -1;
1322 }
1323
1324 left -= outbytes;
1325 buff += outbytes;
1326 }
1327
1328return len;
1329}
1330
1331
1332
1333/*************************************************
1334* Close down a TLS session *
1335*************************************************/
1336
1337/* This is also called from within a delivery subprocess forked from the
1338daemon, to shut down the TLS library, without actually doing a shutdown (which
1339would tamper with the TLS session in the parent process).
1340
1341Arguments: TRUE if gnutls_bye is to be called
1342Returns: nothing
1343*/
1344
1345void
1346tls_close(BOOL shutdown)
1347{
1348if (tls_active < 0) return; /* TLS was not active */
1349
1350if (shutdown)
1351 {
1352 DEBUG(D_tls) debug_printf("tls_close(): shutting down TLS\n");
1353 gnutls_bye(tls_session, GNUTLS_SHUT_WR);
1354 }
1355
1356gnutls_deinit(tls_session);
1357tls_session = NULL;
1358gnutls_global_deinit();
1359
1360tls_active = -1;
1361}
1362
36f12725
NM
1363
1364
1365
1366/*************************************************
1367* Report the library versions. *
1368*************************************************/
1369
1370/* See a description in tls-openssl.c for an explanation of why this exists.
1371
1372Arguments: a FILE* to print the results to
1373Returns: nothing
1374*/
1375
1376void
1377tls_version_report(FILE *f)
1378{
754a0503
PP
1379fprintf(f, "Library version: GnuTLS: Compile: %s\n"
1380 " Runtime: %s\n",
1381 LIBGNUTLS_VERSION,
1382 gnutls_check_version(NULL));
36f12725
NM
1383}
1384
059ec3d9 1385/* End of tls-gnu.c */