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