From b762acadeb09618a63140e30fb385ea106730635 Mon Sep 17 00:00:00 2001 From: "Dr. Stephen Henson" Date: Wed, 26 Dec 2012 15:21:53 +0000 Subject: Add support for certificate stores in CERT structure. This makes it possible to have different stores per SSL structure or one store in the parent SSL_CTX. Include distint stores for certificate chain verification and chain building. New ctrl SSL_CTRL_BUILD_CERT_CHAIN to build and store a certificate chain in CERT structure: returing an error if the chain cannot be built: this will allow applications to test if a chain is correctly configured. Note: if the CERT based stores are not set then the parent SSL_CTX store is used to retain compatibility with existing behaviour. (backport from HEAD) --- apps/s_apps.h | 2 +- apps/s_cb.c | 32 ++++++++++++++++++++++---- apps/s_client.c | 8 +++++-- apps/s_server.c | 71 ++++++++++++++++++++++++++++++++++++++++++++++++++++++--- 4 files changed, 103 insertions(+), 10 deletions(-) (limited to 'apps') diff --git a/apps/s_apps.h b/apps/s_apps.h index c04e2d3611..c7e6926a27 100644 --- a/apps/s_apps.h +++ b/apps/s_apps.h @@ -155,7 +155,7 @@ int MS_CALLBACK verify_callback(int ok, X509_STORE_CTX *ctx); #ifdef HEADER_SSL_H int set_cert_stuff(SSL_CTX *ctx, char *cert_file, char *key_file); int set_cert_key_stuff(SSL_CTX *ctx, X509 *cert, EVP_PKEY *key, - STACK_OF(X509) *chain); + STACK_OF(X509) *chain, int build_chain); # ifndef OPENSSL_NO_TLSEXT int set_cert_key_and_authz(SSL_CTX *ctx, X509 *cert, EVP_PKEY *key, unsigned char *authz, size_t authz_length); diff --git a/apps/s_cb.c b/apps/s_cb.c index 6e26d43de4..f994fbd93b 100644 --- a/apps/s_cb.c +++ b/apps/s_cb.c @@ -251,7 +251,7 @@ int set_cert_stuff(SSL_CTX *ctx, char *cert_file, char *key_file) } int set_cert_key_stuff(SSL_CTX *ctx, X509 *cert, EVP_PKEY *key, - STACK_OF(X509) *chain) + STACK_OF(X509) *chain, int build_chain) { if (cert == NULL) return 1; @@ -282,6 +282,13 @@ int set_cert_key_stuff(SSL_CTX *ctx, X509 *cert, EVP_PKEY *key, ERR_print_errors(bio_err); return 0; } + if (!chain && build_chain && !SSL_CTX_build_cert_chain(ctx, 0)) + { + BIO_printf(bio_err,"error building certificate chain\n"); + ERR_print_errors(bio_err); + return 0; + } + return 1; } @@ -1125,6 +1132,7 @@ struct ssl_excert_st X509 *cert; EVP_PKEY *key; STACK_OF(X509) *chain; + int build_chain; struct ssl_excert_st *next, *prev; }; @@ -1152,7 +1160,16 @@ static int set_cert_cb(SSL *ssl, void *arg) { SSL_use_certificate(ssl, exc->cert); SSL_use_PrivateKey(ssl, exc->key); - if (exc->chain) + /* NB: we wouldn't normally do this as it is + * not efficient building chains on each connection + * better to cache the chain in advance. + */ + if (exc->build_chain) + { + if (!SSL_build_cert_chain(ssl, 0)) + return 0; + } + else if (exc->chain) SSL_set1_chain(ssl, exc->chain); } exc = exc->prev; @@ -1178,6 +1195,7 @@ static int ssl_excert_prepend(SSL_EXCERT **pexc) exc->key = NULL; exc->chain = NULL; exc->prev = NULL; + exc->build_chain = 0; exc->next = *pexc; *pexc = exc; @@ -1262,6 +1280,7 @@ int args_excert(char ***pargs, int *pargc, { char *arg = **pargs, *argn = (*pargs)[1]; SSL_EXCERT *exc = *pexc; + int narg = 2; if (!exc) { if (ssl_excert_prepend(&exc)) @@ -1318,6 +1337,11 @@ int args_excert(char ***pargs, int *pargc, } exc->chainfile = argn; } + else if (strcmp(arg,"-xchain_build") == 0) + { + narg = 1; + exc->build_chain = 1; + } else if (strcmp(arg,"-xcertform") == 0) { if (!argn) @@ -1339,10 +1363,10 @@ int args_excert(char ***pargs, int *pargc, else return 0; - (*pargs) += 2; + (*pargs) += narg; if (pargc) - *pargc -= 2; + *pargc -= narg; *pexc = exc; diff --git a/apps/s_client.c b/apps/s_client.c index 999bd2043c..90b6af80cb 100644 --- a/apps/s_client.c +++ b/apps/s_client.c @@ -558,6 +558,7 @@ int MAIN(int argc, char **argv) { unsigned int off=0, clr=0; unsigned int cert_flags=0; + int build_chain = 0; SSL *con=NULL; #ifndef OPENSSL_NO_KRB5 KSSL_CTX *kctx; @@ -867,6 +868,8 @@ int MAIN(int argc, char **argv) if (--argc < 1) goto bad; CApath= *(++argv); } + else if (strcmp(*argv,"-build_chain") == 0) + build_chain = 1; else if (strcmp(*argv,"-CAfile") == 0) { if (--argc < 1) goto bad; @@ -1201,8 +1204,6 @@ bad: #endif SSL_CTX_set_verify(ctx,verify,verify_callback); - if (!set_cert_key_stuff(ctx,cert,key, NULL)) - goto end; if ((!SSL_CTX_load_verify_locations(ctx,CAfile,CApath)) || (!SSL_CTX_set_default_verify_paths(ctx))) @@ -1212,6 +1213,9 @@ bad: /* goto end; */ } + if (!set_cert_key_stuff(ctx,cert,key, NULL, build_chain)) + goto end; + #ifndef OPENSSL_NO_TLSEXT if (curves != NULL) if(!SSL_CTX_set1_curves_list(ctx,curves)) { diff --git a/apps/s_server.c b/apps/s_server.c index 92ca0a7f85..cabe0980a6 100644 --- a/apps/s_server.c +++ b/apps/s_server.c @@ -212,6 +212,9 @@ static int init_ssl_connection(SSL *s); static void print_stats(BIO *bp,SSL_CTX *ctx); static int generate_session_id(const SSL *ssl, unsigned char *id, unsigned int *id_len); +static int ssl_load_stores(SSL_CTX *sctx, + const char *vfyCApath, const char *vfyCAfile, + const char *chCApath, const char *chCAfile); #ifndef OPENSSL_NO_DH static DH *load_dh_param(const char *dhfile); static DH *get_dh512(void); @@ -942,6 +945,8 @@ int MAIN(int argc, char *argv[]) int badarg = 0; short port=PORT; char *CApath=NULL,*CAfile=NULL; + char *chCApath=NULL,*chCAfile=NULL; + char *vfyCApath=NULL,*vfyCAfile=NULL; unsigned char *context = NULL; char *dhfile = NULL; #ifndef OPENSSL_NO_ECDH @@ -951,6 +956,7 @@ int MAIN(int argc, char *argv[]) int ret=1; int off=0; unsigned int cert_flags = 0; + int build_chain = 0; int no_tmp_rsa=0,no_dhe=0,no_ecdhe=0,nocert=0; int state=0; const SSL_METHOD *meth=NULL; @@ -1125,6 +1131,16 @@ int MAIN(int argc, char *argv[]) if (--argc < 1) goto bad; CApath= *(++argv); } + else if (strcmp(*argv,"-chainCApath") == 0) + { + if (--argc < 1) goto bad; + chCApath= *(++argv); + } + else if (strcmp(*argv,"-verifyCApath") == 0) + { + if (--argc < 1) goto bad; + vfyCApath= *(++argv); + } else if (strcmp(*argv,"-no_cache") == 0) no_cache = 1; else if (args_verify(&argv, &argc, &badarg, bio_err, &vpm)) @@ -1150,11 +1166,23 @@ int MAIN(int argc, char *argv[]) if (--argc < 1) goto bad; cipher= *(++argv); } + else if (strcmp(*argv,"-build_chain") == 0) + build_chain = 1; else if (strcmp(*argv,"-CAfile") == 0) { if (--argc < 1) goto bad; CAfile= *(++argv); } + else if (strcmp(*argv,"-chainCAfile") == 0) + { + if (--argc < 1) goto bad; + chCAfile= *(++argv); + } + else if (strcmp(*argv,"-verifyCAfile") == 0) + { + if (--argc < 1) goto bad; + vfyCAfile= *(++argv); + } #ifdef FIONBIO else if (strcmp(*argv,"-nbio") == 0) { s_nbio=1; } @@ -1647,6 +1675,13 @@ bad: if (vpm) SSL_CTX_set1_param(ctx, vpm); + if (!ssl_load_stores(ctx, vfyCApath, vfyCAfile, chCApath, chCAfile)) + { + BIO_printf(bio_err, "Error loading store locations\n"); + ERR_print_errors(bio_err); + goto end; + } + #ifndef OPENSSL_NO_TLSEXT if (s_cert2) { @@ -1807,19 +1842,19 @@ bad: } #endif - if (!set_cert_key_stuff(ctx, s_cert, s_key, s_chain)) + if (!set_cert_key_stuff(ctx, s_cert, s_key, s_chain, build_chain)) goto end; #ifndef OPENSSL_NO_TLSEXT if (s_authz_file != NULL && !SSL_CTX_use_authz_file(ctx, s_authz_file)) goto end; #endif #ifndef OPENSSL_NO_TLSEXT - if (ctx2 && !set_cert_key_stuff(ctx2,s_cert2,s_key2, NULL)) + if (ctx2 && !set_cert_key_stuff(ctx2,s_cert2,s_key2, NULL, build_chain)) goto end; #endif if (s_dcert != NULL) { - if (!set_cert_key_stuff(ctx, s_dcert, s_dkey, s_dchain)) + if (!set_cert_key_stuff(ctx, s_dcert, s_dkey, s_dchain, build_chain)) goto end; } @@ -3139,3 +3174,33 @@ static int generate_session_id(const SSL *ssl, unsigned char *id, return 0; return 1; } + +static int ssl_load_stores(SSL_CTX *sctx, + const char *vfyCApath, const char *vfyCAfile, + const char *chCApath, const char *chCAfile) + { + X509_STORE *vfy = NULL, *ch = NULL; + int rv = 0; + if (vfyCApath || vfyCAfile) + { + vfy = X509_STORE_new(); + if (!X509_STORE_load_locations(vfy, vfyCAfile, vfyCApath)) + goto err; + SSL_CTX_set1_verify_cert_store(ctx, vfy); + } + if (chCApath || chCAfile) + { + ch = X509_STORE_new(); + if (!X509_STORE_load_locations(ch, chCAfile, chCApath)) + goto err; + /*X509_STORE_set_verify_cb(ch, verify_callback);*/ + SSL_CTX_set1_chain_cert_store(ctx, ch); + } + rv = 1; + err: + if (vfy) + X509_STORE_free(vfy); + if (ch) + X509_STORE_free(ch); + return rv; + } -- cgit v1.2.3