1 /* $Cambridge: exim/src/src/tls-gnu.c,v 1.14 2006/10/16 13:20:18 ph10 Exp $ */
3 /*************************************************
4 * Exim - an Internet mail transport agent *
5 *************************************************/
7 /* Copyright (c) University of Cambridge 1995 - 2006 */
8 /* See the file NOTICE for conditions of use and distribution. */
10 /* This module provides TLS (aka SSL) support for Exim using the GnuTLS
11 library. It is #included into tls.c when that library is used. The code herein
12 is based on a patch that was contributed by Nikos Mavroyanopoulos.
14 No cryptographic code is included in Exim. All this module does is to call
15 functions from the GnuTLS library. */
18 /* Heading stuff for GnuTLS */
20 #include <gnutls/gnutls.h>
21 #include <gnutls/x509.h>
24 #define UNKNOWN_NAME "unknown"
26 #define PARAM_SIZE 2*1024
29 /* Values for verify_requirment and initialized */
31 enum { VERIFY_NONE, VERIFY_OPTIONAL, VERIFY_REQUIRED };
32 enum { INITIALIZED_NOT, INITIALIZED_SERVER, INITIALIZED_CLIENT };
34 /* Local static variables for GNUTLS */
36 static BOOL initialized = INITIALIZED_NOT;
37 static host_item *client_host;
39 static gnutls_dh_params dh_params = NULL;
41 static gnutls_certificate_server_credentials x509_cred = NULL;
42 static gnutls_session tls_session = NULL;
44 static char ssl_errstring[256];
46 static int ssl_session_timeout = 200;
47 static int verify_requirement;
49 /* Priorities for TLS algorithms to use. At present, only the cipher priority
50 vector can be altered. */
52 static const int protocol_priority[16] = { GNUTLS_TLS1, GNUTLS_SSL3, 0 };
54 static const int kx_priority[16] = {
60 static int default_cipher_priority[16] = {
61 GNUTLS_CIPHER_AES_256_CBC,
62 GNUTLS_CIPHER_AES_128_CBC,
63 GNUTLS_CIPHER_3DES_CBC,
64 GNUTLS_CIPHER_ARCFOUR_128,
67 static int cipher_priority[16];
69 static const int mac_priority[16] = {
74 static const int comp_priority[16] = { GNUTLS_COMP_NULL, 0 };
75 static const int cert_type_priority[16] = { GNUTLS_CRT_X509, 0 };
77 /* Tables of cipher names and equivalent numbers */
79 typedef struct pri_item {
84 static int arcfour_128_codes[] = { GNUTLS_CIPHER_ARCFOUR_128, 0 };
85 static int arcfour_40_codes[] = { GNUTLS_CIPHER_ARCFOUR_40, 0 };
86 static int arcfour_codes[] = { GNUTLS_CIPHER_ARCFOUR_128,
87 GNUTLS_CIPHER_ARCFOUR_40, 0 };
88 static int aes_256_codes[] = { GNUTLS_CIPHER_AES_256_CBC, 0 };
89 static int aes_128_codes[] = { GNUTLS_CIPHER_AES_128_CBC, 0 };
90 static int aes_codes[] = { GNUTLS_CIPHER_AES_256_CBC,
91 GNUTLS_CIPHER_AES_128_CBC, 0 };
92 static int des3_codes[] = { GNUTLS_CIPHER_3DES_CBC, 0 };
94 static 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 }
106 /*************************************************
108 *************************************************/
110 /* Called from lots of places when errors occur before actually starting to do
111 the TLS handshake, that is, while the session is still in clear. Always returns
112 DEFER for a server and FAIL for a client so that most calls can use "return
113 tls_error(...)" to do this processing and then give an appropriate return. A
114 single function is used for both server and client, because it is called from
115 some shared functions.
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
123 Returns: OK/DEFER/FAIL
127 tls_error(uschar *prefix, host_item *host, int err)
129 uschar *errtext = US"";
130 if (err != 0) errtext = string_sprintf(": %s", gnutls_strerror(err));
133 log_write(0, LOG_MAIN, "TLS error on connection from %s (%s)%s",
134 (sender_fullhost != NULL)? sender_fullhost : US "local process",
140 log_write(0, LOG_MAIN, "TLS error on connection to %s [%s] (%s)%s",
141 host->name, host->address, prefix, errtext);
148 /*************************************************
149 * Verify certificate *
150 *************************************************/
152 /* Called after a successful handshake, when certificate verification is
153 required or optional, for both server and client.
156 session GNUTLS session
157 error where to put text giving a reason for failure
163 verify_certificate(gnutls_session session, uschar **error)
166 uschar *dn_string = US"";
167 const gnutls_datum *cert;
168 unsigned int cert_size = 0;
172 /* Get the peer's certificate. If it sent one, extract it's DN, and then
173 attempt to verify the certificate. If no certificate is supplied, verification
174 is forced to fail. */
176 cert = gnutls_certificate_get_peers(session, &cert_size);
180 gnutls_x509_crt gcert;
182 gnutls_x509_crt_init(&gcert);
183 dn_string = US"unknown";
185 if (gnutls_x509_crt_import(gcert, cert, GNUTLS_X509_FMT_DER) == 0)
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);
192 verify = gnutls_certificate_verify_peers(session);
196 DEBUG(D_tls) debug_printf("no peer certificate supplied\n");
197 verify = GNUTLS_CERT_INVALID;
198 *error = US"not supplied";
201 /* Handle the result of verification. INVALID seems to be set as well
202 as REVOKED, but leave the test for both. */
204 if ((verify & (GNUTLS_CERT_INVALID|GNUTLS_CERT_REVOKED)) != 0)
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)
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 */
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);
221 tls_certificate_verified = TRUE;
222 DEBUG(D_tls) debug_printf("TLS certificate verified: peerdn=%s\n",
226 tls_peerdn = dn_string;
227 return TRUE; /* accept */
232 /*************************************************
233 * Setup up DH parameters *
234 *************************************************/
236 /* Generating the D-H parameters may take a long time. They only need to
237 be re-generated every so often, depending on security policy. What we do is to
238 keep these parameters in a file in the spool directory. If the file does not
239 exist, we generate them. This means that it is easy to cause a regeneration.
241 The new file is written as a temporary file and renamed, so that an incomplete
242 file is never present. If two processes both compute some new parameters, you
243 waste a bit of effort, but it doesn't seem worth messing around with locking to
247 host NULL for server, server for client (for error handling)
249 Returns: OK/DEFER/FAIL
253 init_dh(host_item *host)
258 uschar filename[200];
260 /* Initialize the data structures for holding the parameters */
262 ret = gnutls_dh_params_init(&dh_params);
263 if (ret < 0) return tls_error(US"init dh_params", host, ret);
265 /* Set up the name of the cache file */
267 if (!string_format(filename, sizeof(filename), "%s/gnutls-params",
269 return tls_error(US"overlong filename", host, 0);
271 /* Open the cache file for reading and if successful, read it and set up the
274 fd = Uopen(filename, O_RDONLY, 0);
278 if (fstat(fd, &statbuf) < 0)
281 return tls_error(US"TLS cache stat failed", host, 0);
284 m.size = statbuf.st_size;
285 m.data = malloc(m.size);
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);
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);
294 DEBUG(D_tls) debug_printf("read D-H parameters from file\n");
299 /* If the file does not exist, fall through to compute new data and cache it.
300 If there was any other opening error, it is serious. */
302 else if (errno == ENOENT)
306 debug_printf("parameter cache file %s does not exist\n", filename);
309 return tls_error(string_open_failed(errno, "%s for reading", filename),
312 /* If ret < 0, either the cache file does not exist, or the data it contains
313 is not useful. One particular case of this is when upgrading from an older
314 release of Exim in which the data was stored in a different format. We don't
315 try to be clever and support both formats; we just regenerate new data in this
320 uschar tempfilename[sizeof(filename) + 10];
322 DEBUG(D_tls) debug_printf("generating %d bit Diffie-Hellman key...\n",
324 ret = gnutls_dh_params_generate2(dh_params, DH_BITS);
325 if (ret < 0) return tls_error(US"D-H key generation", host, ret);
327 /* Write the parameters to a file in the spool directory so that we
328 can use them from other Exim processes. */
330 sprintf(CS tempfilename, "%s-%d", filename, (int)getpid());
331 fd = Uopen(tempfilename, O_WRONLY|O_CREAT, 0400);
333 return tls_error(string_open_failed(errno, "%s for writing", filename),
335 (void)fchown(fd, exim_uid, exim_gid); /* Probably not necessary */
337 /* export the parameters in a format that can be generated using GNUTLS'
338 * certtool or other programs.
340 * The commands for certtool are:
341 * $ certtool --generate-dh-params --bits 1024 > params
345 m.data = malloc(m.size);
347 return tls_error(US"memory allocation failed", host, 0);
350 ret = gnutls_dh_params_export_pkcs3(dh_params, GNUTLS_X509_FMT_PEM, m.data,
352 if (ret < 0) return tls_error(US"DH params export", host, ret);
354 m.size = Ustrlen(m.data);
355 if (write(fd, m.data, m.size) != m.size || write(fd, "\n", 1) != 1)
356 return tls_error(US"TLS cache write failed", host, 0);
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);
365 DEBUG(D_tls) debug_printf("wrote D-H parameters to file %s\n", filename);
368 DEBUG(D_tls) debug_printf("initialized D-H parameters\n");
375 /*************************************************
376 * Initialize for GnuTLS *
377 *************************************************/
379 /* Called from both server and client code. In the case of a server, errors
380 before actual TLS negotiation return DEFER.
383 host connected host, if client; NULL if server
384 certificate certificate file
385 privatekey private key file
389 Returns: OK/DEFER/FAIL
393 tls_init(host_item *host, uschar *certificate, uschar *privatekey, uschar *cas,
397 uschar *cert_expanded, *key_expanded, *cas_expanded, *crl_expanded;
399 initialized = (host == NULL)? INITIALIZED_SERVER : INITIALIZED_CLIENT;
401 rc = gnutls_global_init();
402 if (rc < 0) return tls_error(US"tls-init", host, rc);
404 /* Create D-H parameters, or read them from the cache file. This function does
405 its own SMTP error messaging. */
408 if (rc != OK) return rc;
410 /* Create the credentials structure */
412 rc = gnutls_certificate_allocate_credentials(&x509_cred);
413 if (rc < 0) return tls_error(US"certificate_allocate_credentials", host, rc);
415 /* This stuff must be done for each session, because different certificates
416 may be required for different sessions. */
418 if (!expand_check(certificate, US"tls_certificate", &cert_expanded))
422 if (privatekey != NULL)
424 if (!expand_check(privatekey, US"tls_privatekey", &key_expanded))
428 /* If expansion was forced to fail, key_expanded will be NULL. If the result of
429 the expansion is an empty string, ignore it also, and assume that the private
430 key is in the same file as the certificate. */
432 if (key_expanded == NULL || *key_expanded == 0)
433 key_expanded = cert_expanded;
435 /* Set the certificate and private keys */
437 if (cert_expanded != NULL)
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);
445 uschar *msg = string_sprintf("cert/key setup: cert=%s key=%s",
446 cert_expanded, key_expanded);
447 return tls_error(msg, host, rc);
451 /* A certificate is mandatory in a server, but not in a client */
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");
460 /* Set the trusted CAs file if one is provided, and then add the CRL if one is
461 provided. Experiment shows that, if the certificate file is empty, an unhelpful
462 error message is provided. However, if we just refrain from setting anything up
463 in that case, certificate verification fails, which seems to be the correct
470 if (!expand_check(cas, US"tls_verify_certificates", &cas_expanded))
473 if (stat(CS cas_expanded, &statbuf) < 0)
475 log_write(0, LOG_MAIN|LOG_PANIC, "could not stat %s "
476 "(tls_verify_certificates): %s", cas_expanded, strerror(errno));
480 DEBUG(D_tls) debug_printf("verify certificates = %s size=" OFF_T_FMT "\n",
481 cas_expanded, statbuf.st_size);
483 /* If the cert file is empty, there's no point in loading the CRL file. */
485 if (statbuf.st_size > 0)
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);
491 if (crl != NULL && *crl != 0)
493 if (!expand_check(crl, US"tls_crl", &crl_expanded))
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);
503 /* Associate the parameters with the x509 credentials structure. */
505 gnutls_certificate_set_dh_params(x509_cred, dh_params);
507 DEBUG(D_tls) debug_printf("initialized certificate stuff\n");
514 /*************************************************
515 * Remove ciphers from priority list *
516 *************************************************/
518 /* Cautiously written so that it will remove duplicates if present.
521 list a zero-terminated list
522 remove_list a zero-terminated list to be removed
528 remove_ciphers(int *list, int *remove_list)
530 for (; *remove_list != 0; remove_list++)
535 if (*p == *remove_list)
538 do { pp[0] = pp[1]; pp++; } while (*pp != 0);
547 /*************************************************
548 * Add ciphers to priority list *
549 *************************************************/
551 /* Cautiously written to check the list size
554 list a zero-terminated list
555 list_max maximum offset in the list
556 add_list a zero-terminated list to be added
558 Returns: TRUE if OK; FALSE if list overflows
562 add_ciphers(int *list, int list_max, int *add_list)
565 while (list[next] != 0) next++;
566 while (*add_list != 0)
568 if (next >= list_max) return FALSE;
569 list[next++] = *add_list++;
577 /*************************************************
578 * Initialize a single GNUTLS session *
579 *************************************************/
581 /* Set the algorithm, the db backend, whether to request certificates etc.
583 TLS in Exim was first implemented using OpenSSL. This has a function to which
584 you pass a list of cipher suites that are permitted/not permitted. GnuTLS works
585 differently. It operates using priority lists for the different components of
588 For compatibility of configuration, we scan a list of cipher suites and set
589 priorities therefrom. However, at the moment, we pay attention only to the bulk
593 side one of GNUTLS_SERVER, GNUTLS_CLIENT
594 expciphers expanded ciphers list
596 Returns: a gnutls_session, or NULL if there is a problem
599 static gnutls_session
600 tls_session_init(int side, uschar *expciphers)
602 gnutls_session session;
604 gnutls_init(&session, side);
606 /* Handle the list of permitted ciphers */
608 memcpy(cipher_priority, default_cipher_priority, sizeof(cipher_priority));
610 if (expciphers != NULL)
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. */
621 uschar *s = expciphers;
622 while (*s != 0) { if (*s == '-') *s = '_'; s++; }
624 while ((cipher = string_nextinlist(&expciphers, &sep, big_buffer,
625 big_buffer_size)) != NULL)
628 BOOL exclude = cipher[0] == '!';
629 if (first && !exclude) cipher_priority[0] = 0;
632 for (i = 0; i < sizeof(cipher_index)/sizeof(pri_item); i++)
634 uschar *ss = strstric(cipher, cipher_index[i].name, FALSE);
637 uschar *endss = ss + Ustrlen(cipher_index[i].name);
638 if ((ss == cipher || !isalnum(ss[-1])) && !isalnum(*endss))
641 remove_ciphers(cipher_priority, cipher_index[i].values);
644 if (!add_ciphers(cipher_priority,
645 sizeof(cipher_priority)/sizeof(pri_item),
646 cipher_index[i].values))
648 log_write(0, LOG_MAIN|LOG_PANIC, "GnuTLS init failed: cipher "
649 "priority table overflow");
650 gnutls_deinit(session);
661 int *ptr = cipher_priority;
662 debug_printf("adjusted cipher priorities:");
663 while (*ptr != 0) debug_printf(" %d", *ptr++);
668 /* Define the various priorities */
670 gnutls_cipher_set_priority(session, cipher_priority);
671 gnutls_compression_set_priority(session, comp_priority);
672 gnutls_kx_set_priority(session, kx_priority);
673 gnutls_protocol_set_priority(session, protocol_priority);
674 gnutls_mac_set_priority(session, mac_priority);
676 gnutls_cred_set(session, GNUTLS_CRD_CERTIFICATE, x509_cred);
678 gnutls_dh_set_prime_bits(session, DH_BITS);
680 /* Request or demand a certificate of the peer, as configured. This will
681 happen only in a server. */
683 if (verify_requirement != VERIFY_NONE)
684 gnutls_certificate_server_set_request(session,
685 (verify_requirement == VERIFY_OPTIONAL)?
686 GNUTLS_CERT_REQUEST : GNUTLS_CERT_REQUIRE);
688 gnutls_db_set_cache_expiration(session, ssl_session_timeout);
690 DEBUG(D_tls) debug_printf("initialized GnuTLS session\n");
696 /*************************************************
697 * Get name of cipher in use *
698 *************************************************/
700 /* The answer is left in a static buffer, and tls_cipher is set to point
703 Argument: pointer to a GnuTLS session
708 construct_cipher_name(gnutls_session session)
710 static uschar cipherbuf[256];
712 int bits, c, kx, mac;
715 US gnutls_protocol_get_name(gnutls_protocol_get_version(session)));
716 if (Ustrncmp(ver, "TLS ", 4) == 0) ver[3] = '-'; /* Don't want space */
718 c = gnutls_cipher_get(session);
719 bits = gnutls_cipher_get_key_size(c);
721 mac = gnutls_mac_get(session);
722 kx = gnutls_kx_get(session);
724 string_format(cipherbuf, sizeof(cipherbuf), "%s:%s:%u", ver,
725 gnutls_cipher_suite_get_name(kx, c, mac), bits);
726 tls_cipher = cipherbuf;
728 DEBUG(D_tls) debug_printf("cipher: %s\n", cipherbuf);
733 /*************************************************
734 * Start a TLS session in a server *
735 *************************************************/
737 /* This is called when Exim is running as a server, after having received
738 the STARTTLS command. It must respond to that command, and then negotiate
742 require_ciphers list of allowed ciphers
744 Returns: OK on success
745 DEFER for errors before the start of the negotiation
746 FAIL for errors during the negotation; the server can't
751 tls_server_start(uschar *require_ciphers)
755 uschar *expciphers = NULL;
757 /* Check for previous activation */
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");
768 /* Initialize the library. If it fails, it will already have logged the error
769 and sent an SMTP response. */
771 DEBUG(D_tls) debug_printf("initializing GnuTLS as a server\n");
773 rc = tls_init(NULL, tls_certificate, tls_privatekey, tls_verify_certificates,
775 if (rc != OK) return rc;
777 if (!expand_check(require_ciphers, US"tls_require_ciphers", &expciphers))
780 /* If this is a host for which certificate verification is mandatory or
781 optional, set up appropriately. */
783 tls_certificate_verified = FALSE;
784 verify_requirement = VERIFY_NONE;
786 if (verify_check_host(&tls_verify_hosts) == OK)
787 verify_requirement = VERIFY_REQUIRED;
788 else if (verify_check_host(&tls_try_verify_hosts) == OK)
789 verify_requirement = VERIFY_OPTIONAL;
791 /* Prepare for new connection */
793 tls_session = tls_session_init(GNUTLS_SERVER, expciphers);
794 if (tls_session == NULL)
795 return tls_error(US"tls_session_init", NULL, GNUTLS_E_MEMORY_ERROR);
797 /* Set context and tell client to go ahead, except in the case of TLS startup
798 on connection, where outputting anything now upsets the clients and tends to
799 make them disconnect. We need to have an explicit fflush() here, to force out
800 the response. Other smtp_printf() calls do not need it, because in non-TLS
801 mode, the fflush() happens when smtp_getc() is called. */
805 smtp_printf("220 TLS go ahead\r\n");
809 /* Now negotiate the TLS session. We put our own timer on it, since it seems
810 that the GnuTLS library doesn't. */
812 gnutls_transport_set_ptr(tls_session, (gnutls_transport_ptr)fileno(smtp_out));
814 sigalrm_seen = FALSE;
815 if (smtp_receive_timeout > 0) alarm(smtp_receive_timeout);
816 rc = gnutls_handshake(tls_session);
822 Ustrcpy(ssl_errstring, "timed out");
824 Ustrcpy(ssl_errstring, gnutls_strerror(rc));
825 log_write(0, LOG_MAIN,
826 "TLS error on connection from %s (gnutls_handshake): %s",
827 (sender_fullhost != NULL)? sender_fullhost : US"local process",
830 /* It seems that, except in the case of a timeout, we have to close the
831 connection right here; otherwise if the other end is running OpenSSL it hangs
832 until the server times out. */
836 (void)fclose(smtp_out);
837 (void)fclose(smtp_in);
843 DEBUG(D_tls) debug_printf("gnutls_handshake was successful\n");
845 if (verify_requirement != VERIFY_NONE &&
846 !verify_certificate(tls_session, &error))
848 log_write(0, LOG_MAIN,
849 "TLS error on connection from %s: certificate verification failed (%s)",
850 (sender_fullhost != NULL)? sender_fullhost : US"local process", error);
854 construct_cipher_name(tls_session);
856 /* TLS has been set up. Adjust the input functions to read via TLS,
857 and initialize appropriately. */
859 ssl_xfer_buffer = store_malloc(ssl_xfer_buffer_size);
860 ssl_xfer_buffer_lwm = ssl_xfer_buffer_hwm = 0;
861 ssl_xfer_eof = ssl_xfer_error = 0;
863 receive_getc = tls_getc;
864 receive_ungetc = tls_ungetc;
865 receive_feof = tls_feof;
866 receive_ferror = tls_ferror;
868 tls_active = fileno(smtp_out);
876 /*************************************************
877 * Start a TLS session in a client *
878 *************************************************/
880 /* Called from the smtp transport after STARTTLS has been accepted.
883 fd the fd of the connection
884 host connected host (for messages)
886 dhparam DH parameter file
887 certificate certificate file
888 privatekey private key file
889 verify_certs file for certificate verify
890 verify_crl CRL for verify
891 require_ciphers list of allowed ciphers
892 timeout startup timeout
894 Returns: OK/DEFER/FAIL (because using common functions),
895 but for a client, DEFER and FAIL have the same meaning
899 tls_client_start(int fd, host_item *host, address_item *addr, uschar *dhparam,
900 uschar *certificate, uschar *privatekey, uschar *verify_certs,
901 uschar *verify_crl, uschar *require_ciphers, int timeout)
903 const gnutls_datum *server_certs;
904 uschar *expciphers = NULL;
906 unsigned int server_certs_size;
909 DEBUG(D_tls) debug_printf("initializing GnuTLS as a client\n");
912 verify_requirement = (verify_certs == NULL)? VERIFY_NONE : VERIFY_REQUIRED;
913 rc = tls_init(host, certificate, privatekey, verify_certs, verify_crl);
914 if (rc != OK) return rc;
916 if (!expand_check(require_ciphers, US"tls_require_ciphers", &expciphers))
919 tls_session = tls_session_init(GNUTLS_CLIENT, expciphers);
920 if (tls_session == NULL)
921 return tls_error(US "tls_session_init", host, GNUTLS_E_MEMORY_ERROR);
923 gnutls_transport_set_ptr(tls_session, (gnutls_transport_ptr)fd);
925 /* There doesn't seem to be a built-in timeout on connection. */
927 sigalrm_seen = FALSE;
929 rc = gnutls_handshake(tls_session);
936 log_write(0, LOG_MAIN, "TLS error on connection to %s [%s]: "
937 "gnutls_handshake timed out", host->name, host->address);
940 else return tls_error(US "gnutls_handshake", host, rc);
943 server_certs = gnutls_certificate_get_peers(tls_session, &server_certs_size);
945 if (server_certs != NULL)
948 gnutls_x509_crt gcert;
950 gnutls_x509_crt_init(&gcert);
951 tls_peerdn = US"unknown";
953 if (gnutls_x509_crt_import(gcert, server_certs, GNUTLS_X509_FMT_DER) == 0)
955 size_t bufsize = sizeof(buff);
956 if (gnutls_x509_crt_get_dn(gcert, CS buff, &bufsize) >= 0)
957 tls_peerdn = string_copy_malloc(buff);
961 /* Should we also verify the hostname here? */
963 if (verify_requirement != VERIFY_NONE &&
964 !verify_certificate(tls_session, &error))
966 log_write(0, LOG_MAIN,
967 "TLS error on connection to %s [%s]: certificate verification failed (%s)",
968 host->name, host->address, error);
972 construct_cipher_name(tls_session); /* Sets tls_cipher */
979 /*************************************************
980 * Deal with logging errors during I/O *
981 *************************************************/
983 /* We have to get the identity of the peer from saved data.
986 ec the GnuTLS error code, or 0 if it's a local error
987 when text identifying read or write
988 text local error text when ec is 0
994 record_io_error(int ec, uschar *when, uschar *text)
996 uschar *additional = US"";
998 if (ec == GNUTLS_E_FATAL_ALERT_RECEIVED)
999 additional = string_sprintf(": %s",
1000 gnutls_alert_get_name(gnutls_alert_get(tls_session)));
1002 if (initialized == INITIALIZED_SERVER)
1003 log_write(0, LOG_MAIN, "TLS %s error on connection from %s: %s%s", when,
1004 (sender_fullhost != NULL)? sender_fullhost : US "local process",
1005 (ec == 0)? text : US gnutls_strerror(ec), additional);
1008 log_write(0, LOG_MAIN, "TLS %s error on connection to %s [%s]: %s%s", when,
1009 client_host->name, client_host->address,
1010 (ec == 0)? text : US gnutls_strerror(ec), additional);
1015 /*************************************************
1016 * TLS version of getc *
1017 *************************************************/
1019 /* This gets the next byte from the TLS input buffer. If the buffer is empty,
1020 it refills the buffer via the GnuTLS reading function.
1023 Returns: the next character or EOF
1029 if (ssl_xfer_buffer_lwm >= ssl_xfer_buffer_hwm)
1033 DEBUG(D_tls) debug_printf("Calling gnutls_record_recv(%lx, %lx, %u)\n",
1034 (long) tls_session, (long) ssl_xfer_buffer, ssl_xfer_buffer_size);
1036 if (smtp_receive_timeout > 0) alarm(smtp_receive_timeout);
1037 inbytes = gnutls_record_recv(tls_session, CS ssl_xfer_buffer,
1038 ssl_xfer_buffer_size);
1041 /* A zero-byte return appears to mean that the TLS session has been
1042 closed down, not that the socket itself has been closed down. Revert to
1043 non-TLS handling. */
1047 DEBUG(D_tls) debug_printf("Got TLS_EOF\n");
1049 receive_getc = smtp_getc;
1050 receive_ungetc = smtp_ungetc;
1051 receive_feof = smtp_feof;
1052 receive_ferror = smtp_ferror;
1054 gnutls_deinit(tls_session);
1063 /* Handle genuine errors */
1065 else if (inbytes < 0)
1067 record_io_error(inbytes, US"recv", NULL);
1072 ssl_xfer_buffer_hwm = inbytes;
1073 ssl_xfer_buffer_lwm = 0;
1077 /* Something in the buffer; return next uschar */
1079 return ssl_xfer_buffer[ssl_xfer_buffer_lwm++];
1084 /*************************************************
1085 * Read bytes from TLS channel *
1086 *************************************************/
1093 Returns: the number of bytes read
1094 -1 after a failed read
1098 tls_read(uschar *buff, size_t len)
1102 DEBUG(D_tls) debug_printf("Calling gnutls_record_recv(%lx, %lx, %u)\n",
1103 (long) tls_session, (long) buff, len);
1105 inbytes = gnutls_record_recv(tls_session, CS buff, len);
1106 if (inbytes > 0) return inbytes;
1109 DEBUG(D_tls) debug_printf("Got TLS_EOF\n");
1111 else record_io_error(inbytes, US"recv", NULL);
1118 /*************************************************
1119 * Write bytes down TLS channel *
1120 *************************************************/
1127 Returns: the number of bytes after a successful write,
1128 -1 after a failed write
1132 tls_write(const uschar *buff, size_t len)
1137 DEBUG(D_tls) debug_printf("tls_do_write(%lx, %d)\n", (long) buff, left);
1140 DEBUG(D_tls) debug_printf("gnutls_record_send(SSL, %lx, %d)\n", (long)buff,
1142 outbytes = gnutls_record_send(tls_session, CS buff, left);
1144 DEBUG(D_tls) debug_printf("outbytes=%d\n", outbytes);
1147 record_io_error(outbytes, US"send", NULL);
1152 record_io_error(0, US"send", US"TLS channel closed on write");
1165 /*************************************************
1166 * Close down a TLS session *
1167 *************************************************/
1169 /* This is also called from within a delivery subprocess forked from the
1170 daemon, to shut down the TLS library, without actually doing a shutdown (which
1171 would tamper with the TLS session in the parent process).
1173 Arguments: TRUE if gnutls_bye is to be called
1178 tls_close(BOOL shutdown)
1180 if (tls_active < 0) return; /* TLS was not active */
1184 DEBUG(D_tls) debug_printf("tls_close(): shutting down TLS\n");
1185 gnutls_bye(tls_session, GNUTLS_SHUT_WR);
1188 gnutls_deinit(tls_session);
1190 gnutls_global_deinit();
1195 /* End of tls-gnu.c */