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