From a9376dbff94c9ddd06639264389ae9777bcb2d30 Mon Sep 17 00:00:00 2001 From: Geoff Thorpe Date: Wed, 29 Nov 2000 19:22:54 +0000 Subject: [PATCH 1/1] More little changes to the tunala demo; * A little bit of code-cleanup * Reformat the usage string (not so wide) * Allow adding an alternative (usually DSA) cert/key pair (a la s_server) * Allow control over cert-chain verify depth --- demos/tunala/cb.c | 20 ++-- demos/tunala/tunala.c | 235 +++++++++++++++++++++++++++--------------- demos/tunala/tunala.h | 1 + 3 files changed, 166 insertions(+), 90 deletions(-) diff --git a/demos/tunala/cb.c b/demos/tunala/cb.c index 37a474e37e..4633c0993e 100644 --- a/demos/tunala/cb.c +++ b/demos/tunala/cb.c @@ -7,8 +7,8 @@ static FILE *fp_cb_ssl_info = NULL; static FILE *fp_cb_ssl_verify = NULL; /* Other static rubbish (to mirror s_cb.c where required) */ -static int verify_depth = 10; -static int verify_error = X509_V_OK; +static int int_verify_depth = 10; +static int int_verify_error = X509_V_OK; /* This function is largely borrowed from the one used in OpenSSL's "s_client" * and "s_server" utilities. */ @@ -61,13 +61,10 @@ int cb_ssl_verify(int ok, X509_STORE_CTX *ctx) if(!ok) { fprintf(fp_cb_ssl_verify,"verify error:num=%d:%s\n",err, X509_verify_cert_error_string(err)); - if(verify_depth >= depth) { - ok = 1; - verify_error = X509_V_OK; - } else { - ok=0; - verify_error = X509_V_ERR_CERT_CHAIN_TOO_LONG; - } + if((int)int_verify_depth >= depth) + int_verify_error = err; + else + int_verify_error = X509_V_ERR_CERT_CHAIN_TOO_LONG; } switch (ctx->error) { case X509_V_ERR_UNABLE_TO_GET_ISSUER_CERT: @@ -97,5 +94,10 @@ void cb_ssl_verify_set_output(FILE *fp) fp_cb_ssl_verify = fp; } +void cb_ssl_verify_set_depth(unsigned int verify_depth) +{ + int_verify_depth = verify_depth; +} + #endif /* !defined(NO_OPENSSL) */ diff --git a/demos/tunala/tunala.c b/demos/tunala/tunala.c index 30c71d837d..19d7d1150d 100644 --- a/demos/tunala/tunala.c +++ b/demos/tunala/tunala.c @@ -68,8 +68,9 @@ typedef struct _tunala_world_t { static SSL_CTX *initialise_ssl_ctx(int server_mode, const char *engine_id, const char *CAfile, const char *cert, const char *key, - const char *cipher_list, int out_state, int out_verify, - int verify_mode); + const char *dcert, const char *dkey, const char *cipher_list, + int out_state, int out_verify, int verify_mode, + unsigned int verify_depth); static void selector_init(tunala_selector_t *selector); static void selector_add_listener(tunala_selector_t *selector, int fd); static void selector_add_tunala(tunala_selector_t *selector, tunala_item_t *t); @@ -92,34 +93,40 @@ static int def_max_tunnels = 50; static const char *def_cacert = NULL; static const char *def_cert = NULL; static const char *def_key = NULL; +static const char *def_dcert = NULL; +static const char *def_dkey = NULL; static const char *def_engine_id = NULL; static int def_server_mode = 0; static const char *def_cipher_list = NULL; static int def_out_state = 0; static int def_out_verify = 0; static int def_verify_mode = 0; +static unsigned int def_verify_depth = 10; static const char *helpstring = - "\n'Tunala' (A tunneler with a New Zealand accent)\n" - "Usage: tunala [options], where options are from;\n" - " -listen [host:] (default = 127.0.0.1:8080)\n" - " -proxy : (default = 127.0.0.1:443)\n" - " -maxtunnels (default = 50)\n" - " -cacert (default = NULL)\n" - " -cert (default = NULL)\n" - " -key (default = whatever '-cert' is)\n" - " -engine (default = NULL)\n" - " -server <0|1> (default = 0, ie. an SSL client)\n" - " -cipher (specifies cipher list to use)\n" - " -out_state (prints SSL handshake states)\n" - " -out_verify (prints certificate verification states)\n" - " -v_peer (verify the peer certificate)\n" - " -v_strict (do not continue if peer validation fails)\n" - " -v_once (no verification in renegotiates)\n" - " - (displays this help screen)\n" - "NB: It is recommended to specify a cert+key when operating as an\n" - "SSL server. If you only specify '-cert', the same file must\n" - "contain a matching private key.\n"; +"\n'Tunala' (A tunneler with a New Zealand accent)\n" +"Usage: tunala [options], where options are from;\n" +" -listen [host:] (default = 127.0.0.1:8080)\n" +" -proxy : (default = 127.0.0.1:443)\n" +" -maxtunnels (default = 50)\n" +" -cacert (default = NULL)\n" +" -cert (default = NULL)\n" +" -key (default = whatever '-cert' is)\n" +" -dcert (usually for DSA, default = NULL)\n" +" -dkey (usually for DSA, default = whatever '-dcert' is)\n" +" -engine (default = NULL)\n" +" -server <0|1> (default = 0, ie. an SSL client)\n" +" -cipher (specifies cipher list to use)\n" +" -out_state (prints SSL handshake states)\n" +" -out_verify (prints certificate verification states)\n" +" -v_peer (verify the peer certificate)\n" +" -v_strict (do not continue if peer doesn't authenticate)\n" +" -v_once (no verification in renegotiates)\n" +" -v_depth (limit certificate chain depth, default = 10)\n" +" - (displays this help screen)\n" +"NB: It is recommended to specify a cert+key when operating as an\n" +"SSL server. If you only specify '-cert', the same file must\n" +"contain a matching private key.\n"; static int usage(const char *errstr, int isunknownarg) { @@ -173,6 +180,20 @@ static int parse_server_mode(const char *s, int *servermode) return 1; } +static int parse_verify_depth(const char *s, unsigned int *verify_depth) +{ + unsigned long l; + char *temp; + l = strtoul(s, &temp, 10); + if((temp == s) || (*temp != '\0') || (l < 1) || (l > 50)) { + fprintf(stderr, "Error, '%s' is an invalid value for " + "verify_depth\n", s); + return 0; + } + *verify_depth = (unsigned int)l; + return 1; +} + int main(int argc, char *argv[]) { unsigned int loop; @@ -188,12 +209,15 @@ int main(int argc, char *argv[]) const char *cacert = def_cacert; const char *cert = def_cert; const char *key = def_key; + const char *dcert = def_dcert; + const char *dkey = def_dkey; const char *engine_id = def_engine_id; int server_mode = def_server_mode; const char *cipher_list = def_cipher_list; int out_state = def_out_state; int out_verify = def_out_verify; int verify_mode = def_verify_mode; + unsigned int verify_depth = def_verify_depth; /* Parse command-line arguments */ next_arg: @@ -245,6 +269,24 @@ next_arg: else key = *argv; goto next_arg; + } else if(strcmp(*argv, "-dcert") == 0) { + if(argc < 2) + return usage("-dcert requires an argument", 0); + argc--; argv++; + if(strcmp(*argv, "NULL") == 0) + dcert = NULL; + else + dcert = *argv; + goto next_arg; + } else if(strcmp(*argv, "-dkey") == 0) { + if(argc < 2) + return usage("-dkey requires an argument", 0); + argc--; argv++; + if(strcmp(*argv, "NULL") == 0) + dkey = NULL; + else + dkey = *argv; + goto next_arg; } else if(strcmp(*argv, "-engine") == 0) { if(argc < 2) return usage("-engine requires an argument", 0); @@ -279,6 +321,13 @@ next_arg: } else if(strcmp(*argv, "-v_once") == 0) { verify_mode |= SSL_VERIFY_CLIENT_ONCE; goto next_arg; + } else if(strcmp(*argv, "-v_depth") == 0) { + if(argc < 2) + return usage("-v_depth requires an argument", 0); + argc--; argv++; + if(!parse_verify_depth(*argv, &verify_depth)) + return 1; + goto next_arg; } else if((strcmp(*argv, "-h") == 0) || (strcmp(*argv, "-help") == 0) || (strcmp(*argv, "-?") == 0)) { @@ -294,8 +343,8 @@ next_arg: err_str0("ip_initialise succeeded"); /* Create the SSL_CTX */ if((world.ssl_ctx = initialise_ssl_ctx(server_mode, engine_id, - cacert, cert, key, cipher_list, out_state, out_verify, - verify_mode)) == NULL) + cacert, cert, key, dcert, dkey, cipher_list, out_state, + out_verify, verify_mode, verify_depth)) == NULL) return err_str1("initialise_ssl_ctx(engine_id=%s) failed", (engine_id == NULL) ? "NULL" : engine_id); err_str1("initialise_ssl_ctx(engine_id=%s) succeeded", @@ -380,55 +429,13 @@ main_loop: /* OpenSSL bits */ /****************/ -static SSL_CTX *initialise_ssl_ctx(int server_mode, const char *engine_id, - const char *CAfile, const char *cert, const char *key, - const char *cipher_list, int out_state, int out_verify, - int verify_mode) +static int ctx_set_cert(SSL_CTX *ctx, const char *cert, const char *key) { - SSL_CTX *ctx, *ret = NULL; - SSL_METHOD *meth; - ENGINE *e = NULL; FILE *fp = NULL; X509 *x509 = NULL; EVP_PKEY *pkey = NULL; + int toret = 0; /* Assume an error */ - OpenSSL_add_ssl_algorithms(); - SSL_load_error_strings(); - - meth = (server_mode ? SSLv23_server_method() : SSLv23_client_method()); - if(meth == NULL) - goto err; - if(engine_id) { - if((e = ENGINE_by_id(engine_id)) == NULL) { - fprintf(stderr, "Error obtaining '%s' engine, openssl " - "errors follow\n", engine_id); - goto err; - } - if(!ENGINE_set_default(e, ENGINE_METHOD_ALL)) { - fprintf(stderr, "Error assigning '%s' engine, openssl " - "errors follow\n", engine_id); - goto err; - } - ENGINE_free(e); - } - if((ctx = SSL_CTX_new(meth)) == NULL) - goto err; - /* cacert */ - if(CAfile) { - if(!X509_STORE_load_locations(SSL_CTX_get_cert_store(ctx), - CAfile, NULL)) { - fprintf(stderr, "Error loading CA cert(s) in '%s'\n", - CAfile); - goto err; - } - fprintf(stderr, "Info, operating with CA cert(s) in '%s'\n", - CAfile); - } else - fprintf(stderr, "Info, operating without a CA cert(-list)\n"); - if(!SSL_CTX_set_default_verify_paths(ctx)) { - fprintf(stderr, "Error setting default verify paths\n"); - goto err; - } /* cert */ if(cert) { if((fp = fopen(cert, "r")) == NULL) { @@ -445,19 +452,23 @@ static SSL_CTX *initialise_ssl_ctx(int server_mode, const char *engine_id, cert); goto err; } - fprintf(stderr, "Info, operating with cert in '%s'\n", cert); + /* Clear the FILE* for reuse in the "key" code */ fclose(fp); fp = NULL; + fprintf(stderr, "Info, operating with cert in '%s'\n", cert); /* If a cert was given without matching key, we assume the same * file contains the required key. */ if(!key) key = cert; - } else - if(key) { + } else { + if(key) fprintf(stderr, "Error, can't specify a key without a " "corresponding certificate\n"); - goto err; - } + else + fprintf(stderr, "Error, ctx_set_cert called with " + "NULLs!\n"); + goto err; + } /* key */ if(key) { if((fp = fopen(key, "r")) == NULL) { @@ -477,6 +488,71 @@ static SSL_CTX *initialise_ssl_ctx(int server_mode, const char *engine_id, fprintf(stderr, "Info, operating with key in '%s'\n", key); } else fprintf(stderr, "Info, operating without a cert or key\n"); + /* Success */ + toret = 1; err: + if(x509) + X509_free(x509); + if(pkey) + EVP_PKEY_free(pkey); + if(fp) + fclose(fp); + return toret; +} + +static SSL_CTX *initialise_ssl_ctx(int server_mode, const char *engine_id, + const char *CAfile, const char *cert, const char *key, + const char *dcert, const char *dkey, const char *cipher_list, + int out_state, int out_verify, int verify_mode, + unsigned int verify_depth) +{ + SSL_CTX *ctx, *ret = NULL; + SSL_METHOD *meth; + ENGINE *e = NULL; + + OpenSSL_add_ssl_algorithms(); + SSL_load_error_strings(); + + meth = (server_mode ? SSLv23_server_method() : SSLv23_client_method()); + if(meth == NULL) + goto err; + if(engine_id) { + if((e = ENGINE_by_id(engine_id)) == NULL) { + fprintf(stderr, "Error obtaining '%s' engine, openssl " + "errors follow\n", engine_id); + goto err; + } + if(!ENGINE_set_default(e, ENGINE_METHOD_ALL)) { + fprintf(stderr, "Error assigning '%s' engine, openssl " + "errors follow\n", engine_id); + goto err; + } + ENGINE_free(e); + } + if((ctx = SSL_CTX_new(meth)) == NULL) + goto err; + /* cacert */ + if(CAfile) { + if(!X509_STORE_load_locations(SSL_CTX_get_cert_store(ctx), + CAfile, NULL)) { + fprintf(stderr, "Error loading CA cert(s) in '%s'\n", + CAfile); + goto err; + } + fprintf(stderr, "Info, operating with CA cert(s) in '%s'\n", + CAfile); + } else + fprintf(stderr, "Info, operating without a CA cert(-list)\n"); + if(!SSL_CTX_set_default_verify_paths(ctx)) { + fprintf(stderr, "Error setting default verify paths\n"); + goto err; + } + + /* cert and key */ + if((cert || key) && !ctx_set_cert(ctx, cert, key)) + goto err; + /* dcert and dkey */ + if((dcert || dkey) && !ctx_set_cert(ctx, dcert, dkey)) + goto err; /* cipher_list */ if(cipher_list) { @@ -493,11 +569,14 @@ static SSL_CTX *initialise_ssl_ctx(int server_mode, const char *engine_id, if(out_state) cb_ssl_info_set_output(stderr); - /* out_verify & verify_mode */ + /* out_verify */ if(out_verify) cb_ssl_verify_set_output(stderr); - /* Success! */ + /* verify_depth */ + cb_ssl_verify_set_depth(verify_depth); + + /* Success! (includes setting verify_mode) */ SSL_CTX_set_info_callback(ctx, cb_ssl_info); SSL_CTX_set_verify(ctx, verify_mode, cb_ssl_verify); ret = ctx; @@ -507,12 +586,6 @@ err: if(ctx) SSL_CTX_free(ctx); } - if(fp) - fclose(fp); - if(x509) - X509_free(x509); - if(pkey) - EVP_PKEY_free(pkey); return ret; } diff --git a/demos/tunala/tunala.h b/demos/tunala/tunala.h index 5d35f9ff01..1aaa3e0ab7 100644 --- a/demos/tunala/tunala.h +++ b/demos/tunala/tunala.h @@ -95,6 +95,7 @@ void cb_ssl_info(SSL *s, int where, int ret); void cb_ssl_info_set_output(FILE *fp); /* Called if output should be sent too */ int cb_ssl_verify(int ok, X509_STORE_CTX *ctx); void cb_ssl_verify_set_output(FILE *fp); +void cb_ssl_verify_set_depth(unsigned int verify_depth); #endif /* !defined(NO_OPENSSL) */ #endif /* !defined(NO_BUFFER) */ -- 2.34.1