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