~ubuntu-branches/ubuntu/precise/wget/precise-proposed

« back to all changes in this revision

Viewing changes to src/openssl.c

  • Committer: Bazaar Package Importer
  • Author(s): Steve Langasek
  • Date: 2011-10-19 00:00:09 UTC
  • mfrom: (2.1.13 sid)
  • Revision ID: james.westby@ubuntu.com-20111019000009-8p33w3wz4b1rdri0
Tags: 1.13-1ubuntu1
* Merge from Debian unstable, remaining changes:
  - Add wget-udeb to ship wget.gnu as alternative to busybox wget
    implementation.
  - Depend on libssl-dev 0.9.8k-7ubuntu4 (LP: #503339)
* Dropped changes, superseded in Debian:
  - Keep build dependencies in main:
    + debian/control: remove info2man build-dep
    + debian/patches/series: disable wget-infopod_generated_manpage
  - Mark wget Multi-Arch: foreign, so packages that aren't of the same arch
    can depend on it.
* Pass --with-ssl=openssl; we don't want to use gnutls, there's no udeb for
  it.
* Add a second build pass for the udeb, so we can build without libidn.

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
1
/* SSL support via OpenSSL library.
2
2
   Copyright (C) 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008,
3
 
   2009 Free Software Foundation, Inc.
 
3
   2009, 2010, 2011 Free Software Foundation, Inc.
4
4
   Originally contributed by Christian Fraenkel.
5
5
 
6
6
This file is part of GNU Wget.
33
33
 
34
34
#include <assert.h>
35
35
#include <errno.h>
36
 
#ifdef HAVE_UNISTD_H
37
 
# include <unistd.h>
38
 
#endif
 
36
#include <unistd.h>
39
37
#include <string.h>
40
38
 
41
39
#include <openssl/ssl.h>
42
 
#include <openssl/x509.h>
 
40
#include <openssl/x509v3.h>
43
41
#include <openssl/err.h>
44
42
#include <openssl/rand.h>
45
43
 
48
46
#include "url.h"
49
47
#include "ssl.h"
50
48
 
 
49
#ifdef WINDOWS
 
50
# include <w32sock.h>
 
51
#endif
 
52
 
51
53
/* Application-wide SSL context.  This is common to all SSL
52
54
   connections.  */
53
55
static SSL_CTX *ssl_ctx;
184
186
    case secure_protocol_auto:
185
187
      meth = SSLv23_client_method ();
186
188
      break;
187
 
#ifndef NO_SSLv2
 
189
#ifndef OPENSSL_NO_SSL2
188
190
    case secure_protocol_sslv2:
189
191
      meth = SSLv2_client_method ();
190
192
      break;
263
265
  while (ret == -1
264
266
         && SSL_get_error (conn, ret) == SSL_ERROR_SYSCALL
265
267
         && errno == EINTR);
 
268
 
266
269
  return ret;
267
270
}
268
271
 
285
288
{
286
289
  struct openssl_transport_context *ctx = arg;
287
290
  SSL *conn = ctx->conn;
 
291
  if (SSL_pending (conn))
 
292
    return 1;
288
293
  if (timeout == 0)
289
294
    return 1;
290
 
  if (SSL_pending (conn))
291
 
    return 1;
292
295
  return select_fd (fd, timeout, wait_for);
293
296
}
294
297
 
298
301
  int ret;
299
302
  struct openssl_transport_context *ctx = arg;
300
303
  SSL *conn = ctx->conn;
 
304
  if (! openssl_poll (fd, 0.0, WAIT_FOR_READ, arg))
 
305
    return 0;
301
306
  do
302
307
    ret = SSL_peek (conn, buf, bufsize);
303
308
  while (ret == -1
366
371
  xfree_null (ctx->last_error);
367
372
  xfree (ctx);
368
373
 
369
 
#if defined(WINDOWS) || defined(USE_WATT32)
370
 
  closesocket (fd);
371
 
#else
372
374
  close (fd);
373
 
#endif
374
375
 
375
376
  DEBUGP (("Closed %d/SSL 0x%0*lx\n", fd, PTR_FORMAT (conn)));
376
377
}
403
404
  conn = SSL_new (ssl_ctx);
404
405
  if (!conn)
405
406
    goto error;
406
 
  if (!SSL_set_fd (conn, fd))
 
407
#ifndef FD_TO_SOCKET
 
408
# define FD_TO_SOCKET(X) (X)
 
409
#endif
 
410
  if (!SSL_set_fd (conn, FD_TO_SOCKET (fd)))
407
411
    goto error;
408
412
  SSL_set_connect_state (conn);
409
413
  if (SSL_connect (conn) <= 0 || conn->state != SSL_ST_OK)
488
492
ssl_check_certificate (int fd, const char *host)
489
493
{
490
494
  X509 *cert;
 
495
  GENERAL_NAMES *subjectAltNames;
491
496
  char common_name[256];
492
497
  long vresult;
493
498
  bool success = true;
 
499
  bool alt_name_checked = false;
494
500
 
495
501
  /* If the user has specified --no-check-cert, we still want to warn
496
502
     him about problems with the server's certificate.  */
538
544
          break;
539
545
        case X509_V_ERR_SELF_SIGNED_CERT_IN_CHAIN:
540
546
        case X509_V_ERR_DEPTH_ZERO_SELF_SIGNED_CERT:
541
 
          logprintf (LOG_NOTQUIET, _("  Self-signed certificate encountered.\n"));
 
547
          logprintf (LOG_NOTQUIET,
 
548
                     _("  Self-signed certificate encountered.\n"));
542
549
          break;
543
550
        case X509_V_ERR_CERT_NOT_YET_VALID:
544
551
          logprintf (LOG_NOTQUIET, _("  Issued certificate not yet valid.\n"));
560
567
  /* Check that HOST matches the common name in the certificate.
561
568
     #### The following remains to be done:
562
569
 
563
 
     - It should use dNSName/ipAddress subjectAltName extensions if
564
 
       available; according to rfc2818: "If a subjectAltName extension
565
 
       of type dNSName is present, that MUST be used as the identity."
566
 
 
567
570
     - When matching against common names, it should loop over all
568
571
       common names and choose the most specific one, i.e. the last
569
572
       one, not the first one, which the current code picks.
571
574
     - Ensure that ASN1 strings from the certificate are encoded as
572
575
       UTF-8 which can be meaningfully compared to HOST.  */
573
576
 
574
 
  X509_NAME *xname = X509_get_subject_name(cert);
575
 
  common_name[0] = '\0';
576
 
  X509_NAME_get_text_by_NID (xname, NID_commonName, common_name,
577
 
                             sizeof (common_name));
 
577
  subjectAltNames = X509_get_ext_d2i (cert, NID_subject_alt_name, NULL, NULL);
578
578
 
579
 
  if (!pattern_match (common_name, host))
 
579
  if (subjectAltNames)
580
580
    {
581
 
      logprintf (LOG_NOTQUIET, _("\
582
 
%s: certificate common name %s doesn't match requested host name %s.\n"),
583
 
                 severity, quote_n (0, common_name), quote_n (1, host));
584
 
      success = false;
 
581
      /* Test subject alternative names */
 
582
 
 
583
      /* Do we want to check for dNSNAmes or ipAddresses (see RFC 2818)?
 
584
       * Signal it by host_in_octet_string. */
 
585
      ASN1_OCTET_STRING *host_in_octet_string = a2i_IPADDRESS (host);
 
586
 
 
587
      int numaltnames = sk_GENERAL_NAME_num (subjectAltNames);
 
588
      int i;
 
589
      for (i=0; i < numaltnames; i++)
 
590
        {
 
591
          const GENERAL_NAME *name =
 
592
            sk_GENERAL_NAME_value (subjectAltNames, i);
 
593
          if (name)
 
594
            {
 
595
              if (host_in_octet_string)
 
596
                {
 
597
                  if (name->type == GEN_IPADD)
 
598
                    {
 
599
                      /* Check for ipAddress */
 
600
                      /* TODO: Should we convert between IPv4-mapped IPv6
 
601
                       * addresses and IPv4 addresses? */
 
602
                      alt_name_checked = true;
 
603
                      if (!ASN1_STRING_cmp (host_in_octet_string,
 
604
                            name->d.iPAddress))
 
605
                        break;
 
606
                    }
 
607
                }
 
608
              else if (name->type == GEN_DNS)
 
609
                {
 
610
                  /* dNSName should be IA5String (i.e. ASCII), however who
 
611
                   * does trust CA? Convert it into UTF-8 for sure. */
 
612
                  unsigned char *name_in_utf8 = NULL;
 
613
 
 
614
                  /* Check for dNSName */
 
615
                  alt_name_checked = true;
 
616
 
 
617
                  if (0 <= ASN1_STRING_to_UTF8 (&name_in_utf8, name->d.dNSName))
 
618
                    {
 
619
                      /* Compare and check for NULL attack in ASN1_STRING */
 
620
                      if (pattern_match ((char *)name_in_utf8, host) &&
 
621
                            (strlen ((char *)name_in_utf8) ==
 
622
                                ASN1_STRING_length (name->d.dNSName)))
 
623
                        {
 
624
                          OPENSSL_free (name_in_utf8);
 
625
                          break;
 
626
                        }
 
627
                      OPENSSL_free (name_in_utf8);
 
628
                    }
 
629
                }
 
630
            }
 
631
        }
 
632
      sk_GENERAL_NAME_free (subjectAltNames);
 
633
      if (host_in_octet_string)
 
634
        ASN1_OCTET_STRING_free(host_in_octet_string);
 
635
 
 
636
      if (alt_name_checked == true && i >= numaltnames)
 
637
        {
 
638
          logprintf (LOG_NOTQUIET,
 
639
              _("%s: no certificate subject alternative name matches\n"
 
640
                "\trequested host name %s.\n"),
 
641
                     severity, quote_n (1, host));
 
642
          success = false;
 
643
        }
585
644
    }
586
 
  else
 
645
  
 
646
  if (alt_name_checked == false)
587
647
    {
588
 
      /* We now determine the length of the ASN1 string. If it differs from
589
 
       * common_name's length, then there is a \0 before the string terminates.
590
 
       * This can be an instance of a null-prefix attack.
591
 
       *
592
 
       * https://www.blackhat.com/html/bh-usa-09/bh-usa-09-archives.html#Marlinspike
593
 
       * */
594
 
 
595
 
      int i = -1, j;
596
 
      X509_NAME_ENTRY *xentry;
597
 
      ASN1_STRING *sdata;
598
 
 
599
 
      if (xname) {
600
 
        for (;;)
601
 
          {
602
 
            j = X509_NAME_get_index_by_NID (xname, NID_commonName, i);
603
 
            if (j == -1) break;
604
 
            i = j;
 
648
      /* Test commomName */
 
649
      X509_NAME *xname = X509_get_subject_name(cert);
 
650
      common_name[0] = '\0';
 
651
      X509_NAME_get_text_by_NID (xname, NID_commonName, common_name,
 
652
                                 sizeof (common_name));
 
653
 
 
654
      if (!pattern_match (common_name, host))
 
655
        {
 
656
          logprintf (LOG_NOTQUIET, _("\
 
657
    %s: certificate common name %s doesn't match requested host name %s.\n"),
 
658
                     severity, quote_n (0, common_name), quote_n (1, host));
 
659
          success = false;
 
660
        }
 
661
      else
 
662
        {
 
663
          /* We now determine the length of the ASN1 string. If it
 
664
           * differs from common_name's length, then there is a \0
 
665
           * before the string terminates.  This can be an instance of a
 
666
           * null-prefix attack.
 
667
           *
 
668
           * https://www.blackhat.com/html/bh-usa-09/bh-usa-09-archives.html#Marlinspike
 
669
           * */
 
670
 
 
671
          int i = -1, j;
 
672
          X509_NAME_ENTRY *xentry;
 
673
          ASN1_STRING *sdata;
 
674
 
 
675
          if (xname) {
 
676
            for (;;)
 
677
              {
 
678
                j = X509_NAME_get_index_by_NID (xname, NID_commonName, i);
 
679
                if (j == -1) break;
 
680
                i = j;
 
681
              }
605
682
          }
606
 
      }
607
683
 
608
 
      xentry = X509_NAME_get_entry(xname,i);
609
 
      sdata = X509_NAME_ENTRY_get_data(xentry);
610
 
      if (strlen (common_name) != ASN1_STRING_length (sdata))
611
 
        {
612
 
          logprintf (LOG_NOTQUIET, _("\
613
 
%s: certificate common name is invalid (contains a NUL character).\n\
614
 
This may be an indication that the host is not who it claims to be\n\
615
 
(that is, it is not the real %s).\n"),
616
 
                     severity, quote (host));
617
 
          success = false;
 
684
          xentry = X509_NAME_get_entry(xname,i);
 
685
          sdata = X509_NAME_ENTRY_get_data(xentry);
 
686
          if (strlen (common_name) != ASN1_STRING_length (sdata))
 
687
            {
 
688
              logprintf (LOG_NOTQUIET, _("\
 
689
    %s: certificate common name is invalid (contains a NUL character).\n\
 
690
    This may be an indication that the host is not who it claims to be\n\
 
691
    (that is, it is not the real %s).\n"),
 
692
                         severity, quote (host));
 
693
              success = false;
 
694
            }
618
695
        }
619
696
    }
620
697
 
633
710
  /* Allow --no-check-cert to disable certificate checking. */
634
711
  return opt.check_cert ? success : true;
635
712
}
 
713
 
 
714
/*
 
715
 * vim: tabstop=2 shiftwidth=2 softtabstop=2
 
716
 */