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