diff --git a/demos/tunala/cb.c b/demos/tunala/cb.c index ebc69bc690..37a474e37e 100644 --- a/demos/tunala/cb.c +++ b/demos/tunala/cb.c @@ -4,6 +4,11 @@ /* For callbacks generating output, here are their file-descriptors. */ 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; /* This function is largely borrowed from the one used in OpenSSL's "s_client" * and "s_server" utilities. */ @@ -21,12 +26,12 @@ void cb_ssl_info(SSL *s, int where, int ret) str2 = SSL_state_string_long(s); if (where & SSL_CB_LOOP) - fprintf(stderr, "%s:%s\n", str1, str2); + fprintf(fp_cb_ssl_info, "%s:%s\n", str1, str2); else if (where & SSL_CB_EXIT) { if (ret == 0) - fprintf(stderr, "%s:failed in %s\n", str1, str2); + fprintf(fp_cb_ssl_info, "%s:failed in %s\n", str1, str2); else if (ret < 0) - fprintf(stderr, "%s:error in %s\n", str1, str2); + fprintf(fp_cb_ssl_info, "%s:error in %s\n", str1, str2); } } @@ -35,5 +40,62 @@ void cb_ssl_info_set_output(FILE *fp) fp_cb_ssl_info = fp; } +/* Stolen wholesale from apps/s_cb.c :-) */ +int cb_ssl_verify(int ok, X509_STORE_CTX *ctx) +{ + char buf[256]; + X509 *err_cert; + int err, depth; + BIO *bio; + + if(!fp_cb_ssl_verify) + return ok; + /* There's no FILE* version of ASN1_TIME_print */ + bio = BIO_new_fp(fp_cb_ssl_verify, BIO_NOCLOSE); + err_cert = X509_STORE_CTX_get_current_cert(ctx); + err = X509_STORE_CTX_get_error(ctx); + depth = X509_STORE_CTX_get_error_depth(ctx); + + X509_NAME_oneline(X509_get_subject_name(err_cert), buf, 256); + fprintf(fp_cb_ssl_verify, "depth=%d %s\n", depth, buf); + 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; + } + } + switch (ctx->error) { + case X509_V_ERR_UNABLE_TO_GET_ISSUER_CERT: + X509_NAME_oneline(X509_get_issuer_name(ctx->current_cert), + buf, 256); + fprintf(fp_cb_ssl_verify, "issuer= %s\n", buf); + break; + case X509_V_ERR_CERT_NOT_YET_VALID: + case X509_V_ERR_ERROR_IN_CERT_NOT_BEFORE_FIELD: + fprintf(fp_cb_ssl_verify, "notBefore="); + ASN1_TIME_print(bio, X509_get_notBefore(ctx->current_cert)); + fprintf(fp_cb_ssl_verify, "\n"); + break; + case X509_V_ERR_CERT_HAS_EXPIRED: + case X509_V_ERR_ERROR_IN_CERT_NOT_AFTER_FIELD: + fprintf(fp_cb_ssl_verify, "notAfter="); + ASN1_TIME_print(bio, X509_get_notAfter(ctx->current_cert)); + fprintf(fp_cb_ssl_verify, "\n"); + break; + } + fprintf(fp_cb_ssl_verify, "verify return:%d\n",ok); + return ok; +} + +void cb_ssl_verify_set_output(FILE *fp) +{ + fp_cb_ssl_verify = fp; +} + #endif /* !defined(NO_OPENSSL) */ diff --git a/demos/tunala/tunala.c b/demos/tunala/tunala.c index bb90338582..30c71d837d 100644 --- a/demos/tunala/tunala.c +++ b/demos/tunala/tunala.c @@ -68,7 +68,8 @@ 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); + const char *cipher_list, int out_state, int out_verify, + int verify_mode); 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); @@ -95,6 +96,8 @@ 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 const char *helpstring = "\n'Tunala' (A tunneler with a New Zealand accent)\n" @@ -109,6 +112,10 @@ static const char *helpstring = " -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" @@ -185,6 +192,8 @@ int main(int argc, char *argv[]) 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; /* Parse command-line arguments */ next_arg: @@ -258,6 +267,18 @@ next_arg: } else if(strcmp(*argv, "-out_state") == 0) { out_state = 1; goto next_arg; + } else if(strcmp(*argv, "-out_verify") == 0) { + out_verify = 1; + goto next_arg; + } else if(strcmp(*argv, "-v_peer") == 0) { + verify_mode |= SSL_VERIFY_PEER; + goto next_arg; + } else if(strcmp(*argv, "-v_strict") == 0) { + verify_mode |= SSL_VERIFY_FAIL_IF_NO_PEER_CERT; + goto next_arg; + } else if(strcmp(*argv, "-v_once") == 0) { + verify_mode |= SSL_VERIFY_CLIENT_ONCE; + goto next_arg; } else if((strcmp(*argv, "-h") == 0) || (strcmp(*argv, "-help") == 0) || (strcmp(*argv, "-?") == 0)) { @@ -273,7 +294,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)) == NULL) + cacert, cert, key, cipher_list, out_state, out_verify, + verify_mode)) == 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", @@ -360,7 +382,8 @@ main_loop: 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) + const char *cipher_list, int out_state, int out_verify, + int verify_mode) { SSL_CTX *ctx, *ret = NULL; SSL_METHOD *meth; @@ -467,12 +490,16 @@ static SSL_CTX *initialise_ssl_ctx(int server_mode, const char *engine_id, fprintf(stderr, "Info, operating with default cipher list\n"); /* out_state (output of SSL handshake states to screen). */ - if(out_state) { - SSL_CTX_set_info_callback(ctx, cb_ssl_info); + if(out_state) cb_ssl_info_set_output(stderr); - } + + /* out_verify & verify_mode */ + if(out_verify) + cb_ssl_verify_set_output(stderr); /* Success! */ + SSL_CTX_set_info_callback(ctx, cb_ssl_info); + SSL_CTX_set_verify(ctx, verify_mode, cb_ssl_verify); ret = ctx; err: if(!ret) { diff --git a/demos/tunala/tunala.h b/demos/tunala/tunala.h index 2f4040462b..5d35f9ff01 100644 --- a/demos/tunala/tunala.h +++ b/demos/tunala/tunala.h @@ -93,6 +93,8 @@ void buffer_to_BIO(buffer_t *buf, BIO *bio); /* Callbacks */ 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); #endif /* !defined(NO_OPENSSL) */ #endif /* !defined(NO_BUFFER) */