]> sjero.net Git - wget/blob - src/openssl.c
[svn] Add --random-file option. Bail out in case of error during
[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/bio.h>
45 #include <openssl/crypto.h>
46 #include <openssl/x509.h>
47 #include <openssl/ssl.h>
48 #include <openssl/err.h>
49 #include <openssl/pem.h>
50 #include <openssl/rand.h>
51
52 #include "wget.h"
53 #include "utils.h"
54 #include "connect.h"
55 #include "url.h"
56 #include "ssl.h"
57
58 #ifndef errno
59 extern int errno;
60 #endif
61
62 /* Application-wide SSL context.  This is common to all SSL
63    connections.  */
64 SSL_CTX *ssl_ctx;
65
66 /* Initialize the SSL's PRNG using various methods. */
67
68 static void
69 init_prng (void)
70 {
71   char namebuf[256];
72   const char *random_file;
73
74   if (RAND_status ())
75     /* The PRNG has been seeded; no further action is necessary. */
76     return;
77
78   /* Seed from a file specified by the user.  This will be the file
79      specified with --random-file, $RANDFILE, if set, or ~/.rnd, if it
80      exists.  */
81   if (opt.random_file)
82     random_file = opt.random_file;
83   else
84     {
85       /* Get the random file name using RAND_file_name. */
86       namebuf[0] = '\0';
87       random_file = RAND_file_name (namebuf, sizeof (namebuf));
88     }
89
90   if (random_file && *random_file)
91     /* Seed at most 16k (apparently arbitrary value borrowed from
92        curl) from random file. */
93     RAND_load_file (random_file, 16384);
94
95   if (RAND_status ())
96     return;
97
98   /* Get random data from EGD if opt.egd_file was used.  */
99   if (opt.egd_file && *opt.egd_file)
100     RAND_egd (opt.egd_file);
101
102   if (RAND_status ())
103     return;
104
105 #ifdef WINDOWS
106   /* Under Windows, we can try to seed the PRNG using screen content.
107      This may or may not work, depending on whether we'll calling Wget
108      interactively.  */
109
110   RAND_screen ();
111   if (RAND_status ())
112     return;
113 #endif
114
115 #if 0 /* don't do this by default */
116   {
117     int maxrand = 500;
118
119     /* Still not random enough, presumably because neither /dev/random
120        nor EGD were available.  Try to seed OpenSSL's PRNG with libc
121        PRNG.  This is cryptographically weak and defeats the purpose
122        of using OpenSSL, which is why it is highly discouraged.  */
123
124     logprintf (LOG_NOTQUIET, _("WARNING: using a weak random seed.\n"));
125
126     while (RAND_status () == 0 && maxrand-- > 0)
127       {
128         unsigned char rnd = random_number (256);
129         RAND_seed (&rnd, sizeof (rnd));
130       }
131   }
132 #endif
133 }
134
135 /* #### Someone should audit and document this. */
136
137 static int
138 verify_callback (int ok, X509_STORE_CTX *ctx)
139 {
140   char buf[256];
141   /* #### Why are we not using the result of this call? */
142   X509_NAME_oneline (X509_get_subject_name (ctx->current_cert),
143                      buf, sizeof (buf));
144   if (ok == 0)
145     {
146       switch (ctx->error)
147         {
148         case X509_V_ERR_CERT_NOT_YET_VALID:
149         case X509_V_ERR_CERT_HAS_EXPIRED:
150           /* This mean the CERT is not valid !!! */
151           ok = 0;
152           break;
153         case X509_V_ERR_DEPTH_ZERO_SELF_SIGNED_CERT:
154           /* Unsure if we should handle that this way */
155           ok = 1;
156           break;
157         }
158     }
159   return ok;
160 }
161
162 /* Print errors in the OpenSSL error stack. */
163
164 static void
165 print_errors (void) 
166 {
167   unsigned long curerr = 0;
168   while ((curerr = ERR_get_error ()) != 0)
169     logprintf (LOG_NOTQUIET, "OpenSSL: %s\n", ERR_error_string (curerr, NULL));
170 }
171
172 /* Convert keyfile type as used by options.h to a type as accepted by
173    SSL_CTX_use_certificate_file and SSL_CTX_use_PrivateKey_file.
174
175    (options.h intentionally doesn't use values from openssl/ssl.h so
176    it doesn't depend specifically on OpenSSL for SSL functionality.)  */
177
178 static int
179 key_type_to_ssl_type (enum keyfile_type type)
180 {
181   switch (type)
182     {
183     case keyfile_pem:
184       return SSL_FILETYPE_PEM;
185     case keyfile_asn1:
186       return SSL_FILETYPE_ASN1;
187     default:
188       abort ();
189     }
190 }
191
192 /* Create an SSL Context and set default paths etc.  Called the first
193    time an HTTP download is attempted.
194
195    Returns 0 on success, non-zero otherwise.  */
196
197 int
198 ssl_init ()
199 {
200   SSL_METHOD *meth;
201
202   if (ssl_ctx)
203     /* The SSL has already been initialized. */
204     return 1;
205
206   /* Init the PRNG.  If that fails, bail out.  */
207   init_prng ();
208   if (RAND_status () != 1)
209     {
210       logprintf (LOG_NOTQUIET,
211                  _("Could not seed PRNG; consider using --random-file.\n"));
212       goto error;
213     }
214
215   SSL_library_init ();
216   SSL_load_error_strings ();
217   SSLeay_add_all_algorithms ();
218   SSLeay_add_ssl_algorithms ();
219
220   switch (opt.secure_protocol)
221     {
222     case secure_protocol_auto:
223       meth = SSLv23_client_method ();
224       break;
225     case secure_protocol_sslv2:
226       meth = SSLv2_client_method ();
227       break;
228     case secure_protocol_sslv3:
229       meth = SSLv3_client_method ();
230       break;
231     case secure_protocol_tlsv1:
232       meth = TLSv1_client_method ();
233       break;
234     default:
235       abort ();
236     }
237
238   ssl_ctx = SSL_CTX_new (meth);
239   if (!ssl_ctx)
240     goto error;
241
242   SSL_CTX_set_default_verify_paths (ssl_ctx);
243   SSL_CTX_load_verify_locations (ssl_ctx, opt.ca_cert, opt.ca_directory);
244   SSL_CTX_set_verify (ssl_ctx,
245                       opt.check_cert ? SSL_VERIFY_PEER : SSL_VERIFY_NONE,
246                       verify_callback);
247
248   if (opt.cert_file)
249     if (SSL_CTX_use_certificate_file (ssl_ctx, opt.cert_file,
250                                       key_type_to_ssl_type (opt.cert_type))
251         != 1)
252       goto error;
253   if (opt.private_key)
254     if (SSL_CTX_use_PrivateKey_file (ssl_ctx, opt.private_key,
255                                      key_type_to_ssl_type (opt.private_key_type))
256         != 1)
257       goto error;
258
259   return 1;
260
261  error:
262   if (ssl_ctx)
263     SSL_CTX_free (ssl_ctx);
264   print_errors ();
265   return 0;
266 }
267
268 static int
269 openssl_read (int fd, char *buf, int bufsize, void *ctx)
270 {
271   int ret;
272   SSL *ssl = (SSL *) ctx;
273   do
274     ret = SSL_read (ssl, buf, bufsize);
275   while (ret == -1
276          && SSL_get_error (ssl, ret) == SSL_ERROR_SYSCALL
277          && errno == EINTR);
278   return ret;
279 }
280
281 static int
282 openssl_write (int fd, char *buf, int bufsize, void *ctx)
283 {
284   int ret = 0;
285   SSL *ssl = (SSL *) ctx;
286   do
287     ret = SSL_write (ssl, buf, bufsize);
288   while (ret == -1
289          && SSL_get_error (ssl, ret) == SSL_ERROR_SYSCALL
290          && errno == EINTR);
291   return ret;
292 }
293
294 static int
295 openssl_poll (int fd, double timeout, int wait_for, void *ctx)
296 {
297   SSL *ssl = (SSL *) ctx;
298   if (timeout == 0)
299     return 1;
300   if (SSL_pending (ssl))
301     return 1;
302   return select_fd (fd, timeout, wait_for);
303 }
304
305 static int
306 openssl_peek (int fd, char *buf, int bufsize, void *ctx)
307 {
308   int ret;
309   SSL *ssl = (SSL *) ctx;
310   do
311     ret = SSL_peek (ssl, buf, bufsize);
312   while (ret == -1
313          && SSL_get_error (ssl, ret) == SSL_ERROR_SYSCALL
314          && errno == EINTR);
315   return ret;
316 }
317
318 static void
319 openssl_close (int fd, void *ctx)
320 {
321   SSL *ssl = (SSL *) ctx;
322   SSL_shutdown (ssl);
323   SSL_free (ssl);
324
325 #ifdef WINDOWS
326   closesocket (fd);
327 #else
328   close (fd);
329 #endif
330
331   DEBUGP (("Closed %d/SSL 0x%0lx\n", fd, (unsigned long) ssl));
332 }
333
334 /* Sets up a SSL structure and performs the handshake on fd.  The
335    resulting SSL structure is registered with the file descriptor FD
336    using fd_register_transport.  That way subsequent calls to xread,
337    xwrite, etc., will use the appropriate SSL functions.
338
339    Returns 1 on success, 0 on failure.  */
340
341 int
342 ssl_connect (int fd) 
343 {
344   SSL *ssl;
345
346   assert (ssl_ctx != NULL);
347   ssl = SSL_new (ssl_ctx);
348   if (!ssl)
349     goto err;
350   if (!SSL_set_fd (ssl, fd))
351     goto err;
352   SSL_set_connect_state (ssl);
353   if (SSL_connect (ssl) <= 0 || ssl->state != SSL_ST_OK)
354     goto err;
355
356   /* Register FD with Wget's transport layer, i.e. arrange that
357      SSL-enabled functions are used for reading, writing, and polling.
358      That way the rest of Wget can keep using fd_read, fd_write, and
359      friends and not care what happens underneath.  */
360   fd_register_transport (fd, openssl_read, openssl_write, openssl_poll,
361                          openssl_peek, openssl_close, ssl);
362   DEBUGP (("Connected %d to SSL 0x%0*lx\n", fd, 2 * sizeof (void *),
363            (unsigned long) ssl));
364   return 1;
365
366  err:
367   print_errors ();
368   if (ssl)
369     SSL_free (ssl);
370   return 0;
371 }