int set_cert_key_stuff(SSL_CTX *ctx, X509 *cert, EVP_PKEY *key,
STACK_OF(X509) *chain, int build_chain)
{
+ int chflags = chain ? SSL_BUILD_CHAIN_FLAG_CHECK : 0;
if (cert == NULL)
return 1;
if (SSL_CTX_use_certificate(ctx,cert) <= 0)
ERR_print_errors(bio_err);
return 0;
}
- if (!chain && build_chain && !SSL_CTX_build_cert_chain(ctx, 0))
+ if (build_chain && !SSL_CTX_build_cert_chain(ctx, chflags))
{
BIO_printf(bio_err,"error building certificate chain\n");
ERR_print_errors(bio_err);
current certificate of B<ctx>. (This is implemented by calling
SSL_CTX_set0_chain() with B<sk> set to B<NULL>).
-SSL_CTX_build_cert_chain() builds the certificate chain for B<ctx> using the
-chain store. Any existing chain certificates are used as untrusted CAs.
+SSL_CTX_build_cert_chain() builds the certificate chain for B<ctx> normally
+this uses the chain store or the verify store if the chain store is not set.
If the function is successful the built chain will replace any existing chain.
-The B<flags> parameter can be set to B<SSL_BUILD_CHAIN_FLAG_NO_ROOT> to omit
-the root CA from the built chain.
+The B<flags> parameter can be set to B<SSL_BUILD_CHAIN_FLAG_UNTRUSTED> to use
+existing chain certificates as untrusted CAs, B<SSL_BUILD_CHAIN_FLAG_NO_ROOT>
+to omit the root CA from the built chain, B<SSL_BUILD_CHAIN_FLAG_CHECK> to
+use all existing chain certificates only to build the chain (effectively
+sanity checking and rearranging them if necessary), the flag
+B<SSL_BUILD_CHAIN_FLAG_IGNORE_ERROR> ignores any errors during verification.
Each of these functions operates on the I<current> end entity
(i.e. server or client) certificate. This is the last certificate loaded or
subordinate CAs are sent in the correct order. Misconfigured applications
sending incorrect certificate chains often cause problems with peers.
+For example an application can add any set of certificates using
+SSL_CTX_use_certificate_chain_file() then call SSL_CTX_build_cert_chain()
+with the option B<SSL_BUILD_CHAIN_FLAG_CHECK> to check and reorder them.
+
Calling SSL_CTX_build_cert_chain() or SSL_build_cert_chain() is more
efficient than the automatic chain building as it is only performed once.
Automatic chain building is performed on each new session.
=head1 RETURN VALUES
-All these functions return 1 for success and 0 for failure.
+SSL_set_current_cert() with B<SSL_CERT_SET_SERVER> return 1 for success, 2 if
+no server certificate is used because the ciphersuites is anonymous and 0
+for failure.
+
+All other functions return 1 for success and 0 for failure.
=back
/* Flags for building certificate chains */
/* Treat any existing certificates as untrusted CAs */
-#define SSL_BUILD_CHAIN_FLAG_UNTRUSTED 0x1
+#define SSL_BUILD_CHAIN_FLAG_UNTRUSTED 0x1
/* Don't include root CA in chain */
-#define SSL_BUILD_CHAIN_FLAG_NO_ROOT 0x2
+#define SSL_BUILD_CHAIN_FLAG_NO_ROOT 0x2
+/* Just check certificates already there */
+#define SSL_BUILD_CHAIN_FLAG_CHECK 0x4
+/* Ignore verification errors */
+#define SSL_BUILD_CHAIN_FLAG_IGNORE_ERROR 0x8
/* Flags returned by SSL_check_chain */
/* Certificate can be used with this session */
X509_STORE_CTX xs_ctx;
STACK_OF(X509) *chain = NULL, *untrusted = NULL;
X509 *x;
- int i;
+ int i, rv = 0;
if (!cpk->x509)
{
SSLerr(SSL_F_SSL_BUILD_CERT_CHAIN, SSL_R_NO_CERTIFICATE_SET);
- return 0;
+ goto err;
}
+ /* Rearranging and check the chain: add everything to a store */
+ if (flags & SSL_BUILD_CHAIN_FLAG_CHECK)
+ {
+ chain_store = X509_STORE_new();
+ if (!chain_store)
+ goto err;
+ for (i = 0; i < sk_X509_num(cpk->chain); i++)
+ {
+ x = sk_X509_value(cpk->chain, i);
+ if (!X509_STORE_add_cert(chain_store, x))
+ goto err;
+ }
+ /* Add EE cert too: it might be self signed */
+ if (!X509_STORE_add_cert(chain_store, cpk->x509))
+ goto err;
+ }
+ else
+ {
+ if (c->chain_store)
+ chain_store = c->chain_store;
- if (c->chain_store)
- chain_store = c->chain_store;
-
- if (flags & SSL_BUILD_CHAIN_FLAG_UNTRUSTED)
- untrusted = cpk->chain;
+ 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;
+ goto err;
}
/* Set suite B flags if needed */
X509_STORE_CTX_set_flags(&xs_ctx, c->cert_flags & SSL_CERT_FLAG_SUITEB_128_LOS);
i = X509_verify_cert(&xs_ctx);
+ if (i <= 0 && flags & SSL_BUILD_CHAIN_FLAG_IGNORE_ERROR)
+ {
+ ERR_clear_error();
+ i = 1;
+ }
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;
+ i = X509_STORE_CTX_get_error(&xs_ctx);
+ ERR_add_error_data(2, "Verify error:",
+ X509_verify_cert_error_string(i));
+
+ X509_STORE_CTX_cleanup(&xs_ctx);
+ goto err;
}
+ X509_STORE_CTX_cleanup(&xs_ctx);
if (cpk->chain)
sk_X509_pop_free(cpk->chain, X509_free);
/* Remove EE certificate from chain */
X509_free(x);
if (flags & SSL_BUILD_CHAIN_FLAG_NO_ROOT)
{
- x = sk_X509_pop(chain);
- X509_free(x);
+ if (sk_X509_num(chain) > 0)
+ {
+ /* See if last cert is self signed */
+ x = sk_X509_value(chain, sk_X509_num(chain) - 1);
+ X509_check_purpose(x, -1, 0);
+ if (x->ex_flags & EXFLAG_SS)
+ {
+ x = sk_X509_pop(chain);
+ X509_free(x);
+ }
+ }
}
cpk->chain = chain;
+ rv = 1;
+ err:
+ if (flags & SSL_BUILD_CHAIN_FLAG_CHECK)
+ X509_STORE_free(chain_store);
- return 1;
+ return rv;
}
int ssl_cert_set_cert_store(CERT *c, X509_STORE *store, int chain, int ref)