]> sjero.net Git - wget/blob - src/gen_sslfunc.c
[svn] Commit IPv6 support by Thomas Lussnig.
[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 #include <config.h>
22
23 #ifdef HAVE_SSL
24
25 #include <assert.h>
26 #include <errno.h>
27 #ifdef HAVE_UNISTD_H
28 # include <unistd.h>
29 #endif
30 #ifdef HAVE_STRING_H
31 # include <string.h>
32 #else
33 # include <strings.h>
34 #endif
35
36 #include <openssl/bio.h>
37 #include <openssl/crypto.h>
38 #include <openssl/x509.h>
39 #include <openssl/ssl.h>
40 #include <openssl/err.h>
41 #include <openssl/pem.h>
42 #include <openssl/rand.h>
43
44 #include "wget.h"
45 #include "utils.h"
46 #include "connect.h"
47 #include "url.h"
48
49 #ifndef errno
50 extern int errno;
51 #endif
52
53 static int verify_callback PARAMS ((int, X509_STORE_CTX *));
54
55 void
56 ssl_init_prng (void)
57 {
58   /* It is likely that older versions of OpenSSL will fail on
59      non-Linux machines because this code is unable to seed the PRNG
60      on older versions of the library.  */
61
62 #if SSLEAY_VERSION_NUMBER >= 0x00905100
63   char rand_file[256];
64   int maxrand = 500;
65
66   /* First, seed from a file specified by the user.  This will be
67      $RANDFILE, if set, or ~/.rnd.  */
68   RAND_file_name (rand_file, sizeof (rand_file));
69   if (rand_file)
70     /* Seed at most 16k (value borrowed from curl) from random file. */
71     RAND_load_file (rand_file, 16384);
72
73   if (RAND_status ())
74     return;
75
76   /* Get random data from EGD if opt.sslegdsock was set.  */
77   if (opt.sslegdsock && *opt.sslegdsock)
78     RAND_egd (opt.sslegdsock);
79
80   if (RAND_status ())
81     return;
82
83 #ifdef WINDOWS
84   /* Under Windows, we can try to seed the PRNG using screen content.
85      This may or may not work, depending on whether we'll calling Wget
86      interactively.  */
87
88   RAND_screen ();
89   if (RAND_status ())
90     return;
91 #endif
92
93   /* Still not enough randomness, presumably because neither random
94      file nor EGD have been available.  Use the stupidest possible
95      method -- seed OpenSSL's PRNG with the system's PRNG.  This is
96      insecure in the cryptographic sense, but people who care about
97      security will use /dev/random or their own source of randomness
98      anyway.  */
99
100   while (RAND_status () == 0 && maxrand-- > 0)
101     {
102       unsigned char rnd = random_number (256);
103       RAND_seed (&rnd, sizeof (rnd));
104     }
105
106   if (RAND_status () == 0)
107     {
108       logprintf (LOG_NOTQUIET,
109                  _("Could not seed OpenSSL PRNG; disabling SSL.\n"));
110       scheme_disable (SCHEME_HTTPS);
111     }
112 #endif /* SSLEAY_VERSION_NUMBER >= 0x00905100 */
113 }
114
115 /* Creates a SSL Context and sets some defaults for it */
116 uerr_t
117 init_ssl (SSL_CTX **ctx)
118 {
119   SSL_METHOD *meth = NULL;
120   int verify = SSL_VERIFY_NONE;
121   SSL_library_init ();
122   SSL_load_error_strings ();
123   SSLeay_add_all_algorithms ();
124   SSLeay_add_ssl_algorithms ();
125   meth = SSLv23_client_method ();
126   *ctx = SSL_CTX_new (meth);
127   SSL_CTX_set_verify (*ctx, verify, verify_callback);
128   if (*ctx == NULL) 
129     return SSLERRCTXCREATE;
130   if (opt.sslcertfile)
131     {
132       if (SSL_CTX_use_certificate_file (*ctx, opt.sslcertfile,
133                                         SSL_FILETYPE_PEM) <= 0)
134         return SSLERRCERTFILE;
135       if (opt.sslcertkey == NULL) 
136         opt.sslcertkey=opt.sslcertfile;
137       if (SSL_CTX_use_PrivateKey_file (*ctx, opt.sslcertkey,
138                                        SSL_FILETYPE_PEM) <= 0)
139         return SSLERRCERTKEY;
140   }
141   return 0; /* Succeded */
142 }
143
144 /* Sets up a SSL structure and performs the handshake on fd 
145    Returns 0 if everything went right
146    Returns 1 if something went wrong ----- TODO: More exit codes
147 */
148 int
149 connect_ssl (SSL **con, SSL_CTX *ctx, int fd) 
150 {
151   *con = (SSL *)SSL_new (ctx);
152   SSL_set_fd (*con, fd);
153   SSL_set_connect_state (*con); 
154   SSL_connect (*con);  
155   if ((*con)->state != SSL_ST_OK)
156     return 1;
157   /*while((SSLerror=ERR_get_error())!=0)
158     printf("%s\n", ERR_error_string(SSLerror,NULL));*/
159
160   return 0;
161 }
162
163 void
164 shutdown_ssl (SSL* con)
165 {
166   SSL_shutdown (con);
167   if (con != NULL)
168     SSL_free (con);
169 }
170
171 void
172 free_ssl_ctx (SSL_CTX * ctx)
173 {
174   SSL_CTX_free (ctx);
175 }
176
177 int
178 verify_callback (int ok, X509_STORE_CTX *ctx)
179 {
180   char *s, buf[256];
181   s = X509_NAME_oneline (X509_get_subject_name (ctx->current_cert), buf, 256);
182   if (ok == 0) {
183     switch (ctx->error) {
184     case X509_V_ERR_CERT_NOT_YET_VALID:
185     case X509_V_ERR_CERT_HAS_EXPIRED:
186     case X509_V_ERR_DEPTH_ZERO_SELF_SIGNED_CERT:
187       ok = 1;
188     }
189   }
190   return ok;
191 }
192
193 /* pass all ssl errors to DEBUGP
194    returns the number of printed errors */
195 int
196 ssl_printerrors (void) 
197 {
198   int ocerr = 0;
199   unsigned long curerr = 0;
200   char errbuff[1024];
201   memset(errbuff, 0, sizeof(errbuff));
202   for (curerr = ERR_get_error (); curerr; curerr = ERR_get_error ())
203     {
204       DEBUGP (("OpenSSL: %s\n", ERR_error_string (curerr, errbuff)));
205       ++ocerr;
206     }
207   return ocerr;
208 }
209
210 /* SSL version of iread. Only exchanged read for SSL_read 
211    Read at most LEN bytes from FD, storing them to BUF.  This is
212    virtually the same as read(), but takes care of EINTR braindamage
213    and uses select() to timeout the stale connections (a connection is
214    stale if more than OPT.TIMEOUT time is spent in select() or
215    read()).  */
216 int
217 ssl_iread (SSL *con, char *buf, int len)
218 {
219   int res;
220   int fd;
221   BIO_get_fd (con->rbio, &fd);
222   do
223     {
224 #ifdef HAVE_SELECT
225       if (opt.timeout && !SSL_pending (con))
226         {
227           do
228             {
229               res = select_fd (fd, opt.timeout, 0);
230             }
231           while (res == -1 && errno == EINTR);
232           if (res <= 0)
233             {
234               /* Set errno to ETIMEDOUT on timeout.  */
235               if (res == 0)
236                 /* #### Potentially evil!  */
237                 errno = ETIMEDOUT;
238               return -1;
239             }
240         }
241 #endif
242       res = SSL_read (con, buf, len);
243     }
244   while (res == -1 && errno == EINTR);
245
246   return res;
247 }
248
249 /* SSL version of iwrite. Only exchanged write for SSL_write 
250    Write LEN bytes from BUF to FD.  This is similar to iread(), but
251    doesn't bother with select().  Unlike iread(), it makes sure that
252    all of BUF is actually written to FD, so callers needn't bother
253    with checking that the return value equals to LEN.  Instead, you
254    should simply check for -1.  */
255 int
256 ssl_iwrite (SSL *con, char *buf, int len)
257 {
258   int res = 0;
259   int fd;
260   BIO_get_fd (con->rbio, &fd);
261   /* `write' may write less than LEN bytes, thus the outward loop
262      keeps trying it until all was written, or an error occurred.  The
263      inner loop is reserved for the usual EINTR f*kage, and the
264      innermost loop deals with the same during select().  */
265   while (len > 0)
266     {
267       do
268         {
269 #ifdef HAVE_SELECT
270           if (opt.timeout)
271             {
272               do
273                 {
274                   res = select_fd (fd, opt.timeout, 1);
275                 }
276               while (res == -1 && errno == EINTR);
277               if (res <= 0)
278                 {
279                   /* Set errno to ETIMEDOUT on timeout.  */
280                   if (res == 0)
281                     /* #### Potentially evil!  */
282                     errno = ETIMEDOUT;
283                   return -1;
284                 }
285             }
286 #endif
287           res = SSL_write (con, buf, len);
288         }
289       while (res == -1 && errno == EINTR);
290       if (res <= 0)
291         break;
292       buf += res;
293       len -= res;
294     }
295   return res;
296 }
297 #endif /* HAVE_SSL */