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