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.
19 #include <gnutls/gnutls.h>
20 #include <gnutls/x509.h>
23 #include "mutt_socket.h"
24 #include "mutt_curses.h"
25 #include "mutt_menu.h"
27 #include "mutt_regex.h"
29 typedef struct _tlssockdata
32 gnutls_certificate_credentials xcred;
36 /* local prototypes */
37 static int tls_socket_read (CONNECTION* conn, char* buf, size_t len);
38 static int tls_socket_write (CONNECTION* conn, const char* buf, size_t len);
39 static int tls_socket_open (CONNECTION* conn);
40 static int tls_socket_close (CONNECTION* conn);
41 static int tls_starttls_close (CONNECTION* conn);
43 static int tls_init (void);
44 static int tls_negotiate (CONNECTION* conn);
45 static int tls_check_certificate (CONNECTION* conn);
48 static int tls_init (void)
50 static unsigned char init_complete = 0;
56 err = gnutls_global_init();
59 mutt_error ("gnutls_global_init: %s", gnutls_strerror(err));
68 int mutt_gnutls_socket_setup (CONNECTION* conn)
73 conn->open = tls_socket_open;
74 conn->read = tls_socket_read;
75 conn->write = tls_socket_write;
76 conn->close = tls_socket_close;
81 static int tls_socket_read (CONNECTION* conn, char* buf, size_t len)
83 tlssockdata *data = conn->sockdata;
88 mutt_error ("Error: no TLS socket open");
93 ret = gnutls_record_recv (data->state, buf, len);
94 if (gnutls_error_is_fatal(ret) == 1)
96 mutt_error ("tls_socket_read (%s)", gnutls_strerror (ret));
103 static int tls_socket_write (CONNECTION* conn, const char* buf, size_t len)
105 tlssockdata *data = conn->sockdata;
110 mutt_error ("Error: no TLS socket open");
115 ret = gnutls_record_send (data->state, buf, len);
116 if (gnutls_error_is_fatal(ret) == 1)
118 mutt_error ("tls_socket_write (%s)", gnutls_strerror (ret));
125 static int tls_socket_open (CONNECTION* conn)
127 if (raw_socket_open (conn) < 0)
130 if (tls_negotiate (conn) < 0)
132 tls_socket_close (conn);
139 int mutt_gnutls_starttls (CONNECTION* conn)
144 if (tls_negotiate (conn) < 0)
147 conn->read = tls_socket_read;
148 conn->write = tls_socket_write;
149 conn->close = tls_starttls_close;
154 static int protocol_priority[] = {GNUTLS_TLS1, GNUTLS_SSL3, 0};
156 /* tls_negotiate: After TLS state has been initialised, attempt to negotiate
157 * TLS over the wire, including certificate checks. */
158 static int tls_negotiate (CONNECTION * conn)
163 data = (tlssockdata *) safe_calloc (1, sizeof (tlssockdata));
164 conn->sockdata = data;
165 err = gnutls_certificate_allocate_credentials (&data->xcred);
168 FREE(&conn->sockdata);
169 mutt_error ("gnutls_certificate_allocate_credentials: %s", gnutls_strerror(err));
174 gnutls_certificate_set_x509_trust_file (data->xcred, SslCertFile,
175 GNUTLS_X509_FMT_PEM);
176 /* ignore errors, maybe file doesn't exist yet */
180 gnutls_certificate_set_x509_trust_file (data->xcred, SslCACertFile,
181 GNUTLS_X509_FMT_PEM);
185 gnutls_set_x509_client_key (data->xcred, "", "");
186 gnutls_set_x509_cert_callback (data->xcred, cert_callback);
189 gnutls_init(&data->state, GNUTLS_CLIENT);
192 gnutls_transport_set_ptr (data->state, (gnutls_transport_ptr)conn->fd);
194 /* disable TLS/SSL protocols as needed */
195 if (!option(OPTTLSV1) && !option(OPTSSLV3))
197 mutt_error (_("All available protocols for TLS/SSL connection disabled"));
200 else if (!option(OPTTLSV1))
202 protocol_priority[0] = GNUTLS_SSL3;
203 protocol_priority[1] = 0;
205 else if (!option(OPTSSLV3))
207 protocol_priority[0] = GNUTLS_TLS1;
208 protocol_priority[1] = 0;
212 use the list set above
215 /* We use default priorities (see gnutls documentation),
216 except for protocol version */
217 gnutls_set_default_priority (data->state);
218 gnutls_protocol_set_priority (data->state, protocol_priority);
220 if (SslDHPrimeBits > 0)
222 gnutls_dh_set_prime_bits (data->state, SslDHPrimeBits);
226 gnutls_set_cred (data->state, GNUTLS_ANON, NULL);
229 gnutls_credentials_set (data->state, GNUTLS_CRD_CERTIFICATE, data->xcred);
231 err = gnutls_handshake(data->state);
233 while (err == GNUTLS_E_AGAIN || err == GNUTLS_E_INTERRUPTED)
235 err = gnutls_handshake(data->state);
238 if (err == GNUTLS_E_FATAL_ALERT_RECEIVED)
240 mutt_error("gnutls_handshake: %s(%s)", gnutls_strerror(err),
241 gnutls_alert_get_name(gnutls_alert_get(data->state)));
245 mutt_error("gnutls_handshake: %s", gnutls_strerror(err));
251 if (!tls_check_certificate(conn))
254 /* set Security Strength Factor (SSF) for SASL */
255 /* NB: gnutls_cipher_get_key_size() returns key length in bytes */
256 conn->ssf = gnutls_cipher_get_key_size (gnutls_cipher_get (data->state)) * 8;
258 mutt_message (_("SSL/TLS connection using %s (%s/%s/%s)"),
259 gnutls_protocol_get_name (gnutls_protocol_get_version (data->state)),
260 gnutls_kx_get_name (gnutls_kx_get (data->state)),
261 gnutls_cipher_get_name (gnutls_cipher_get (data->state)),
262 gnutls_mac_get_name (gnutls_mac_get (data->state)));
268 gnutls_certificate_free_credentials (data->xcred);
269 gnutls_deinit (data->state);
270 FREE(&conn->sockdata);
274 static int tls_socket_close (CONNECTION* conn)
276 tlssockdata *data = conn->sockdata;
279 gnutls_bye (data->state, GNUTLS_SHUT_RDWR);
281 gnutls_certificate_free_credentials (data->xcred);
282 gnutls_deinit (data->state);
283 safe_free ((void **) &conn->sockdata);
286 return raw_socket_close (conn);
289 static int tls_starttls_close (CONNECTION* conn)
293 rc = tls_socket_close (conn);
294 conn->read = raw_socket_read;
295 conn->write = raw_socket_write;
296 conn->close = raw_socket_close;
301 #define CERT_SEP "-----BEGIN"
303 /* this bit is based on read_ca_file() in gnutls */
304 static int tls_compare_certificates (const gnutls_datum *peercert)
310 gnutls_datum b64_data;
311 unsigned char *b64_data_data;
312 struct stat filestat;
314 if (stat(SslCertFile, &filestat) == -1)
317 b64_data.size = filestat.st_size+1;
318 b64_data_data = (unsigned char *) safe_calloc (1, b64_data.size);
319 b64_data_data[b64_data.size-1] = '\0';
320 b64_data.data = b64_data_data;
322 fd1 = fopen(SslCertFile, "r");
327 b64_data.size = fread(b64_data.data, 1, b64_data.size, fd1);
331 ret = gnutls_pem_base64_decode_alloc(NULL, &b64_data, &cert);
334 FREE (&b64_data_data);
338 ptr = (unsigned char *)strstr(b64_data.data, CERT_SEP) + 1;
339 ptr = (unsigned char *)strstr(ptr, CERT_SEP);
341 b64_data.size = b64_data.size - (ptr - b64_data.data);
344 if (cert.size == peercert->size)
346 if (memcmp (cert.data, peercert->data, cert.size) == 0)
349 gnutls_free(cert.data);
350 FREE (&b64_data_data);
355 gnutls_free(cert.data);
356 } while (ptr != NULL);
359 FREE (&b64_data_data);
363 static void tls_fingerprint (gnutls_digest_algorithm algo,
364 char* s, int l, const gnutls_datum* data)
366 unsigned char md[36];
372 if (gnutls_fingerprint (algo, data, (char *)md, &n) < 0)
374 snprintf (s, l, _("[unable to calculate]"));
378 for (j = 0; j < (int) n; j++)
381 snprintf (ch, 8, "%02X%s", md[j], (j % 2 ? " " : ""));
384 s[2*n+n/2-1] = '\0'; /* don't want trailing space */
388 static char *tls_make_date (time_t t, char *s, size_t len)
390 struct tm *l = gmtime (&t);
393 snprintf (s, len, "%s, %d %s %d %02d:%02d:%02d UTC",
394 Weekdays[l->tm_wday], l->tm_mday, Months[l->tm_mon],
395 l->tm_year + 1900, l->tm_hour, l->tm_min, l->tm_sec);
397 strfcpy (s, _("[invalid date]"), len);
402 static int tls_check_stored_hostname (const gnutls_datum *cert,
403 const char *hostname)
407 char *linestr = NULL;
411 regmatch_t pmatch[3];
413 /* try checking against names stored in stored certs file */
414 if ((fp = fopen (SslCertFile, "r")))
416 if (regcomp(&preg, "^#H ([a-zA-Z0-9_\\.-]+) ([0-9A-F]{4}( [0-9A-F]{4}){7})[ \t]*$", REG_ICASE|REG_EXTENDED) != 0)
423 tls_fingerprint (GNUTLS_DIG_MD5, buf, sizeof (buf), cert);
424 while ((linestr = mutt_read_line(linestr, &linestrsize, fp, &linenum)) != NULL)
426 if(linestr[0] == '#' && linestr[1] == 'H')
428 if (regexec(&preg, linestr, 3, pmatch, 0) == 0)
430 linestr[pmatch[1].rm_eo] = '\0';
431 linestr[pmatch[2].rm_eo] = '\0';
432 if (strcmp(linestr + pmatch[1].rm_so, hostname) == 0 &&
433 strcmp(linestr + pmatch[2].rm_so, buf) == 0)
436 safe_free((void**)&linestr);
448 /* not found a matching name */
452 static int tls_check_certificate (CONNECTION* conn)
454 tlssockdata *data = conn->sockdata;
455 gnutls_session state = data->state;
456 char helpstr[SHORT_STRING];
457 char buf[SHORT_STRING];
458 char fpbuf[SHORT_STRING];
460 char dn_common_name[SHORT_STRING];
461 char dn_email[SHORT_STRING];
462 char dn_organization[SHORT_STRING];
463 char dn_organizational_unit[SHORT_STRING];
464 char dn_locality[SHORT_STRING];
465 char dn_province[SHORT_STRING];
466 char dn_country[SHORT_STRING];
468 int done, row, i, ret;
472 const gnutls_datum *cert_list;
473 int cert_list_size = 0;
474 gnutls_certificate_status certstat;
476 gnutls_x509_crt cert;
477 gnutls_datum pemdata;
478 int certerr_expired = 0;
479 int certerr_notyetvalid = 0;
480 int certerr_hostname = 0;
481 int certerr_nottrusted = 0;
482 int certerr_revoked = 0;
483 int certerr_signernotca = 0;
485 if (gnutls_auth_get_type(state) != GNUTLS_CRD_CERTIFICATE)
487 mutt_error (_("Unable to get certificate from peer"));
492 certstat = gnutls_certificate_verify_peers(state);
494 if (certstat == GNUTLS_E_NO_CERTIFICATE_FOUND)
496 mutt_error (_("Unable to get certificate from peer"));
502 mutt_error (_("Certificate verification error (%s)"), gnutls_strerror(certstat));
507 /* We only support X.509 certificates (not OpenPGP) at the moment */
508 if (gnutls_certificate_type_get(state) != GNUTLS_CRT_X509)
510 mutt_error (_("Error certificate is not X.509"));
515 if (gnutls_x509_crt_init(&cert) < 0)
517 mutt_error (_("Error initialising gnutls certificate data"));
522 cert_list = gnutls_certificate_get_peers(state, &cert_list_size);
525 mutt_error (_("Unable to get certificate from peer"));
530 /* FIXME: Currently only check first certificate in chain. */
531 if (gnutls_x509_crt_import(cert, &cert_list[0], GNUTLS_X509_FMT_DER) < 0)
533 mutt_error (_("Error processing certificate data"));
538 if (gnutls_x509_crt_get_expiration_time(cert) < time(NULL))
543 if (gnutls_x509_crt_get_activation_time(cert) > time(NULL))
545 certerr_notyetvalid = 1;
548 if (!gnutls_x509_crt_check_hostname(cert, conn->account.host) &&
549 !tls_check_stored_hostname (&cert_list[0], conn->account.host))
551 certerr_hostname = 1;
554 /* see whether certificate is in our cache (certificates file) */
555 if (tls_compare_certificates (&cert_list[0]))
557 if (certstat & GNUTLS_CERT_INVALID)
559 /* doesn't matter - have decided is valid because server
560 certificate is in our trusted cache */
561 certstat ^= GNUTLS_CERT_INVALID;
564 if (certstat & GNUTLS_CERT_SIGNER_NOT_FOUND)
566 /* doesn't matter that we haven't found the signer, since
567 certificate is in our trusted cache */
568 certstat ^= GNUTLS_CERT_SIGNER_NOT_FOUND;
571 if (certstat & GNUTLS_CERT_SIGNER_NOT_CA)
573 /* Hmm. Not really sure how to handle this, but let's say
574 that we don't care if the CA certificate hasn't got the
575 correct X.509 basic constraints if server certificate is
577 certstat ^= GNUTLS_CERT_SIGNER_NOT_CA;
582 if (certstat & GNUTLS_CERT_REVOKED)
585 certstat ^= GNUTLS_CERT_REVOKED;
588 if (certstat & GNUTLS_CERT_INVALID)
590 certerr_nottrusted = 1;
591 certstat ^= GNUTLS_CERT_INVALID;
594 if (certstat & GNUTLS_CERT_SIGNER_NOT_FOUND)
596 /* NB: already cleared if cert in cache */
597 certerr_nottrusted = 1;
598 certstat ^= GNUTLS_CERT_SIGNER_NOT_FOUND;
601 if (certstat & GNUTLS_CERT_SIGNER_NOT_CA)
603 /* NB: already cleared if cert in cache */
604 certerr_signernotca = 1;
605 certstat ^= GNUTLS_CERT_SIGNER_NOT_CA;
608 /* OK if signed by (or is) a trusted certificate */
609 /* we've been zeroing the interesting bits in certstat -
610 don't return OK if there are any unhandled bits we don't
612 if (!(certerr_expired || certerr_notyetvalid ||
613 certerr_hostname || certerr_nottrusted) && certstat == 0)
615 gnutls_x509_crt_deinit(cert);
620 /* interactive check from user */
621 menu = mutt_new_menu ();
623 menu->dialog = (char **) safe_calloc (1, menu->max * sizeof (char *));
624 for (i = 0; i < menu->max; i++)
625 menu->dialog[i] = (char *) safe_calloc (1, SHORT_STRING * sizeof (char));
628 strfcpy (menu->dialog[row], _("This certificate belongs to:"), SHORT_STRING);
631 buflen = sizeof(dn_common_name);
632 if (gnutls_x509_crt_get_dn_by_oid(cert, GNUTLS_OID_X520_COMMON_NAME, 0, 0,
633 dn_common_name, &buflen) != 0)
634 dn_common_name[0] = '\0';
635 buflen = sizeof(dn_email);
636 if (gnutls_x509_crt_get_dn_by_oid(cert, GNUTLS_OID_PKCS9_EMAIL, 0, 0,
637 dn_email, &buflen) != 0)
639 buflen = sizeof(dn_organization);
640 if (gnutls_x509_crt_get_dn_by_oid(cert, GNUTLS_OID_X520_ORGANIZATION_NAME, 0, 0,
641 dn_organization, &buflen) != 0)
642 dn_organization[0] = '\0';
643 buflen = sizeof(dn_organizational_unit);
644 if (gnutls_x509_crt_get_dn_by_oid(cert, GNUTLS_OID_X520_ORGANIZATIONAL_UNIT_NAME, 0, 0,
645 dn_organizational_unit, &buflen) != 0)
646 dn_organizational_unit[0] = '\0';
647 buflen = sizeof(dn_locality);
648 if (gnutls_x509_crt_get_dn_by_oid(cert, GNUTLS_OID_X520_LOCALITY_NAME, 0, 0,
649 dn_locality, &buflen) != 0)
650 dn_locality[0] = '\0';
651 buflen = sizeof(dn_province);
652 if (gnutls_x509_crt_get_dn_by_oid(cert, GNUTLS_OID_X520_STATE_OR_PROVINCE_NAME, 0, 0,
653 dn_province, &buflen) != 0)
654 dn_province[0] = '\0';
655 buflen = sizeof(dn_country);
656 if (gnutls_x509_crt_get_dn_by_oid(cert, GNUTLS_OID_X520_COUNTRY_NAME, 0, 0,
657 dn_country, &buflen) != 0)
658 dn_country[0] = '\0';
660 snprintf (menu->dialog[row++], SHORT_STRING, " %s %s", dn_common_name, dn_email);
661 snprintf (menu->dialog[row++], SHORT_STRING, " %s", dn_organization);
662 snprintf (menu->dialog[row++], SHORT_STRING, " %s", dn_organizational_unit);
663 snprintf (menu->dialog[row++], SHORT_STRING, " %s %s %s",
664 dn_locality, dn_province, dn_country);
667 strfcpy (menu->dialog[row], _("This certificate was issued by:"), SHORT_STRING);
670 buflen = sizeof(dn_common_name);
671 if (gnutls_x509_crt_get_issuer_dn_by_oid(cert, GNUTLS_OID_X520_COMMON_NAME, 0, 0,
672 dn_common_name, &buflen) != 0)
673 dn_common_name[0] = '\0';
674 buflen = sizeof(dn_email);
675 if (gnutls_x509_crt_get_issuer_dn_by_oid(cert, GNUTLS_OID_PKCS9_EMAIL, 0, 0,
676 dn_email, &buflen) != 0)
678 buflen = sizeof(dn_organization);
679 if (gnutls_x509_crt_get_issuer_dn_by_oid(cert, GNUTLS_OID_X520_ORGANIZATION_NAME, 0, 0,
680 dn_organization, &buflen) != 0)
681 dn_organization[0] = '\0';
682 buflen = sizeof(dn_organizational_unit);
683 if (gnutls_x509_crt_get_issuer_dn_by_oid(cert, GNUTLS_OID_X520_ORGANIZATIONAL_UNIT_NAME, 0, 0,
684 dn_organizational_unit, &buflen) != 0)
685 dn_organizational_unit[0] = '\0';
686 buflen = sizeof(dn_locality);
687 if (gnutls_x509_crt_get_issuer_dn_by_oid(cert, GNUTLS_OID_X520_LOCALITY_NAME, 0, 0,
688 dn_locality, &buflen) != 0)
689 dn_locality[0] = '\0';
690 buflen = sizeof(dn_province);
691 if (gnutls_x509_crt_get_issuer_dn_by_oid(cert, GNUTLS_OID_X520_STATE_OR_PROVINCE_NAME, 0, 0,
692 dn_province, &buflen) != 0)
693 dn_province[0] = '\0';
694 buflen = sizeof(dn_country);
695 if (gnutls_x509_crt_get_issuer_dn_by_oid(cert, GNUTLS_OID_X520_COUNTRY_NAME, 0, 0,
696 dn_country, &buflen) != 0)
697 dn_country[0] = '\0';
699 snprintf (menu->dialog[row++], SHORT_STRING, " %s %s", dn_common_name, dn_email);
700 snprintf (menu->dialog[row++], SHORT_STRING, " %s", dn_organization);
701 snprintf (menu->dialog[row++], SHORT_STRING, " %s", dn_organizational_unit);
702 snprintf (menu->dialog[row++], SHORT_STRING, " %s %s %s",
703 dn_locality, dn_province, dn_country);
706 snprintf (menu->dialog[row++], SHORT_STRING, _("This certificate is valid"));
708 t = gnutls_x509_crt_get_activation_time(cert);
709 snprintf (menu->dialog[row++], SHORT_STRING, _(" from %s"),
710 tls_make_date(t, datestr, 30));
712 t = gnutls_x509_crt_get_expiration_time(cert);
713 snprintf (menu->dialog[row++], SHORT_STRING, _(" to %s"),
714 tls_make_date(t, datestr, 30));
717 tls_fingerprint (GNUTLS_DIG_SHA, fpbuf, sizeof (fpbuf), &cert_list[0]);
718 snprintf (menu->dialog[row++], SHORT_STRING, _("SHA1 Fingerprint: %s"), fpbuf);
720 tls_fingerprint (GNUTLS_DIG_MD5, fpbuf, sizeof (fpbuf), &cert_list[0]);
721 snprintf (menu->dialog[row++], SHORT_STRING, _("MD5 Fingerprint: %s"), fpbuf);
723 if (certerr_notyetvalid)
726 strfcpy (menu->dialog[row], _("WARNING: Server certificate is not yet valid"), SHORT_STRING);
731 strfcpy (menu->dialog[row], _("WARNING: Server certificate has expired"), SHORT_STRING);
736 strfcpy (menu->dialog[row], _("WARNING: Server certificate has been revoked"), SHORT_STRING);
738 if (certerr_hostname)
741 strfcpy (menu->dialog[row], _("WARNING: Server hostname does not match certificate"), SHORT_STRING);
743 if (certerr_signernotca)
746 strfcpy (menu->dialog[row], _("WARNING: Signer of server certificate is not a CA"), SHORT_STRING);
749 menu->title = _("TLS/SSL Certificate check");
750 /* certificates with bad dates, or that are revoked, must be
751 accepted manually each and every time */
752 if (SslCertFile && !certerr_expired && !certerr_notyetvalid && !certerr_revoked)
754 menu->prompt = _("(r)eject, accept (o)nce, (a)ccept always");
755 menu->keys = _("roa");
759 menu->prompt = _("(r)eject, accept (o)nce");
760 menu->keys = _("ro");
764 mutt_make_help (buf, sizeof (buf), _("Exit "), MENU_GENERIC, OP_EXIT);
765 strncat (helpstr, buf, sizeof (helpstr));
766 mutt_make_help (buf, sizeof (buf), _("Help"), MENU_GENERIC, OP_HELP);
767 strncat (helpstr, buf, sizeof (helpstr));
768 menu->help = helpstr;
773 switch (mutt_menuLoop (menu))
776 case OP_MAX + 1: /* reject */
780 case OP_MAX + 3: /* accept always */
782 if ((fp = fopen (SslCertFile, "a")))
784 /* save hostname if necessary */
785 if (certerr_hostname)
787 fprintf(fp, "#H %s %s\n", conn->account.host, fpbuf);
790 if (certerr_nottrusted)
793 ret = gnutls_pem_base64_encode_alloc ("CERTIFICATE", &cert_list[0],
797 if (fwrite(pemdata.data, pemdata.size, 1, fp) == 1)
801 gnutls_free(pemdata.data);
808 mutt_error (_("Warning: Couldn't save certificate"));
813 mutt_message (_("Certificate saved"));
817 case OP_MAX + 2: /* accept once */
822 mutt_menuDestroy (&menu);
823 gnutls_x509_crt_deinit(cert);