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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, 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 /* certificate error bitmap values */
37 #define CERTERR_VALID 0
38 #define CERTERR_EXPIRED 1
39 #define CERTERR_NOTYETVALID 2
40 #define CERTERR_REVOKED 4
41 #define CERTERR_NOTTRUSTED 8
42 #define CERTERR_HOSTNAME 16
43 #define CERTERR_SIGNERNOTCA 32
44 #define CERTERR_INSECUREALG 64
46 typedef struct _tlssockdata
49 gnutls_certificate_credentials xcred;
53 /* local prototypes */
54 static int tls_socket_read (CONNECTION* conn, char* buf, size_t len);
55 static int tls_socket_write (CONNECTION* conn, const char* buf, size_t len);
56 static int tls_socket_open (CONNECTION* conn);
57 static int tls_socket_close (CONNECTION* conn);
58 static int tls_starttls_close (CONNECTION* conn);
60 static int tls_init (void);
61 static int tls_negotiate (CONNECTION* conn);
62 static int tls_check_certificate (CONNECTION* conn);
65 static int tls_init (void)
67 static unsigned char init_complete = 0;
73 err = gnutls_global_init();
76 mutt_error ("gnutls_global_init: %s", gnutls_strerror(err));
85 int mutt_ssl_socket_setup (CONNECTION* conn)
90 conn->conn_open = tls_socket_open;
91 conn->conn_read = tls_socket_read;
92 conn->conn_write = tls_socket_write;
93 conn->conn_close = tls_socket_close;
94 conn->conn_poll = raw_socket_poll;
99 static int tls_socket_read (CONNECTION* conn, char* buf, size_t len)
101 tlssockdata *data = conn->sockdata;
106 mutt_error (_("Error: no TLS socket open"));
112 ret = gnutls_record_recv (data->state, buf, len);
113 if (ret < 0 && gnutls_error_is_fatal(ret) == 1)
115 mutt_error ("tls_socket_read (%s)", gnutls_strerror (ret));
120 while (ret == GNUTLS_E_AGAIN || ret == GNUTLS_E_INTERRUPTED);
125 static int tls_socket_write (CONNECTION* conn, const char* buf, size_t len)
127 tlssockdata *data = conn->sockdata;
133 mutt_error (_("Error: no TLS socket open"));
140 ret = gnutls_record_send (data->state, buf + sent, len - sent);
143 if (gnutls_error_is_fatal(ret) == 1)
145 mutt_error ("tls_socket_write (%s)", gnutls_strerror (ret));
152 } while (sent < len);
157 static int tls_socket_open (CONNECTION* conn)
159 if (raw_socket_open (conn) < 0)
162 if (tls_negotiate (conn) < 0)
164 tls_socket_close (conn);
171 int mutt_ssl_starttls (CONNECTION* conn)
176 if (tls_negotiate (conn) < 0)
179 conn->conn_read = tls_socket_read;
180 conn->conn_write = tls_socket_write;
181 conn->conn_close = tls_starttls_close;
186 static void tls_get_client_cert (CONNECTION* conn)
188 tlssockdata *data = conn->sockdata;
189 const gnutls_datum_t* crtdata;
190 gnutls_x509_crt_t clientcrt;
196 /* get our cert CN if we have one */
197 if (!(crtdata = gnutls_certificate_get_ours (data->state)))
200 if (gnutls_x509_crt_init (&clientcrt) < 0)
202 dprint (1, (debugfile, "Failed to init gnutls crt\n"));
205 if (gnutls_x509_crt_import (clientcrt, crtdata, GNUTLS_X509_FMT_DER) < 0)
207 dprint (1, (debugfile, "Failed to import gnutls client crt\n"));
210 /* get length of DN */
212 gnutls_x509_crt_get_dn (clientcrt, NULL, &dnlen);
213 if (!(dn = calloc (1, dnlen)))
215 dprint (1, (debugfile, "could not allocate DN\n"));
218 gnutls_x509_crt_get_dn (clientcrt, dn, &dnlen);
219 dprint (2, (debugfile, "client certificate DN: %s\n", dn));
221 /* extract CN to use as external user name */
222 if (!(cn = strstr (dn, "CN=")))
224 dprint (1, (debugfile, "no CN found in DN\n"));
229 if ((cnend = strstr (dn, ",EMAIL=")))
232 /* if we are using a client cert, SASL may expect an external auth name */
233 mutt_account_getuser (&conn->account);
238 gnutls_x509_crt_deinit (clientcrt);
241 static int protocol_priority[] = {GNUTLS_TLS1, GNUTLS_SSL3, 0};
243 /* tls_negotiate: After TLS state has been initialised, attempt to negotiate
244 * TLS over the wire, including certificate checks. */
245 static int tls_negotiate (CONNECTION * conn)
250 data = (tlssockdata *) safe_calloc (1, sizeof (tlssockdata));
251 conn->sockdata = data;
252 err = gnutls_certificate_allocate_credentials (&data->xcred);
255 FREE(&conn->sockdata);
256 mutt_error ("gnutls_certificate_allocate_credentials: %s", gnutls_strerror(err));
261 gnutls_certificate_set_x509_trust_file (data->xcred, SslCertFile,
262 GNUTLS_X509_FMT_PEM);
263 /* ignore errors, maybe file doesn't exist yet */
267 gnutls_certificate_set_x509_trust_file (data->xcred, SslCACertFile,
268 GNUTLS_X509_FMT_PEM);
273 dprint (2, (debugfile, "Using client certificate %s\n", SslClientCert));
274 gnutls_certificate_set_x509_key_file (data->xcred, SslClientCert,
275 SslClientCert, GNUTLS_X509_FMT_PEM);
278 #if HAVE_DECL_GNUTLS_VERIFY_DISABLE_TIME_CHECKS
279 /* disable checking certificate activation/expiration times
280 in gnutls, we do the checks ourselves */
281 gnutls_certificate_set_verify_flags(data->xcred, GNUTLS_VERIFY_DISABLE_TIME_CHECKS);
284 gnutls_init(&data->state, GNUTLS_CLIENT);
287 gnutls_transport_set_ptr (data->state, (gnutls_transport_ptr)conn->fd);
289 /* disable TLS/SSL protocols as needed */
290 if (!option(OPTTLSV1) && !option(OPTSSLV3))
292 mutt_error (_("All available protocols for TLS/SSL connection disabled"));
295 else if (!option(OPTTLSV1))
297 protocol_priority[0] = GNUTLS_SSL3;
298 protocol_priority[1] = 0;
300 else if (!option(OPTSSLV3))
302 protocol_priority[0] = GNUTLS_TLS1;
303 protocol_priority[1] = 0;
307 use the list set above
310 /* We use default priorities (see gnutls documentation),
311 except for protocol version */
312 gnutls_set_default_priority (data->state);
313 gnutls_protocol_set_priority (data->state, protocol_priority);
315 if (SslDHPrimeBits > 0)
317 gnutls_dh_set_prime_bits (data->state, SslDHPrimeBits);
321 gnutls_set_cred (data->state, GNUTLS_ANON, NULL);
324 gnutls_credentials_set (data->state, GNUTLS_CRD_CERTIFICATE, data->xcred);
326 err = gnutls_handshake(data->state);
328 while (err == GNUTLS_E_AGAIN || err == GNUTLS_E_INTERRUPTED)
330 err = gnutls_handshake(data->state);
333 if (err == GNUTLS_E_FATAL_ALERT_RECEIVED)
335 mutt_error("gnutls_handshake: %s(%s)", gnutls_strerror(err),
336 gnutls_alert_get_name(gnutls_alert_get(data->state)));
340 mutt_error("gnutls_handshake: %s", gnutls_strerror(err));
346 if (!tls_check_certificate(conn))
349 /* set Security Strength Factor (SSF) for SASL */
350 /* NB: gnutls_cipher_get_key_size() returns key length in bytes */
351 conn->ssf = gnutls_cipher_get_key_size (gnutls_cipher_get (data->state)) * 8;
353 tls_get_client_cert (conn);
355 if (!option(OPTNOCURSES)) {
356 mutt_message (_("SSL/TLS connection using %s (%s/%s/%s)"),
357 gnutls_protocol_get_name (gnutls_protocol_get_version (data->state)),
358 gnutls_kx_get_name (gnutls_kx_get (data->state)),
359 gnutls_cipher_get_name (gnutls_cipher_get (data->state)),
360 gnutls_mac_get_name (gnutls_mac_get (data->state)));
367 gnutls_certificate_free_credentials (data->xcred);
368 gnutls_deinit (data->state);
369 FREE(&conn->sockdata);
373 static int tls_socket_close (CONNECTION* conn)
375 tlssockdata *data = conn->sockdata;
378 gnutls_bye (data->state, GNUTLS_SHUT_RDWR);
380 gnutls_certificate_free_credentials (data->xcred);
381 gnutls_deinit (data->state);
382 FREE (&conn->sockdata);
385 return raw_socket_close (conn);
388 static int tls_starttls_close (CONNECTION* conn)
392 rc = tls_socket_close (conn);
393 conn->conn_read = raw_socket_read;
394 conn->conn_write = raw_socket_write;
395 conn->conn_close = raw_socket_close;
400 #define CERT_SEP "-----BEGIN"
402 /* this bit is based on read_ca_file() in gnutls */
403 static int tls_compare_certificates (const gnutls_datum *peercert)
409 gnutls_datum b64_data;
410 unsigned char *b64_data_data;
411 struct stat filestat;
413 if (stat(SslCertFile, &filestat) == -1)
416 b64_data.size = filestat.st_size+1;
417 b64_data_data = (unsigned char *) safe_calloc (1, b64_data.size);
418 b64_data_data[b64_data.size-1] = '\0';
419 b64_data.data = b64_data_data;
421 fd1 = fopen(SslCertFile, "r");
426 b64_data.size = fread(b64_data.data, 1, b64_data.size, fd1);
430 ret = gnutls_pem_base64_decode_alloc(NULL, &b64_data, &cert);
433 FREE (&b64_data_data);
437 ptr = (unsigned char *)strstr((char*)b64_data.data, CERT_SEP) + 1;
438 ptr = (unsigned char *)strstr((char*)ptr, CERT_SEP);
440 b64_data.size = b64_data.size - (ptr - b64_data.data);
443 if (cert.size == peercert->size)
445 if (memcmp (cert.data, peercert->data, cert.size) == 0)
448 gnutls_free(cert.data);
449 FREE (&b64_data_data);
454 gnutls_free(cert.data);
455 } while (ptr != NULL);
458 FREE (&b64_data_data);
462 static void tls_fingerprint (gnutls_digest_algorithm algo,
463 char* s, int l, const gnutls_datum* data)
465 unsigned char md[36];
471 if (gnutls_fingerprint (algo, data, (char *)md, &n) < 0)
473 snprintf (s, l, _("[unable to calculate]"));
477 for (j = 0; j < (int) n; j++)
480 snprintf (ch, 8, "%02X%s", md[j], (j % 2 ? " " : ""));
481 safe_strcat (s, l, ch);
483 s[2*n+n/2-1] = '\0'; /* don't want trailing space */
487 static char *tls_make_date (time_t t, char *s, size_t len)
489 struct tm *l = gmtime (&t);
492 snprintf (s, len, "%s, %d %s %d %02d:%02d:%02d UTC",
493 Weekdays[l->tm_wday], l->tm_mday, Months[l->tm_mon],
494 l->tm_year + 1900, l->tm_hour, l->tm_min, l->tm_sec);
496 strfcpy (s, _("[invalid date]"), len);
501 static int tls_check_stored_hostname (const gnutls_datum *cert,
502 const char *hostname)
506 char *linestr = NULL;
510 regmatch_t pmatch[3];
512 /* try checking against names stored in stored certs file */
513 if ((fp = fopen (SslCertFile, "r")))
515 if (regcomp(&preg, "^#H ([a-zA-Z0-9_\\.-]+) ([0-9A-F]{4}( [0-9A-F]{4}){7})[ \t]*$", REG_ICASE|REG_EXTENDED) != 0)
522 tls_fingerprint (GNUTLS_DIG_MD5, buf, sizeof (buf), cert);
523 while ((linestr = mutt_read_line(linestr, &linestrsize, fp, &linenum, 0)) != NULL)
525 if(linestr[0] == '#' && linestr[1] == 'H')
527 if (regexec(&preg, linestr, 3, pmatch, 0) == 0)
529 linestr[pmatch[1].rm_eo] = '\0';
530 linestr[pmatch[2].rm_eo] = '\0';
531 if (strcmp(linestr + pmatch[1].rm_so, hostname) == 0 &&
532 strcmp(linestr + pmatch[2].rm_so, buf) == 0)
547 /* not found a matching name */
551 static int tls_check_preauth (const gnutls_datum_t *certdata,
552 gnutls_certificate_status certstat,
553 const char *hostname, int chainidx, int* certerr,
556 gnutls_x509_crt cert;
558 *certerr = CERTERR_VALID;
561 if (gnutls_x509_crt_init (&cert) < 0)
563 mutt_error (_("Error initialising gnutls certificate data"));
568 if (gnutls_x509_crt_import (cert, certdata, GNUTLS_X509_FMT_DER) < 0)
570 mutt_error (_("Error processing certificate data"));
572 gnutls_x509_crt_deinit (cert);
576 if (option (OPTSSLVERIFYDATES) != M_NO)
578 if (gnutls_x509_crt_get_expiration_time (cert) < time(NULL))
579 *certerr |= CERTERR_EXPIRED;
580 if (gnutls_x509_crt_get_activation_time (cert) > time(NULL))
581 *certerr |= CERTERR_NOTYETVALID;
584 if (chainidx == 0 && option (OPTSSLVERIFYHOST) != M_NO
585 && !gnutls_x509_crt_check_hostname (cert, hostname)
586 && !tls_check_stored_hostname (certdata, hostname))
587 *certerr |= CERTERR_HOSTNAME;
589 /* see whether certificate is in our cache (certificates file) */
590 if (tls_compare_certificates (certdata))
594 if (chainidx == 0 && certstat & GNUTLS_CERT_INVALID)
596 /* doesn't matter - have decided is valid because server
597 certificate is in our trusted cache */
598 certstat ^= GNUTLS_CERT_INVALID;
601 if (chainidx == 0 && certstat & GNUTLS_CERT_SIGNER_NOT_FOUND)
603 /* doesn't matter that we haven't found the signer, since
604 certificate is in our trusted cache */
605 certstat ^= GNUTLS_CERT_SIGNER_NOT_FOUND;
608 if (chainidx <= 1 && certstat & GNUTLS_CERT_SIGNER_NOT_CA)
610 /* Hmm. Not really sure how to handle this, but let's say
611 that we don't care if the CA certificate hasn't got the
612 correct X.509 basic constraints if server or first signer
613 certificate is in our cache. */
614 certstat ^= GNUTLS_CERT_SIGNER_NOT_CA;
617 if (chainidx == 0 && certstat & GNUTLS_CERT_INSECURE_ALGORITHM)
619 /* doesn't matter that it was signed using an insecure
620 algorithm, since certificate is in our trusted cache */
621 certstat ^= GNUTLS_CERT_INSECURE_ALGORITHM;
625 if (certstat & GNUTLS_CERT_REVOKED)
627 *certerr |= CERTERR_REVOKED;
628 certstat ^= GNUTLS_CERT_REVOKED;
631 if (certstat & GNUTLS_CERT_INVALID)
633 *certerr |= CERTERR_NOTTRUSTED;
634 certstat ^= GNUTLS_CERT_INVALID;
637 if (certstat & GNUTLS_CERT_SIGNER_NOT_FOUND)
639 /* NB: already cleared if cert in cache */
640 *certerr |= CERTERR_NOTTRUSTED;
641 certstat ^= GNUTLS_CERT_SIGNER_NOT_FOUND;
644 if (certstat & GNUTLS_CERT_SIGNER_NOT_CA)
646 /* NB: already cleared if cert in cache */
647 *certerr |= CERTERR_SIGNERNOTCA;
648 certstat ^= GNUTLS_CERT_SIGNER_NOT_CA;
651 if (certstat & GNUTLS_CERT_INSECURE_ALGORITHM)
653 /* NB: already cleared if cert in cache */
654 *certerr |= CERTERR_INSECUREALG;
655 certstat ^= GNUTLS_CERT_INSECURE_ALGORITHM;
658 gnutls_x509_crt_deinit (cert);
660 /* we've been zeroing the interesting bits in certstat -
661 don't return OK if there are any unhandled bits we don't
663 if (*certerr == CERTERR_VALID && certstat == 0)
669 static int tls_check_one_certificate (const gnutls_datum_t *certdata,
670 gnutls_certificate_status certstat,
671 const char* hostname, int idx, int len)
673 int certerr, savedcert;
674 gnutls_x509_crt cert;
675 char buf[SHORT_STRING];
676 char fpbuf[SHORT_STRING];
678 char dn_common_name[SHORT_STRING];
679 char dn_email[SHORT_STRING];
680 char dn_organization[SHORT_STRING];
681 char dn_organizational_unit[SHORT_STRING];
682 char dn_locality[SHORT_STRING];
683 char dn_province[SHORT_STRING];
684 char dn_country[SHORT_STRING];
688 char helpstr[LONG_STRING];
691 gnutls_datum pemdata;
692 int i, row, done, ret;
694 if (!tls_check_preauth (certdata, certstat, hostname, idx, &certerr,
698 /* skip signers if insecure algorithm was used */
699 if (idx && (certerr & CERTERR_INSECUREALG))
703 mutt_error (_("Warning: Server certificate was signed using an insecure algorithm"));
709 /* interactive check from user */
710 if (gnutls_x509_crt_init (&cert) < 0)
712 mutt_error (_("Error initialising gnutls certificate data"));
717 if (gnutls_x509_crt_import (cert, certdata, GNUTLS_X509_FMT_DER) < 0)
719 mutt_error (_("Error processing certificate data"));
721 gnutls_x509_crt_deinit (cert);
725 menu = mutt_new_menu (-1);
727 menu->dialog = (char **) safe_calloc (1, menu->max * sizeof (char *));
728 for (i = 0; i < menu->max; i++)
729 menu->dialog[i] = (char *) safe_calloc (1, SHORT_STRING * sizeof (char));
732 strfcpy (menu->dialog[row], _("This certificate belongs to:"), SHORT_STRING);
735 buflen = sizeof (dn_common_name);
736 if (gnutls_x509_crt_get_dn_by_oid (cert, GNUTLS_OID_X520_COMMON_NAME, 0, 0,
737 dn_common_name, &buflen) != 0)
738 dn_common_name[0] = '\0';
739 buflen = sizeof (dn_email);
740 if (gnutls_x509_crt_get_dn_by_oid (cert, GNUTLS_OID_PKCS9_EMAIL, 0, 0,
741 dn_email, &buflen) != 0)
743 buflen = sizeof (dn_organization);
744 if (gnutls_x509_crt_get_dn_by_oid (cert, GNUTLS_OID_X520_ORGANIZATION_NAME, 0, 0,
745 dn_organization, &buflen) != 0)
746 dn_organization[0] = '\0';
747 buflen = sizeof (dn_organizational_unit);
748 if (gnutls_x509_crt_get_dn_by_oid (cert, GNUTLS_OID_X520_ORGANIZATIONAL_UNIT_NAME, 0, 0,
749 dn_organizational_unit, &buflen) != 0)
750 dn_organizational_unit[0] = '\0';
751 buflen = sizeof (dn_locality);
752 if (gnutls_x509_crt_get_dn_by_oid (cert, GNUTLS_OID_X520_LOCALITY_NAME, 0, 0,
753 dn_locality, &buflen) != 0)
754 dn_locality[0] = '\0';
755 buflen = sizeof (dn_province);
756 if (gnutls_x509_crt_get_dn_by_oid (cert, GNUTLS_OID_X520_STATE_OR_PROVINCE_NAME, 0, 0,
757 dn_province, &buflen) != 0)
758 dn_province[0] = '\0';
759 buflen = sizeof (dn_country);
760 if (gnutls_x509_crt_get_dn_by_oid (cert, GNUTLS_OID_X520_COUNTRY_NAME, 0, 0,
761 dn_country, &buflen) != 0)
762 dn_country[0] = '\0';
764 snprintf (menu->dialog[row++], SHORT_STRING, " %s %s", dn_common_name, dn_email);
765 snprintf (menu->dialog[row++], SHORT_STRING, " %s", dn_organization);
766 snprintf (menu->dialog[row++], SHORT_STRING, " %s", dn_organizational_unit);
767 snprintf (menu->dialog[row++], SHORT_STRING, " %s %s %s",
768 dn_locality, dn_province, dn_country);
771 strfcpy (menu->dialog[row], _("This certificate was issued by:"), SHORT_STRING);
774 buflen = sizeof (dn_common_name);
775 if (gnutls_x509_crt_get_issuer_dn_by_oid (cert, GNUTLS_OID_X520_COMMON_NAME, 0, 0,
776 dn_common_name, &buflen) != 0)
777 dn_common_name[0] = '\0';
778 buflen = sizeof (dn_email);
779 if (gnutls_x509_crt_get_issuer_dn_by_oid (cert, GNUTLS_OID_PKCS9_EMAIL, 0, 0,
780 dn_email, &buflen) != 0)
782 buflen = sizeof (dn_organization);
783 if (gnutls_x509_crt_get_issuer_dn_by_oid (cert, GNUTLS_OID_X520_ORGANIZATION_NAME, 0, 0,
784 dn_organization, &buflen) != 0)
785 dn_organization[0] = '\0';
786 buflen = sizeof (dn_organizational_unit);
787 if (gnutls_x509_crt_get_issuer_dn_by_oid (cert, GNUTLS_OID_X520_ORGANIZATIONAL_UNIT_NAME, 0, 0,
788 dn_organizational_unit, &buflen) != 0)
789 dn_organizational_unit[0] = '\0';
790 buflen = sizeof (dn_locality);
791 if (gnutls_x509_crt_get_issuer_dn_by_oid (cert, GNUTLS_OID_X520_LOCALITY_NAME, 0, 0,
792 dn_locality, &buflen) != 0)
793 dn_locality[0] = '\0';
794 buflen = sizeof (dn_province);
795 if (gnutls_x509_crt_get_issuer_dn_by_oid (cert, GNUTLS_OID_X520_STATE_OR_PROVINCE_NAME, 0, 0,
796 dn_province, &buflen) != 0)
797 dn_province[0] = '\0';
798 buflen = sizeof (dn_country);
799 if (gnutls_x509_crt_get_issuer_dn_by_oid (cert, GNUTLS_OID_X520_COUNTRY_NAME, 0, 0,
800 dn_country, &buflen) != 0)
801 dn_country[0] = '\0';
803 snprintf (menu->dialog[row++], SHORT_STRING, " %s %s", dn_common_name, dn_email);
804 snprintf (menu->dialog[row++], SHORT_STRING, " %s", dn_organization);
805 snprintf (menu->dialog[row++], SHORT_STRING, " %s", dn_organizational_unit);
806 snprintf (menu->dialog[row++], SHORT_STRING, " %s %s %s",
807 dn_locality, dn_province, dn_country);
810 snprintf (menu->dialog[row++], SHORT_STRING, _("This certificate is valid"));
812 t = gnutls_x509_crt_get_activation_time (cert);
813 snprintf (menu->dialog[row++], SHORT_STRING, _(" from %s"),
814 tls_make_date (t, datestr, 30));
816 t = gnutls_x509_crt_get_expiration_time (cert);
817 snprintf (menu->dialog[row++], SHORT_STRING, _(" to %s"),
818 tls_make_date (t, datestr, 30));
821 tls_fingerprint (GNUTLS_DIG_SHA, fpbuf, sizeof (fpbuf), certdata);
822 snprintf (menu->dialog[row++], SHORT_STRING, _("SHA1 Fingerprint: %s"), fpbuf);
824 tls_fingerprint (GNUTLS_DIG_MD5, fpbuf, sizeof (fpbuf), certdata);
825 snprintf (menu->dialog[row++], SHORT_STRING, _("MD5 Fingerprint: %s"), fpbuf);
827 if (certerr & CERTERR_NOTYETVALID)
830 strfcpy (menu->dialog[row], _("WARNING: Server certificate is not yet valid"), SHORT_STRING);
832 if (certerr & CERTERR_EXPIRED)
835 strfcpy (menu->dialog[row], _("WARNING: Server certificate has expired"), SHORT_STRING);
837 if (certerr & CERTERR_REVOKED)
840 strfcpy (menu->dialog[row], _("WARNING: Server certificate has been revoked"), SHORT_STRING);
842 if (certerr & CERTERR_HOSTNAME)
845 strfcpy (menu->dialog[row], _("WARNING: Server hostname does not match certificate"), SHORT_STRING);
847 if (certerr & CERTERR_SIGNERNOTCA)
850 strfcpy (menu->dialog[row], _("WARNING: Signer of server certificate is not a CA"), SHORT_STRING);
853 snprintf (title, sizeof (title),
854 _("SSL Certificate check (certificate %d of %d in chain)"),
857 /* certificates with bad dates, or that are revoked, must be
858 accepted manually each and every time */
859 if (SslCertFile && !savedcert
860 && !(certerr & (CERTERR_EXPIRED | CERTERR_NOTYETVALID
863 menu->prompt = _("(r)eject, accept (o)nce, (a)ccept always");
864 menu->keys = _("roa");
868 menu->prompt = _("(r)eject, accept (o)nce");
869 menu->keys = _("ro");
873 mutt_make_help (buf, sizeof (buf), _("Exit "), MENU_GENERIC, OP_EXIT);
874 safe_strcat (helpstr, sizeof (helpstr), buf);
875 mutt_make_help (buf, sizeof (buf), _("Help"), MENU_GENERIC, OP_HELP);
876 safe_strcat (helpstr, sizeof (helpstr), buf);
877 menu->help = helpstr;
880 set_option (OPTUNBUFFEREDINPUT);
883 switch (mutt_menuLoop (menu))
886 case OP_MAX + 1: /* reject */
890 case OP_MAX + 3: /* accept always */
892 if ((fp = fopen (SslCertFile, "a")))
894 /* save hostname if necessary */
895 if (certerr & CERTERR_HOSTNAME)
897 fprintf(fp, "#H %s %s\n", hostname, fpbuf);
900 if (certerr & CERTERR_NOTTRUSTED)
903 ret = gnutls_pem_base64_encode_alloc ("CERTIFICATE", certdata,
907 if (fwrite (pemdata.data, pemdata.size, 1, fp) == 1)
911 gnutls_free (pemdata.data);
918 mutt_error (_("Warning: Couldn't save certificate"));
923 mutt_message (_("Certificate saved"));
927 case OP_MAX + 2: /* accept once */
932 unset_option (OPTUNBUFFEREDINPUT);
933 mutt_menuDestroy (&menu);
934 gnutls_x509_crt_deinit (cert);
939 /* sanity-checking wrapper for gnutls_certificate_verify_peers */
940 static gnutls_certificate_status tls_verify_peers (gnutls_session tlsstate)
942 gnutls_certificate_status certstat;
944 certstat = gnutls_certificate_verify_peers (tlsstate);
948 if (certstat == GNUTLS_E_NO_CERTIFICATE_FOUND)
950 mutt_error (_("Unable to get certificate from peer"));
956 mutt_error (_("Certificate verification error (%s)"),
957 gnutls_strerror (certstat));
962 /* We only support X.509 certificates (not OpenPGP) at the moment */
963 if (gnutls_certificate_type_get (tlsstate) != GNUTLS_CRT_X509)
965 mutt_error (_("Certificate is not X.509"));
973 static int tls_check_certificate (CONNECTION* conn)
975 tlssockdata *data = conn->sockdata;
976 gnutls_session state = data->state;
977 const gnutls_datum *cert_list;
978 unsigned int cert_list_size = 0;
979 gnutls_certificate_status certstat;
980 int certerr, i, preauthrc, savedcert, rc = 0;
982 if (gnutls_auth_get_type (state) != GNUTLS_CRD_CERTIFICATE)
984 mutt_error (_("Unable to get certificate from peer"));
989 certstat = tls_verify_peers (state);
991 cert_list = gnutls_certificate_get_peers (state, &cert_list_size);
994 mutt_error (_("Unable to get certificate from peer"));
999 /* tls_verify_peers doesn't check hostname or expiration, so walk
1000 * from most specific to least checking these. If we see a saved certificate,
1001 * its status short-circuits the remaining checks. */
1003 for (i = 0; i < cert_list_size; i++) {
1004 rc = tls_check_preauth(&cert_list[i], certstat, conn->account.host, i,
1005 &certerr, &savedcert);
1017 /* then check interactively, starting from chain root */
1018 for (i = cert_list_size - 1; i >= 0; i--)
1020 rc = tls_check_one_certificate (&cert_list[i], certstat, conn->account.host,
1023 /* add signers to trust set, then reverify */
1025 rc = gnutls_certificate_set_x509_trust_mem (data->xcred, &cert_list[i],
1026 GNUTLS_X509_FMT_DER);
1028 dprint (1, (debugfile, "error trusting certificate %d: %d\n", i, rc));
1030 certstat = tls_verify_peers (state);