[svn] Implement several SSL features.

- 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>.
This commit is contained in:
hniksic 2002-04-20 19:26:48 -07:00
parent bf018d5721
commit 91a190a770
5 changed files with 213 additions and 72 deletions

View 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

View 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. */

View 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 },

View 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);

View 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;