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