Add support for distinct certificate chains per key type and per SSL structure. Before this the only way to add a custom chain was in the parent SSL_CTX (which is shared by all key types and SSL structures) or rely on auto chain building (which is performed on each handshake) from the trust store.
diff --git a/ssl/ssl_cert.c b/ssl/ssl_cert.c index 94b6dea..2f43d2e 100644 --- a/ssl/ssl_cert.c +++ b/ssl/ssl_cert.c
@@ -317,11 +317,23 @@ SSLerr(SSL_F_SSL_CERT_DUP, SSL_R_LIBRARY_BUG); } } + + if (cpk->chain) + { + rpk->chain = sk_X509_dup(cpk->chain); + if (!rpk->chain) + { + SSLerr(SSL_F_SSL_CERT_DUP, ERR_R_MALLOC_FAILURE); + goto err; + } + for (i = 0; i < sk_X509_num(rpk->chain); i++) + { + X509 *x = sk_X509_value(rpk->chain, i); + CRYPTO_add(&x->references, 1, CRYPTO_LOCK_X509); + } + } } - /* ret->extra_certs *should* exist, but currently the own certificate - * chain is held inside SSL_CTX */ - ret->references=1; /* Set digests to defaults. NB: we don't copy existing values as they * will be set during handshake. @@ -353,6 +365,8 @@ X509_free(rpk->x509); if (rpk->privatekey != NULL) EVP_PKEY_free(rpk->privatekey); + if (rpk->chain) + sk_X509_pop_free(rpk->chain, X509_free); } @@ -397,6 +411,8 @@ X509_free(cpk->x509); if (cpk->privatekey != NULL) EVP_PKEY_free(cpk->privatekey); + if (cpk->chain) + sk_X509_pop_free(cpk->chain, X509_free); #if 0 if (c->pkeys[i].publickey != NULL) EVP_PKEY_free(c->pkeys[i].publickey); @@ -433,6 +449,59 @@ return(1); } +int ssl_cert_set0_chain(CERT *c, STACK_OF(X509) *chain) + { + CERT_PKEY *cpk = c->key; + if (!cpk) + return 0; + if (cpk->chain) + sk_X509_pop_free(cpk->chain, X509_free); + cpk->chain = chain; + return 1; + } + +int ssl_cert_set1_chain(CERT *c, STACK_OF(X509) *chain) + { + STACK_OF(X509) *dchain; + X509 *x; + int i; + if (!chain) + return ssl_cert_set0_chain(c, NULL); + dchain = sk_X509_dup(chain); + if (!dchain) + return 0; + for (i = 0; i < sk_X509_num(dchain); i++) + { + x = sk_X509_value(dchain, i); + CRYPTO_add(&x->references, 1, CRYPTO_LOCK_X509); + } + if (!ssl_cert_set0_chain(c, dchain)) + { + sk_X509_pop_free(dchain, X509_free); + return 0; + } + return 1; + } + +int ssl_cert_add0_chain_cert(CERT *c, X509 *x) + { + CERT_PKEY *cpk = c->key; + if (!cpk) + return 0; + if (!cpk->chain) + cpk->chain = sk_X509_new_null(); + if (!cpk->chain || !sk_X509_push(cpk->chain, x)) + return 0; + return 1; + } + +int ssl_cert_add1_chain_cert(CERT *c, X509 *x) + { + if (!ssl_cert_add0_chain_cert(c, x)) + return 0; + CRYPTO_add(&x->references, 1, CRYPTO_LOCK_X509); + return 1; + } SESS_CERT *ssl_sess_cert_new(void) { @@ -884,13 +953,22 @@ int i; X509 *x; + STACK_OF(X509) *extra_certs; if (cpk) x = cpk->x509; else x = NULL; - if ((s->mode & SSL_MODE_NO_AUTO_CHAIN) || s->ctx->extra_certs) + /* If we have a certificate specific chain use it, else use + * parent ctx. + */ + if (cpk && cpk->chain) + extra_certs = cpk->chain; + else + extra_certs = s->ctx->extra_certs; + + if ((s->mode & SSL_MODE_NO_AUTO_CHAIN) || extra_certs) no_chain = 1; else no_chain = 0; @@ -933,10 +1011,9 @@ X509_STORE_CTX_cleanup(&xs_ctx); } } - /* Thawte special :-) */ - for (i=0; i<sk_X509_num(s->ctx->extra_certs); i++) + for (i=0; i<sk_X509_num(extra_certs); i++) { - x=sk_X509_value(s->ctx->extra_certs,i); + x=sk_X509_value(extra_certs,i); if (!ssl_add_cert_to_buf(buf, l, x)) return 0; }