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.
This commit is contained in:
18
ssl/s3_lib.c
18
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;
|
||||
|
||||
32
ssl/ssl.h
32
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
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
@@ -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"},
|
||||
|
||||
@@ -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);
|
||||
|
||||
Reference in New Issue
Block a user