1 /* Copyright (C) 2001 Marco d'Itri <md@linux.it>
2 * Copyright (C) 2001-2004 Andrew McDonald <andrew@mcdonald.org.uk>
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation; either version 2 of the License, or
7 * (at your option) any later version.
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
14 * You should have received a copy of the GNU General Public License
15 * along with this program; if not, write to the Free Software
16 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111, USA.
23 #include <gnutls/gnutls.h>
24 #include <gnutls/x509.h>
25 #ifdef HAVE_GNUTLS_OPENSSL_H
26 #include <gnutls/openssl.h>
30 #include "mutt_socket.h"
31 #include "mutt_curses.h"
32 #include "mutt_menu.h"
34 #include "mutt_regex.h"
36 typedef struct _tlssockdata
39 gnutls_certificate_credentials xcred;
43 /* local prototypes */
44 static int tls_socket_read (CONNECTION* conn, char* buf, size_t len);
45 static int tls_socket_write (CONNECTION* conn, const char* buf, size_t len);
46 static int tls_socket_open (CONNECTION* conn);
47 static int tls_socket_close (CONNECTION* conn);
48 static int tls_starttls_close (CONNECTION* conn);
50 static int tls_init (void);
51 static int tls_negotiate (CONNECTION* conn);
52 static int tls_check_certificate (CONNECTION* conn);
55 static int tls_init (void)
57 static unsigned char init_complete = 0;
63 err = gnutls_global_init();
66 mutt_error ("gnutls_global_init: %s", gnutls_strerror(err));
75 int mutt_gnutls_socket_setup (CONNECTION* conn)
80 conn->open = tls_socket_open;
81 conn->read = tls_socket_read;
82 conn->write = tls_socket_write;
83 conn->close = tls_socket_close;
88 static int tls_socket_read (CONNECTION* conn, char* buf, size_t len)
90 tlssockdata *data = conn->sockdata;
95 mutt_error ("Error: no TLS socket open");
100 ret = gnutls_record_recv (data->state, buf, len);
101 if (gnutls_error_is_fatal(ret) == 1)
103 mutt_error ("tls_socket_read (%s)", gnutls_strerror (ret));
110 static int tls_socket_write (CONNECTION* conn, const char* buf, size_t len)
112 tlssockdata *data = conn->sockdata;
117 mutt_error ("Error: no TLS socket open");
122 ret = gnutls_record_send (data->state, buf, len);
123 if (gnutls_error_is_fatal(ret) == 1)
125 mutt_error ("tls_socket_write (%s)", gnutls_strerror (ret));
132 static int tls_socket_open (CONNECTION* conn)
134 if (raw_socket_open (conn) < 0)
137 if (tls_negotiate (conn) < 0)
139 tls_socket_close (conn);
146 int mutt_gnutls_starttls (CONNECTION* conn)
151 if (tls_negotiate (conn) < 0)
154 conn->read = tls_socket_read;
155 conn->write = tls_socket_write;
156 conn->close = tls_starttls_close;
161 static int protocol_priority[] = {GNUTLS_TLS1, GNUTLS_SSL3, 0};
163 /* tls_negotiate: After TLS state has been initialised, attempt to negotiate
164 * TLS over the wire, including certificate checks. */
165 static int tls_negotiate (CONNECTION * conn)
170 data = (tlssockdata *) safe_calloc (1, sizeof (tlssockdata));
171 conn->sockdata = data;
172 err = gnutls_certificate_allocate_credentials (&data->xcred);
175 FREE(&conn->sockdata);
176 mutt_error ("gnutls_certificate_allocate_credentials: %s", gnutls_strerror(err));
181 gnutls_certificate_set_x509_trust_file (data->xcred, SslCertFile,
182 GNUTLS_X509_FMT_PEM);
183 /* ignore errors, maybe file doesn't exist yet */
187 gnutls_certificate_set_x509_trust_file (data->xcred, SslCACertFile,
188 GNUTLS_X509_FMT_PEM);
192 gnutls_set_x509_client_key (data->xcred, "", "");
193 gnutls_set_x509_cert_callback (data->xcred, cert_callback);
196 gnutls_init(&data->state, GNUTLS_CLIENT);
199 gnutls_transport_set_ptr (data->state, (gnutls_transport_ptr)conn->fd);
201 /* disable TLS/SSL protocols as needed */
202 if (!option(OPTTLSV1) && !option(OPTSSLV3))
204 mutt_error (_("All available protocols for TLS/SSL connection disabled"));
207 else if (!option(OPTTLSV1))
209 protocol_priority[0] = GNUTLS_SSL3;
210 protocol_priority[1] = 0;
212 else if (!option(OPTSSLV3))
214 protocol_priority[0] = GNUTLS_TLS1;
215 protocol_priority[1] = 0;
219 use the list set above
222 /* We use default priorities (see gnutls documentation),
223 except for protocol version */
224 gnutls_set_default_priority (data->state);
225 gnutls_protocol_set_priority (data->state, protocol_priority);
227 if (SslDHPrimeBits > 0)
229 gnutls_dh_set_prime_bits (data->state, SslDHPrimeBits);
233 gnutls_set_cred (data->state, GNUTLS_ANON, NULL);
236 gnutls_credentials_set (data->state, GNUTLS_CRD_CERTIFICATE, data->xcred);
238 err = gnutls_handshake(data->state);
240 while (err == GNUTLS_E_AGAIN || err == GNUTLS_E_INTERRUPTED)
242 err = gnutls_handshake(data->state);
245 if (err == GNUTLS_E_FATAL_ALERT_RECEIVED)
247 mutt_error("gnutls_handshake: %s(%s)", gnutls_strerror(err),
248 gnutls_alert_get_name(gnutls_alert_get(data->state)));
252 mutt_error("gnutls_handshake: %s", gnutls_strerror(err));
258 if (!tls_check_certificate(conn))
261 /* set Security Strength Factor (SSF) for SASL */
262 /* NB: gnutls_cipher_get_key_size() returns key length in bytes */
263 conn->ssf = gnutls_cipher_get_key_size (gnutls_cipher_get (data->state)) * 8;
265 mutt_message (_("SSL/TLS connection using %s (%s/%s/%s)"),
266 gnutls_protocol_get_name (gnutls_protocol_get_version (data->state)),
267 gnutls_kx_get_name (gnutls_kx_get (data->state)),
268 gnutls_cipher_get_name (gnutls_cipher_get (data->state)),
269 gnutls_mac_get_name (gnutls_mac_get (data->state)));
275 gnutls_certificate_free_credentials (data->xcred);
276 gnutls_deinit (data->state);
277 FREE(&conn->sockdata);
281 static int tls_socket_close (CONNECTION* conn)
283 tlssockdata *data = conn->sockdata;
286 gnutls_bye (data->state, GNUTLS_SHUT_RDWR);
288 gnutls_certificate_free_credentials (data->xcred);
289 gnutls_deinit (data->state);
290 safe_free ((void **) &conn->sockdata);
293 return raw_socket_close (conn);
296 static int tls_starttls_close (CONNECTION* conn)
300 rc = tls_socket_close (conn);
301 conn->read = raw_socket_read;
302 conn->write = raw_socket_write;
303 conn->close = raw_socket_close;
308 #define CERT_SEP "-----BEGIN"
310 /* this bit is based on read_ca_file() in gnutls */
311 static int tls_compare_certificates (const gnutls_datum *peercert)
317 gnutls_datum b64_data;
318 unsigned char *b64_data_data;
319 struct stat filestat;
321 if (stat(SslCertFile, &filestat) == -1)
324 b64_data.size = filestat.st_size+1;
325 b64_data_data = (unsigned char *) safe_calloc (1, b64_data.size);
326 b64_data_data[b64_data.size-1] = '\0';
327 b64_data.data = b64_data_data;
329 fd1 = fopen(SslCertFile, "r");
334 b64_data.size = fread(b64_data.data, 1, b64_data.size, fd1);
338 ret = gnutls_pem_base64_decode_alloc(NULL, &b64_data, &cert);
341 FREE (&b64_data_data);
345 ptr = (unsigned char *)strstr(b64_data.data, CERT_SEP) + 1;
346 ptr = (unsigned char *)strstr(ptr, CERT_SEP);
348 b64_data.size = b64_data.size - (ptr - b64_data.data);
351 if (cert.size == peercert->size)
353 if (memcmp (cert.data, peercert->data, cert.size) == 0)
356 gnutls_free(cert.data);
357 FREE (&b64_data_data);
362 gnutls_free(cert.data);
363 } while (ptr != NULL);
366 FREE (&b64_data_data);
370 static void tls_fingerprint (gnutls_digest_algorithm algo,
371 char* s, int l, const gnutls_datum* data)
373 unsigned char md[36];
379 if (gnutls_fingerprint (algo, data, (char *)md, &n) < 0)
381 snprintf (s, l, _("[unable to calculate]"));
385 for (j = 0; j < (int) n; j++)
388 snprintf (ch, 8, "%02X%s", md[j], (j % 2 ? " " : ""));
391 s[2*n+n/2-1] = '\0'; /* don't want trailing space */
395 static char *tls_make_date (time_t t, char *s, size_t len)
397 struct tm *l = gmtime (&t);
400 snprintf (s, len, "%s, %d %s %d %02d:%02d:%02d UTC",
401 Weekdays[l->tm_wday], l->tm_mday, Months[l->tm_mon],
402 l->tm_year + 1900, l->tm_hour, l->tm_min, l->tm_sec);
404 strfcpy (s, _("[invalid date]"), len);
409 static int tls_check_stored_hostname (const gnutls_datum *cert,
410 const char *hostname)
414 char *linestr = NULL;
418 regmatch_t pmatch[3];
420 /* try checking against names stored in stored certs file */
421 if ((fp = fopen (SslCertFile, "r")))
423 if (regcomp(&preg, "^#H ([a-zA-Z0-9_\\.-]+) ([0-9A-F]{4}( [0-9A-F]{4}){7})[ \t]*$", REG_ICASE|REG_EXTENDED) != 0)
430 tls_fingerprint (GNUTLS_DIG_MD5, buf, sizeof (buf), cert);
431 while ((linestr = mutt_read_line(linestr, &linestrsize, fp, &linenum)) != NULL)
433 if(linestr[0] == '#' && linestr[1] == 'H')
435 if (regexec(&preg, linestr, 3, pmatch, 0) == 0)
437 linestr[pmatch[1].rm_eo] = '\0';
438 linestr[pmatch[2].rm_eo] = '\0';
439 if (strcmp(linestr + pmatch[1].rm_so, hostname) == 0 &&
440 strcmp(linestr + pmatch[2].rm_so, buf) == 0)
443 safe_free((void**)&linestr);
455 /* not found a matching name */
459 static int tls_check_certificate (CONNECTION* conn)
461 tlssockdata *data = conn->sockdata;
462 gnutls_session state = data->state;
463 char helpstr[SHORT_STRING];
464 char buf[SHORT_STRING];
465 char fpbuf[SHORT_STRING];
467 char dn_common_name[SHORT_STRING];
468 char dn_email[SHORT_STRING];
469 char dn_organization[SHORT_STRING];
470 char dn_organizational_unit[SHORT_STRING];
471 char dn_locality[SHORT_STRING];
472 char dn_province[SHORT_STRING];
473 char dn_country[SHORT_STRING];
475 int done, row, i, ret;
479 const gnutls_datum *cert_list;
480 int cert_list_size = 0;
481 gnutls_certificate_status certstat;
483 gnutls_x509_crt cert;
484 gnutls_datum pemdata;
485 int certerr_expired = 0;
486 int certerr_notyetvalid = 0;
487 int certerr_hostname = 0;
488 int certerr_nottrusted = 0;
489 int certerr_revoked = 0;
490 int certerr_signernotca = 0;
492 if (gnutls_auth_get_type(state) != GNUTLS_CRD_CERTIFICATE)
494 mutt_error (_("Unable to get certificate from peer"));
499 certstat = gnutls_certificate_verify_peers(state);
501 if (certstat == GNUTLS_E_NO_CERTIFICATE_FOUND)
503 mutt_error (_("Unable to get certificate from peer"));
509 mutt_error (_("Certificate verification error (%s)"), gnutls_strerror(certstat));
514 /* We only support X.509 certificates (not OpenPGP) at the moment */
515 if (gnutls_certificate_type_get(state) != GNUTLS_CRT_X509)
517 mutt_error (_("Error certificate is not X.509"));
522 if (gnutls_x509_crt_init(&cert) < 0)
524 mutt_error (_("Error initialising gnutls certificate data"));
529 cert_list = gnutls_certificate_get_peers(state, &cert_list_size);
532 mutt_error (_("Unable to get certificate from peer"));
537 /* FIXME: Currently only check first certificate in chain. */
538 if (gnutls_x509_crt_import(cert, &cert_list[0], GNUTLS_X509_FMT_DER) < 0)
540 mutt_error (_("Error processing certificate data"));
545 if (gnutls_x509_crt_get_expiration_time(cert) < time(NULL))
550 if (gnutls_x509_crt_get_activation_time(cert) > time(NULL))
552 certerr_notyetvalid = 1;
555 if (!gnutls_x509_crt_check_hostname(cert, conn->account.host) &&
556 !tls_check_stored_hostname (&cert_list[0], conn->account.host))
558 certerr_hostname = 1;
561 /* see whether certificate is in our cache (certificates file) */
562 if (tls_compare_certificates (&cert_list[0]))
564 if (certstat & GNUTLS_CERT_INVALID)
566 /* doesn't matter - have decided is valid because server
567 certificate is in our trusted cache */
568 certstat ^= GNUTLS_CERT_INVALID;
571 if (certstat & GNUTLS_CERT_SIGNER_NOT_FOUND)
573 /* doesn't matter that we haven't found the signer, since
574 certificate is in our trusted cache */
575 certstat ^= GNUTLS_CERT_SIGNER_NOT_FOUND;
578 if (certstat & GNUTLS_CERT_SIGNER_NOT_CA)
580 /* Hmm. Not really sure how to handle this, but let's say
581 that we don't care if the CA certificate hasn't got the
582 correct X.509 basic constraints if server certificate is
584 certstat ^= GNUTLS_CERT_SIGNER_NOT_CA;
589 if (certstat & GNUTLS_CERT_REVOKED)
592 certstat ^= GNUTLS_CERT_REVOKED;
595 if (certstat & GNUTLS_CERT_INVALID)
597 certerr_nottrusted = 1;
598 certstat ^= GNUTLS_CERT_INVALID;
601 if (certstat & GNUTLS_CERT_SIGNER_NOT_FOUND)
603 /* NB: already cleared if cert in cache */
604 certerr_nottrusted = 1;
605 certstat ^= GNUTLS_CERT_SIGNER_NOT_FOUND;
608 if (certstat & GNUTLS_CERT_SIGNER_NOT_CA)
610 /* NB: already cleared if cert in cache */
611 certerr_signernotca = 1;
612 certstat ^= GNUTLS_CERT_SIGNER_NOT_CA;
615 /* OK if signed by (or is) a trusted certificate */
616 /* we've been zeroing the interesting bits in certstat -
617 don't return OK if there are any unhandled bits we don't
619 if (!(certerr_expired || certerr_notyetvalid ||
620 certerr_hostname || certerr_nottrusted) && certstat == 0)
622 gnutls_x509_crt_deinit(cert);
627 /* interactive check from user */
628 menu = mutt_new_menu ();
630 menu->dialog = (char **) safe_calloc (1, menu->max * sizeof (char *));
631 for (i = 0; i < menu->max; i++)
632 menu->dialog[i] = (char *) safe_calloc (1, SHORT_STRING * sizeof (char));
635 strfcpy (menu->dialog[row], _("This certificate belongs to:"), SHORT_STRING);
638 buflen = sizeof(dn_common_name);
639 if (gnutls_x509_crt_get_dn_by_oid(cert, GNUTLS_OID_X520_COMMON_NAME, 0, 0,
640 dn_common_name, &buflen) != 0)
641 dn_common_name[0] = '\0';
642 buflen = sizeof(dn_email);
643 if (gnutls_x509_crt_get_dn_by_oid(cert, GNUTLS_OID_PKCS9_EMAIL, 0, 0,
644 dn_email, &buflen) != 0)
646 buflen = sizeof(dn_organization);
647 if (gnutls_x509_crt_get_dn_by_oid(cert, GNUTLS_OID_X520_ORGANIZATION_NAME, 0, 0,
648 dn_organization, &buflen) != 0)
649 dn_organization[0] = '\0';
650 buflen = sizeof(dn_organizational_unit);
651 if (gnutls_x509_crt_get_dn_by_oid(cert, GNUTLS_OID_X520_ORGANIZATIONAL_UNIT_NAME, 0, 0,
652 dn_organizational_unit, &buflen) != 0)
653 dn_organizational_unit[0] = '\0';
654 buflen = sizeof(dn_locality);
655 if (gnutls_x509_crt_get_dn_by_oid(cert, GNUTLS_OID_X520_LOCALITY_NAME, 0, 0,
656 dn_locality, &buflen) != 0)
657 dn_locality[0] = '\0';
658 buflen = sizeof(dn_province);
659 if (gnutls_x509_crt_get_dn_by_oid(cert, GNUTLS_OID_X520_STATE_OR_PROVINCE_NAME, 0, 0,
660 dn_province, &buflen) != 0)
661 dn_province[0] = '\0';
662 buflen = sizeof(dn_country);
663 if (gnutls_x509_crt_get_dn_by_oid(cert, GNUTLS_OID_X520_COUNTRY_NAME, 0, 0,
664 dn_country, &buflen) != 0)
665 dn_country[0] = '\0';
667 snprintf (menu->dialog[row++], SHORT_STRING, " %s %s", dn_common_name, dn_email);
668 snprintf (menu->dialog[row++], SHORT_STRING, " %s", dn_organization);
669 snprintf (menu->dialog[row++], SHORT_STRING, " %s", dn_organizational_unit);
670 snprintf (menu->dialog[row++], SHORT_STRING, " %s %s %s",
671 dn_locality, dn_province, dn_country);
674 strfcpy (menu->dialog[row], _("This certificate was issued by:"), SHORT_STRING);
677 buflen = sizeof(dn_common_name);
678 if (gnutls_x509_crt_get_issuer_dn_by_oid(cert, GNUTLS_OID_X520_COMMON_NAME, 0, 0,
679 dn_common_name, &buflen) != 0)
680 dn_common_name[0] = '\0';
681 buflen = sizeof(dn_email);
682 if (gnutls_x509_crt_get_issuer_dn_by_oid(cert, GNUTLS_OID_PKCS9_EMAIL, 0, 0,
683 dn_email, &buflen) != 0)
685 buflen = sizeof(dn_organization);
686 if (gnutls_x509_crt_get_issuer_dn_by_oid(cert, GNUTLS_OID_X520_ORGANIZATION_NAME, 0, 0,
687 dn_organization, &buflen) != 0)
688 dn_organization[0] = '\0';
689 buflen = sizeof(dn_organizational_unit);
690 if (gnutls_x509_crt_get_issuer_dn_by_oid(cert, GNUTLS_OID_X520_ORGANIZATIONAL_UNIT_NAME, 0, 0,
691 dn_organizational_unit, &buflen) != 0)
692 dn_organizational_unit[0] = '\0';
693 buflen = sizeof(dn_locality);
694 if (gnutls_x509_crt_get_issuer_dn_by_oid(cert, GNUTLS_OID_X520_LOCALITY_NAME, 0, 0,
695 dn_locality, &buflen) != 0)
696 dn_locality[0] = '\0';
697 buflen = sizeof(dn_province);
698 if (gnutls_x509_crt_get_issuer_dn_by_oid(cert, GNUTLS_OID_X520_STATE_OR_PROVINCE_NAME, 0, 0,
699 dn_province, &buflen) != 0)
700 dn_province[0] = '\0';
701 buflen = sizeof(dn_country);
702 if (gnutls_x509_crt_get_issuer_dn_by_oid(cert, GNUTLS_OID_X520_COUNTRY_NAME, 0, 0,
703 dn_country, &buflen) != 0)
704 dn_country[0] = '\0';
706 snprintf (menu->dialog[row++], SHORT_STRING, " %s %s", dn_common_name, dn_email);
707 snprintf (menu->dialog[row++], SHORT_STRING, " %s", dn_organization);
708 snprintf (menu->dialog[row++], SHORT_STRING, " %s", dn_organizational_unit);
709 snprintf (menu->dialog[row++], SHORT_STRING, " %s %s %s",
710 dn_locality, dn_province, dn_country);
713 snprintf (menu->dialog[row++], SHORT_STRING, _("This certificate is valid"));
715 t = gnutls_x509_crt_get_activation_time(cert);
716 snprintf (menu->dialog[row++], SHORT_STRING, _(" from %s"),
717 tls_make_date(t, datestr, 30));
719 t = gnutls_x509_crt_get_expiration_time(cert);
720 snprintf (menu->dialog[row++], SHORT_STRING, _(" to %s"),
721 tls_make_date(t, datestr, 30));
724 tls_fingerprint (GNUTLS_DIG_SHA, fpbuf, sizeof (fpbuf), &cert_list[0]);
725 snprintf (menu->dialog[row++], SHORT_STRING, _("SHA1 Fingerprint: %s"), fpbuf);
727 tls_fingerprint (GNUTLS_DIG_MD5, fpbuf, sizeof (fpbuf), &cert_list[0]);
728 snprintf (menu->dialog[row++], SHORT_STRING, _("MD5 Fingerprint: %s"), fpbuf);
730 if (certerr_notyetvalid)
733 strfcpy (menu->dialog[row], _("WARNING: Server certificate is not yet valid"), SHORT_STRING);
738 strfcpy (menu->dialog[row], _("WARNING: Server certificate has expired"), SHORT_STRING);
743 strfcpy (menu->dialog[row], _("WARNING: Server certificate has been revoked"), SHORT_STRING);
745 if (certerr_hostname)
748 strfcpy (menu->dialog[row], _("WARNING: Server hostname does not match certificate"), SHORT_STRING);
750 if (certerr_signernotca)
753 strfcpy (menu->dialog[row], _("WARNING: Signer of server certificate is not a CA"), SHORT_STRING);
756 menu->title = _("TLS/SSL Certificate check");
757 /* certificates with bad dates, or that are revoked, must be
758 accepted manually each and every time */
759 if (SslCertFile && !certerr_expired && !certerr_notyetvalid && !certerr_revoked)
761 menu->prompt = _("(r)eject, accept (o)nce, (a)ccept always");
762 menu->keys = _("roa");
766 menu->prompt = _("(r)eject, accept (o)nce");
767 menu->keys = _("ro");
771 mutt_make_help (buf, sizeof (buf), _("Exit "), MENU_GENERIC, OP_EXIT);
772 strncat (helpstr, buf, sizeof (helpstr));
773 mutt_make_help (buf, sizeof (buf), _("Help"), MENU_GENERIC, OP_HELP);
774 strncat (helpstr, buf, sizeof (helpstr));
775 menu->help = helpstr;
780 switch (mutt_menuLoop (menu))
783 case OP_MAX + 1: /* reject */
787 case OP_MAX + 3: /* accept always */
789 if ((fp = fopen (SslCertFile, "a")))
791 /* save hostname if necessary */
792 if (certerr_hostname)
794 fprintf(fp, "#H %s %s\n", conn->account.host, fpbuf);
797 if (certerr_nottrusted)
800 ret = gnutls_pem_base64_encode_alloc ("CERTIFICATE", &cert_list[0],
804 if (fwrite(pemdata.data, pemdata.size, 1, fp) == 1)
808 gnutls_free(pemdata.data);
815 mutt_error (_("Warning: Couldn't save certificate"));
820 mutt_message (_("Certificate saved"));
824 case OP_MAX + 2: /* accept once */
829 mutt_menuDestroy (&menu);
830 gnutls_x509_crt_deinit(cert);