From dc4bdf592f2865197312ebf7aee2c1d0a1e30b4f Mon Sep 17 00:00:00 2001 From: Rob Stradling Date: Mon, 11 Nov 2013 18:04:24 +0100 Subject: [PATCH] Additional "chain_cert" functions. PR#3169 This patch, which currently applies successfully against master and 1_0_2, adds the following functions: SSL_[CTX_]select_current_cert() - set the current certificate without disturbing the existing structure. SSL_[CTX_]get0_chain_certs() - get the current certificate's chain. SSL_[CTX_]clear_chain_certs() - clear the current certificate's chain. The patch also adds these functions to, and fixes some existing errors in, SSL_CTX_add1_chain_cert.pod. (cherry picked from commit 2f56c9c015dbca45379c9a725915b3b8e765a119) --- doc/ssl/SSL_CTX_add1_chain_cert.pod | 50 ++++++++++++++++++++--------- ssl/s3_lib.c | 14 ++++++++ ssl/ssl.h | 16 +++++++++ ssl/ssl_cert.c | 14 ++++++++ ssl/ssl_locl.h | 1 + 5 files changed, 80 insertions(+), 15 deletions(-) diff --git a/doc/ssl/SSL_CTX_add1_chain_cert.pod b/doc/ssl/SSL_CTX_add1_chain_cert.pod index ef26c9f86b..a97969260d 100644 --- a/doc/ssl/SSL_CTX_add1_chain_cert.pod +++ b/doc/ssl/SSL_CTX_add1_chain_cert.pod @@ -3,9 +3,11 @@ =head1 NAME SSL_CTX_set0_chain, SSL_CTX_set1_chain, SSL_CTX_add0_chain_cert, -SSL_CTX_add1_chain_cert, SSL_set0_chain, SSL_set1_chain, -SSL_add0_chain_cert, SSL_add1_chain_cert, SSL_CTX_build_cert_chain, -SSL_build_cert_chain - extra chain certificate processing +SSL_CTX_add1_chain_cert, SSL_CTX_get0_chain_certs, SSL_CTX_clear_chain_certs, +SSL_set0_chain, SSL_set1_chain, SSL_add0_chain_cert, SSL_add1_chain_cert, +SSL_get0_chain_certs, SSL_clear_chain_certs, SSL_CTX_build_cert_chain, +SSL_build_cert_chain, SSL_CTX_select_current_cert, +SSL_select_current_cert - extra chain certificate processing =head1 SYNOPSIS @@ -13,36 +15,58 @@ SSL_build_cert_chain - extra chain certificate processing int SSL_CTX_set0_chain(SSL_CTX *ctx, STACK_OF(X509) *sk); int SSL_CTX_set1_chain(SSL_CTX *ctx, STACK_OF(X509) *sk); - int SSL_CTX_add0_chain_cert(SSL_CTX *ctx, STACK_OF(X509) *x509); + int SSL_CTX_add0_chain_cert(SSL_CTX *ctx, X509 *x509); int SSL_CTX_add1_chain_cert(SSL_CTX *ctx, X509 *x509); + int SSL_CTX_get0_chain_certs(SSL_CTX *ctx, STACK_OF(X509) **sk); + int SSL_CTX_clear_chain_certs(SSL_CTX *ctx); int SSL_set0_chain(SSL *ssl, STACK_OF(X509) *sk); int SSL_set1_chain(SSL *ssl, STACK_OF(X509) *sk); - int SSL_add0_chain_cert(SSL *ssl, STACK_OF(X509) *x509); + int SSL_add0_chain_cert(SSL *ssl, X509 *x509); int SSL_add1_chain_cert(SSL *ssl, X509 *x509); + int SSL_get0_chain_certs(SSL *ssl, STACK_OF(X509) **sk); + int SSL_clear_chain_certs(SSL *ssl); int SSL_CTX_build_cert_chain(SSL_CTX *ctx, flags); - int SSL_build_cert_chain(SSL_CTX *ctx, flags); + int SSL_build_cert_chain(SSL *ssl, flags); + + int SSL_CTX_select_current_cert(SSL_CTX *ctx, X509 *x509); + int SSL_select_current_cert(SSL *ssl, X509 *x509); =head1 DESCRIPTION SSL_CTX_set0_chain() and SSL_CTX_set1_chain() set the certificate chain -associated with the current certificate of B to B. If B is set -to B any existing chain is cleared. +associated with the current certificate of B to B. SSL_CTX_add0_chain_cert() and SSL_CTX_add1_chain_cert() append the single certificate B to the chain associated with the current certificate of B. +SSL_CTX_get0_chain_certs() retrieves the chain associated with the current +certificate of B. + +SSL_CTX_clear_chain_certs() clears any existing chain associated with the +current certificate of B. (This is implemented by calling +SSL_CTX_set0_chain() with B set to B). + SSL_CTX_build_cert_chain() builds the certificate chain for B using the chain store. Any existing chain certificates are used as untrusted CAs. If the function is successful the built chain will replace any existing chain. The B parameter can be set to B to omit the root CA from the built chain. -SSL_set0_chain(), SSL_set1_chain(), SSL_add0_chain_cert(), SSL_add0_chain_cert() -and SSL_build_cert_chain() are similar except they apply to SSL structure -B. +Each of these functions operates on the I end entity +(i.e. server or client) certificate. This is the last certificate loaded or +selected on the corresponding B structure. + +SSL_CTX_select_current_cert() selects B as the current end entity +certificate, but only if B has already been loaded into B using a +function such as SSL_CTX_use_certificate(). + +SSL_set0_chain(), SSL_set1_chain(), SSL_add0_chain_cert(), +SSL_add1_chain_cert(), SSL_get0_chain_certs(), SSL_clear_chain_certs(), +SSL_build_cert_chain() and SSL_select_current_cert() are similar except they +apply to SSL structure B. All these functions are implemented as macros. Those containing a B<1> increment the reference count of the supplied certificate or chain so it must @@ -56,10 +80,6 @@ The chains associate with an SSL_CTX structure are copied to any SSL structures when SSL_new() is called. SSL structures will not be affected by any chains subsequently changed in the parent SSL_CTX. -Each of these functions operates on the I end entity -(i.e. server or client) certificate. This is the last certificate set -on the corresponding B or B structure. - One chain can be set for each key type supported by a server. So, for example, an RSA and a DSA certificate can (and often will) have different chains. diff --git a/ssl/s3_lib.c b/ssl/s3_lib.c index 92b87c3876..e52d2dbb42 100644 --- a/ssl/s3_lib.c +++ b/ssl/s3_lib.c @@ -3431,6 +3431,13 @@ long ssl3_ctrl(SSL *s, int cmd, long larg, void *parg) else return ssl_cert_add0_chain_cert(s->cert, (X509 *)parg); + case SSL_CTRL_GET_CHAIN_CERTS: + *(STACK_OF(X509) **)parg = s->cert->key->chain; + break; + + case SSL_CTRL_SELECT_CURRENT_CERT: + return ssl_cert_select_current(s->cert, (X509 *)parg); + #ifndef OPENSSL_NO_EC case SSL_CTRL_GET_CURVES: { @@ -3929,6 +3936,13 @@ long ssl3_ctx_ctrl(SSL_CTX *ctx, int cmd, long larg, void *parg) else return ssl_cert_add0_chain_cert(ctx->cert, (X509 *)parg); + case SSL_CTRL_GET_CHAIN_CERTS: + *(STACK_OF(X509) **)parg = ctx->cert->key->chain; + break; + + case SSL_CTRL_SELECT_CURRENT_CERT: + return ssl_cert_select_current(ctx->cert, (X509 *)parg); + default: return(0); } diff --git a/ssl/ssl.h b/ssl/ssl.h index 5e5a2955fc..a33b0fbc0d 100644 --- a/ssl/ssl.h +++ b/ssl/ssl.h @@ -1863,6 +1863,9 @@ DECLARE_PEM_rw(SSL_SESSION, SSL_SESSION) #define SSL_CTRL_SET_TLSA_RECORD 113 #define SSL_CTRL_PULL_TLSA_RECORD 114 +#define SSL_CTRL_GET_CHAIN_CERTS 115 +#define SSL_CTRL_SELECT_CURRENT_CERT 116 + #define DTLSv1_get_timeout(ssl, arg) \ SSL_ctrl(ssl,DTLS_CTRL_GET_TIMEOUT,0, (void *)arg) #define DTLSv1_handle_timeout(ssl) \ @@ -1912,8 +1915,14 @@ 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_get0_chain_certs(ctx,px509) \ + SSL_CTX_ctrl(ctx,SSL_CTRL_GET_CHAIN_CERTS,0,px509) +#define SSL_CTX_clear_chain_certs(ctx) \ + SSL_CTX_set0_chain(ctx,NULL) #define SSL_CTX_build_cert_chain(ctx, flags) \ SSL_CTX_ctrl(ctx,SSL_CTRL_BUILD_CERT_CHAIN, flags, NULL) +#define SSL_CTX_select_current_cert(ctx,x509) \ + SSL_CTX_ctrl(ctx,SSL_CTRL_SELECT_CURRENT_CERT,0,(char *)x509) #define SSL_CTX_set0_verify_cert_store(ctx,st) \ SSL_CTX_ctrl(ctx,SSL_CTRL_SET_VERIFY_CERT_STORE,0,(char *)st) @@ -1932,8 +1941,15 @@ 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_get0_chain_certs(ctx,px509) \ + SSL_ctrl(ctx,SSL_CTRL_GET_CHAIN_CERTS,0,px509) +#define SSL_clear_chain_certs(ctx) \ + SSL_set0_chain(ctx,NULL) #define SSL_build_cert_chain(s, flags) \ SSL_ctrl(s,SSL_CTRL_BUILD_CERT_CHAIN, flags, NULL) +#define SSL_select_current_cert(ctx,x509) \ + SSL_ctrl(ctx,SSL_CTRL_SELECT_CURRENT_CERT,0,(char *)x509) + #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) \ diff --git a/ssl/ssl_cert.c b/ssl/ssl_cert.c index 1180f15227..a4550ed2d3 100644 --- a/ssl/ssl_cert.c +++ b/ssl/ssl_cert.c @@ -621,6 +621,20 @@ int ssl_cert_add1_chain_cert(CERT *c, X509 *x) return 1; } +int ssl_cert_select_current(CERT *c, X509 *x) + { + int i; + for (i = 0; i < SSL_PKEY_NUM; i++) + { + if (c->pkeys[i].x509 == x) + { + c->key = &c->pkeys[i]; + return 1; + } + } + return 0; + } + void ssl_cert_set_cert_cb(CERT *c, int (*cb)(SSL *ssl, void *arg), void *arg) { c->cert_cb = cb; diff --git a/ssl/ssl_locl.h b/ssl/ssl_locl.h index 52e93e23e0..273f277a24 100644 --- a/ssl/ssl_locl.h +++ b/ssl/ssl_locl.h @@ -1000,6 +1000,7 @@ 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_cert_select_current(CERT *c, X509 *x); 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); -- 2.25.1