summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDr. Stephen Henson <steve@openssl.org>2012-07-23 23:34:28 +0000
committerDr. Stephen Henson <steve@openssl.org>2012-07-23 23:34:28 +0000
commit74ecfab401fe65d23d9b297bf396efca3e419e47 (patch)
tree8973a35de9df0e74464f8b6dcef0703aa2636dee
parent5818a07a4fdae6cff28c625f947b409f21b34c53 (diff)
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.
-rw-r--r--CHANGES13
-rw-r--r--apps/s_apps.h2
-rw-r--r--apps/s_cb.c32
-rw-r--r--apps/s_client.c8
-rw-r--r--apps/s_server.c72
-rw-r--r--ssl/s3_lib.c18
-rw-r--r--ssl/ssl.h32
-rw-r--r--ssl/ssl_cert.c98
-rw-r--r--ssl/ssl_err.c1
-rw-r--r--ssl/ssl_locl.h8
10 files changed, 271 insertions, 13 deletions
diff --git a/CHANGES b/CHANGES
index 8759585721..7e9e7c5395 100644
--- a/CHANGES
+++ b/CHANGES
@@ -4,6 +4,19 @@
Changes between 1.0.1 and 1.1.0 [xx XXX xxxx]
+ *) 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.
+
+ [Steve Henson]
+
*) New function ssl_set_client_disabled to set a ciphersuite disabled
mask based on the current session, check mask when sending client
hello and checking the requested ciphersuite.
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 afc30f2650..2ac3f969a8 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;
}
@@ -1123,6 +1130,7 @@ struct ssl_excert_st
X509 *cert;
EVP_PKEY *key;
STACK_OF(X509) *chain;
+ int build_chain;
struct ssl_excert_st *next, *prev;
};
@@ -1150,7 +1158,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;
@@ -1176,6 +1193,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;
@@ -1260,6 +1278,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))
@@ -1316,6 +1335,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)
@@ -1337,10 +1361,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 97f7cbd922..783a49e083 100644
--- a/apps/s_client.c
+++ b/apps/s_client.c
@@ -559,6 +559,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;
@@ -877,6 +878,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;
@@ -1212,8 +1215,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)))
@@ -1223,6 +1224,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 5dd9e8e059..bbe24929fb 100644
--- a/apps/s_server.c
+++ b/apps/s_server.c
@@ -215,6 +215,9 @@ static int generate_session_id(const SSL *ssl, unsigned char *id,
unsigned int *id_len);
static void init_session_cache_ctx(SSL_CTX *sctx);
static void free_sessions(void);
+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);
@@ -952,6 +955,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
@@ -961,6 +966,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;
@@ -1135,6 +1141,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 (strcmp(*argv,"-ext_cache") == 0)
@@ -1162,11 +1178,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; }
@@ -1672,6 +1700,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)
{
@@ -1834,19 +1869,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;
}
@@ -3305,7 +3340,36 @@ static void free_sessions(void)
}
first = NULL;
}
-
+
+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;
+ }
diff --git a/ssl/s3_lib.c b/ssl/s3_lib.c
index 457a5c7b5c..3bc5ce952a 100644
--- a/ssl/s3_lib.c
+++ b/ssl/s3_lib.c
@@ -3449,6 +3449,15 @@ long ssl3_ctrl(SSL *s, int cmd, long larg, void *parg)
return 0;
return ssl3_set_req_cert_type(s->cert, parg, larg);
+ case SSL_CTRL_BUILD_CERT_CHAIN:
+ return ssl_build_cert_chain(s->cert, s->ctx->cert_store, larg);
+
+ case SSL_CTRL_SET_VERIFY_CERT_STORE:
+ return ssl_cert_set_cert_store(s->cert, parg, 0, larg);
+
+ case SSL_CTRL_SET_CHAIN_CERT_STORE:
+ return ssl_cert_set_cert_store(s->cert, parg, 1, larg);
+
default:
break;
}
@@ -3746,6 +3755,15 @@ long ssl3_ctx_ctrl(SSL_CTX *ctx, int cmd, long larg, void *parg)
case SSL_CTRL_SET_CLIENT_CERT_TYPES:
return ssl3_set_req_cert_type(ctx->cert, parg, larg);
+ case SSL_CTRL_BUILD_CERT_CHAIN:
+ return ssl_build_cert_chain(ctx->cert, ctx->cert_store, larg);
+
+ case SSL_CTRL_SET_VERIFY_CERT_STORE:
+ return ssl_cert_set_cert_store(ctx->cert, parg, 0, larg);
+
+ case SSL_CTRL_SET_CHAIN_CERT_STORE:
+ return ssl_cert_set_cert_store(ctx->cert, parg, 1, larg);
+
case SSL_CTRL_SET_TLSEXT_AUTHZ_SERVER_AUDIT_PROOF_CB_ARG:
ctx->tlsext_authz_server_audit_proof_cb_arg = parg;
break;
diff --git a/ssl/ssl.h b/ssl/ssl.h
index 0e78fb7d66..ff6dcd7d11 100644
--- a/ssl/ssl.h
+++ b/ssl/ssl.h
@@ -656,6 +656,12 @@ struct ssl_session_st
*/
#define SSL_CERT_FLAG_TLS_STRICT 0x00000001L
+/* Flags for building certificate chains */
+/* Treat any existing certificates as untrusted CAs */
+#define SSL_BUILD_CHAIN_FLAG_UNTRUSTED 0x1
+/* Con't include root CA in chain */
+#define SSL_BUILD_CHAIN_FLAG_NO_ROOT 0x2
+
/* Note: SSL[_CTX]_set_{options,mode} use |= op on the previous value,
* they cannot be used to clear bits. */
@@ -1666,6 +1672,9 @@ DECLARE_PEM_rw(SSL_SESSION, SSL_SESSION)
#define SSL_CTRL_SET_CLIENT_SIGALGS_LIST 102
#define SSL_CTRL_GET_CLIENT_CERT_TYPES 103
#define SSL_CTRL_SET_CLIENT_CERT_TYPES 104
+#define SSL_CTRL_BUILD_CERT_CHAIN 105
+#define SSL_CTRL_SET_VERIFY_CERT_STORE 106
+#define SSL_CTRL_SET_CHAIN_CERT_STORE 107
#define DTLSv1_get_timeout(ssl, arg) \
SSL_ctrl(ssl,DTLS_CTRL_GET_TIMEOUT,0, (void *)arg)
@@ -1716,6 +1725,17 @@ DECLARE_PEM_rw(SSL_SESSION, SSL_SESSION)
SSL_CTX_ctrl(ctx,SSL_CTRL_CHAIN_CERT,0,(char *)x509)
#define SSL_CTX_add1_chain_cert(ctx,x509) \
SSL_CTX_ctrl(ctx,SSL_CTRL_CHAIN_CERT,1,(char *)x509)
+#define SSL_CTX_build_cert_chain(ctx, flags) \
+ SSL_CTX_ctrl(ctx,SSL_CTRL_BUILD_CERT_CHAIN, flags, NULL)
+
+#define SSL_CTX_set0_verify_cert_store(ctx,st) \
+ SSL_CTX_ctrl(ctx,SSL_CTRL_SET_VERIFY_CERT_STORE,0,(char *)st)
+#define SSL_CTX_set1_verify_cert_store(ctx,st) \
+ SSL_CTX_ctrl(ctx,SSL_CTRL_SET_VERIFY_CERT_STORE,1,(char *)st)
+#define SSL_CTX_set0_chain_cert_store(ctx,st) \
+ SSL_CTX_ctrl(ctx,SSL_CTRL_SET_CHAIN_CERT_STORE,0,(char *)st)
+#define SSL_CTX_set1_chain_cert_store(ctx,st) \
+ SSL_CTX_ctrl(ctx,SSL_CTRL_SET_CHAIN_CERT_STORE,1,(char *)st)
#define SSL_set0_chain(ctx,sk) \
SSL_ctrl(ctx,SSL_CTRL_CHAIN,0,(char *)sk)
@@ -1725,6 +1745,17 @@ DECLARE_PEM_rw(SSL_SESSION, SSL_SESSION)
SSL_ctrl(ctx,SSL_CTRL_CHAIN_CERT,0,(char *)x509)
#define SSL_add1_chain_cert(ctx,x509) \
SSL_ctrl(ctx,SSL_CTRL_CHAIN_CERT,1,(char *)x509)
+#define SSL_build_cert_chain(s, flags) \
+ SSL_ctrl(s,SSL_CTRL_BUILD_CERT_CHAIN, flags, NULL)
+#define SSL_set0_verify_cert_store(s,st) \
+ SSL_ctrl(s,SSL_CTRL_SET_VERIFY_CERT_STORE,0,(char *)st)
+#define SSL_set1_verify_cert_store(s,st) \
+ SSL_ctrl(s,SSL_CTRL_SET_VERIFY_CERT_STORE,1,(char *)st)
+#define SSL_set0_chain_cert_store(s,st) \
+ SSL_ctrl(s,SSL_CTRL_SET_CHAIN_CERT_STORE,0,(char *)st)
+#define SSL_set1_chain_cert_store(s,st) \
+ SSL_ctrl(s,SSL_CTRL_SET_CHAIN_CERT_STORE,1,(char *)st)
+
#define SSL_get1_curves(ctx, s) \
SSL_ctrl(ctx,SSL_CTRL_GET_CURVES,0,(char *)s)
#define SSL_CTX_set1_curves(ctx, clist, clistlen) \
@@ -2328,6 +2359,7 @@ void ERR_load_SSL_strings(void);
#define SSL_F_SSL_ADD_SERVERHELLO_TLSEXT 278
#define SSL_F_SSL_ADD_SERVERHELLO_USE_SRTP_EXT 308
#define SSL_F_SSL_BAD_METHOD 160
+#define SSL_F_SSL_BUILD_CERT_CHAIN 332
#define SSL_F_SSL_BYTES_TO_CIPHER_LIST 161
#define SSL_F_SSL_CERT_DUP 221
#define SSL_F_SSL_CERT_INST 222
diff --git a/ssl/ssl_cert.c b/ssl/ssl_cert.c
index 59a8544431..95478141a8 100644
--- a/ssl/ssl_cert.c
+++ b/ssl/ssl_cert.c
@@ -403,6 +403,18 @@ CERT *ssl_cert_dup(CERT *cert)
ret->cert_cb = cert->cert_cb;
ret->cert_cb_arg = cert->cert_cb_arg;
+ if (cert->verify_store)
+ {
+ CRYPTO_add(&cert->verify_store->references, 1, CRYPTO_LOCK_X509_STORE);
+ ret->verify_store = cert->verify_store;
+ }
+
+ if (cert->chain_store)
+ {
+ CRYPTO_add(&cert->chain_store->references, 1, CRYPTO_LOCK_X509_STORE);
+ ret->chain_store = cert->chain_store;
+ }
+
return(ret);
#if !defined(OPENSSL_NO_DH) || !defined(OPENSSL_NO_ECDH)
@@ -500,6 +512,10 @@ void ssl_cert_free(CERT *c)
OPENSSL_free(c->shared_sigalgs);
if (c->ctypes)
OPENSSL_free(c->ctypes);
+ if (c->verify_store)
+ X509_STORE_free(c->verify_store);
+ if (c->chain_store)
+ X509_STORE_free(c->chain_store);
OPENSSL_free(c);
}
@@ -671,13 +687,19 @@ int ssl_verify_cert_chain(SSL *s,STACK_OF(X509) *sk)
{
X509 *x;
int i;
+ X509_STORE *verify_store;
X509_STORE_CTX ctx;
+ if (s->cert->verify_store)
+ verify_store = s->cert->verify_store;
+ else
+ verify_store = s->ctx->cert_store;
+
if ((sk == NULL) || (sk_X509_num(sk) == 0))
return(0);
x=sk_X509_value(sk,0);
- if(!X509_STORE_CTX_init(&ctx,s->ctx->cert_store,x,sk))
+ if(!X509_STORE_CTX_init(&ctx,verify_store,x,sk))
{
SSLerr(SSL_F_SSL_VERIFY_CERT_CHAIN,ERR_R_X509_LIB);
return(0);
@@ -1042,12 +1064,18 @@ int ssl_add_cert_chain(SSL *s, CERT_PKEY *cpk, unsigned long *l)
X509 *x;
STACK_OF(X509) *extra_certs;
+ X509_STORE *chain_store;
if (cpk)
x = cpk->x509;
else
x = NULL;
+ if (s->cert->chain_store)
+ chain_store = s->cert->chain_store;
+ else
+ chain_store = s->ctx->cert_store;
+
/* If we have a certificate specific chain use it, else use
* parent ctx.
*/
@@ -1078,7 +1106,7 @@ int ssl_add_cert_chain(SSL *s, CERT_PKEY *cpk, unsigned long *l)
{
X509_STORE_CTX xs_ctx;
- if (!X509_STORE_CTX_init(&xs_ctx,s->ctx->cert_store,x,NULL))
+ if (!X509_STORE_CTX_init(&xs_ctx,chain_store,x,NULL))
{
SSLerr(SSL_F_SSL_ADD_CERT_CHAIN,ERR_R_X509_LIB);
return(0);
@@ -1109,3 +1137,69 @@ int ssl_add_cert_chain(SSL *s, CERT_PKEY *cpk, unsigned long *l)
return 1;
}
+/* Build a certificate chain for current certificate */
+int ssl_build_cert_chain(CERT *c, X509_STORE *chain_store, int flags)
+ {
+ CERT_PKEY *cpk = c->key;
+ X509_STORE_CTX xs_ctx;
+ STACK_OF(X509) *chain = NULL, *untrusted = NULL;
+ X509 *x;
+ int i;
+
+ if (!cpk->x509)
+ {
+ SSLerr(SSL_F_SSL_BUILD_CERT_CHAIN, SSL_R_NO_CERTIFICATE_SET);
+ return 0;
+ }
+
+ if (c->chain_store)
+ chain_store = c->chain_store;
+
+ if (flags & SSL_BUILD_CHAIN_FLAG_UNTRUSTED)
+ untrusted = cpk->chain;
+
+ if (!X509_STORE_CTX_init(&xs_ctx, chain_store, cpk->x509, untrusted))
+ {
+ SSLerr(SSL_F_SSL_BUILD_CERT_CHAIN, ERR_R_X509_LIB);
+ return 0;
+ }
+
+ i = X509_verify_cert(&xs_ctx);
+ if (i > 0)
+ chain = X509_STORE_CTX_get1_chain(&xs_ctx);
+ X509_STORE_CTX_cleanup(&xs_ctx);
+ if (i <= 0)
+ {
+ SSLerr(SSL_F_SSL_BUILD_CERT_CHAIN, SSL_R_CERTIFICATE_VERIFY_FAILED);
+ return 0;
+ }
+ if (cpk->chain)
+ sk_X509_pop_free(cpk->chain, X509_free);
+ /* Remove EE certificate from chain */
+ x = sk_X509_shift(chain);
+ X509_free(x);
+ if (flags & SSL_BUILD_CHAIN_FLAG_NO_ROOT)
+ {
+ x = sk_X509_pop(chain);
+ X509_free(x);
+ }
+ cpk->chain = chain;
+
+ return 1;
+ }
+
+int ssl_cert_set_cert_store(CERT *c, X509_STORE *store, int chain, int ref)
+ {
+ X509_STORE **pstore;
+ if (chain)
+ pstore = &c->chain_store;
+ else
+ pstore = &c->verify_store;
+ if (*pstore)
+ X509_STORE_free(*pstore);
+ *pstore = store;
+ if (ref && store)
+ CRYPTO_add(&store->references, 1, CRYPTO_LOCK_X509_STORE);
+ return 1;
+ }
+
diff --git a/ssl/ssl_err.c b/ssl/ssl_err.c
index a51937b93f..9301013727 100644
--- a/ssl/ssl_err.c
+++ b/ssl/ssl_err.c
@@ -195,6 +195,7 @@ static ERR_STRING_DATA SSL_str_functs[]=
{ERR_FUNC(SSL_F_SSL_ADD_SERVERHELLO_TLSEXT), "ssl_add_serverhello_tlsext"},
{ERR_FUNC(SSL_F_SSL_ADD_SERVERHELLO_USE_SRTP_EXT), "ssl_add_serverhello_use_srtp_ext"},
{ERR_FUNC(SSL_F_SSL_BAD_METHOD), "ssl_bad_method"},
+{ERR_FUNC(SSL_F_SSL_BUILD_CERT_CHAIN), "ssl_build_cert_chain"},
{ERR_FUNC(SSL_F_SSL_BYTES_TO_CIPHER_LIST), "ssl_bytes_to_cipher_list"},
{ERR_FUNC(SSL_F_SSL_CERT_DUP), "ssl_cert_dup"},
{ERR_FUNC(SSL_F_SSL_CERT_INST), "ssl_cert_inst"},
diff --git a/ssl/ssl_locl.h b/ssl/ssl_locl.h
index e64228fbac..7b1c12c662 100644
--- a/ssl/ssl_locl.h
+++ b/ssl/ssl_locl.h
@@ -583,6 +583,12 @@ typedef struct cert_st
int (*cert_cb)(SSL *ssl, void *arg);
void *cert_cb_arg;
+ /* Optional X509_STORE for chain building or certificate validation
+ * If NULL the parent SSL_CTX store is used instead.
+ */
+ X509_STORE *chain_store;
+ X509_STORE *verify_store;
+
int references; /* >1 only if SSL_copy_session_id is used */
} CERT;
@@ -925,6 +931,8 @@ void ssl_cert_set_cert_cb(CERT *c, int (*cb)(SSL *ssl, void *arg), void *arg);
int ssl_verify_cert_chain(SSL *s,STACK_OF(X509) *sk);
int ssl_add_cert_chain(SSL *s, CERT_PKEY *cpk, unsigned long *l);
+int ssl_build_cert_chain(CERT *c, X509_STORE *chain_store, int flags);
+int ssl_cert_set_cert_store(CERT *c, X509_STORE *store, int chain, int ref);
int ssl_undefined_function(SSL *s);
int ssl_undefined_void_function(void);
int ssl_undefined_const_function(const SSL *s);