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.
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]
#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;
}
}
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);
}
#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) \
#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);
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.
X509_free(rpk->x509);
if (rpk->privatekey != NULL)
EVP_PKEY_free(rpk->privatekey);
+ if (rpk->chain)
+ sk_X509_pop_free(rpk->chain, X509_free);
}
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);
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)
{
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;
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;
}
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
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);