1 /* SSL support via OpenSSL library.
2 Copyright (C) 2000-2005 Free Software Foundation, Inc.
3 Originally contributed by Christian Fraenkel.
5 This file is part of GNU Wget.
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.
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.
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.
21 In addition, as a special exception, the Free Software Foundation
22 gives permission to link the code of its release of Wget with the
23 OpenSSL project's "OpenSSL" library (or with modified versions of it
24 that use the same license as the "OpenSSL" library), and distribute
25 the linked executables. You must obey the GNU General Public License
26 in all respects for all of the code used other than "OpenSSL". If you
27 modify this file, you may extend this exception to your version of the
28 file, but you are not obligated to do so. If you do not wish to do
29 so, delete this exception statement from your version. */
44 #include <openssl/ssl.h>
45 #include <openssl/x509.h>
46 #include <openssl/err.h>
47 #include <openssl/rand.h>
59 /* Application-wide SSL context. This is common to all SSL
63 /* Initialize the SSL's PRNG using various methods. */
69 const char *random_file;
72 /* The PRNG has been seeded; no further action is necessary. */
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
79 random_file = opt.random_file;
82 /* Get the random file name using RAND_file_name. */
84 random_file = RAND_file_name (namebuf, sizeof (namebuf));
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);
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);
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
112 #if 0 /* don't do this by default */
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. */
121 logprintf (LOG_NOTQUIET, _("WARNING: using a weak random seed.\n"));
123 while (RAND_status () == 0 && maxrand-- > 0)
125 unsigned char rnd = random_number (256);
126 RAND_seed (&rnd, sizeof (rnd));
132 /* Print errors in the OpenSSL error stack. */
137 unsigned long curerr = 0;
138 while ((curerr = ERR_get_error ()) != 0)
139 logprintf (LOG_NOTQUIET, "OpenSSL: %s\n", ERR_error_string (curerr, NULL));
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.
145 (options.h intentionally doesn't use values from openssl/ssl.h so
146 it doesn't depend specifically on OpenSSL for SSL functionality.) */
149 key_type_to_ssl_type (enum keyfile_type type)
154 return SSL_FILETYPE_PEM;
156 return SSL_FILETYPE_ASN1;
162 /* Create an SSL Context and set default paths etc. Called the first
163 time an HTTP download is attempted.
165 Returns 1 on success, 0 otherwise. */
173 /* The SSL has already been initialized. */
176 /* Init the PRNG. If that fails, bail out. */
178 if (RAND_status () != 1)
180 logprintf (LOG_NOTQUIET,
181 _("Could not seed PRNG; consider using --random-file.\n"));
186 SSL_load_error_strings ();
187 SSLeay_add_all_algorithms ();
188 SSLeay_add_ssl_algorithms ();
190 switch (opt.secure_protocol)
192 case secure_protocol_auto:
193 meth = SSLv23_client_method ();
195 case secure_protocol_sslv2:
196 meth = SSLv2_client_method ();
198 case secure_protocol_sslv3:
199 meth = SSLv3_client_method ();
201 case secure_protocol_tlsv1:
202 meth = TLSv1_client_method ();
208 ssl_ctx = SSL_CTX_new (meth);
212 SSL_CTX_set_default_verify_paths (ssl_ctx);
213 SSL_CTX_load_verify_locations (ssl_ctx, opt.ca_cert, opt.ca_directory);
215 /* Specify whether the connect should fail if the verification of
216 the peer fails or if it should go ahead. */
217 SSL_CTX_set_verify (ssl_ctx,
218 opt.check_cert ? SSL_VERIFY_PEER : SSL_VERIFY_NONE, NULL);
221 if (SSL_CTX_use_certificate_file (ssl_ctx, opt.cert_file,
222 key_type_to_ssl_type (opt.cert_type))
226 if (SSL_CTX_use_PrivateKey_file (ssl_ctx, opt.private_key,
227 key_type_to_ssl_type (opt.private_key_type))
231 /* Since fd_write unconditionally assumes partial writes (and
232 handles them correctly), allow them in OpenSSL. */
233 SSL_CTX_set_mode (ssl_ctx, SSL_MODE_ENABLE_PARTIAL_WRITE);
239 SSL_CTX_free (ssl_ctx);
245 openssl_read (int fd, char *buf, int bufsize, void *ctx)
248 SSL *ssl = (SSL *) ctx;
250 ret = SSL_read (ssl, buf, bufsize);
252 && SSL_get_error (ssl, ret) == SSL_ERROR_SYSCALL
258 openssl_write (int fd, char *buf, int bufsize, void *ctx)
261 SSL *ssl = (SSL *) ctx;
263 ret = SSL_write (ssl, buf, bufsize);
265 && SSL_get_error (ssl, ret) == SSL_ERROR_SYSCALL
271 openssl_poll (int fd, double timeout, int wait_for, void *ctx)
273 SSL *ssl = (SSL *) ctx;
276 if (SSL_pending (ssl))
278 return select_fd (fd, timeout, wait_for);
282 openssl_peek (int fd, char *buf, int bufsize, void *ctx)
285 SSL *ssl = (SSL *) ctx;
287 ret = SSL_peek (ssl, buf, bufsize);
289 && SSL_get_error (ssl, ret) == SSL_ERROR_SYSCALL
295 openssl_close (int fd, void *ctx)
297 SSL *ssl = (SSL *) ctx;
307 DEBUGP (("Closed %d/SSL 0x%0lx\n", fd, (unsigned long) ssl));
310 /* Sets up a SSL structure and performs the handshake on fd. The
311 resulting SSL structure is registered with the file descriptor FD
312 using fd_register_transport. That way subsequent calls to xread,
313 xwrite, etc., will use the appropriate SSL functions.
315 Returns 1 on success, 0 on failure. */
322 assert (ssl_ctx != NULL);
323 ssl = SSL_new (ssl_ctx);
326 if (!SSL_set_fd (ssl, fd))
328 SSL_set_connect_state (ssl);
329 if (SSL_connect (ssl) <= 0 || ssl->state != SSL_ST_OK)
332 /* Register FD with Wget's transport layer, i.e. arrange that
333 SSL-enabled functions are used for reading, writing, and polling.
334 That way the rest of Wget can keep using fd_read, fd_write, and
335 friends and not care what happens underneath. */
336 fd_register_transport (fd, openssl_read, openssl_write, openssl_poll,
337 openssl_peek, openssl_close, ssl);
338 DEBUGP (("Connected %d to SSL 0x%0*lx\n", fd, 2 * sizeof (void *),
339 (unsigned long) ssl));
349 /* Return 1 is STRING (case-insensitively) matches PATTERN, 0
350 otherwise. The recognized wildcard character is "*", which matches
351 any character in STRING except ".". Any number of the "*" wildcard
352 may be present in the pattern.
354 This is used to match of hosts as indicated in rfc2818: "Names may
355 contain the wildcard character * which is considered to match any
356 single domain name component or component fragment. E.g., *.a.com
357 matches foo.a.com but not bar.foo.a.com. f*.com matches foo.com but
361 pattern_match (const char *pattern, const char *string)
363 const char *p = pattern, *n = string;
365 for (; (c = TOLOWER (*p++)) != '\0'; n++)
368 for (c = TOLOWER (*p); c == '*'; c = TOLOWER (*++p))
370 for (; *n != '\0'; n++)
371 if (TOLOWER (*n) == c && pattern_match (p, n))
379 if (c != TOLOWER (*n))
385 /* Check that the identity of the remote host, as presented by its
386 server certificate, corresponds to HOST, which is the host name the
387 user thinks he's connecting to. This assumes that FD has been
388 connected to an SSL context using ssl_connect. Return 1 if the
389 identity checks out, 0 otherwise.
391 If opt.check_cert is 0, this always returns 1, but still warns the
392 user about the mismatches, if any. */
395 ssl_check_server_identity (int fd, const char *host)
397 X509 *peer_cert = NULL;
402 /* If the user has specified --no-check-cert, we still want to warn
403 him about problems with the server's certificate. */
404 const char *severity = opt.check_cert ? _("ERROR") : _("WARNING");
406 SSL *ssl = (SSL *) fd_transport_context (fd);
407 assert (ssl != NULL);
409 peer_cert = SSL_get_peer_certificate (ssl);
412 logprintf (LOG_NOTQUIET, _("%s: No certificate presented by %s.\n"),
413 severity, escnonprint (host));
421 char *subject = X509_NAME_oneline (X509_get_subject_name (peer_cert), 0, 0);
422 char *issuer = X509_NAME_oneline (X509_get_issuer_name (peer_cert), 0, 0);
423 DEBUGP (("certificate:\n subject: %s\n issuer: %s\n",
424 escnonprint (subject), escnonprint (issuer)));
425 OPENSSL_free (subject);
426 OPENSSL_free (issuer);
430 vresult = SSL_get_verify_result (ssl);
431 if (vresult != X509_V_OK)
433 logprintf (LOG_NOTQUIET,
434 _("%s: Certificate verification error for %s: %s\n"),
435 severity, escnonprint (host),
436 X509_verify_cert_error_string (vresult));
441 /* Check that the common name in the presented certificate matches
442 HOST. This should be improved in the following ways:
444 - It should use dNSName/ipAddress subjectAltName extensions if
445 available; according to rfc2818: "If a subjectAltName extension
446 of type dNSName is present, that MUST be used as the identity."
448 - When matching against common names, it should loop over all
449 common names and choose the most specific one, i.e. the last
450 one, not the first one, which the current code picks. */
453 X509_NAME_get_text_by_NID (X509_get_subject_name (peer_cert),
454 NID_commonName, peer_CN, sizeof (peer_CN));
455 if (!pattern_match (peer_CN, host))
457 logprintf (LOG_NOTQUIET, _("\
458 %s: certificate common name `%s' doesn't match requested host name `%s'.\n"),
459 severity, escnonprint (peer_CN), escnonprint (host));
464 /* The certificate was found, verified, and matched HOST. */
469 X509_free (peer_cert);
471 /* Allow --no-check-cert to disable certificate checking. */
472 return opt.check_cert ? retval : 1;