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