]> sjero.net Git - wget/blob - src/openssl.c
[svn] Minor doc. clarification.
[wget] / src / openssl.c
1 /* SSL support via OpenSSL library.
2    Copyright (C) 2000-2005 Free Software Foundation, Inc.
3    Originally contributed by Christian Fraenkel.
4
5 This file is part of GNU Wget.
6
7 GNU Wget is free software; you can redistribute it and/or modify
8 it under the terms of the GNU General Public License as published by
9 the Free Software Foundation; either version 2 of the License, or
10 (at your option) any later version.
11
12 GNU Wget is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15 GNU General Public License for more details.
16
17 You should have received a copy of the GNU General Public License
18 along with Wget; if not, write to the Free Software
19 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
20
21 In addition, as a special exception, the Free Software Foundation
22 gives permission to link the code of its release of Wget with the
23 OpenSSL project's "OpenSSL" library (or with modified versions of it
24 that use the same license as the "OpenSSL" library), and distribute
25 the linked executables.  You must obey the GNU General Public License
26 in all respects for all of the code used other than "OpenSSL".  If you
27 modify this file, you may extend this exception to your version of the
28 file, but you are not obligated to do so.  If you do not wish to do
29 so, delete this exception statement from your version.  */
30
31 #include <config.h>
32
33 #include <assert.h>
34 #include <errno.h>
35 #ifdef HAVE_UNISTD_H
36 # include <unistd.h>
37 #endif
38 #ifdef HAVE_STRING_H
39 # include <string.h>
40 #else
41 # include <strings.h>
42 #endif
43
44 #include <openssl/ssl.h>
45 #include <openssl/x509.h>
46 #include <openssl/err.h>
47 #include <openssl/rand.h>
48
49 #include "wget.h"
50 #include "utils.h"
51 #include "connect.h"
52 #include "url.h"
53 #include "ssl.h"
54
55 #ifndef errno
56 extern int errno;
57 #endif
58
59 /* Application-wide SSL context.  This is common to all SSL
60    connections.  */
61 SSL_CTX *ssl_ctx;
62
63 /* Initialize the SSL's PRNG using various methods. */
64
65 static void
66 init_prng (void)
67 {
68   char namebuf[256];
69   const char *random_file;
70
71   if (RAND_status ())
72     /* The PRNG has been seeded; no further action is necessary. */
73     return;
74
75   /* Seed from a file specified by the user.  This will be the file
76      specified with --random-file, $RANDFILE, if set, or ~/.rnd, if it
77      exists.  */
78   if (opt.random_file)
79     random_file = opt.random_file;
80   else
81     {
82       /* Get the random file name using RAND_file_name. */
83       namebuf[0] = '\0';
84       random_file = RAND_file_name (namebuf, sizeof (namebuf));
85     }
86
87   if (random_file && *random_file)
88     /* Seed at most 16k (apparently arbitrary value borrowed from
89        curl) from random file. */
90     RAND_load_file (random_file, 16384);
91
92   if (RAND_status ())
93     return;
94
95   /* Get random data from EGD if opt.egd_file was used.  */
96   if (opt.egd_file && *opt.egd_file)
97     RAND_egd (opt.egd_file);
98
99   if (RAND_status ())
100     return;
101
102 #ifdef WINDOWS
103   /* Under Windows, we can try to seed the PRNG using screen content.
104      This may or may not work, depending on whether we'll calling Wget
105      interactively.  */
106
107   RAND_screen ();
108   if (RAND_status ())
109     return;
110 #endif
111
112 #if 0 /* don't do this by default */
113   {
114     int maxrand = 500;
115
116     /* Still not random enough, presumably because neither /dev/random
117        nor EGD were available.  Try to seed OpenSSL's PRNG with libc
118        PRNG.  This is cryptographically weak and defeats the purpose
119        of using OpenSSL, which is why it is highly discouraged.  */
120
121     logprintf (LOG_NOTQUIET, _("WARNING: using a weak random seed.\n"));
122
123     while (RAND_status () == 0 && maxrand-- > 0)
124       {
125         unsigned char rnd = random_number (256);
126         RAND_seed (&rnd, sizeof (rnd));
127       }
128   }
129 #endif
130 }
131
132 /* Print errors in the OpenSSL error stack. */
133
134 static void
135 print_errors (void) 
136 {
137   unsigned long curerr = 0;
138   while ((curerr = ERR_get_error ()) != 0)
139     logprintf (LOG_NOTQUIET, "OpenSSL: %s\n", ERR_error_string (curerr, NULL));
140 }
141
142 /* Convert keyfile type as used by options.h to a type as accepted by
143    SSL_CTX_use_certificate_file and SSL_CTX_use_PrivateKey_file.
144
145    (options.h intentionally doesn't use values from openssl/ssl.h so
146    it doesn't depend specifically on OpenSSL for SSL functionality.)  */
147
148 static int
149 key_type_to_ssl_type (enum keyfile_type type)
150 {
151   switch (type)
152     {
153     case keyfile_pem:
154       return SSL_FILETYPE_PEM;
155     case keyfile_asn1:
156       return SSL_FILETYPE_ASN1;
157     default:
158       abort ();
159     }
160 }
161
162 /* Create an SSL Context and set default paths etc.  Called the first
163    time an HTTP download is attempted.
164
165    Returns 1 on success, 0 otherwise.  */
166
167 int
168 ssl_init ()
169 {
170   SSL_METHOD *meth;
171
172   if (ssl_ctx)
173     /* The SSL has already been initialized. */
174     return 1;
175
176   /* Init the PRNG.  If that fails, bail out.  */
177   init_prng ();
178   if (RAND_status () != 1)
179     {
180       logprintf (LOG_NOTQUIET,
181                  _("Could not seed PRNG; consider using --random-file.\n"));
182       goto error;
183     }
184
185   SSL_library_init ();
186   SSL_load_error_strings ();
187   SSLeay_add_all_algorithms ();
188   SSLeay_add_ssl_algorithms ();
189
190   switch (opt.secure_protocol)
191     {
192     case secure_protocol_auto:
193       meth = SSLv23_client_method ();
194       break;
195     case secure_protocol_sslv2:
196       meth = SSLv2_client_method ();
197       break;
198     case secure_protocol_sslv3:
199       meth = SSLv3_client_method ();
200       break;
201     case secure_protocol_tlsv1:
202       meth = TLSv1_client_method ();
203       break;
204     default:
205       abort ();
206     }
207
208   ssl_ctx = SSL_CTX_new (meth);
209   if (!ssl_ctx)
210     goto error;
211
212   SSL_CTX_set_default_verify_paths (ssl_ctx);
213   SSL_CTX_load_verify_locations (ssl_ctx, opt.ca_cert, opt.ca_directory);
214
215   /* SSL_VERIFY_NONE instructs OpenSSL not to abort SSL_connect if the
216      certificate is invalid.  We verify the certificate separately in
217      ssl_check_certificate, which provides much better diagnostics
218      than examining the error stack after a failed SSL_connect.  */
219   SSL_CTX_set_verify (ssl_ctx, SSL_VERIFY_NONE, NULL);
220
221   if (opt.cert_file)
222     if (SSL_CTX_use_certificate_file (ssl_ctx, opt.cert_file,
223                                       key_type_to_ssl_type (opt.cert_type))
224         != 1)
225       goto error;
226   if (opt.private_key)
227     if (SSL_CTX_use_PrivateKey_file (ssl_ctx, opt.private_key,
228                                      key_type_to_ssl_type (opt.private_key_type))
229         != 1)
230       goto error;
231
232   /* Since fd_write unconditionally assumes partial writes (and
233      handles them correctly), allow them in OpenSSL.  */
234   SSL_CTX_set_mode (ssl_ctx, SSL_MODE_ENABLE_PARTIAL_WRITE);
235
236   return 1;
237
238  error:
239   if (ssl_ctx)
240     SSL_CTX_free (ssl_ctx);
241   print_errors ();
242   return 0;
243 }
244
245 static int
246 openssl_read (int fd, char *buf, int bufsize, void *ctx)
247 {
248   int ret;
249   SSL *ssl = (SSL *) ctx;
250   do
251     ret = SSL_read (ssl, buf, bufsize);
252   while (ret == -1
253          && SSL_get_error (ssl, ret) == SSL_ERROR_SYSCALL
254          && errno == EINTR);
255   return ret;
256 }
257
258 static int
259 openssl_write (int fd, char *buf, int bufsize, void *ctx)
260 {
261   int ret = 0;
262   SSL *ssl = (SSL *) ctx;
263   do
264     ret = SSL_write (ssl, buf, bufsize);
265   while (ret == -1
266          && SSL_get_error (ssl, ret) == SSL_ERROR_SYSCALL
267          && errno == EINTR);
268   return ret;
269 }
270
271 static int
272 openssl_poll (int fd, double timeout, int wait_for, void *ctx)
273 {
274   SSL *ssl = (SSL *) ctx;
275   if (timeout == 0)
276     return 1;
277   if (SSL_pending (ssl))
278     return 1;
279   return select_fd (fd, timeout, wait_for);
280 }
281
282 static int
283 openssl_peek (int fd, char *buf, int bufsize, void *ctx)
284 {
285   int ret;
286   SSL *ssl = (SSL *) ctx;
287   do
288     ret = SSL_peek (ssl, buf, bufsize);
289   while (ret == -1
290          && SSL_get_error (ssl, ret) == SSL_ERROR_SYSCALL
291          && errno == EINTR);
292   return ret;
293 }
294
295 static void
296 openssl_close (int fd, void *ctx)
297 {
298   SSL *ssl = (SSL *) ctx;
299   SSL_shutdown (ssl);
300   SSL_free (ssl);
301
302 #ifdef WINDOWS
303   closesocket (fd);
304 #else
305   close (fd);
306 #endif
307
308   DEBUGP (("Closed %d/SSL 0x%0lx\n", fd, (unsigned long) ssl));
309 }
310
311 /* Perform the SSL handshake on file descriptor FD, which is assumed
312    to be connected to an SSL server.  The SSL handle provided by
313    OpenSSL is registered with the file descriptor FD using
314    fd_register_transport, so that subsequent calls to fd_read,
315    fd_write, etc., will use the corresponding SSL functions.
316
317    Returns 1 on success, 0 on failure.  */
318
319 int
320 ssl_connect (int fd) 
321 {
322   SSL *ssl;
323
324   DEBUGP (("Initiating SSL handshake.\n"));
325
326   assert (ssl_ctx != NULL);
327   ssl = SSL_new (ssl_ctx);
328   if (!ssl)
329     goto error;
330   if (!SSL_set_fd (ssl, fd))
331     goto error;
332   SSL_set_connect_state (ssl);
333   if (SSL_connect (ssl) <= 0 || ssl->state != SSL_ST_OK)
334     goto error;
335
336   /* Register FD with Wget's transport layer, i.e. arrange that our
337      functions are used for reading, writing, and polling.  */
338   fd_register_transport (fd, openssl_read, openssl_write, openssl_poll,
339                          openssl_peek, openssl_close, ssl);
340   DEBUGP (("Handshake successful; connected socket %d to SSL handle 0x%0*lx\n",
341            fd, PTR_FORMAT (ssl)));
342   return 1;
343
344  error:
345   DEBUGP (("SSL handshake failed.\n"));
346   print_errors ();
347   if (ssl)
348     SSL_free (ssl);
349   return 0;
350 }
351
352 #define ASTERISK_EXCLUDES_DOT   /* mandated by rfc2818 */
353
354 /* Return 1 is STRING (case-insensitively) matches PATTERN, 0
355    otherwise.  The recognized wildcard character is "*", which matches
356    any character in STRING except ".".  Any number of the "*" wildcard
357    may be present in the pattern.
358
359    This is used to match of hosts as indicated in rfc2818: "Names may
360    contain the wildcard character * which is considered to match any
361    single domain name component or component fragment. E.g., *.a.com
362    matches foo.a.com but not bar.foo.a.com. f*.com matches foo.com but
363    not bar.com [or foo.bar.com]."
364
365    If the pattern contain no wildcards, pattern_match(a, b) is
366    equivalent to !strcasecmp(a, b).  */
367
368 static int
369 pattern_match (const char *pattern, const char *string)
370 {
371   const char *p = pattern, *n = string;
372   char c;
373   for (; (c = TOLOWER (*p++)) != '\0'; n++)
374     if (c == '*')
375       {
376         for (c = TOLOWER (*p); c == '*'; c = TOLOWER (*++p))
377           ;
378         for (; *n != '\0'; n++)
379           if (TOLOWER (*n) == c && pattern_match (p, n))
380             return 1;
381 #ifdef ASTERISK_EXCLUDES_DOT
382           else if (*n == '.')
383             return 0;
384 #endif
385         return c == '\0';
386       }
387     else
388       {
389         if (c != TOLOWER (*n))
390           return 0;
391       }
392   return *n == '\0';
393 }
394
395 /* Verify the validity of the certificate presented by the server.
396    Also check that the "common name" of the server, as presented by
397    its certificate, corresponds to HOST.  (HOST typically comes from
398    the URL and is what the user thinks he's connecting to.)
399
400    This assumes that ssl_connect has successfully finished, i.e. that
401    the SSL handshake has been performed and that FD is connected to an
402    SSL handle.
403
404    If opt.check_cert is non-zero (the default), this returns 1 if the
405    certificate is valid, 0 otherwise.  If opt.check_cert is 0, the
406    function always returns 1, but should still be called because it
407    warns the user about any problems with the certificate.  */
408
409 int
410 ssl_check_certificate (int fd, const char *host)
411 {
412   X509 *cert;
413   char common_name[256];
414   long vresult;
415   int success = 1;
416
417   /* If the user has specified --no-check-cert, we still want to warn
418      him about problems with the server's certificate.  */
419   const char *severity = opt.check_cert ? _("ERROR") : _("WARNING");
420
421   SSL *ssl = (SSL *) fd_transport_context (fd);
422   assert (ssl != NULL);
423
424   cert = SSL_get_peer_certificate (ssl);
425   if (!cert)
426     {
427       logprintf (LOG_NOTQUIET, _("%s: No certificate presented by %s.\n"),
428                  severity, escnonprint (host));
429       success = 0;
430       goto no_cert;             /* must bail out since CERT is NULL */
431     }
432
433 #ifdef ENABLE_DEBUG
434   if (opt.debug)
435     {
436       char *subject = X509_NAME_oneline (X509_get_subject_name (cert), 0, 0);
437       char *issuer = X509_NAME_oneline (X509_get_issuer_name (cert), 0, 0);
438       DEBUGP (("certificate:\n  subject: %s\n  issuer:  %s\n",
439                escnonprint (subject), escnonprint (issuer)));
440       OPENSSL_free (subject);
441       OPENSSL_free (issuer);
442     }
443 #endif
444
445   vresult = SSL_get_verify_result (ssl);
446   if (vresult != X509_V_OK)
447     {
448       /* #### We might want to print saner (and translatable) error
449          messages for several frequently encountered errors.  The
450          candidates would include
451          X509_V_ERR_UNABLE_TO_GET_ISSUER_CERT_LOCALLY,
452          X509_V_ERR_SELF_SIGNED_CERT_IN_CHAIN,
453          X509_V_ERR_DEPTH_ZERO_SELF_SIGNED_CERT,
454          X509_V_ERR_CERT_NOT_YET_VALID, X509_V_ERR_CERT_HAS_EXPIRED,
455          and possibly others.  The current approach would still be
456          used for the less frequent failure cases.  */
457       logprintf (LOG_NOTQUIET,
458                  _("%s: Certificate verification error for %s: %s\n"),
459                  severity, escnonprint (host),
460                  X509_verify_cert_error_string (vresult));
461       success = 0;
462       /* Fall through, so that the user is warned about *all* issues
463          with the cert (important with --no-check-certificate.)  */
464     }
465
466   /* Check that HOST matches the common name in the certificate.
467      #### The following remains to be done:
468
469      - It should use dNSName/ipAddress subjectAltName extensions if
470        available; according to rfc2818: "If a subjectAltName extension
471        of type dNSName is present, that MUST be used as the identity."
472
473      - When matching against common names, it should loop over all
474        common names and choose the most specific one, i.e. the last
475        one, not the first one, which the current code picks.
476
477      - Ensure that ASN1 strings from the certificate are encoded as
478        UTF-8 which can be meaningfully compared to HOST.  */
479
480   common_name[0] = '\0';
481   X509_NAME_get_text_by_NID (X509_get_subject_name (cert),
482                              NID_commonName, common_name, sizeof (common_name));
483   if (!pattern_match (common_name, host))
484     {
485       logprintf (LOG_NOTQUIET, _("\
486 %s: certificate common name `%s' doesn't match requested host name `%s'.\n"),
487                  severity, escnonprint (common_name), escnonprint (host));
488       success = 0;
489     }
490
491   if (success)
492     DEBUGP (("X509 certificate successfully verified and matches host %s\n",
493              escnonprint (host)));
494   X509_free (cert);
495
496  no_cert:
497   if (opt.check_cert && !success)
498     logprintf (LOG_NOTQUIET, _("\
499 To connect to %s insecurely, use `--no-check-certificate'.\n"),
500                escnonprint (host));
501
502   /* Allow --no-check-cert to disable certificate checking. */
503   return opt.check_cert ? success : 1;
504 }