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