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