]> git.llucax.com Git - software/mutt-debian.git/blob - mutt_ssl.c
added a note for DM-Upload-Allowed
[software/mutt-debian.git] / mutt_ssl.c
1 /*
2  * Copyright (C) 1999-2001 Tommi Komulainen <Tommi.Komulainen@iki.fi>
3  *
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.
8  *
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.
13  *
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.
17  */
18
19 #if HAVE_CONFIG_H
20 # include "config.h"
21 #endif
22
23 #include <openssl/ssl.h>
24 #include <openssl/x509.h>
25 #include <openssl/x509v3.h>
26 #include <openssl/err.h>
27 #include <openssl/rand.h>
28
29 #undef _
30
31 #include <string.h>
32
33 #include "mutt.h"
34 #include "mutt_socket.h"
35 #include "mutt_menu.h"
36 #include "mutt_curses.h"
37 #include "mutt_ssl.h"
38 #include "mutt_idna.h"
39
40 #if OPENSSL_VERSION_NUMBER >= 0x00904000L
41 #define READ_X509_KEY(fp, key)  PEM_read_X509(fp, key, NULL, NULL)
42 #else
43 #define READ_X509_KEY(fp, key)  PEM_read_X509(fp, key, NULL)
44 #endif
45
46 /* Just in case OpenSSL doesn't define DEVRANDOM */
47 #ifndef DEVRANDOM
48 #define DEVRANDOM "/dev/urandom"
49 #endif
50
51 /* This is ugly, but as RAND_status came in on OpenSSL version 0.9.5
52  * and the code has to support older versions too, this is seemed to
53  * be cleaner way compared to having even uglier #ifdefs all around.
54  */
55 #ifdef HAVE_RAND_STATUS
56 #define HAVE_ENTROPY()  (RAND_status() == 1)
57 #else
58 static int entropy_byte_count = 0;
59 /* OpenSSL fills the entropy pool from /dev/urandom if it exists */
60 #define HAVE_ENTROPY()  (!access(DEVRANDOM, R_OK) || entropy_byte_count >= 16)
61 #endif
62
63 /* keep a handle on accepted certificates in case we want to
64  * open up another connection to the same server in this session */
65 static STACK_OF(X509) *SslSessionCerts = NULL;
66
67 typedef struct _sslsockdata
68 {
69   SSL_CTX *ctx;
70   SSL *ssl;
71   X509 *cert;
72 }
73 sslsockdata;
74
75 /* local prototypes */
76 static int ssl_init (void);
77 static int add_entropy (const char *file);
78 static int ssl_socket_read (CONNECTION* conn, char* buf, size_t len);
79 static int ssl_socket_write (CONNECTION* conn, const char* buf, size_t len);
80 static int ssl_socket_open (CONNECTION * conn);
81 static int ssl_socket_close (CONNECTION * conn);
82 static int tls_close (CONNECTION* conn);
83 static int ssl_cache_trusted_cert (X509 *cert);
84 static int ssl_check_certificate (CONNECTION *conn, sslsockdata * data);
85 static int interactive_check_cert (X509 *cert, int idx, int len);
86 static void ssl_get_client_cert(sslsockdata *ssldata, CONNECTION *conn);
87 static int ssl_passwd_cb(char *buf, int size, int rwflag, void *userdata);
88 static int ssl_negotiate (CONNECTION *conn, sslsockdata*);
89
90 /* mutt_ssl_starttls: Negotiate TLS over an already opened connection.
91  *   TODO: Merge this code better with ssl_socket_open. */
92 int mutt_ssl_starttls (CONNECTION* conn)
93 {
94   sslsockdata* ssldata;
95   int maxbits;
96
97   if (ssl_init())
98     goto bail;
99
100   ssldata = (sslsockdata*) safe_calloc (1, sizeof (sslsockdata));
101   /* the ssl_use_xxx protocol options don't apply. We must use TLS in TLS. */
102   if (! (ssldata->ctx = SSL_CTX_new (TLSv1_client_method ())))
103   {
104     dprint (1, (debugfile, "mutt_ssl_starttls: Error allocating SSL_CTX\n"));
105     goto bail_ssldata;
106   }
107
108   ssl_get_client_cert(ssldata, conn);
109
110   if (! (ssldata->ssl = SSL_new (ssldata->ctx)))
111   {
112     dprint (1, (debugfile, "mutt_ssl_starttls: Error allocating SSL\n"));
113     goto bail_ctx;
114   }
115
116   if (SSL_set_fd (ssldata->ssl, conn->fd) != 1)
117   {
118     dprint (1, (debugfile, "mutt_ssl_starttls: Error setting fd\n"));
119     goto bail_ssl;
120   }
121
122   if (ssl_negotiate (conn, ssldata))
123     goto bail_ssl;
124
125   /* hmm. watch out if we're starting TLS over any method other than raw. */
126   conn->sockdata = ssldata;
127   conn->conn_read = ssl_socket_read;
128   conn->conn_write = ssl_socket_write;
129   conn->conn_close = tls_close;
130
131   conn->ssf = SSL_CIPHER_get_bits (SSL_get_current_cipher (ssldata->ssl),
132     &maxbits);
133
134   return 0;
135
136  bail_ssl:
137   FREE (&ssldata->ssl);
138  bail_ctx:
139   FREE (&ssldata->ctx);
140  bail_ssldata:
141   FREE (&ssldata);
142  bail:
143   return -1;
144 }
145
146 /*
147  * OpenSSL library needs to be fed with sufficient entropy. On systems
148  * with /dev/urandom, this is done transparently by the library itself,
149  * on other systems we need to fill the entropy pool ourselves.
150  *
151  * Even though only OpenSSL 0.9.5 and later will complain about the
152  * lack of entropy, we try to our best and fill the pool with older
153  * versions also. (That's the reason for the ugly #ifdefs and macros,
154  * otherwise I could have simply #ifdef'd the whole ssl_init funcion)
155  */
156 static int ssl_init (void)
157 {
158   char path[_POSIX_PATH_MAX];
159   static unsigned char init_complete = 0;
160
161   if (init_complete)
162     return 0;
163
164   if (! HAVE_ENTROPY())
165   {
166     /* load entropy from files */
167     add_entropy (SslEntropyFile);
168     add_entropy (RAND_file_name (path, sizeof (path)));
169
170     /* load entropy from egd sockets */
171 #ifdef HAVE_RAND_EGD
172     add_entropy (getenv ("EGDSOCKET"));
173     snprintf (path, sizeof(path), "%s/.entropy", NONULL(Homedir));
174     add_entropy (path);
175     add_entropy ("/tmp/entropy");
176 #endif
177
178     /* shuffle $RANDFILE (or ~/.rnd if unset) */
179     RAND_write_file (RAND_file_name (path, sizeof (path)));
180     mutt_clear_error ();
181     if (! HAVE_ENTROPY())
182     {
183       mutt_error (_("Failed to find enough entropy on your system"));
184       mutt_sleep (2);
185       return -1;
186     }
187   }
188
189   /* I don't think you can do this just before reading the error. The call
190    * itself might clobber the last SSL error. */
191   SSL_load_error_strings();
192   SSL_library_init();
193   init_complete = 1;
194   return 0;
195 }
196
197 static int add_entropy (const char *file)
198 {
199   struct stat st;
200   int n = -1;
201
202   if (!file) return 0;
203
204   if (stat (file, &st) == -1)
205     return errno == ENOENT ? 0 : -1;
206
207   mutt_message (_("Filling entropy pool: %s...\n"),
208                 file);
209
210   /* check that the file permissions are secure */
211   if (st.st_uid != getuid () ||
212       ((st.st_mode & (S_IWGRP | S_IRGRP)) != 0) ||
213       ((st.st_mode & (S_IWOTH | S_IROTH)) != 0))
214   {
215     mutt_error (_("%s has insecure permissions!"), file);
216     mutt_sleep (2);
217     return -1;
218   }
219
220 #ifdef HAVE_RAND_EGD
221   n = RAND_egd (file);
222 #endif
223   if (n <= 0)
224     n = RAND_load_file (file, -1);
225
226 #ifndef HAVE_RAND_STATUS
227   if (n > 0) entropy_byte_count += n;
228 #endif
229   return n;
230 }
231
232 static int ssl_socket_open_err (CONNECTION *conn)
233 {
234   mutt_error (_("SSL disabled due the lack of entropy"));
235   mutt_sleep (2);
236   return -1;
237 }
238
239
240 int mutt_ssl_socket_setup (CONNECTION * conn)
241 {
242   if (ssl_init() < 0)
243   {
244     conn->conn_open = ssl_socket_open_err;
245     return -1;
246   }
247
248   conn->conn_open       = ssl_socket_open;
249   conn->conn_read       = ssl_socket_read;
250   conn->conn_write      = ssl_socket_write;
251   conn->conn_close      = ssl_socket_close;
252   conn->conn_poll       = raw_socket_poll;
253
254   return 0;
255 }
256
257 static int ssl_socket_read (CONNECTION* conn, char* buf, size_t len)
258 {
259   sslsockdata *data = conn->sockdata;
260   return SSL_read (data->ssl, buf, len);
261 }
262
263 static int ssl_socket_write (CONNECTION* conn, const char* buf, size_t len)
264 {
265   sslsockdata *data = conn->sockdata;
266   return SSL_write (data->ssl, buf, len);
267 }
268
269 static int ssl_socket_open (CONNECTION * conn)
270 {
271   sslsockdata *data;
272   int maxbits;
273
274   if (raw_socket_open (conn) < 0)
275     return -1;
276
277   data = (sslsockdata *) safe_calloc (1, sizeof (sslsockdata));
278   conn->sockdata = data;
279
280   data->ctx = SSL_CTX_new (SSLv23_client_method ());
281
282   /* disable SSL protocols as needed */
283   if (!option(OPTTLSV1))
284   {
285     SSL_CTX_set_options(data->ctx, SSL_OP_NO_TLSv1);
286   }
287   if (!option(OPTSSLV2))
288   {
289     SSL_CTX_set_options(data->ctx, SSL_OP_NO_SSLv2);
290   }
291   if (!option(OPTSSLV3))
292   {
293     SSL_CTX_set_options(data->ctx, SSL_OP_NO_SSLv3);
294   }
295
296   ssl_get_client_cert(data, conn);
297
298   data->ssl = SSL_new (data->ctx);
299   SSL_set_fd (data->ssl, conn->fd);
300
301   if (ssl_negotiate(conn, data))
302   {
303     mutt_socket_close (conn);
304     return -1;
305   }
306
307   conn->ssf = SSL_CIPHER_get_bits (SSL_get_current_cipher (data->ssl),
308     &maxbits);
309
310   return 0;
311 }
312
313 /* ssl_negotiate: After SSL state has been initialised, attempt to negotiate
314  *   SSL over the wire, including certificate checks. */
315 static int ssl_negotiate (CONNECTION *conn, sslsockdata* ssldata)
316 {
317   int err;
318   const char* errmsg;
319
320 #if OPENSSL_VERSION_NUMBER >= 0x00906000L
321   /* This only exists in 0.9.6 and above. Without it we may get interrupted
322    *   reads or writes. Bummer. */
323   SSL_set_mode (ssldata->ssl, SSL_MODE_AUTO_RETRY);
324 #endif
325
326   if ((err = SSL_connect (ssldata->ssl)) != 1)
327   {
328     switch (SSL_get_error (ssldata->ssl, err))
329     {
330     case SSL_ERROR_SYSCALL:
331       errmsg = _("I/O error");
332       break;
333     case SSL_ERROR_SSL:
334       errmsg = ERR_error_string (ERR_get_error (), NULL);
335       break;
336     default:
337       errmsg = _("unknown error");
338     }
339
340     mutt_error (_("SSL failed: %s"), errmsg);
341     mutt_sleep (1);
342
343     return -1;
344   }
345
346   ssldata->cert = SSL_get_peer_certificate (ssldata->ssl);
347   if (!ssldata->cert)
348   {
349     mutt_error (_("Unable to get certificate from peer"));
350     mutt_sleep (1);
351     return -1;
352   }
353
354   if (!ssl_check_certificate (conn, ssldata))
355     return -1;
356
357   mutt_message (_("SSL connection using %s (%s)"),
358     SSL_get_cipher_version (ssldata->ssl), SSL_get_cipher_name (ssldata->ssl));
359   mutt_sleep (0);
360
361   return 0;
362 }
363
364 static int ssl_socket_close (CONNECTION * conn)
365 {
366   sslsockdata *data = conn->sockdata;
367   if (data)
368   {
369     SSL_shutdown (data->ssl);
370
371     /* hold onto this for the life of mutt, in case we want to reconnect.
372      * The purist in me wants a mutt_exit hook. */
373 #if 0
374     X509_free (data->cert);
375 #endif
376     SSL_free (data->ssl);
377     SSL_CTX_free (data->ctx);
378     FREE (&conn->sockdata);
379   }
380
381   return raw_socket_close (conn);
382 }
383
384 static int tls_close (CONNECTION* conn)
385 {
386   int rc;
387
388   rc = ssl_socket_close (conn);
389   conn->conn_read = raw_socket_read;
390   conn->conn_write = raw_socket_write;
391   conn->conn_close = raw_socket_close;
392
393   return rc;
394 }
395
396 static char *x509_get_part (char *line, const char *ndx)
397 {
398   static char ret[SHORT_STRING];
399   char *c, *c2;
400
401   strfcpy (ret, _("Unknown"), sizeof (ret));
402
403   c = strstr (line, ndx);
404   if (c)
405   {
406     c += strlen (ndx);
407     c2 = strchr (c, '/');
408     if (c2)
409       *c2 = '\0';
410     strfcpy (ret, c, sizeof (ret));
411     if (c2)
412       *c2 = '/';
413   }
414
415   return ret;
416 }
417
418 static void x509_fingerprint (char *s, int l, X509 * cert)
419 {
420   unsigned char md[EVP_MAX_MD_SIZE];
421   unsigned int n;
422   int j;
423
424   if (!X509_digest (cert, EVP_md5 (), md, &n))
425   {
426     snprintf (s, l, _("[unable to calculate]"));
427   }
428   else
429   {
430     for (j = 0; j < (int) n; j++)
431     {
432       char ch[8];
433       snprintf (ch, 8, "%02X%s", md[j], (j % 2 ? " " : ""));
434       safe_strcat (s, l, ch);
435     }
436   }
437 }
438
439 static char *asn1time_to_string (ASN1_UTCTIME *tm)
440 {
441   static char buf[64];
442   BIO *bio;
443
444   strfcpy (buf, _("[invalid date]"), sizeof (buf));
445
446   bio = BIO_new (BIO_s_mem());
447   if (bio)
448   {
449     if (ASN1_TIME_print (bio, tm))
450       (void) BIO_read (bio, buf, sizeof (buf));
451     BIO_free (bio);
452   }
453
454   return buf;
455 }
456
457 static int check_certificate_by_signer (X509 *peercert)
458 {
459   X509_STORE_CTX xsc;
460   X509_STORE *ctx;
461   int pass = 0, i;
462
463   ctx = X509_STORE_new ();
464   if (ctx == NULL) return 0;
465
466   if (option (OPTSSLSYSTEMCERTS))
467   {
468     if (X509_STORE_set_default_paths (ctx))
469       pass++;
470     else
471       dprint (2, (debugfile, "X509_STORE_set_default_paths failed\n"));
472   }
473
474   if (X509_STORE_load_locations (ctx, SslCertFile, NULL))
475     pass++;
476   else
477     dprint (2, (debugfile, "X509_STORE_load_locations_failed\n"));
478
479   for (i = 0; i < sk_X509_num (SslSessionCerts); i++)
480     pass += (X509_STORE_add_cert (ctx, sk_X509_value (SslSessionCerts, i)) != 0);
481
482   if (pass == 0)
483   {
484     /* nothing to do */
485     X509_STORE_free (ctx);
486     return 0;
487   }
488
489   X509_STORE_CTX_init (&xsc, ctx, peercert, SslSessionCerts);
490
491   pass = (X509_verify_cert (&xsc) > 0);
492 #ifdef DEBUG
493   if (! pass)
494   {
495     char buf[SHORT_STRING];
496     int err;
497
498     err = X509_STORE_CTX_get_error (&xsc);
499     snprintf (buf, sizeof (buf), "%s (%d)",
500         X509_verify_cert_error_string(err), err);
501     dprint (2, (debugfile, "X509_verify_cert: %s\n", buf));
502     dprint (2, (debugfile, " [%s]\n", peercert->name));
503   }
504 #endif
505   X509_STORE_CTX_cleanup (&xsc);
506   X509_STORE_free (ctx);
507
508   return pass;
509 }
510
511 static int compare_certificates (X509 *cert, X509 *peercert,
512   unsigned char *peermd, unsigned int peermdlen)
513 {
514   unsigned char md[EVP_MAX_MD_SIZE];
515   unsigned int mdlen;
516
517   /* Avoid CPU-intensive digest calculation if the certificates are
518     * not even remotely equal.
519     */
520   if (X509_subject_name_cmp (cert, peercert) != 0 ||
521       X509_issuer_name_cmp (cert, peercert) != 0)
522     return -1;
523
524   if (!X509_digest (cert, EVP_sha1(), md, &mdlen) || peermdlen != mdlen)
525     return -1;
526
527   if (memcmp(peermd, md, mdlen) != 0)
528     return -1;
529
530   return 0;
531 }
532
533 static int check_certificate_cache (X509 *peercert)
534 {
535   unsigned char peermd[EVP_MAX_MD_SIZE];
536   unsigned int peermdlen;
537   X509 *cert;
538   int i;
539
540   if (!X509_digest (peercert, EVP_sha1(), peermd, &peermdlen)
541       || !SslSessionCerts)
542   {
543     return 0;
544   }
545
546   for (i = sk_X509_num (SslSessionCerts); i-- > 0;)
547   {
548     cert = sk_X509_value (SslSessionCerts, i);
549     if (!compare_certificates (cert, peercert, peermd, peermdlen))
550     {
551       return 1;
552     }
553   }
554
555   return 0;
556 }
557
558 static int check_certificate_by_digest (X509 *peercert)
559 {
560   unsigned char peermd[EVP_MAX_MD_SIZE];
561   unsigned int peermdlen;
562   X509 *cert = NULL;
563   int pass = 0;
564   FILE *fp;
565
566   /* expiration check */
567   if (option (OPTSSLVERIFYDATES) != M_NO)
568   {
569     if (X509_cmp_current_time (X509_get_notBefore (peercert)) >= 0)
570     {
571       dprint (2, (debugfile, "Server certificate is not yet valid\n"));
572       mutt_error (_("Server certificate is not yet valid"));
573       mutt_sleep (2);
574       return 0;
575     }
576     if (X509_cmp_current_time (X509_get_notAfter (peercert)) <= 0)
577     {
578       dprint (2, (debugfile, "Server certificate has expired"));
579       mutt_error (_("Server certificate has expired"));
580       mutt_sleep (2);
581       return 0;
582     }
583   }
584
585   if ((fp = fopen (SslCertFile, "rt")) == NULL)
586     return 0;
587
588   if (!X509_digest (peercert, EVP_sha1(), peermd, &peermdlen))
589   {
590     safe_fclose (&fp);
591     return 0;
592   }
593
594   while ((cert = READ_X509_KEY (fp, &cert)) != NULL)
595   {
596     pass = compare_certificates (cert, peercert, peermd, peermdlen) ? 0 : 1;
597
598     if (pass)
599       break;
600   }
601   X509_free (cert);
602   safe_fclose (&fp);
603
604   return pass;
605 }
606
607 /* port to mutt from msmtp's tls.c */
608 static int hostname_match (const char *hostname, const char *certname)
609 {
610   const char *cmp1, *cmp2;
611
612   if (strncmp(certname, "*.", 2) == 0)
613   {
614     cmp1 = certname + 2;
615     cmp2 = strchr(hostname, '.');
616     if (!cmp2)
617     {
618       return 0;
619     }
620     else
621     {
622       cmp2++;
623     }
624   }
625   else
626   {
627     cmp1 = certname;
628     cmp2 = hostname;
629   }
630
631   if (*cmp1 == '\0' || *cmp2 == '\0')
632   {
633     return 0;
634   }
635
636   if (strcasecmp(cmp1, cmp2) != 0)
637   {
638     return 0;
639   }
640
641   return 1;
642 }
643
644 /* port to mutt from msmtp's tls.c */
645 static int check_host (X509 *x509cert, const char *hostname, char *err, size_t errlen)
646 {
647   int i, rc = 0;
648   /* hostname in ASCII format: */
649   char *hostname_ascii = NULL;
650   /* needed to get the common name: */
651   X509_NAME *x509_subject;
652   char *buf = NULL;
653   int bufsize;
654   /* needed to get the DNS subjectAltNames: */
655   STACK *subj_alt_names;
656   int subj_alt_names_count;
657   GENERAL_NAME *subj_alt_name;
658   /* did we find a name matching hostname? */
659   int match_found;
660
661   /* Check if 'hostname' matches the one of the subjectAltName extensions of
662    * type DNS or the Common Name (CN). */
663
664 #ifdef HAVE_LIBIDN
665   if (idna_to_ascii_lz(hostname, &hostname_ascii, 0) != IDNA_SUCCESS)
666   {
667     hostname_ascii = safe_strdup(hostname);
668   }
669 #else
670   hostname_ascii = safe_strdup(hostname);
671 #endif
672
673   /* Try the DNS subjectAltNames. */
674   match_found = 0;
675   if ((subj_alt_names = X509_get_ext_d2i(x509cert, NID_subject_alt_name,
676                                          NULL, NULL)))
677   {
678     subj_alt_names_count = sk_GENERAL_NAME_num(subj_alt_names);
679     for (i = 0; i < subj_alt_names_count; i++)
680     {
681       subj_alt_name = sk_GENERAL_NAME_value(subj_alt_names, i);
682       if (subj_alt_name->type == GEN_DNS)
683       {
684         if ((match_found = hostname_match(hostname_ascii,
685                                           (char *)(subj_alt_name->d.ia5->data))))
686         {
687           break;
688         }
689       }
690     }
691   }
692
693   if (!match_found)
694   {
695     /* Try the common name */
696     if (!(x509_subject = X509_get_subject_name(x509cert)))
697     {
698       if (err && errlen)
699         strfcpy (err, _("cannot get certificate subject"), errlen);
700       goto out;
701     }
702
703     bufsize = X509_NAME_get_text_by_NID(x509_subject, NID_commonName,
704                                         NULL, 0);
705     bufsize++;
706     buf = safe_malloc((size_t)bufsize);
707     if (X509_NAME_get_text_by_NID(x509_subject, NID_commonName,
708                                   buf, bufsize) == -1)
709     {
710       if (err && errlen)
711         strfcpy (err, _("cannot get certificate common name"), errlen);
712       goto out;
713     }
714     match_found = hostname_match(hostname_ascii, buf);
715   }
716
717   if (!match_found)
718   {
719     if (err && errlen)
720       snprintf (err, errlen, _("certificate owner does not match hostname %s"),
721                 hostname);
722     goto out;
723   }
724
725   rc = 1;
726
727 out:
728   FREE(&buf);
729   FREE(&hostname_ascii);
730
731   return rc;
732 }
733
734 static int ssl_cache_trusted_cert (X509 *c)
735 {
736   dprint (1, (debugfile, "trusted: %s\n", c->name));
737   if (!SslSessionCerts)
738     SslSessionCerts = sk_new_null();
739   return (sk_X509_push (SslSessionCerts, X509_dup(c)));
740 }
741
742 /* check whether cert is preauthorized. If host is not null, verify that
743  * it matches the certificate.
744  * Return > 0: authorized, < 0: problems, 0: unknown validity */
745 static int ssl_check_preauth (X509 *cert, const char* host)
746 {
747   char buf[SHORT_STRING];
748
749   /* check session cache first */
750   if (check_certificate_cache (cert))
751   {
752     dprint (2, (debugfile, "ssl_check_preauth: using cached certificate\n"));
753     return 1;
754   }
755
756   buf[0] = 0;
757   if (host && option (OPTSSLVERIFYHOST) != M_NO)
758   {
759     if (!check_host (cert, host, buf, sizeof (buf)))
760     {
761       mutt_error (_("Certificate host check failed: %s"), buf);
762       mutt_sleep (2);
763       return -1;
764     }
765     dprint (2, (debugfile, "ssl_check_preauth: hostname check passed\n"));
766   }
767
768   if (check_certificate_by_signer (cert))
769   {
770     dprint (2, (debugfile, "ssl_check_preauth: signer check passed\n"));
771     return 1;
772   }
773
774   /* automatic check from user's database */
775   if (SslCertFile && check_certificate_by_digest (cert))
776   {
777     dprint (2, (debugfile, "ssl_check_preauth: digest check passed\n"));
778     return 1;
779   }
780
781   return 0;
782 }
783
784 static int ssl_check_certificate (CONNECTION *conn, sslsockdata *data)
785 {
786   int i, preauthrc, chain_len;
787   STACK_OF(X509) *chain;
788   X509 *cert;
789
790   if ((preauthrc = ssl_check_preauth (data->cert, conn->account.host)) > 0)
791     return preauthrc;
792
793   chain = SSL_get_peer_cert_chain (data->ssl);
794   chain_len = sk_X509_num (chain);
795   /* negative preauthrc means the certificate won't be accepted without
796    * manual override. */
797   if (preauthrc < 0 || !chain || (chain_len <= 1))
798     return interactive_check_cert (data->cert, 0, 0);
799
800   /* check the chain from root to peer. */
801   for (i = chain_len-1; i >= 0; i--)
802   {
803     cert = sk_X509_value (chain, i);
804
805     /* if the certificate validates or is manually accepted, then add it to
806      * the trusted set and recheck the peer certificate */
807     if (ssl_check_preauth (cert, NULL)
808         || interactive_check_cert (cert, i, chain_len))
809     {
810       ssl_cache_trusted_cert (cert);
811       if (ssl_check_preauth (data->cert, conn->account.host))
812         return 1;
813     }
814   }
815
816   return 0;
817 }
818
819 static int interactive_check_cert (X509 *cert, int idx, int len)
820 {
821   char *part[] =
822     {"/CN=", "/Email=", "/O=", "/OU=", "/L=", "/ST=", "/C="};
823   char helpstr[LONG_STRING];
824   char buf[STRING];
825   char title[STRING];
826   MUTTMENU *menu = mutt_new_menu (-1);
827   int done, row, i;
828   FILE *fp;
829   char *name = NULL, *c;
830
831   dprint (2, (debugfile, "interactive_check_cert: %s\n", cert->name));
832
833   menu->max = 19;
834   menu->dialog = (char **) safe_calloc (1, menu->max * sizeof (char *));
835   for (i = 0; i < menu->max; i++)
836     menu->dialog[i] = (char *) safe_calloc (1, SHORT_STRING * sizeof (char));
837
838   row = 0;
839   strfcpy (menu->dialog[row], _("This certificate belongs to:"), SHORT_STRING);
840   row++;
841   name = X509_NAME_oneline (X509_get_subject_name (cert),
842                             buf, sizeof (buf));
843   dprint (2, (debugfile, "oneline: %s\n", name));
844
845   for (i = 0; i < 5; i++)
846   {
847     c = x509_get_part (name, part[i]);
848     snprintf (menu->dialog[row++], SHORT_STRING, "   %s", c);
849   }
850
851   row++;
852   strfcpy (menu->dialog[row], _("This certificate was issued by:"), SHORT_STRING);
853   row++;
854   name = X509_NAME_oneline (X509_get_issuer_name (cert),
855                             buf, sizeof (buf));
856   for (i = 0; i < 5; i++)
857   {
858     c = x509_get_part (name, part[i]);
859     snprintf (menu->dialog[row++], SHORT_STRING, "   %s", c);
860   }
861
862   row++;
863   snprintf (menu->dialog[row++], SHORT_STRING, _("This certificate is valid"));
864   snprintf (menu->dialog[row++], SHORT_STRING, _("   from %s"),
865       asn1time_to_string (X509_get_notBefore (cert)));
866   snprintf (menu->dialog[row++], SHORT_STRING, _("     to %s"),
867       asn1time_to_string (X509_get_notAfter (cert)));
868
869   row++;
870   buf[0] = '\0';
871   x509_fingerprint (buf, sizeof (buf), cert);
872   snprintf (menu->dialog[row++], SHORT_STRING, _("Fingerprint: %s"), buf);
873
874   snprintf (title, sizeof (title),
875             _("SSL Certificate check (certificate %d of %d in chain)"),
876             len - idx, len);
877   menu->title = title;
878   if (SslCertFile
879       && (option (OPTSSLVERIFYDATES) == M_NO
880           || (X509_cmp_current_time (X509_get_notAfter (cert)) >= 0
881               && X509_cmp_current_time (X509_get_notBefore (cert)) < 0)))
882   {
883     menu->prompt = _("(r)eject, accept (o)nce, (a)ccept always");
884     menu->keys = _("roa");
885   }
886   else
887   {
888     menu->prompt = _("(r)eject, accept (o)nce");
889     menu->keys = _("ro");
890   }
891
892   helpstr[0] = '\0';
893   mutt_make_help (buf, sizeof (buf), _("Exit  "), MENU_GENERIC, OP_EXIT);
894   safe_strcat (helpstr, sizeof (helpstr), buf);
895   mutt_make_help (buf, sizeof (buf), _("Help"), MENU_GENERIC, OP_HELP);
896   safe_strcat (helpstr, sizeof (helpstr), buf);
897   menu->help = helpstr;
898
899   done = 0;
900   set_option(OPTUNBUFFEREDINPUT);
901   while (!done)
902   {
903     switch (mutt_menuLoop (menu))
904     {
905       case -1:                  /* abort */
906       case OP_MAX + 1:          /* reject */
907       case OP_EXIT:
908         done = 1;
909         break;
910       case OP_MAX + 3:          /* accept always */
911         done = 0;
912         if ((fp = fopen (SslCertFile, "a")))
913         {
914           if (PEM_write_X509 (fp, cert))
915             done = 1;
916           safe_fclose (&fp);
917         }
918         if (!done)
919         {
920           mutt_error (_("Warning: Couldn't save certificate"));
921           mutt_sleep (2);
922         }
923         else
924         {
925           mutt_message (_("Certificate saved"));
926           mutt_sleep (0);
927         }
928         /* fall through */
929       case OP_MAX + 2:          /* accept once */
930         done = 2;
931         ssl_cache_trusted_cert (cert);
932         break;
933     }
934   }
935   unset_option(OPTUNBUFFEREDINPUT);
936   mutt_menuDestroy (&menu);
937   dprint (2, (debugfile, "ssl interactive_check_cert: done=%d\n", done));
938   return (done == 2);
939 }
940
941 static void ssl_get_client_cert(sslsockdata *ssldata, CONNECTION *conn)
942 {
943   if (SslClientCert)
944   {
945     dprint (2, (debugfile, "Using client certificate %s\n", SslClientCert));
946     SSL_CTX_set_default_passwd_cb_userdata(ssldata->ctx, &conn->account);
947     SSL_CTX_set_default_passwd_cb(ssldata->ctx, ssl_passwd_cb);
948     SSL_CTX_use_certificate_file(ssldata->ctx, SslClientCert, SSL_FILETYPE_PEM);
949     SSL_CTX_use_PrivateKey_file(ssldata->ctx, SslClientCert, SSL_FILETYPE_PEM);
950
951     /* if we are using a client cert, SASL may expect an external auth name */
952     mutt_account_getuser (&conn->account);
953   }
954 }
955
956 static int ssl_passwd_cb(char *buf, int size, int rwflag, void *userdata)
957 {
958   ACCOUNT *account = (ACCOUNT*)userdata;
959
960   if (mutt_account_getuser (account))
961     return 0;
962
963   dprint (2, (debugfile, "ssl_passwd_cb: getting password for %s@%s:%u\n",
964               account->user, account->host, account->port));
965
966   if (mutt_account_getpass (account))
967     return 0;
968
969   return snprintf(buf, size, "%s", account->pass);
970 }