From fbd2164044f92383955a801ad1b2857d71e83f27 Mon Sep 17 00:00:00 2001 From: "Dr. Stephen Henson" Date: Thu, 25 Feb 2010 00:17:22 +0000 Subject: [PATCH] Experimental support for partial chain verification: if an intermediate certificate is explicitly trusted (using -addtrust option to x509 utility for example) the verification is sucessful even if the chain is not complete. --- CHANGES | 10 +++++++ crypto/x509/x509_trs.c | 9 +++++++ crypto/x509/x509_vfy.c | 60 +++++++++++++++++++++++------------------- 3 files changed, 52 insertions(+), 27 deletions(-) diff --git a/CHANGES b/CHANGES index ec2ee0d17d..7aae336e37 100644 --- a/CHANGES +++ b/CHANGES @@ -4,6 +4,16 @@ Changes between 1.0.0 and 1.1.0 [xx XXX xxxx] + *) Initial experimental support for explicitly trusted non-root CAs. + OpenSSL still tries to build a complete chain to a root but if an + intermediate CA has a trust setting included that is used. The first + setting is used: whether to trust or reject. + [Steve Henson] + + *) New -verify_name option in command line utilities to set verification + parameters by name. + [Steve Henson] + *) Initial CMAC implementation. WARNING: EXPERIMENTAL, API MAY CHANGE. Add CMAC pkey methods. [Steve Henson] diff --git a/crypto/x509/x509_trs.c b/crypto/x509/x509_trs.c index a6cb9c8b1b..3d7e06815c 100644 --- a/crypto/x509/x509_trs.c +++ b/crypto/x509/x509_trs.c @@ -114,6 +114,15 @@ int X509_check_trust(X509 *x, int id, int flags) X509_TRUST *pt; int idx; if(id == -1) return 1; + /* We get this as a default value */ + if (id == 0) + { + int rv; + rv = obj_trust(NID_anyExtendedKeyUsage, x, 0); + if (rv != X509_TRUST_UNTRUSTED) + return rv; + return trust_compat(NULL, x, 0); + } idx = X509_TRUST_get_by_id(id); if(idx == -1) return default_trust(id, x, flags); pt = X509_TRUST_get0(idx); diff --git a/crypto/x509/x509_vfy.c b/crypto/x509/x509_vfy.c index 87ebf62525..14e29f2782 100644 --- a/crypto/x509/x509_vfy.c +++ b/crypto/x509/x509_vfy.c @@ -312,8 +312,13 @@ int X509_verify_cert(X509_STORE_CTX *ctx) /* we now have our chain, lets check it... */ xn=X509_get_issuer_name(x); - /* Is last certificate looked up self signed? */ - if (!ctx->check_issued(ctx,x,x)) + i = check_trust(ctx); + + /* If explicitly rejected error */ + if (i == X509_TRUST_REJECTED) + goto end; + /* If not explicitly trusted then indicate error */ + if (i != X509_TRUST_TRUSTED) { if ((chain_ss == NULL) || !ctx->check_issued(ctx, x, chain_ss)) { @@ -351,12 +356,6 @@ int X509_verify_cert(X509_STORE_CTX *ctx) if (!ok) goto end; - /* The chain extensions are OK: check trust */ - - if (param->trust > 0) ok = check_trust(ctx); - - if (!ok) goto end; - /* We may as well copy down any DSA parameters that are required */ X509_get_pubkey_parameters(NULL,ctx->chain); @@ -647,28 +646,35 @@ static int check_name_constraints(X509_STORE_CTX *ctx) static int check_trust(X509_STORE_CTX *ctx) { -#ifdef OPENSSL_NO_CHAIN_VERIFY - return 1; -#else int i, ok; - X509 *x; + X509 *x = NULL; int (*cb)(int xok,X509_STORE_CTX *xctx); cb=ctx->verify_cb; -/* For now just check the last certificate in the chain */ - i = sk_X509_num(ctx->chain) - 1; - x = sk_X509_value(ctx->chain, i); - ok = X509_check_trust(x, ctx->param->trust, 0); - if (ok == X509_TRUST_TRUSTED) - return 1; - ctx->error_depth = i; - ctx->current_cert = x; - if (ok == X509_TRUST_REJECTED) - ctx->error = X509_V_ERR_CERT_REJECTED; - else - ctx->error = X509_V_ERR_CERT_UNTRUSTED; - ok = cb(0, ctx); - return ok; -#endif + /* Check all trusted certificates in chain */ + for (i = ctx->last_untrusted; i < sk_X509_num(ctx->chain); i++) + { + x = sk_X509_value(ctx->chain, i); + ok = X509_check_trust(x, ctx->param->trust, 0); + /* If explicitly trusted return trusted */ + if (ok == X509_TRUST_TRUSTED) + return X509_TRUST_TRUSTED; + /* If explicitly rejected notify callback and reject if + * not overridden. + */ + if (ok == X509_TRUST_REJECTED) + { + ctx->error_depth = i; + ctx->current_cert = x; + ctx->error = X509_V_ERR_CERT_REJECTED; + ok = cb(0, ctx); + if (!ok) + return X509_TRUST_REJECTED; + } + } + /* If no trusted certs in chain at all return untrusted and + * allow standard (no issuer cert) etc errors to be indicated. + */ + return X509_TRUST_UNTRUSTED; } static int check_revocation(X509_STORE_CTX *ctx)