summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorsteve <steve>2012-01-31 14:00:08 +0000
committersteve <steve>2012-01-31 14:00:08 +0000
commit7167532b740d7d21138286303a853c597d32642a (patch)
treea1f824995bd30c6dcfb786c6f9ed37d22d9a49d5
parent2c8d675dc9c231938728f3f330806553c044d7fc (diff)
downloadopenssl-7167532b740d7d21138286303a853c597d32642a.tar.gz
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.
-rw-r--r--CHANGES4
-rw-r--r--ssl/s3_lib.c29
-rw-r--r--ssl/ssl.h21
-rw-r--r--ssl/ssl_cert.c91
-rw-r--r--ssl/ssl_locl.h7
5 files changed, 145 insertions, 7 deletions
diff --git a/CHANGES b/CHANGES
index 39fa10f29..86b2f9258 100644
--- a/CHANGES
+++ b/CHANGES
@@ -4,6 +4,10 @@
Changes between 1.0.1 and 1.1.0 [xx XXX xxxx]
+ *) Enhance SSL/TLS certificate chain handling to support different
+ chains for each certificate instead of one chain in the parent SSL_CTX.
+ [Steve Henson]
+
*) Support for fixed DH ciphersuite client authentication: where both
server and client use DH certificates with common parameters.
[Steve Henson]
diff --git a/ssl/s3_lib.c b/ssl/s3_lib.c
index b488cdbb3..d96937915 100644
--- a/ssl/s3_lib.c
+++ b/ssl/s3_lib.c
@@ -3350,6 +3350,21 @@ long ssl3_ctrl(SSL *s, int cmd, long larg, void *parg)
#endif
#endif /* !OPENSSL_NO_TLSEXT */
+
+ case SSL_CTRL_CHAIN:
+ if (larg)
+ return ssl_cert_set1_chain(s->cert,
+ (STACK_OF (X509) *)parg);
+ else
+ return ssl_cert_set0_chain(s->cert,
+ (STACK_OF (X509) *)parg);
+
+ case SSL_CTRL_CHAIN_CERT:
+ if (larg)
+ return ssl_cert_add1_chain_cert(s->cert, (X509 *)parg);
+ else
+ return ssl_cert_add0_chain_cert(s->cert, (X509 *)parg);
+
default:
break;
}
@@ -3642,6 +3657,20 @@ long ssl3_ctx_ctrl(SSL_CTX *ctx, int cmd, long larg, void *parg)
}
break;
+ case SSL_CTRL_CHAIN:
+ if (larg)
+ return ssl_cert_set1_chain(ctx->cert,
+ (STACK_OF (X509) *)parg);
+ else
+ return ssl_cert_set0_chain(ctx->cert,
+ (STACK_OF (X509) *)parg);
+
+ case SSL_CTRL_CHAIN_CERT:
+ if (larg)
+ return ssl_cert_add1_chain_cert(ctx->cert, (X509 *)parg);
+ else
+ return ssl_cert_add0_chain_cert(ctx->cert, (X509 *)parg);
+
default:
return(0);
}
diff --git a/ssl/ssl.h b/ssl/ssl.h
index b9325feb4..3d027af3c 100644
--- a/ssl/ssl.h
+++ b/ssl/ssl.h
@@ -1615,6 +1615,9 @@ DECLARE_PEM_rw(SSL_SESSION, SSL_SESSION)
#define SSL_CTRL_GET_EXTRA_CHAIN_CERTS 82
#define SSL_CTRL_CLEAR_EXTRA_CHAIN_CERTS 83
+#define SSL_CTRL_CHAIN 88
+#define SSL_CTRL_CHAIN_CERT 89
+
#define DTLSv1_get_timeout(ssl, arg) \
SSL_ctrl(ssl,DTLS_CTRL_GET_TIMEOUT,0, (void *)arg)
#define DTLSv1_handle_timeout(ssl) \
@@ -1656,6 +1659,24 @@ DECLARE_PEM_rw(SSL_SESSION, SSL_SESSION)
#define SSL_CTX_clear_extra_chain_certs(ctx) \
SSL_CTX_ctrl(ctx,SSL_CTRL_CLEAR_EXTRA_CHAIN_CERTS,0,NULL)
+#define SSL_CTX_set0_chain(ctx,sk) \
+ SSL_CTX_ctrl(ctx,SSL_CTRL_CHAIN,0,(char *)sk)
+#define SSL_CTX_set1_chain(ctx,sk) \
+ SSL_CTX_ctrl(ctx,SSL_CTRL_CHAIN,1,(char *)sk)
+#define SSL_CTX_add0_chain_cert(ctx,x509) \
+ 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_set0_chain(ctx,sk) \
+ SSL_ctrl(ctx,SSL_CTRL_CHAIN,0,(char *)sk)
+#define SSL_set1_chain(ctx,sk) \
+ SSL_ctrl(ctx,SSL_CTRL_CHAIN,1,(char *)sk)
+#define SSL_add0_chain_cert(ctx,x509) \
+ 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)
+
#ifndef OPENSSL_NO_BIO
BIO_METHOD *BIO_f_ssl(void);
BIO *BIO_new_ssl(SSL_CTX *ctx,int client);
diff --git a/ssl/ssl_cert.c b/ssl/ssl_cert.c
index 94b6deadc..2f43d2ede 100644
--- a/ssl/ssl_cert.c
+++ b/ssl/ssl_cert.c
@@ -317,11 +317,23 @@ CERT *ssl_cert_dup(CERT *cert)
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 @@ err:
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 @@ void ssl_cert_free(CERT *c)
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 @@ int ssl_cert_inst(CERT **o)
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 ssl_add_cert_chain(SSL *s, CERT_PKEY *cpk, unsigned long *l)
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 @@ int ssl_add_cert_chain(SSL *s, CERT_PKEY *cpk, unsigned long *l)
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;
}
diff --git a/ssl/ssl_locl.h b/ssl/ssl_locl.h
index 66605586a..95b531e83 100644
--- a/ssl/ssl_locl.h
+++ b/ssl/ssl_locl.h
@@ -472,6 +472,8 @@ typedef struct cert_pkey_st
EVP_PKEY *privatekey;
/* Digest to use when signing */
const EVP_MD *digest;
+ /* Chain for this certificate */
+ STACK_OF(X509) *chain;
} CERT_PKEY;
typedef struct cert_st
@@ -824,6 +826,11 @@ void ssl_update_cache(SSL *s, int mode);
int ssl_cipher_get_evp(const SSL_SESSION *s,const EVP_CIPHER **enc,
const EVP_MD **md,int *mac_pkey_type,int *mac_secret_size, SSL_COMP **comp);
int ssl_get_handshake_digest(int i,long *mask,const EVP_MD **md);
+int ssl_cert_set0_chain(CERT *c, STACK_OF(X509) *chain);
+int ssl_cert_set1_chain(CERT *c, STACK_OF(X509) *chain);
+int ssl_cert_add0_chain_cert(CERT *c, X509 *x);
+int ssl_cert_add1_chain_cert(CERT *c, X509 *x);
+
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_undefined_function(SSL *s);