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