]> sjero.net Git - wget/blob - src/gen_sslfunc.c
[svn] Remove the "rbuf" buffering layer. Provide peeking primitives instead.
[wget] / src / gen_sslfunc.c
1 /* SSL support.
2    Copyright (C) 2000 Free Software Foundation, Inc.
3    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
57 #ifndef errno
58 extern int errno;
59 #endif
60
61 SSL_CTX *ssl_ctx;
62
63 static void
64 ssl_init_prng (void)
65 {
66   /* It is likely that older versions of OpenSSL will fail on
67      non-Linux machines because this code is unable to seed the PRNG
68      on older versions of the library.  */
69
70 #if SSLEAY_VERSION_NUMBER >= 0x00905100
71   char rand_file[256];
72   int maxrand = 500;
73
74   /* First, seed from a file specified by the user.  This will be
75      $RANDFILE, if set, or ~/.rnd.  */
76   RAND_file_name (rand_file, sizeof (rand_file));
77   if (rand_file)
78     /* Seed at most 16k (value borrowed from curl) from random file. */
79     RAND_load_file (rand_file, 16384);
80
81   if (RAND_status ())
82     return;
83
84   /* Get random data from EGD if opt.sslegdsock was set.  */
85   if (opt.sslegdsock && *opt.sslegdsock)
86     RAND_egd (opt.sslegdsock);
87
88   if (RAND_status ())
89     return;
90
91 #ifdef WINDOWS
92   /* Under Windows, we can try to seed the PRNG using screen content.
93      This may or may not work, depending on whether we'll calling Wget
94      interactively.  */
95
96   RAND_screen ();
97   if (RAND_status ())
98     return;
99 #endif
100
101   /* Still not enough randomness, most likely because neither
102      /dev/random nor EGD were available.  Resort to a simple and
103      stupid method -- seed OpenSSL's PRNG with libc PRNG.  This is
104      cryptographically weak, but people who care about strong
105      cryptography should install /dev/random (default on Linux) or
106      specify their own source of randomness anyway.  */
107
108   logprintf (LOG_VERBOSE, _("Warning: using a weak random seed.\n"));
109
110   while (RAND_status () == 0 && maxrand-- > 0)
111     {
112       unsigned char rnd = random_number (256);
113       RAND_seed (&rnd, sizeof (rnd));
114     }
115 #endif /* SSLEAY_VERSION_NUMBER >= 0x00905100 */
116 }
117
118 static int
119 verify_callback (int ok, X509_STORE_CTX *ctx)
120 {
121   char *s, buf[256];
122   s = X509_NAME_oneline (X509_get_subject_name (ctx->current_cert), buf, 256);
123   if (ok == 0) {
124     switch (ctx->error) {
125     case X509_V_ERR_CERT_NOT_YET_VALID:
126     case X509_V_ERR_CERT_HAS_EXPIRED:
127       /* This mean the CERT is not valid !!! */
128       ok = 0;
129       break;
130     case X509_V_ERR_DEPTH_ZERO_SELF_SIGNED_CERT:
131       /* Unsure if we should handle that this way */
132       ok = 1;
133       break;
134     }
135   }
136   return ok;
137 }
138
139 /* Print SSL errors. */
140
141 void
142 ssl_print_errors (void) 
143 {
144   unsigned long curerr = 0;
145   char errbuff[1024];
146   xzero (errbuff);
147   while ((curerr = ERR_get_error ()) != 0)
148     logprintf (LOG_NOTQUIET, "OpenSSL: %s\n",
149                ERR_error_string (curerr, errbuff));
150 }
151
152 /* Creates a SSL Context and sets some defaults for it */
153 uerr_t
154 ssl_init ()
155 {
156   SSL_METHOD *meth = NULL;
157   int verify;
158   int can_validate;
159
160   if (ssl_ctx)
161     return 0;
162
163   /* Init the PRNG.  If that fails, bail out.  */
164   ssl_init_prng ();
165   if (RAND_status () == 0)
166     {
167       logprintf (LOG_NOTQUIET,
168                  _("Could not seed OpenSSL PRNG; disabling SSL.\n"));
169       scheme_disable (SCHEME_HTTPS);
170       return SSLERRCTXCREATE;
171     }
172
173   SSL_library_init ();
174   SSL_load_error_strings ();
175   SSLeay_add_all_algorithms ();
176   SSLeay_add_ssl_algorithms ();
177   switch (opt.sslprotocol)
178     {
179       default:
180         meth = SSLv23_client_method ();
181         break;
182       case 1 :
183         meth = SSLv2_client_method ();
184         break;
185       case 2 :
186         meth = SSLv3_client_method ();
187         break;
188       case 3 :
189         meth = TLSv1_client_method ();
190         break;
191     }
192   if (meth == NULL)
193     {
194       ssl_print_errors ();
195       return SSLERRCTXCREATE;
196     }
197
198   ssl_ctx = SSL_CTX_new (meth);
199   if (meth == NULL)
200     {
201       ssl_print_errors ();
202       return SSLERRCTXCREATE;
203     }
204   /* Can we validate the server Cert ? */
205   if (opt.sslcadir != NULL || opt.sslcafile != NULL)
206     {
207       SSL_CTX_load_verify_locations (ssl_ctx, opt.sslcafile, opt.sslcadir);
208       can_validate = 1;
209     }
210   else
211     {
212       can_validate = 0;
213     }
214
215   if (!opt.sslcheckcert)
216     {
217       /* check cert but ignore error, do not break handshake on error */
218       verify = SSL_VERIFY_NONE;
219     }
220   else
221     {
222       if (!can_validate)
223         {
224           logprintf (LOG_NOTQUIET, "Warrining validation of Server Cert not possible!\n");
225           verify = SSL_VERIFY_NONE;
226         }
227      else
228         {
229           /* break handshake if server cert is not valid but allow NO-Cert mode */
230           verify = SSL_VERIFY_PEER;
231         }
232     }
233
234   SSL_CTX_set_verify (ssl_ctx, verify, verify_callback);
235
236   if (opt.sslcertfile != NULL || opt.sslcertkey != NULL)
237     {
238       int ssl_cert_type;
239       if (!opt.sslcerttype)
240         ssl_cert_type = SSL_FILETYPE_PEM;
241       else
242         ssl_cert_type = SSL_FILETYPE_ASN1;
243
244       if (opt.sslcertkey == NULL) 
245         opt.sslcertkey = opt.sslcertfile;
246       if (opt.sslcertfile == NULL)
247         opt.sslcertfile = opt.sslcertkey; 
248
249       if (SSL_CTX_use_certificate_file (ssl_ctx, opt.sslcertfile,
250                                         ssl_cert_type) <= 0)
251         {
252           ssl_print_errors ();
253           return SSLERRCERTFILE;
254         }
255       if (SSL_CTX_use_PrivateKey_file  (ssl_ctx, opt.sslcertkey,
256                                         ssl_cert_type) <= 0)
257         {
258           ssl_print_errors ();
259           return SSLERRCERTKEY;
260         }
261     }
262
263   return 0; /* Succeded */
264 }
265
266 static int
267 ssl_read (int fd, char *buf, int bufsize, void *ctx)
268 {
269   int ret;
270   SSL *ssl = (SSL *) ctx;
271   do
272     ret = SSL_read (ssl, buf, bufsize);
273   while (ret == -1
274          && SSL_get_error (ssl, ret) == SSL_ERROR_SYSCALL
275          && errno == EINTR);
276   return ret;
277 }
278
279 static int
280 ssl_write (int fd, char *buf, int bufsize, void *ctx)
281 {
282   int ret = 0;
283   SSL *ssl = (SSL *) ctx;
284   do
285     ret = SSL_write (ssl, buf, bufsize);
286   while (ret == -1
287          && SSL_get_error (ssl, ret) == SSL_ERROR_SYSCALL
288          && errno == EINTR);
289   return ret;
290 }
291
292 static int
293 ssl_poll (int fd, double timeout, int wait_for, void *ctx)
294 {
295   SSL *ssl = (SSL *) ctx;
296   if (timeout == 0)
297     return 1;
298   if (SSL_pending (ssl))
299     return 1;
300   return select_fd (fd, timeout, wait_for);
301 }
302
303 static int
304 ssl_peek (int fd, char *buf, int bufsize, void *ctx)
305 {
306   int ret;
307   SSL *ssl = (SSL *) ctx;
308   do
309     ret = SSL_peek (ssl, buf, bufsize);
310   while (ret == -1
311          && SSL_get_error (ssl, ret) == SSL_ERROR_SYSCALL
312          && errno == EINTR);
313   return ret;
314 }
315
316 static void
317 ssl_close (int fd, void *ctx)
318 {
319   SSL *ssl = (SSL *) ctx;
320   SSL_shutdown (ssl);
321   SSL_free (ssl);
322
323 #ifdef WINDOWS
324   closesocket (fd);
325 #else
326   close (fd);
327 #endif
328
329   DEBUGP (("Closed %d/SSL 0x%0lx\n", fd, (unsigned long) ssl));
330 }
331
332 /* Sets up a SSL structure and performs the handshake on fd. */
333
334 SSL *
335 ssl_connect (int fd) 
336 {
337   SSL *ssl;
338
339   assert (ssl_ctx != NULL);
340   ssl = SSL_new (ssl_ctx);
341   if (!ssl)
342     goto err;
343   if (!SSL_set_fd (ssl, fd))
344     goto err;
345   SSL_set_connect_state (ssl);
346   if (SSL_connect (ssl) <= 0 || ssl->state != SSL_ST_OK)
347     goto err;
348
349   /* Register FD with Wget's transport layer, i.e. arrange that
350      SSL-enabled functions are used for reading, writing, and polling.
351      That way the rest of Wget can keep using xread, xwrite, and
352      friends and not care what happens underneath.  */
353   fd_register_transport (fd, ssl_read, ssl_write, ssl_poll, ssl_peek,
354                          ssl_close, ssl);
355   DEBUGP (("Connected %d to SSL 0x%0lx\n", fd, (unsigned long) ssl));
356   return ssl;
357
358  err:
359   ssl_print_errors ();
360   if (ssl)
361     SSL_free (ssl);
362   return NULL;
363 }