]> sjero.net Git - wget/blob - src/gen_sslfunc.c
[svn] Clean up prototypes and definitions of ssl_init and ssl_connect.
[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 #include "gen_sslfunc.h"
57
58 #ifndef errno
59 extern int errno;
60 #endif
61
62 SSL_CTX *ssl_ctx;
63
64 static void
65 ssl_init_prng (void)
66 {
67   /* It is likely that older versions of OpenSSL will fail on
68      non-Linux machines because this code is unable to seed the PRNG
69      on older versions of the library.  */
70
71 #if SSLEAY_VERSION_NUMBER >= 0x00905100
72   char rand_file[256];
73   int maxrand = 500;
74
75   /* First, seed from a file specified by the user.  This will be
76      $RANDFILE, if set, or ~/.rnd.  */
77   RAND_file_name (rand_file, sizeof (rand_file));
78   if (rand_file)
79     /* Seed at most 16k (value borrowed from curl) from random file. */
80     RAND_load_file (rand_file, 16384);
81
82   if (RAND_status ())
83     return;
84
85   /* Get random data from EGD if opt.sslegdsock was set.  */
86   if (opt.sslegdsock && *opt.sslegdsock)
87     RAND_egd (opt.sslegdsock);
88
89   if (RAND_status ())
90     return;
91
92 #ifdef WINDOWS
93   /* Under Windows, we can try to seed the PRNG using screen content.
94      This may or may not work, depending on whether we'll calling Wget
95      interactively.  */
96
97   RAND_screen ();
98   if (RAND_status ())
99     return;
100 #endif
101
102   /* Still not enough randomness, most likely because neither
103      /dev/random nor EGD were available.  Resort to a simple and
104      stupid method -- seed OpenSSL's PRNG with libc PRNG.  This is
105      cryptographically weak, but people who care about strong
106      cryptography should install /dev/random (default on Linux) or
107      specify their own source of randomness anyway.  */
108
109   logprintf (LOG_VERBOSE, _("Warning: using a weak random seed.\n"));
110
111   while (RAND_status () == 0 && maxrand-- > 0)
112     {
113       unsigned char rnd = random_number (256);
114       RAND_seed (&rnd, sizeof (rnd));
115     }
116 #endif /* SSLEAY_VERSION_NUMBER >= 0x00905100 */
117 }
118
119 static int
120 verify_callback (int ok, X509_STORE_CTX *ctx)
121 {
122   char *s, buf[256];
123   s = X509_NAME_oneline (X509_get_subject_name (ctx->current_cert), buf, 256);
124   if (ok == 0) {
125     switch (ctx->error) {
126     case X509_V_ERR_CERT_NOT_YET_VALID:
127     case X509_V_ERR_CERT_HAS_EXPIRED:
128       /* This mean the CERT is not valid !!! */
129       ok = 0;
130       break;
131     case X509_V_ERR_DEPTH_ZERO_SELF_SIGNED_CERT:
132       /* Unsure if we should handle that this way */
133       ok = 1;
134       break;
135     }
136   }
137   return ok;
138 }
139
140 /* Print SSL errors. */
141
142 static void
143 ssl_print_errors (void) 
144 {
145   unsigned long curerr = 0;
146   while ((curerr = ERR_get_error ()) != 0)
147     logprintf (LOG_NOTQUIET, "OpenSSL: %s\n", ERR_error_string (curerr, NULL));
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   return select_fd (fd, timeout, wait_for);
299 }
300
301 static int
302 ssl_peek (int fd, char *buf, int bufsize, void *ctx)
303 {
304   int ret;
305   SSL *ssl = (SSL *) ctx;
306   do
307     ret = SSL_peek (ssl, buf, bufsize);
308   while (ret == -1
309          && SSL_get_error (ssl, ret) == SSL_ERROR_SYSCALL
310          && errno == EINTR);
311   return ret;
312 }
313
314 static void
315 ssl_close (int fd, void *ctx)
316 {
317   SSL *ssl = (SSL *) ctx;
318   SSL_shutdown (ssl);
319   SSL_free (ssl);
320
321 #ifdef WINDOWS
322   closesocket (fd);
323 #else
324   close (fd);
325 #endif
326
327   DEBUGP (("Closed %d/SSL 0x%0lx\n", fd, (unsigned long) ssl));
328 }
329
330 /* Sets up a SSL structure and performs the handshake on fd.  The
331    resulting SSL structure is registered with the file descriptor FD
332    using fd_register_transport.  That way subsequent calls to xread,
333    xwrite, etc., will use the appropriate SSL functions.
334
335    Returns 1 on success, 0 on failure.  */
336
337 int
338 ssl_connect (int fd) 
339 {
340   SSL *ssl;
341
342   assert (ssl_ctx != NULL);
343   ssl = SSL_new (ssl_ctx);
344   if (!ssl)
345     goto err;
346   if (!SSL_set_fd (ssl, fd))
347     goto err;
348   SSL_set_connect_state (ssl);
349   if (SSL_connect (ssl) <= 0 || ssl->state != SSL_ST_OK)
350     goto err;
351
352   /* Register FD with Wget's transport layer, i.e. arrange that
353      SSL-enabled functions are used for reading, writing, and polling.
354      That way the rest of Wget can keep using xread, xwrite, and
355      friends and not care what happens underneath.  */
356   fd_register_transport (fd, ssl_read, ssl_write, ssl_poll, ssl_peek,
357                          ssl_close, ssl);
358   DEBUGP (("Connected %d to SSL 0x%0*lx\n", fd, 2 * sizeof (void *),
359            (unsigned long) ssl));
360   return 1;
361
362  err:
363   ssl_print_errors ();
364   if (ssl)
365     SSL_free (ssl);
366   return 0;
367 }