]> sjero.net Git - wget/blob - src/gen_sslfunc.c
[svn] Applied Dennis Smit's --preserve-permissions patch.
[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, presumably because neither random
102      file nor EGD have been available.  Use the stupidest possible
103      method -- seed OpenSSL's PRNG with the system's PRNG.  This is
104      insecure in the cryptographic sense, but people who care about
105      security will use /dev/random or their own source of randomness
106      anyway.  */
107
108   while (RAND_status () == 0 && maxrand-- > 0)
109     {
110       unsigned char rnd = random_number (256);
111       RAND_seed (&rnd, sizeof (rnd));
112     }
113 #endif /* SSLEAY_VERSION_NUMBER >= 0x00905100 */
114 }
115
116 static int
117 verify_callback (int ok, X509_STORE_CTX *ctx)
118 {
119   char *s, buf[256];
120   s = X509_NAME_oneline (X509_get_subject_name (ctx->current_cert), buf, 256);
121   if (ok == 0) {
122     switch (ctx->error) {
123     case X509_V_ERR_CERT_NOT_YET_VALID:
124     case X509_V_ERR_CERT_HAS_EXPIRED:
125       /* This mean the CERT is not valid !!! */
126       ok = 0;
127       break;
128     case X509_V_ERR_DEPTH_ZERO_SELF_SIGNED_CERT:
129       /* Unsure if we should handle that this way */
130       ok = 1;
131       break;
132     }
133   }
134   return ok;
135 }
136
137 /* Print SSL errors. */
138
139 void
140 ssl_print_errors (void) 
141 {
142   unsigned long curerr = 0;
143   char errbuff[1024];
144   xzero (errbuff);
145   while ((curerr = ERR_get_error ()) != 0)
146     logprintf (LOG_NOTQUIET, "OpenSSL: %s\n",
147                ERR_error_string (curerr, errbuff));
148 }
149
150 /* Creates a SSL Context and sets some defaults for it */
151 uerr_t
152 ssl_init ()
153 {
154   SSL_METHOD *meth = NULL;
155   int verify;
156   int can_validate;
157
158   if (ssl_ctx)
159     return 0;
160
161   /* Init the PRNG.  If that fails, bail out.  */
162   ssl_init_prng ();
163   if (RAND_status () == 0)
164     {
165       logprintf (LOG_NOTQUIET,
166                  _("Could not seed OpenSSL PRNG; disabling SSL.\n"));
167       scheme_disable (SCHEME_HTTPS);
168       return SSLERRCTXCREATE;
169     }
170
171   SSL_library_init ();
172   SSL_load_error_strings ();
173   SSLeay_add_all_algorithms ();
174   SSLeay_add_ssl_algorithms ();
175   switch (opt.sslprotocol)
176     {
177       default:
178         meth = SSLv23_client_method ();
179         break;
180       case 1 :
181         meth = SSLv2_client_method ();
182         break;
183       case 2 :
184         meth = SSLv3_client_method ();
185         break;
186       case 3 :
187         meth = TLSv1_client_method ();
188         break;
189     }
190   if (meth == NULL)
191     {
192       ssl_print_errors ();
193       return SSLERRCTXCREATE;
194     }
195
196   ssl_ctx = SSL_CTX_new (meth);
197   if (meth == NULL)
198     {
199       ssl_print_errors ();
200       return SSLERRCTXCREATE;
201     }
202   /* Can we validate the server Cert ? */
203   if (opt.sslcadir != NULL || opt.sslcafile != NULL)
204     {
205       SSL_CTX_load_verify_locations (ssl_ctx, opt.sslcafile, opt.sslcadir);
206       can_validate = 1;
207     }
208   else
209     {
210       can_validate = 0;
211     }
212
213   if (!opt.sslcheckcert)
214     {
215       /* check cert but ignore error, do not break handshake on error */
216       verify = SSL_VERIFY_NONE;
217     }
218   else
219     {
220       if (!can_validate)
221         {
222           logprintf (LOG_NOTQUIET, "Warrining validation of Server Cert not possible!\n");
223           verify = SSL_VERIFY_NONE;
224         }
225      else
226         {
227           /* break handshake if server cert is not valid but allow NO-Cert mode */
228           verify = SSL_VERIFY_PEER;
229         }
230     }
231
232   SSL_CTX_set_verify (ssl_ctx, verify, verify_callback);
233
234   if (opt.sslcertfile != NULL || opt.sslcertkey != NULL)
235     {
236       int ssl_cert_type;
237       if (!opt.sslcerttype)
238         ssl_cert_type = SSL_FILETYPE_PEM;
239       else
240         ssl_cert_type = SSL_FILETYPE_ASN1;
241
242       if (opt.sslcertkey == NULL) 
243         opt.sslcertkey = opt.sslcertfile;
244       if (opt.sslcertfile == NULL)
245         opt.sslcertfile = opt.sslcertkey; 
246
247       if (SSL_CTX_use_certificate_file (ssl_ctx, opt.sslcertfile,
248                                         ssl_cert_type) <= 0)
249         {
250           ssl_print_errors ();
251           return SSLERRCERTFILE;
252         }
253       if (SSL_CTX_use_PrivateKey_file  (ssl_ctx, opt.sslcertkey,
254                                         ssl_cert_type) <= 0)
255         {
256           ssl_print_errors ();
257           return SSLERRCERTKEY;
258         }
259     }
260
261   return 0; /* Succeded */
262 }
263
264 static int
265 ssl_read (int fd, char *buf, int bufsize, void *ctx)
266 {
267   int ret;
268   SSL *ssl = (SSL *) ctx;
269   do
270     ret = SSL_read (ssl, buf, bufsize);
271   while (ret == -1
272          && SSL_get_error (ssl, ret) == SSL_ERROR_SYSCALL
273          && errno == EINTR);
274   return ret;
275 }
276
277 static int
278 ssl_write (int fd, char *buf, int bufsize, void *ctx)
279 {
280   int ret = 0;
281   SSL *ssl = (SSL *) ctx;
282   do
283     ret = SSL_write (ssl, buf, bufsize);
284   while (ret == -1
285          && SSL_get_error (ssl, ret) == SSL_ERROR_SYSCALL
286          && errno == EINTR);
287   return ret;
288 }
289
290 static int
291 ssl_poll (int fd, double timeout, int wait_for, void *ctx)
292 {
293   SSL *ssl = (SSL *) ctx;
294   if (timeout == 0)
295     return 1;
296   if (SSL_pending (ssl))
297     return 1;
298 #ifdef HAVE_SELECT
299   return select_fd (fd, timeout, wait_for);
300 #else
301   return 1;
302 #endif
303 }
304
305 static void
306 ssl_close (int fd, void *ctx)
307 {
308   SSL *ssl = (SSL *) ctx;
309   SSL_shutdown (ssl);
310   SSL_free (ssl);
311
312 #ifdef WINDOWS
313   closesocket (fd);
314 #else
315   close (fd);
316 #endif
317
318   DEBUGP (("Closed %d/SSL 0x%0lx\n", fd, (unsigned long) ssl));
319 }
320
321 /* Sets up a SSL structure and performs the handshake on fd. */
322
323 SSL *
324 ssl_connect (int fd) 
325 {
326   SSL *ssl;
327
328   assert (ssl_ctx != NULL);
329   ssl = SSL_new (ssl_ctx);
330   if (!ssl)
331     goto err;
332   if (!SSL_set_fd (ssl, fd))
333     goto err;
334   SSL_set_connect_state (ssl);
335   if (SSL_connect (ssl) <= 0 || ssl->state != SSL_ST_OK)
336     goto err;
337
338   /* Register the FD to use our functions for read, write, etc.  That
339      way the rest of Wget can keep using xread, xwrite, and
340      friends.  */
341   register_extended (fd, ssl_read, ssl_write, ssl_poll, ssl_close, ssl);
342   DEBUGP (("Connected %d to SSL 0x%0lx\n", fd, (unsigned long) ssl));
343   return ssl;
344
345  err:
346   ssl_print_errors ();
347   if (ssl)
348     SSL_free (ssl);
349   return NULL;
350 }