diff options
author | Dr. Stephen Henson <steve@openssl.org> | 2012-07-23 23:34:28 +0000 |
---|---|---|
committer | Dr. Stephen Henson <steve@openssl.org> | 2012-07-23 23:34:28 +0000 |
commit | 74ecfab401fe65d23d9b297bf396efca3e419e47 (patch) | |
tree | 8973a35de9df0e74464f8b6dcef0703aa2636dee /ssl/ssl_cert.c | |
parent | 5818a07a4fdae6cff28c625f947b409f21b34c53 (diff) | |
download | openssl-new-74ecfab401fe65d23d9b297bf396efca3e419e47.tar.gz |
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.
Diffstat (limited to 'ssl/ssl_cert.c')
-rw-r--r-- | ssl/ssl_cert.c | 98 |
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; + } + |