315ba52b0da70070e2041b508c09638d9a19bcca
[apps/madmutt.git] / mutt_ssl.c
1 /*
2  * Copyright notice from original mutt:
3  * Copyright (C) 1999-2001 Tommi Komulainen <Tommi.Komulainen@iki.fi>
4  *
5  * This file is part of mutt-ng, see http://www.muttng.org/.
6  * It's licensed under the GNU General Public License,
7  * please see the file GPL in the top level source directory.
8  */
9
10 #if HAVE_CONFIG_H
11 # include "config.h"
12 #endif
13
14 #ifdef USE_SSL
15
16 #include <openssl/ssl.h>
17 #include <openssl/x509.h>
18 #include <openssl/err.h>
19 #include <openssl/rand.h>
20
21 #include <string.h>
22
23 #include <lib-lib/mem.h>
24 #include <lib-lib/str.h>
25 #include <lib-lib/macros.h>
26
27 #include <lib-ui/curses.h>
28 #include <lib-ui/menu.h>
29
30 #include "mutt.h"
31 #include "mutt_socket.h"
32 #include "mutt_ssl.h"
33
34 #include "lib/debug.h"
35
36 #if OPENSSL_VERSION_NUMBER >= 0x00904000L
37 #define READ_X509_KEY(fp, key)  PEM_read_X509(fp, key, NULL, NULL)
38 #else
39 #define READ_X509_KEY(fp, key)  PEM_read_X509(fp, key, NULL)
40 #endif
41
42 /* Just in case OpenSSL doesn't define DEVRANDOM */
43 #ifndef DEVRANDOM
44 #define DEVRANDOM "/dev/urandom"
45 #endif
46
47 /* This is ugly, but as RAND_status came in on OpenSSL version 0.9.5
48  * and the code has to support older versions too, this is seemed to
49  * be cleaner way compared to having even uglier #ifdefs all around.
50  */
51 #ifdef HAVE_RAND_STATUS
52 #define HAVE_ENTROPY()  (RAND_status() == 1)
53 #else
54 static int entropy_byte_count = 0;
55
56 /* OpenSSL fills the entropy pool from /dev/urandom if it exists */
57 #define HAVE_ENTROPY()  (!access(DEVRANDOM, R_OK) || entropy_byte_count >= 16)
58 #endif
59
60 typedef struct _sslsockdata {
61   SSL_CTX *ctx;
62   SSL *ssl;
63   X509 *cert;
64 } sslsockdata;
65
66 /* local prototypes */
67 static int ssl_init (void);
68 static int add_entropy (const char *file);
69 static int ssl_socket_read (CONNECTION * conn, char *buf, size_t len);
70 static int ssl_socket_write (CONNECTION * conn, const char *buf, size_t len);
71 static int ssl_socket_open (CONNECTION * conn);
72 static int ssl_socket_close (CONNECTION * conn);
73 static int tls_close (CONNECTION * conn);
74 static int ssl_check_certificate (sslsockdata * data);
75 static void ssl_get_client_cert (sslsockdata * ssldata, CONNECTION * conn);
76 static int ssl_passwd_cb (char *buf, int size, int rwflag, void *userdata);
77 static int ssl_negotiate (sslsockdata *);
78
79 /* mutt_ssl_starttls: Negotiate TLS over an already opened connection.
80  *   TODO: Merge this code better with ssl_socket_open. */
81 int mutt_ssl_starttls (CONNECTION * conn)
82 {
83   sslsockdata *ssldata;
84   int maxbits;
85
86   if (ssl_init ())
87     goto bail;
88
89   ssldata = p_new(sslsockdata, 1);
90   /* the ssl_use_xxx protocol options don't apply. We must use TLS in TLS. */
91   if (!(ssldata->ctx = SSL_CTX_new (TLSv1_client_method ()))) {
92     debug_print (1, ("Error allocating SSL_CTX\n"));
93     goto bail_ssldata;
94   }
95
96   ssl_get_client_cert (ssldata, conn);
97
98   if (!(ssldata->ssl = SSL_new (ssldata->ctx))) {
99     debug_print (1, ("Error allocating SSL\n"));
100     goto bail_ctx;
101   }
102
103   if (SSL_set_fd (ssldata->ssl, conn->fd) != 1) {
104     debug_print (1, ("Error setting fd\n"));
105     goto bail_ssl;
106   }
107
108   if (ssl_negotiate (ssldata))
109     goto bail_ssl;
110
111   /* hmm. watch out if we're starting TLS over any method other than raw. */
112   conn->sockdata = ssldata;
113   conn->conn_read = ssl_socket_read;
114   conn->conn_write = ssl_socket_write;
115   conn->conn_close = tls_close;
116
117   conn->ssf = SSL_CIPHER_get_bits (SSL_get_current_cipher (ssldata->ssl),
118                                    &maxbits);
119
120   return 0;
121
122 bail_ssl:
123   p_delete(&ssldata->ssl);
124 bail_ctx:
125   p_delete(&ssldata->ctx);
126 bail_ssldata:
127   p_delete(&ssldata);
128 bail:
129   return -1;
130 }
131
132 /* 
133  * OpenSSL library needs to be fed with sufficient entropy. On systems
134  * with /dev/urandom, this is done transparently by the library itself,
135  * on other systems we need to fill the entropy pool ourselves.
136  *
137  * Even though only OpenSSL 0.9.5 and later will complain about the
138  * lack of entropy, we try to our best and fill the pool with older
139  * versions also. (That's the reason for the ugly #ifdefs and macros,
140  * otherwise I could have simply #ifdef'd the whole ssl_init funcion)
141  */
142 static int ssl_init (void)
143 {
144   char path[_POSIX_PATH_MAX];
145   static unsigned char init_complete = 0;
146
147   if (init_complete)
148     return 0;
149
150   if (!HAVE_ENTROPY ()) {
151     /* load entropy from files */
152     add_entropy (SslEntropyFile);
153     add_entropy (RAND_file_name (path, sizeof (path)));
154
155     /* load entropy from egd sockets */
156 #ifdef HAVE_RAND_EGD
157     add_entropy (getenv ("EGDSOCKET"));
158     snprintf (path, sizeof (path), "%s/.entropy", NONULL (Homedir));
159     add_entropy (path);
160     add_entropy ("/tmp/entropy");
161 #endif
162
163     /* shuffle $RANDFILE (or ~/.rnd if unset) */
164     RAND_write_file (RAND_file_name (path, sizeof (path)));
165     mutt_clear_error ();
166     if (!HAVE_ENTROPY ()) {
167       mutt_error (_("Failed to find enough entropy on your system"));
168       mutt_sleep (2);
169       return -1;
170     }
171   }
172
173   /* I don't think you can do this just before reading the error. The call
174    * itself might clobber the last SSL error. */
175   SSL_load_error_strings ();
176   SSL_library_init ();
177   init_complete = 1;
178   return 0;
179 }
180
181 static int add_entropy (const char *file)
182 {
183   struct stat st;
184   int n = -1;
185
186   if (!file)
187     return 0;
188
189   if (stat (file, &st) == -1)
190     return errno == ENOENT ? 0 : -1;
191
192   mutt_message (_("Filling entropy pool: %s...\n"), file);
193
194   /* check that the file permissions are secure */
195   if (st.st_uid != getuid () ||
196       ((st.st_mode & (S_IWGRP | S_IRGRP)) != 0) ||
197       ((st.st_mode & (S_IWOTH | S_IROTH)) != 0)) {
198     mutt_error (_("%s has insecure permissions!"), file);
199     mutt_sleep (2);
200     return -1;
201   }
202
203 #ifdef HAVE_RAND_EGD
204   n = RAND_egd (file);
205 #endif
206   if (n <= 0)
207     n = RAND_load_file (file, -1);
208
209 #ifndef HAVE_RAND_STATUS
210   if (n > 0)
211     entropy_byte_count += n;
212 #endif
213   return n;
214 }
215
216 static int ssl_socket_open_err (CONNECTION * conn)
217 {
218   mutt_error (_("SSL disabled due the lack of entropy"));
219   mutt_sleep (2);
220   return -1;
221 }
222
223
224 int mutt_ssl_socket_setup (CONNECTION * conn)
225 {
226   if (ssl_init () < 0) {
227     conn->conn_open = ssl_socket_open_err;
228     return -1;
229   }
230
231   conn->conn_open = ssl_socket_open;
232   conn->conn_read = ssl_socket_read;
233   conn->conn_write = ssl_socket_write;
234   conn->conn_close = ssl_socket_close;
235
236   return 0;
237 }
238
239 static int ssl_socket_read (CONNECTION * conn, char *buf, size_t len)
240 {
241   sslsockdata *data = conn->sockdata;
242
243   return SSL_read (data->ssl, buf, len);
244 }
245
246 static int ssl_socket_write (CONNECTION * conn, const char *buf, size_t len)
247 {
248   sslsockdata *data = conn->sockdata;
249
250   return SSL_write (data->ssl, buf, len);
251 }
252
253 static int ssl_socket_open (CONNECTION * conn)
254 {
255   sslsockdata *data;
256   int maxbits;
257
258   if (raw_socket_open (conn) < 0)
259     return -1;
260
261   data = p_new(sslsockdata, 1);
262   conn->sockdata = data;
263
264   data->ctx = SSL_CTX_new (SSLv23_client_method ());
265
266   /* disable SSL protocols as needed */
267   if (!option (OPTTLSV1)) {
268     SSL_CTX_set_options (data->ctx, SSL_OP_NO_TLSv1);
269   }
270   if (!option (OPTSSLV2)) {
271     SSL_CTX_set_options (data->ctx, SSL_OP_NO_SSLv2);
272   }
273   if (!option (OPTSSLV3)) {
274     SSL_CTX_set_options (data->ctx, SSL_OP_NO_SSLv3);
275   }
276
277   ssl_get_client_cert (data, conn);
278
279   data->ssl = SSL_new (data->ctx);
280   SSL_set_fd (data->ssl, conn->fd);
281
282   if (ssl_negotiate (data)) {
283     mutt_socket_close (conn);
284     return -1;
285   }
286
287   conn->ssf = SSL_CIPHER_get_bits (SSL_get_current_cipher (data->ssl),
288                                    &maxbits);
289
290   return 0;
291 }
292
293 /* ssl_negotiate: After SSL state has been initialised, attempt to negotiate
294  *   SSL over the wire, including certificate checks. */
295 static int ssl_negotiate (sslsockdata * ssldata)
296 {
297   int err;
298   const char *errmsg;
299
300 #if OPENSSL_VERSION_NUMBER >= 0x00906000L
301   /* This only exists in 0.9.6 and above. Without it we may get interrupted
302    *   reads or writes. Bummer. */
303   SSL_set_mode (ssldata->ssl, SSL_MODE_AUTO_RETRY);
304 #endif
305
306   if ((err = SSL_connect (ssldata->ssl)) != 1) {
307     switch (SSL_get_error (ssldata->ssl, err)) {
308     case SSL_ERROR_SYSCALL:
309       errmsg = _("I/O error");
310       break;
311     case SSL_ERROR_SSL:
312       errmsg = ERR_error_string (ERR_get_error (), NULL);
313       break;
314     default:
315       errmsg = _("unknown error");
316     }
317
318     mutt_error (_("SSL failed: %s"), errmsg);
319     mutt_sleep (1);
320
321     return -1;
322   }
323
324   ssldata->cert = SSL_get_peer_certificate (ssldata->ssl);
325   if (!ssldata->cert) {
326     mutt_error (_("Unable to get certificate from peer"));
327     mutt_sleep (1);
328     return -1;
329   }
330
331   if (!ssl_check_certificate (ssldata))
332     return -1;
333
334   mutt_message (_("SSL connection using %s (%s)"),
335                 SSL_get_cipher_version (ssldata->ssl),
336                 SSL_get_cipher_name (ssldata->ssl));
337   mutt_sleep (0);
338
339   return 0;
340 }
341
342 static int ssl_socket_close (CONNECTION * conn)
343 {
344   sslsockdata *data = conn->sockdata;
345
346   if (data) {
347     SSL_shutdown (data->ssl);
348 #if 0
349     X509_free (data->cert);
350 #endif
351     SSL_free (data->ssl);
352     SSL_CTX_free (data->ctx);
353     p_delete(&conn->sockdata);
354   }
355
356   return raw_socket_close (conn);
357 }
358
359 static int compare_certificates (X509 *cert, X509 *peercert, 
360                                  unsigned char *peermd,
361                                  unsigned int peermdlen) {
362   unsigned char md[EVP_MAX_MD_SIZE];
363   unsigned int mdlen;
364
365   /* Avoid CPU-intensive digest calculation if the certificates are
366   * not even remotely equal.
367   */
368   if (X509_subject_name_cmp (cert, peercert) != 0 || 
369       X509_issuer_name_cmp (cert, peercert) != 0)
370     return -1;
371
372   if (!X509_digest (cert, EVP_sha1(), md, &mdlen) || peermdlen != mdlen)
373     return -1;
374
375   if (memcmp(peermd, md, mdlen) != 0)
376     return -1;
377
378   return 0;
379 }
380
381 static int check_certificate_cache (X509 *peercert) {
382   unsigned char peermd[EVP_MAX_MD_SIZE];
383   unsigned int peermdlen;
384   X509 *cert;
385   LIST *scert;
386
387   if (!X509_digest (peercert, EVP_sha1(), peermd, &peermdlen)) 
388     return 0;
389
390   for (scert = SslSessionCerts; scert; scert = scert->next) {
391     cert = *(X509**)scert->data;
392     if (!compare_certificates (cert, peercert, peermd, peermdlen)) {
393       return 1;
394     }
395   }
396  return 0;
397 }
398
399 static int tls_close (CONNECTION * conn)
400 {
401   int rc;
402
403   rc = ssl_socket_close (conn);
404   conn->conn_read = raw_socket_read;
405   conn->conn_write = raw_socket_write;
406   conn->conn_close = raw_socket_close;
407
408   return rc;
409 }
410
411 static char *x509_get_part (char *line, const char *ndx)
412 {
413   static char ret[SHORT_STRING];
414   char *c, *c2;
415
416   m_strcpy(ret, sizeof(ret), _("Unknown"));
417
418   c = strstr (line, ndx);
419   if (c) {
420     c += m_strlen(ndx);
421     c2 = strchr (c, '/');
422     if (c2)
423       *c2 = '\0';
424     m_strcpy(ret, sizeof(ret), c);
425     if (c2)
426       *c2 = '/';
427   }
428
429   return ret;
430 }
431
432 static void x509_fingerprint (char *s, int l, X509 * cert)
433 {
434   unsigned char md[EVP_MAX_MD_SIZE];
435   unsigned int n;
436   int j;
437
438   if (!X509_digest (cert, EVP_md5 (), md, &n)) {
439     m_strcpy(s, l, _("[unable to calculate]"));
440   }
441   else {
442     for (j = 0; j < (int) n; j++) {
443       char ch[8];
444
445       snprintf(ch, 8, "%02X%s", md[j], (j % 2 ? " " : ""));
446       m_strcat(s, l, ch);
447     }
448   }
449 }
450
451 static char *asn1time_to_string (ASN1_UTCTIME * tm)
452 {
453   static char buf[64];
454   BIO *bio;
455
456   m_strcpy(buf, sizeof(buf), _("[invalid date]"));
457
458   bio = BIO_new (BIO_s_mem ());
459   if (bio) {
460     if (ASN1_TIME_print (bio, tm))
461       (void) BIO_read (bio, buf, sizeof (buf));
462     BIO_free (bio);
463   }
464
465   return buf;
466 }
467
468 static int check_certificate_by_signer (X509 * peercert)
469 {
470   X509_STORE_CTX xsc;
471   X509_STORE *ctx;
472   int pass = 0;
473
474   ctx = X509_STORE_new ();
475   if (ctx == NULL)
476     return 0;
477
478   if (option (OPTSSLSYSTEMCERTS)) {
479     if (X509_STORE_set_default_paths (ctx))
480       pass++;
481     else
482       debug_print (2, ("X509_STORE_set_default_paths failed\n"));
483   }
484
485   if (X509_STORE_load_locations (ctx, SslCertFile, NULL))
486     pass++;
487   else
488     debug_print (2, ("X509_STORE_load_locations_failed\n"));
489
490   if (pass == 0) {
491     /* nothing to do */
492     X509_STORE_free (ctx);
493     return 0;
494   }
495
496   X509_STORE_CTX_init (&xsc, ctx, peercert, NULL);
497
498   pass = (X509_verify_cert (&xsc) > 0);
499 #ifdef DEBUG
500   if (!pass) {
501     char buf[SHORT_STRING];
502     int err;
503
504     err = X509_STORE_CTX_get_error (&xsc);
505     snprintf (buf, sizeof (buf), "%s (%d)",
506               X509_verify_cert_error_string (err), err);
507     debug_print (2, ("X509_verify_cert: %s\n", buf));
508   }
509 #endif
510   X509_STORE_CTX_cleanup (&xsc);
511   X509_STORE_free (ctx);
512
513   return pass;
514 }
515
516 static int check_certificate_by_digest (X509 * peercert)
517 {
518   unsigned char peermd[EVP_MAX_MD_SIZE];
519   unsigned int peermdlen;
520   X509 *cert = NULL;
521   int pass = 0;
522   FILE *fp;
523
524   /* expiration check */
525   if (X509_cmp_current_time (X509_get_notBefore (peercert)) >= 0) {
526     debug_print (2, ("Server certificate is not yet valid\n"));
527     mutt_error (_("Server certificate is not yet valid"));
528     mutt_sleep (2);
529     return 0;
530   }
531   if (X509_cmp_current_time (X509_get_notAfter (peercert)) <= 0) {
532     debug_print (2, ("Server certificate has expired\n"));
533     mutt_error (_("Server certificate has expired"));
534     mutt_sleep (2);
535     return 0;
536   }
537
538   if ((fp = fopen (SslCertFile, "rt")) == NULL)
539     return 0;
540
541   if (!X509_digest (peercert, EVP_sha1 (), peermd, &peermdlen)) {
542     fclose (fp);
543     return 0;
544   }
545
546   while ((cert = READ_X509_KEY (fp, &cert)) != NULL) {
547     pass = compare_certificates (cert, peercert, peermd, peermdlen) ? 0 : 1;
548     if (pass)
549       break;
550   }
551   X509_free (cert);
552   fclose (fp);
553
554   return pass;
555 }
556
557 static int ssl_check_certificate (sslsockdata * data)
558 {
559   char *part[] = { "/CN=", "/Email=", "/O=", "/OU=", "/L=", "/ST=", "/C=" };
560   char helpstr[SHORT_STRING];
561   char buf[SHORT_STRING];
562   MUTTMENU *menu;
563   int done, row, i;
564   FILE *fp;
565   char *name = NULL, *c;
566
567   /* check session cache first */
568   if (check_certificate_cache (data->cert)) {
569     debug_print (1, ("ssl_check_certificate: using cached certificate\n"));
570     return 1;
571   }
572
573   if (check_certificate_by_signer (data->cert)) {
574     debug_print (1, ("signer check passed\n"));
575     return 1;
576   }
577
578   /* automatic check from user's database */
579   if (SslCertFile && check_certificate_by_digest (data->cert)) {
580     debug_print (1, ("digest check passed\n"));
581     return 1;
582   }
583
584   /* interactive check from user */
585   menu = mutt_new_menu ();
586   menu->max = 19;
587   menu->dialog = p_new(char *, menu->max);
588   for (i = 0; i < menu->max; i++)
589     menu->dialog[i] = p_new(char, SHORT_STRING);
590
591   row = 0;
592   m_strcpy(menu->dialog[row], SHORT_STRING,
593            _("This certificate belongs to:"));
594   row++;
595   name = X509_NAME_oneline (X509_get_subject_name (data->cert),
596                             buf, sizeof (buf));
597   for (i = 0; i < 5; i++) {
598     c = x509_get_part (name, part[i]);
599     snprintf (menu->dialog[row++], SHORT_STRING, "   %s", c);
600   }
601
602   row++;
603   m_strcpy(menu->dialog[row], SHORT_STRING,
604            _("This certificate was issued by:"));
605   row++;
606   name = X509_NAME_oneline (X509_get_issuer_name (data->cert),
607                             buf, sizeof (buf));
608   for (i = 0; i < 5; i++) {
609     c = x509_get_part (name, part[i]);
610     snprintf (menu->dialog[row++], SHORT_STRING, "   %s", c);
611   }
612
613   row++;
614   snprintf (menu->dialog[row++], SHORT_STRING, "%s",
615             _("This certificate is valid"));
616   snprintf (menu->dialog[row++], SHORT_STRING, _("   from %s"),
617             asn1time_to_string (X509_get_notBefore (data->cert)));
618   snprintf (menu->dialog[row++], SHORT_STRING, _("     to %s"),
619             asn1time_to_string (X509_get_notAfter (data->cert)));
620
621   row++;
622   buf[0] = '\0';
623   x509_fingerprint (buf, sizeof (buf), data->cert);
624   snprintf (menu->dialog[row++], SHORT_STRING, _("Fingerprint: %s"), buf);
625
626   menu->title = _("SSL Certificate check");
627
628   if (SslCertFile && X509_cmp_current_time (X509_get_notAfter (data->cert)) >= 0
629       && X509_cmp_current_time (X509_get_notBefore (data->cert)) < 0) {
630     menu->prompt = _("(r)eject, accept (o)nce, (a)ccept always");
631     menu->keys = _("roa");
632   }
633   else {
634     menu->prompt = _("(r)eject, accept (o)nce");
635     menu->keys = _("ro");
636   }
637
638   helpstr[0] = '\0';
639   mutt_make_help (buf, sizeof (buf), _("Exit  "), MENU_GENERIC, OP_EXIT);
640   m_strcat(helpstr, sizeof(helpstr), buf);
641   mutt_make_help (buf, sizeof (buf), _("Help"), MENU_GENERIC, OP_HELP);
642   m_strcat(helpstr, sizeof(helpstr), buf);
643   menu->help = helpstr;
644
645   done = 0;
646   set_option (OPTUNBUFFEREDINPUT);
647   while (!done) {
648     switch (mutt_menuLoop (menu)) {
649     case -1:                   /* abort */
650     case OP_MAX + 1:           /* reject */
651     case OP_EXIT:
652       done = 1;
653       break;
654     case OP_MAX + 3:           /* accept always */
655       done = 0;
656       if ((fp = fopen (SslCertFile, "a"))) {
657         if (PEM_write_X509 (fp, data->cert))
658           done = 1;
659         fclose (fp);
660       }
661       if (!done) {
662         mutt_error (_("Warning: Couldn't save certificate"));
663         mutt_sleep (2);
664       }
665       else {
666         mutt_message (_("Certificate saved"));
667         mutt_sleep (0);
668       }
669       /* fall through */
670     case OP_MAX + 2:           /* accept once */
671       done = 2;
672       /* keep a handle on accepted certificates in case we want to
673        * open up another connection to the same server in this session */
674       SslSessionCerts = mutt_add_list_n (SslSessionCerts, &data->cert,
675                                          sizeof (X509 **));
676       break;
677     }
678   }
679   unset_option (OPTUNBUFFEREDINPUT);
680   mutt_menuDestroy (&menu);
681   return (done == 2);
682 }
683
684 static void ssl_get_client_cert (sslsockdata * ssldata, CONNECTION * conn)
685 {
686   if (SslClientCert) {
687     debug_print (2, ("Using client certificate %s\n", SslClientCert));
688     SSL_CTX_set_default_passwd_cb_userdata (ssldata->ctx, &conn->account);
689     SSL_CTX_set_default_passwd_cb (ssldata->ctx, ssl_passwd_cb);
690     SSL_CTX_use_certificate_file (ssldata->ctx, SslClientCert,
691                                   SSL_FILETYPE_PEM);
692     SSL_CTX_use_PrivateKey_file (ssldata->ctx, SslClientCert,
693                                  SSL_FILETYPE_PEM);
694   }
695 }
696
697 static int ssl_passwd_cb (char *buf, int size, int rwflag, void *userdata)
698 {
699   ACCOUNT *account = (ACCOUNT *) userdata;
700
701   if (mutt_account_getuser (account))
702     return 0;
703
704   debug_print (2, ("getting password for %s@%s:%u\n",
705               account->user, account->host, account->port));
706
707   if (mutt_account_getpass (account))
708     return 0;
709
710   return snprintf (buf, size, "%s", account->pass);
711 }
712
713 #endif /* USE_SSL */