]> sjero.net Git - wget/commitdiff
[svn] Implement several SSL features.
authorhniksic <devnull@localhost>
Sun, 21 Apr 2002 02:26:48 +0000 (19:26 -0700)
committerhniksic <devnull@localhost>
Sun, 21 Apr 2002 02:26:48 +0000 (19:26 -0700)
- allow checking of server cert
- allow defining client cert type
- allow limit of ssl protocol
- check more return values
- added debug message on break
Published by Thomas Lussnig in <3CC09969.5000607@bewegungsmelder.de>.

src/ChangeLog
src/gen_sslfunc.c
src/init.c
src/main.c
src/options.h

index 68c2ae59d103e73efa18d0971017d76a84d05c52..cba701d9ef1f4b65bf13c433a2e5632388aa87b7 100644 (file)
@@ -1,3 +1,12 @@
+2002-04-21  Thomas Lussnig  <thomas.lussnig@bewegungsmelder.de>
+
+       * gen_ssl.c:
+       - allow checking of server cert
+       - allow defining client cert type
+       - allow limit of ssl protocol
+       - check more return values
+       - added debug message on break
+
 2002-04-21  Hrvoje Niksic  <hniksic@arsdigita.com>
 
        * recur.c (download_child_p): Revert order of items in check
 2002-04-21  Hrvoje Niksic  <hniksic@arsdigita.com>
 
        * recur.c (download_child_p): Revert order of items in check
index f03f9c56a50e21b89c9a1b85f316acaff04bf73c..d9515130280f47e05196e562abb29a54ce8cc8ec 100644 (file)
@@ -50,8 +50,6 @@ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.  */
 extern int errno;
 #endif
 
 extern int errno;
 #endif
 
-static int verify_callback PARAMS ((int, X509_STORE_CTX *));
-
 void
 ssl_init_prng (void)
 {
 void
 ssl_init_prng (void)
 {
@@ -112,68 +110,6 @@ ssl_init_prng (void)
 #endif /* SSLEAY_VERSION_NUMBER >= 0x00905100 */
 }
 
 #endif /* SSLEAY_VERSION_NUMBER >= 0x00905100 */
 }
 
-/* Creates a SSL Context and sets some defaults for it */
-uerr_t
-init_ssl (SSL_CTX **ctx)
-{
-  SSL_METHOD *meth = NULL;
-  int verify = SSL_VERIFY_NONE;
-  SSL_library_init ();
-  SSL_load_error_strings ();
-  SSLeay_add_all_algorithms ();
-  SSLeay_add_ssl_algorithms ();
-  meth = SSLv23_client_method ();
-  *ctx = SSL_CTX_new (meth);
-  SSL_CTX_set_verify (*ctx, verify, verify_callback);
-  if (*ctx == NULL) 
-    return SSLERRCTXCREATE;
-  if (opt.sslcertfile)
-    {
-      if (SSL_CTX_use_certificate_file (*ctx, opt.sslcertfile,
-                                       SSL_FILETYPE_PEM) <= 0)
-       return SSLERRCERTFILE;
-      if (opt.sslcertkey == NULL) 
-       opt.sslcertkey=opt.sslcertfile;
-      if (SSL_CTX_use_PrivateKey_file (*ctx, opt.sslcertkey,
-                                      SSL_FILETYPE_PEM) <= 0)
-       return SSLERRCERTKEY;
-  }
-  return 0; /* Succeded */
-}
-
-/* Sets up a SSL structure and performs the handshake on fd 
-   Returns 0 if everything went right
-   Returns 1 if something went wrong ----- TODO: More exit codes
-*/
-int
-connect_ssl (SSL **con, SSL_CTX *ctx, int fd) 
-{
-  *con = (SSL *)SSL_new (ctx);
-  SSL_set_fd (*con, fd);
-  SSL_set_connect_state (*con); 
-  SSL_connect (*con);  
-  if ((*con)->state != SSL_ST_OK)
-    return 1;
-  /*while((SSLerror=ERR_get_error())!=0)
-    printf("%s\n", ERR_error_string(SSLerror,NULL));*/
-
-  return 0;
-}
-
-void
-shutdown_ssl (SSL* con)
-{
-  SSL_shutdown (con);
-  if (con != NULL)
-    SSL_free (con);
-}
-
-void
-free_ssl_ctx (SSL_CTX * ctx)
-{
-  SSL_CTX_free (ctx);
-}
-
 int
 verify_callback (int ok, X509_STORE_CTX *ctx)
 {
 int
 verify_callback (int ok, X509_STORE_CTX *ctx)
 {
@@ -183,8 +119,13 @@ verify_callback (int ok, X509_STORE_CTX *ctx)
     switch (ctx->error) {
     case X509_V_ERR_CERT_NOT_YET_VALID:
     case X509_V_ERR_CERT_HAS_EXPIRED:
     switch (ctx->error) {
     case X509_V_ERR_CERT_NOT_YET_VALID:
     case X509_V_ERR_CERT_HAS_EXPIRED:
+      /* This mean the CERT is not valid !!! */
+      ok = 0;
+      break;
     case X509_V_ERR_DEPTH_ZERO_SELF_SIGNED_CERT:
     case X509_V_ERR_DEPTH_ZERO_SELF_SIGNED_CERT:
+      /* Unsure if we should handle that this way */
       ok = 1;
       ok = 1;
+      break;
     }
   }
   return ok;
     }
   }
   return ok;
@@ -199,7 +140,7 @@ ssl_printerrors (void)
   unsigned long curerr = 0;
   char errbuff[1024];
   memset(errbuff, 0, sizeof(errbuff));
   unsigned long curerr = 0;
   char errbuff[1024];
   memset(errbuff, 0, sizeof(errbuff));
-  for (curerr = ERR_get_error (); curerr; curerr = ERR_get_error ())
+  while ( 0 != (curerr = ERR_get_error ()))
     {
       DEBUGP (("OpenSSL: %s\n", ERR_error_string (curerr, errbuff)));
       ++ocerr;
     {
       DEBUGP (("OpenSSL: %s\n", ERR_error_string (curerr, errbuff)));
       ++ocerr;
@@ -207,6 +148,156 @@ ssl_printerrors (void)
   return ocerr;
 }
 
   return ocerr;
 }
 
+/* Creates a SSL Context and sets some defaults for it */
+uerr_t
+init_ssl (SSL_CTX **ctx)
+{
+  SSL_METHOD *meth = NULL;
+  int verify;
+  int can_validate;
+  SSL_library_init ();
+  SSL_load_error_strings ();
+  SSLeay_add_all_algorithms ();
+  SSLeay_add_ssl_algorithms ();
+  switch (opt.sslprotocol)
+    {
+      default:
+       meth = SSLv23_client_method ();
+       break;
+      case 1 :
+       meth = SSLv2_client_method ();
+       break;
+      case 2 :
+       meth = SSLv3_client_method ();
+       break;
+      case 3 :
+       meth = TLSv1_client_method ();
+       break;
+    }
+  if (meth == NULL)
+    {
+      ssl_printerrors ();
+      return SSLERRCTXCREATE;
+    }
+
+  *ctx = SSL_CTX_new (meth);
+  if (meth == NULL)
+    {
+      ssl_printerrors ();
+      return SSLERRCTXCREATE;
+    }
+  /* Can we validate the server Cert ? */
+  if (opt.sslcadir != NULL || opt.sslcafile != NULL)
+    {
+      SSL_CTX_load_verify_locations (*ctx, opt.sslcafile, opt.sslcadir);
+      can_validate = 1;
+    }
+  else
+    {
+      can_validate = 0;
+    }
+
+  if (!opt.sslcheckcert)
+    {
+      /* check cert but ignore error, do not break handshake on error */
+      verify = SSL_VERIFY_NONE;
+    }
+  else
+    {
+      if (!can_validate)
+       {
+         logprintf (LOG_NOTQUIET, "Warrining validation of Server Cert not possible!\n");
+         verify = SSL_VERIFY_NONE;
+       }
+     else
+       {
+         /* break handshake if server cert is not valid but allow NO-Cert mode */
+         verify = SSL_VERIFY_PEER;
+       }
+    }
+
+  SSL_CTX_set_verify (*ctx, verify, verify_callback);
+
+  if (opt.sslcertfile != NULL || opt.sslcertkey != NULL)
+    {
+      int ssl_cert_type;
+      if (!opt.sslcerttype)
+       ssl_cert_type = SSL_FILETYPE_PEM;
+      else
+       ssl_cert_type = SSL_FILETYPE_ASN1;
+
+      if (opt.sslcertkey == NULL) 
+       opt.sslcertkey = opt.sslcertfile;
+      if (opt.sslcertfile == NULL)
+       opt.sslcertfile = opt.sslcertkey; 
+
+      if (SSL_CTX_use_certificate_file (*ctx, opt.sslcertfile, ssl_cert_type) <= 0)
+       {
+         ssl_printerrors ();
+         return SSLERRCERTFILE;
+       }
+      if (SSL_CTX_use_PrivateKey_file  (*ctx, opt.sslcertkey , ssl_cert_type) <= 0)
+       {
+         ssl_printerrors ();
+         return SSLERRCERTKEY;
+       }
+    }
+
+  return 0; /* Succeded */
+}
+
+void
+shutdown_ssl (SSL* con)
+{
+  if (con == NULL)
+    return;
+  if (0==SSL_shutdown (con))
+    SSL_shutdown (con);
+  SSL_free (con);
+}
+
+/* Sets up a SSL structure and performs the handshake on fd 
+   Returns 0 if everything went right
+   Returns 1 if something went wrong ----- TODO: More exit codes
+*/
+int
+connect_ssl (SSL **con, SSL_CTX *ctx, int fd) 
+{
+  if (NULL == (*con = SSL_new (ctx)))
+    {
+      ssl_printerrors ();
+      return 1;
+    }
+  if (!SSL_set_fd (*con, fd))
+    {
+      ssl_printerrors ();
+      return 1;
+    }
+  SSL_set_connect_state (*con);
+  switch (SSL_connect (*con))
+    {
+      case 1 : 
+       return (*con)->state != SSL_ST_OK;
+      default:
+        ssl_printerrors ();
+       shutdown_ssl (*con);
+       *con = NULL;
+       return 1;
+      case 0 :
+        ssl_printerrors ();
+       SSL_free (*con);
+               *con = NULL;
+       return 1;
+    }
+  return 0;
+}
+
+void
+free_ssl_ctx (SSL_CTX * ctx)
+{
+  SSL_CTX_free (ctx);
+}
+
 /* SSL version of iread.  Only exchanged read for SSL_read Read at
    most LEN bytes from FD, storing them to BUF. */
 
 /* SSL version of iread.  Only exchanged read for SSL_read Read at
    most LEN bytes from FD, storing them to BUF. */
 
index d54c1613f5c70fce83d1c75a4fac0e7cf0c6ed29..2255b29d8e429128b85715d1f43544a8e5bf34b4 100644 (file)
@@ -185,8 +185,13 @@ static struct {
   { "spanhosts",       &opt.spanhost,          cmd_boolean },
   { "spider",          &opt.spider,            cmd_boolean },
 #ifdef HAVE_SSL
   { "spanhosts",       &opt.spanhost,          cmd_boolean },
   { "spider",          &opt.spider,            cmd_boolean },
 #ifdef HAVE_SSL
+  { "sslcadir",                &opt.sslcadir,          cmd_directory },
+  { "sslcafile",       &opt.sslcafile,         cmd_file },
   { "sslcertfile",     &opt.sslcertfile,       cmd_file },
   { "sslcertkey",      &opt.sslcertkey,        cmd_file },
   { "sslcertfile",     &opt.sslcertfile,       cmd_file },
   { "sslcertkey",      &opt.sslcertkey,        cmd_file },
+  { "sslcerttype",     &opt.sslcerttype,       cmd_number },
+  { "sslcheckcert",    &opt.sslcheckcert,      cmd_number },
+  { "sslprotocol",     &opt.sslprotocol,       cmd_number },
 #endif /* HAVE_SSL */
   { "timeout",         &opt.timeout,           cmd_time },
   { "timestamping",    &opt.timestamping,      cmd_boolean },
 #endif /* HAVE_SSL */
   { "timeout",         &opt.timeout,           cmd_time },
   { "timestamping",    &opt.timestamping,      cmd_boolean },
index bbf4a37d07630387d741be6a97f1cab3e37e2f9d..4370f3b8dd4a4ce4319e06a80d2c6d3a746ee863 100644 (file)
@@ -1,5 +1,5 @@
 /* Command line parsing.
 /* Command line parsing.
-   Copyright (C) 1995, 1996, 1997, 1998, 2000, 2001
+   Copyright (C) 1995, 1996, 1997, 1998, 2000, 2001, 2002
    Free Software Foundation, Inc.
 
 This file is part of GNU Wget.
    Free Software Foundation, Inc.
 
 This file is part of GNU Wget.
@@ -148,13 +148,9 @@ Logging and input file:\n\
   -i,  --input-file=FILE      download URLs found in FILE.\n\
   -F,  --force-html           treat input file as HTML.\n\
   -B,  --base=URL             prepends URL to relative links in -F -i file.\n\
   -i,  --input-file=FILE      download URLs found in FILE.\n\
   -F,  --force-html           treat input file as HTML.\n\
   -B,  --base=URL             prepends URL to relative links in -F -i file.\n\
-       --sslcertfile=FILE     optional client certificate.\n\
-       --sslcertkey=KEYFILE   optional keyfile for this certificate.\n\
-       --egd-file=FILE        file name of the EGD socket.\n\
-\n"), stdout);
+\n"),stdout);
   fputs (_("\
 Download:\n\
   fputs (_("\
 Download:\n\
-       --bind-address=ADDRESS   bind to ADDRESS (hostname or IP) on local host.\n\
   -t,  --tries=NUMBER           set number of retries to NUMBER (0 unlimits).\n\
   -O   --output-document=FILE   write documents to FILE.\n\
   -nc, --no-clobber             don\'t clobber existing files or use .# suffixes.\n\
   -t,  --tries=NUMBER           set number of retries to NUMBER (0 unlimits).\n\
   -O   --output-document=FILE   write documents to FILE.\n\
   -nc, --no-clobber             don\'t clobber existing files or use .# suffixes.\n\
@@ -169,6 +165,7 @@ Download:\n\
        --random-wait            wait from 0...2*WAIT secs between retrievals.\n\
   -Y,  --proxy=on/off           turn proxy on or off.\n\
   -Q,  --quota=NUMBER           set retrieval quota to NUMBER.\n\
        --random-wait            wait from 0...2*WAIT secs between retrievals.\n\
   -Y,  --proxy=on/off           turn proxy on or off.\n\
   -Q,  --quota=NUMBER           set retrieval quota to NUMBER.\n\
+       --bind-address=ADDRESS   bind to ADDRESS (hostname or IP) on local host.\n\
        --limit-rate=RATE        limit download rate to RATE.\n\
 \n"), stdout);
   fputs (_("\
        --limit-rate=RATE        limit download rate to RATE.\n\
 \n"), stdout);
   fputs (_("\
@@ -199,6 +196,20 @@ HTTP options:\n\
        --post-data=STRING    use the POST method; send STRING as the data.\n\
        --post-file=FILE      use the POST method; send contents of FILE.\n\
 \n"), stdout);
        --post-data=STRING    use the POST method; send STRING as the data.\n\
        --post-file=FILE      use the POST method; send contents of FILE.\n\
 \n"), stdout);
+#ifdef HAVE_SSL
+  fputs (_("\
+HTTPS (SSL) options:\n\
+       --sslcertfile=FILE     optional client certificate.\n\
+       --sslcertkey=KEYFILE   optional keyfile for this certificate.\n\
+       --egd-file=FILE        file name of the EGD socket.\n\
+       --sslcadir=DIR         dir where hash list of CA's are stured.\n\
+       --sslcafile=FILE       file with bundle of CA's\n\
+       --sslcerttype=0/1      Client-Cert type 0=PEM (default) / 1=ASN1 (DER)\n\
+       --sslcheckcert=0/1     Check the server cert agenst given CA\n\
+       --sslprotocol=0-3      choose SSL protocol; 0=automatic,\n\
+                              1=SSLv2 2=SSLv3 3=TLSv1\n\
+\n"), stdout);
+#endif
   fputs (_("\
 FTP options:\n\
   -nr, --dont-remove-listing   don\'t remove `.listing\' files.\n\
   fputs (_("\
 FTP options:\n\
   -nr, --dont-remove-listing   don\'t remove `.listing\' files.\n\
@@ -208,7 +219,7 @@ FTP options:\n\
 \n"), stdout);
   fputs (_("\
 Recursive retrieval:\n\
 \n"), stdout);
   fputs (_("\
 Recursive retrieval:\n\
-  -r,  --recursive          recursive web-suck -- use with care!\n\
+  -r,  --recursive          recursive download.\n\
   -l,  --level=NUMBER       maximum recursion depth (inf or 0 for infinite).\n\
        --delete-after       delete files locally after downloading them.\n\
   -k,  --convert-links      convert non-relative links to relative.\n\
   -l,  --level=NUMBER       maximum recursion depth (inf or 0 for infinite).\n\
        --delete-after       delete files locally after downloading them.\n\
   -k,  --convert-links      convert non-relative links to relative.\n\
@@ -329,6 +340,11 @@ main (int argc, char *const *argv)
     { "sslcertfile", required_argument, NULL, 158 },
     { "sslcertkey", required_argument, NULL, 159 },
     { "egd-file", required_argument, NULL, 166 },
     { "sslcertfile", required_argument, NULL, 158 },
     { "sslcertkey", required_argument, NULL, 159 },
     { "egd-file", required_argument, NULL, 166 },
+    { "sslcadir",         required_argument, NULL, 169},
+    { "sslcafile",        required_argument, NULL, 170},
+    { "sslcerttype",      required_argument, NULL, 171},
+    { "sslcheckcert",     required_argument, NULL, 172},
+    { "sslprotocol",      required_argument, NULL, 173},
 #endif /* HAVE_SSL */
     { "wait", required_argument, NULL, 'w' },
     { "waitretry", required_argument, NULL, 152 },
 #endif /* HAVE_SSL */
     { "wait", required_argument, NULL, 'w' },
     { "waitretry", required_argument, NULL, 152 },
@@ -552,6 +568,21 @@ GNU General Public License for more details.\n"));
        case 166:
          setval ("egdfile", optarg);
          break;
        case 166:
          setval ("egdfile", optarg);
          break;
+       case 169:
+         setval ("sslcadir", optarg);
+         break;
+       case 170:
+         setval ("sslcafile", optarg);
+         break;
+       case 171:
+         setval ("sslcerttype", optarg);
+         break;
+       case 172:
+         setval ("sslcheckcert", optarg);
+         break;
+       case 173:
+         setval ("sslprotocol", optarg);
+         break;
 #endif /* HAVE_SSL */
        case 167:
          setval ("postdata", optarg);
 #endif /* HAVE_SSL */
        case 167:
          setval ("postdata", optarg);
index c6438602514cab7a96193f310d442033b9a81848..2ecfecad359d8fb329c0265eda8a864046f832bf 100644 (file)
@@ -154,11 +154,16 @@ struct options
                                   necessary to display a page properly. */
   char *bind_address;          /* What local IP address to bind to. */
 #ifdef HAVE_SSL
                                   necessary to display a page properly. */
   char *bind_address;          /* What local IP address to bind to. */
 #ifdef HAVE_SSL
+  char *sslcadir;              /* CA directory (hash files) */
+  char *sslcafile;             /* CA File to use */
   char *sslcertfile;           /* external client cert to use. */
   char *sslcertkey;            /* the keyfile for this certificate
                                   (if not internal) included in the
                                   certfile. */
   char *sslcertfile;           /* external client cert to use. */
   char *sslcertkey;            /* the keyfile for this certificate
                                   (if not internal) included in the
                                   certfile. */
+  int   sslcerttype;           /* 0 = PEM / 1=ASN1 (DER) */
+  int   sslcheckcert;          /* 0 do not check / 1 check server cert */
   char *sslegdsock;             /* optional socket of the egd daemon */
   char *sslegdsock;             /* optional socket of the egd daemon */
+  int   sslprotocol;           /* 0 = auto / 1 = v2 / 2 = v3 / 3 = TLSv1 */
 #endif /* HAVE_SSL */
 
   int   cookies;
 #endif /* HAVE_SSL */
 
   int   cookies;