]> 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
index f03f9c56a50e21b89c9a1b85f316acaff04bf73c..d9515130280f47e05196e562abb29a54ce8cc8ec 100644 (file)
@@ -50,8 +50,6 @@ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.  */
 extern int errno;
 #endif
 
-static int verify_callback PARAMS ((int, X509_STORE_CTX *));
-
 void
 ssl_init_prng (void)
 {
@@ -112,68 +110,6 @@ ssl_init_prng (void)
 #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)
 {
@@ -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:
+      /* This mean the CERT is not valid !!! */
+      ok = 0;
+      break;
     case X509_V_ERR_DEPTH_ZERO_SELF_SIGNED_CERT:
+      /* Unsure if we should handle that this way */
       ok = 1;
+      break;
     }
   }
   return ok;
@@ -199,7 +140,7 @@ ssl_printerrors (void)
   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;
@@ -207,6 +148,156 @@ ssl_printerrors (void)
   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. */
 
index d54c1613f5c70fce83d1c75a4fac0e7cf0c6ed29..2255b29d8e429128b85715d1f43544a8e5bf34b4 100644 (file)
@@ -185,8 +185,13 @@ static struct {
   { "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 },
+  { "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 },
index bbf4a37d07630387d741be6a97f1cab3e37e2f9d..4370f3b8dd4a4ce4319e06a80d2c6d3a746ee863 100644 (file)
@@ -1,5 +1,5 @@
 /* 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.
@@ -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\
-       --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\
-       --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\
@@ -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\
+       --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 (_("\
@@ -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);
+#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\
@@ -208,7 +219,7 @@ FTP options:\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\
@@ -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 },
+    { "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 },
@@ -552,6 +568,21 @@ GNU General Public License for more details.\n"));
        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);
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
+  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. */
+  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 */
+  int   sslprotocol;           /* 0 = auto / 1 = v2 / 2 = v3 / 3 = TLSv1 */
 #endif /* HAVE_SSL */
 
   int   cookies;