source: trunk/essentials/net-misc/wget/src/openssl.c

Last change on this file was 3440, checked in by bird, 18 years ago

wget 1.10.2

File size: 14.1 KB
Line 
1/* SSL support via OpenSSL library.
2 Copyright (C) 2000-2005 Free Software Foundation, Inc.
3 Originally contributed by Christian Fraenkel.
4
5This file is part of GNU Wget.
6
7GNU Wget is free software; you can redistribute it and/or modify
8it under the terms of the GNU General Public License as published by
9the Free Software Foundation; either version 2 of the License, or
10(at your option) any later version.
11
12GNU Wget is distributed in the hope that it will be useful,
13but WITHOUT ANY WARRANTY; without even the implied warranty of
14MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15GNU General Public License for more details.
16
17You should have received a copy of the GNU General Public License
18along with Wget; if not, write to the Free Software
19Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
20
21In addition, as a special exception, the Free Software Foundation
22gives permission to link the code of its release of Wget with the
23OpenSSL project's "OpenSSL" library (or with modified versions of it
24that use the same license as the "OpenSSL" library), and distribute
25the linked executables. You must obey the GNU General Public License
26in all respects for all of the code used other than "OpenSSL". If you
27modify this file, you may extend this exception to your version of the
28file, but you are not obligated to do so. If you do not wish to do
29so, delete this exception statement from your version. */
30
31#include <config.h>
32
33#include <assert.h>
34#include <errno.h>
35#ifdef HAVE_UNISTD_H
36# include <unistd.h>
37#endif
38#ifdef HAVE_STRING_H
39# include <string.h>
40#else
41# include <strings.h>
42#endif
43
44#include <openssl/ssl.h>
45#include <openssl/x509.h>
46#include <openssl/err.h>
47#include <openssl/rand.h>
48
49#include "wget.h"
50#include "utils.h"
51#include "connect.h"
52#include "url.h"
53#include "ssl.h"
54
55#ifndef errno
56extern int errno;
57#endif
58
59/* Application-wide SSL context. This is common to all SSL
60 connections. */
61SSL_CTX *ssl_ctx;
62
63/* Initialize the SSL's PRNG using various methods. */
64
65static void
66init_prng (void)
67{
68 char namebuf[256];
69 const char *random_file;
70
71 if (RAND_status ())
72 /* The PRNG has been seeded; no further action is necessary. */
73 return;
74
75 /* Seed from a file specified by the user. This will be the file
76 specified with --random-file, $RANDFILE, if set, or ~/.rnd, if it
77 exists. */
78 if (opt.random_file)
79 random_file = opt.random_file;
80 else
81 {
82 /* Get the random file name using RAND_file_name. */
83 namebuf[0] = '\0';
84 random_file = RAND_file_name (namebuf, sizeof (namebuf));
85 }
86
87 if (random_file && *random_file)
88 /* Seed at most 16k (apparently arbitrary value borrowed from
89 curl) from random file. */
90 RAND_load_file (random_file, 16384);
91
92 if (RAND_status ())
93 return;
94
95 /* Get random data from EGD if opt.egd_file was used. */
96 if (opt.egd_file && *opt.egd_file)
97 RAND_egd (opt.egd_file);
98
99 if (RAND_status ())
100 return;
101
102#ifdef WINDOWS
103 /* Under Windows, we can try to seed the PRNG using screen content.
104 This may or may not work, depending on whether we'll calling Wget
105 interactively. */
106
107 RAND_screen ();
108 if (RAND_status ())
109 return;
110#endif
111
112#if 0 /* don't do this by default */
113 {
114 int maxrand = 500;
115
116 /* Still not random enough, presumably because neither /dev/random
117 nor EGD were available. Try to seed OpenSSL's PRNG with libc
118 PRNG. This is cryptographically weak and defeats the purpose
119 of using OpenSSL, which is why it is highly discouraged. */
120
121 logprintf (LOG_NOTQUIET, _("WARNING: using a weak random seed.\n"));
122
123 while (RAND_status () == 0 && maxrand-- > 0)
124 {
125 unsigned char rnd = random_number (256);
126 RAND_seed (&rnd, sizeof (rnd));
127 }
128 }
129#endif
130}
131
132/* Print errors in the OpenSSL error stack. */
133
134static void
135print_errors (void)
136{
137 unsigned long curerr = 0;
138 while ((curerr = ERR_get_error ()) != 0)
139 logprintf (LOG_NOTQUIET, "OpenSSL: %s\n", ERR_error_string (curerr, NULL));
140}
141
142/* Convert keyfile type as used by options.h to a type as accepted by
143 SSL_CTX_use_certificate_file and SSL_CTX_use_PrivateKey_file.
144
145 (options.h intentionally doesn't use values from openssl/ssl.h so
146 it doesn't depend specifically on OpenSSL for SSL functionality.) */
147
148static int
149key_type_to_ssl_type (enum keyfile_type type)
150{
151 switch (type)
152 {
153 case keyfile_pem:
154 return SSL_FILETYPE_PEM;
155 case keyfile_asn1:
156 return SSL_FILETYPE_ASN1;
157 default:
158 abort ();
159 }
160}
161
162/* Create an SSL Context and set default paths etc. Called the first
163 time an HTTP download is attempted.
164
165 Returns 1 on success, 0 otherwise. */
166
167int
168ssl_init ()
169{
170 SSL_METHOD *meth;
171
172 if (ssl_ctx)
173 /* The SSL has already been initialized. */
174 return 1;
175
176 /* Init the PRNG. If that fails, bail out. */
177 init_prng ();
178 if (RAND_status () != 1)
179 {
180 logprintf (LOG_NOTQUIET,
181 _("Could not seed PRNG; consider using --random-file.\n"));
182 goto error;
183 }
184
185 SSL_library_init ();
186 SSL_load_error_strings ();
187 SSLeay_add_all_algorithms ();
188 SSLeay_add_ssl_algorithms ();
189
190 switch (opt.secure_protocol)
191 {
192 case secure_protocol_auto:
193 meth = SSLv23_client_method ();
194 break;
195 case secure_protocol_sslv2:
196 meth = SSLv2_client_method ();
197 break;
198 case secure_protocol_sslv3:
199 meth = SSLv3_client_method ();
200 break;
201 case secure_protocol_tlsv1:
202 meth = TLSv1_client_method ();
203 break;
204 default:
205 abort ();
206 }
207
208 ssl_ctx = SSL_CTX_new (meth);
209 if (!ssl_ctx)
210 goto error;
211
212 SSL_CTX_set_default_verify_paths (ssl_ctx);
213 SSL_CTX_load_verify_locations (ssl_ctx, opt.ca_cert, opt.ca_directory);
214
215 /* SSL_VERIFY_NONE instructs OpenSSL not to abort SSL_connect if the
216 certificate is invalid. We verify the certificate separately in
217 ssl_check_certificate, which provides much better diagnostics
218 than examining the error stack after a failed SSL_connect. */
219 SSL_CTX_set_verify (ssl_ctx, SSL_VERIFY_NONE, NULL);
220
221 if (opt.cert_file)
222 if (SSL_CTX_use_certificate_file (ssl_ctx, opt.cert_file,
223 key_type_to_ssl_type (opt.cert_type))
224 != 1)
225 goto error;
226 if (opt.private_key)
227 if (SSL_CTX_use_PrivateKey_file (ssl_ctx, opt.private_key,
228 key_type_to_ssl_type (opt.private_key_type))
229 != 1)
230 goto error;
231
232 /* Since fd_write unconditionally assumes partial writes (and
233 handles them correctly), allow them in OpenSSL. */
234 SSL_CTX_set_mode (ssl_ctx, SSL_MODE_ENABLE_PARTIAL_WRITE);
235
236 /* The OpenSSL library can handle renegotiations automatically, so
237 tell it to do so. */
238 SSL_CTX_set_mode (ssl_ctx, SSL_MODE_AUTO_RETRY);
239
240 return 1;
241
242 error:
243 if (ssl_ctx)
244 SSL_CTX_free (ssl_ctx);
245 print_errors ();
246 return 0;
247}
248
249static int
250openssl_read (int fd, char *buf, int bufsize, void *ctx)
251{
252 int ret;
253 SSL *ssl = (SSL *) ctx;
254 do
255 ret = SSL_read (ssl, buf, bufsize);
256 while (ret == -1
257 && SSL_get_error (ssl, ret) == SSL_ERROR_SYSCALL
258 && errno == EINTR);
259 return ret;
260}
261
262static int
263openssl_write (int fd, char *buf, int bufsize, void *ctx)
264{
265 int ret = 0;
266 SSL *ssl = (SSL *) ctx;
267 do
268 ret = SSL_write (ssl, buf, bufsize);
269 while (ret == -1
270 && SSL_get_error (ssl, ret) == SSL_ERROR_SYSCALL
271 && errno == EINTR);
272 return ret;
273}
274
275static int
276openssl_poll (int fd, double timeout, int wait_for, void *ctx)
277{
278 SSL *ssl = (SSL *) ctx;
279 if (timeout == 0)
280 return 1;
281 if (SSL_pending (ssl))
282 return 1;
283 return select_fd (fd, timeout, wait_for);
284}
285
286static int
287openssl_peek (int fd, char *buf, int bufsize, void *ctx)
288{
289 int ret;
290 SSL *ssl = (SSL *) ctx;
291 do
292 ret = SSL_peek (ssl, buf, bufsize);
293 while (ret == -1
294 && SSL_get_error (ssl, ret) == SSL_ERROR_SYSCALL
295 && errno == EINTR);
296 return ret;
297}
298
299static void
300openssl_close (int fd, void *ctx)
301{
302 SSL *ssl = (SSL *) ctx;
303 SSL_shutdown (ssl);
304 SSL_free (ssl);
305
306#ifdef WINDOWS
307 closesocket (fd);
308#else
309 close (fd);
310#endif
311
312 DEBUGP (("Closed %d/SSL 0x%0lx\n", fd, (unsigned long) ssl));
313}
314
315/* Perform the SSL handshake on file descriptor FD, which is assumed
316 to be connected to an SSL server. The SSL handle provided by
317 OpenSSL is registered with the file descriptor FD using
318 fd_register_transport, so that subsequent calls to fd_read,
319 fd_write, etc., will use the corresponding SSL functions.
320
321 Returns 1 on success, 0 on failure. */
322
323int
324ssl_connect (int fd)
325{
326 SSL *ssl;
327
328 DEBUGP (("Initiating SSL handshake.\n"));
329
330 assert (ssl_ctx != NULL);
331 ssl = SSL_new (ssl_ctx);
332 if (!ssl)
333 goto error;
334 if (!SSL_set_fd (ssl, fd))
335 goto error;
336 SSL_set_connect_state (ssl);
337 if (SSL_connect (ssl) <= 0 || ssl->state != SSL_ST_OK)
338 goto error;
339
340 /* Register FD with Wget's transport layer, i.e. arrange that our
341 functions are used for reading, writing, and polling. */
342 fd_register_transport (fd, openssl_read, openssl_write, openssl_poll,
343 openssl_peek, openssl_close, ssl);
344 DEBUGP (("Handshake successful; connected socket %d to SSL handle 0x%0*lx\n",
345 fd, PTR_FORMAT (ssl)));
346 return 1;
347
348 error:
349 DEBUGP (("SSL handshake failed.\n"));
350 print_errors ();
351 if (ssl)
352 SSL_free (ssl);
353 return 0;
354}
355
356#define ASTERISK_EXCLUDES_DOT /* mandated by rfc2818 */
357
358/* Return 1 is STRING (case-insensitively) matches PATTERN, 0
359 otherwise. The recognized wildcard character is "*", which matches
360 any character in STRING except ".". Any number of the "*" wildcard
361 may be present in the pattern.
362
363 This is used to match of hosts as indicated in rfc2818: "Names may
364 contain the wildcard character * which is considered to match any
365 single domain name component or component fragment. E.g., *.a.com
366 matches foo.a.com but not bar.foo.a.com. f*.com matches foo.com but
367 not bar.com [or foo.bar.com]."
368
369 If the pattern contain no wildcards, pattern_match(a, b) is
370 equivalent to !strcasecmp(a, b). */
371
372static int
373pattern_match (const char *pattern, const char *string)
374{
375 const char *p = pattern, *n = string;
376 char c;
377 for (; (c = TOLOWER (*p++)) != '\0'; n++)
378 if (c == '*')
379 {
380 for (c = TOLOWER (*p); c == '*'; c = TOLOWER (*++p))
381 ;
382 for (; *n != '\0'; n++)
383 if (TOLOWER (*n) == c && pattern_match (p, n))
384 return 1;
385#ifdef ASTERISK_EXCLUDES_DOT
386 else if (*n == '.')
387 return 0;
388#endif
389 return c == '\0';
390 }
391 else
392 {
393 if (c != TOLOWER (*n))
394 return 0;
395 }
396 return *n == '\0';
397}
398
399/* Verify the validity of the certificate presented by the server.
400 Also check that the "common name" of the server, as presented by
401 its certificate, corresponds to HOST. (HOST typically comes from
402 the URL and is what the user thinks he's connecting to.)
403
404 This assumes that ssl_connect has successfully finished, i.e. that
405 the SSL handshake has been performed and that FD is connected to an
406 SSL handle.
407
408 If opt.check_cert is non-zero (the default), this returns 1 if the
409 certificate is valid, 0 otherwise. If opt.check_cert is 0, the
410 function always returns 1, but should still be called because it
411 warns the user about any problems with the certificate. */
412
413int
414ssl_check_certificate (int fd, const char *host)
415{
416 X509 *cert;
417 char common_name[256];
418 long vresult;
419 int success = 1;
420
421 /* If the user has specified --no-check-cert, we still want to warn
422 him about problems with the server's certificate. */
423 const char *severity = opt.check_cert ? _("ERROR") : _("WARNING");
424
425 SSL *ssl = (SSL *) fd_transport_context (fd);
426 assert (ssl != NULL);
427
428 cert = SSL_get_peer_certificate (ssl);
429 if (!cert)
430 {
431 logprintf (LOG_NOTQUIET, _("%s: No certificate presented by %s.\n"),
432 severity, escnonprint (host));
433 success = 0;
434 goto no_cert; /* must bail out since CERT is NULL */
435 }
436
437#ifdef ENABLE_DEBUG
438 if (opt.debug)
439 {
440 char *subject = X509_NAME_oneline (X509_get_subject_name (cert), 0, 0);
441 char *issuer = X509_NAME_oneline (X509_get_issuer_name (cert), 0, 0);
442 DEBUGP (("certificate:\n subject: %s\n issuer: %s\n",
443 escnonprint (subject), escnonprint (issuer)));
444 OPENSSL_free (subject);
445 OPENSSL_free (issuer);
446 }
447#endif
448
449 vresult = SSL_get_verify_result (ssl);
450 if (vresult != X509_V_OK)
451 {
452 /* #### We might want to print saner (and translatable) error
453 messages for several frequently encountered errors. The
454 candidates would include
455 X509_V_ERR_UNABLE_TO_GET_ISSUER_CERT_LOCALLY,
456 X509_V_ERR_SELF_SIGNED_CERT_IN_CHAIN,
457 X509_V_ERR_DEPTH_ZERO_SELF_SIGNED_CERT,
458 X509_V_ERR_CERT_NOT_YET_VALID, X509_V_ERR_CERT_HAS_EXPIRED,
459 and possibly others. The current approach would still be
460 used for the less frequent failure cases. */
461 logprintf (LOG_NOTQUIET,
462 _("%s: Certificate verification error for %s: %s\n"),
463 severity, escnonprint (host),
464 X509_verify_cert_error_string (vresult));
465 success = 0;
466 /* Fall through, so that the user is warned about *all* issues
467 with the cert (important with --no-check-certificate.) */
468 }
469
470 /* Check that HOST matches the common name in the certificate.
471 #### The following remains to be done:
472
473 - It should use dNSName/ipAddress subjectAltName extensions if
474 available; according to rfc2818: "If a subjectAltName extension
475 of type dNSName is present, that MUST be used as the identity."
476
477 - When matching against common names, it should loop over all
478 common names and choose the most specific one, i.e. the last
479 one, not the first one, which the current code picks.
480
481 - Ensure that ASN1 strings from the certificate are encoded as
482 UTF-8 which can be meaningfully compared to HOST. */
483
484 common_name[0] = '\0';
485 X509_NAME_get_text_by_NID (X509_get_subject_name (cert),
486 NID_commonName, common_name, sizeof (common_name));
487 if (!pattern_match (common_name, host))
488 {
489 logprintf (LOG_NOTQUIET, _("\
490%s: certificate common name `%s' doesn't match requested host name `%s'.\n"),
491 severity, escnonprint (common_name), escnonprint (host));
492 success = 0;
493 }
494
495 if (success)
496 DEBUGP (("X509 certificate successfully verified and matches host %s\n",
497 escnonprint (host)));
498 X509_free (cert);
499
500 no_cert:
501 if (opt.check_cert && !success)
502 logprintf (LOG_NOTQUIET, _("\
503To connect to %s insecurely, use `--no-check-certificate'.\n"),
504 escnonprint (host));
505
506 /* Allow --no-check-cert to disable certificate checking. */
507 return opt.check_cert ? success : 1;
508}
Note: See TracBrowser for help on using the repository browser.