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