summaryrefslogtreecommitdiffstats
path: root/ssl/ssl_cert.c
diff options
context:
space:
mode:
authorDr. Stephen Henson <steve@openssl.org>2012-12-26 15:21:53 +0000
committerDr. Stephen Henson <steve@openssl.org>2012-12-26 15:21:53 +0000
commitb762acadeb09618a63140e30fb385ea106730635 (patch)
tree8a22cd4ed3d9a467a6bbdd8ab88ee20e995f41cf /ssl/ssl_cert.c
parent7d779eefb43309319818090c27778bd3f904748e (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. (backport from HEAD)
Diffstat (limited to 'ssl/ssl_cert.c')
-rw-r--r--ssl/ssl_cert.c98
1 files changed, 96 insertions, 2 deletions
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;
+ }
+