static int null_callback(int ok,X509_STORE_CTX *e);
static int check_issued(X509_STORE_CTX *ctx, X509 *x, X509 *issuer);
static X509 *find_issuer(X509_STORE_CTX *ctx, STACK_OF(X509) *sk, X509 *x);
-static int check_chain_purpose(X509_STORE_CTX *ctx);
+static int check_chain_extensions(X509_STORE_CTX *ctx);
static int check_trust(X509_STORE_CTX *ctx);
static int check_revocation(X509_STORE_CTX *ctx);
static int check_cert(X509_STORE_CTX *ctx);
}
/* We have the chain complete: now we need to check its purpose */
- if (ctx->purpose > 0) ok = check_chain_purpose(ctx);
+ ok = check_chain_extensions(ctx);
if (!ok) goto end;
else
return 0;
}
-
+
/* Check a certificate chains extensions for consistency
* with the supplied purpose
*/
-static int check_chain_purpose(X509_STORE_CTX *ctx)
+static int check_chain_extensions(X509_STORE_CTX *ctx)
{
#ifdef OPENSSL_NO_CHAIN_VERIFY
return 1;
#else
- int i, ok=0;
+ int i, ok=0, must_be_ca;
X509 *x;
int (*cb)();
cb=ctx->verify_cb;
+
+ /* must_be_ca can have 1 of 3 values:
+ -1: we accept both CA and non-CA certificates, to allow direct
+ use of self-signed certificates (which are marked as CA).
+ 0: we only accept non-CA certificates. This is currently not
+ used, but the possibility is present for future extensions.
+ 1: we only accept CA certificates. This is currently used for
+ all certificates in the chain except the leaf certificate.
+ */
+ must_be_ca = -1;
/* Check all untrusted certificates */
for (i = 0; i < ctx->last_untrusted; i++)
{
+ int ret;
x = sk_X509_value(ctx->chain, i);
if (!(ctx->flags & X509_V_FLAG_IGNORE_CRITICAL)
&& (x->ex_flags & EXFLAG_CRITICAL))
ok=cb(0,ctx);
if (!ok) goto end;
}
- if (!X509_check_purpose(x, ctx->purpose, i))
+ ret = X509_check_ca(x);
+ switch(must_be_ca)
{
- if (i)
+ case -1:
+ if ((ctx->flags & X509_V_FLAG_X509_STRICT)
+ && (ret != 1) && (ret != 0))
+ {
+ ret = 0;
ctx->error = X509_V_ERR_INVALID_CA;
+ }
else
- ctx->error = X509_V_ERR_INVALID_PURPOSE;
+ ret = 1;
+ break;
+ case 0:
+ if (ret != 0)
+ {
+ ret = 0;
+ ctx->error = X509_V_ERR_INVALID_NON_CA;
+ }
+ else
+ ret = 1;
+ break;
+ default:
+ if ((ret == 0)
+ || ((ctx->flags & X509_V_FLAG_X509_STRICT)
+ && (ret != 1)))
+ {
+ ret = 0;
+ ctx->error = X509_V_ERR_INVALID_CA;
+ }
+ else
+ ret = 1;
+ break;
+ }
+ if (ret == 0)
+ {
ctx->error_depth = i;
ctx->current_cert = x;
ok=cb(0,ctx);
if (!ok) goto end;
}
+ if (ctx->purpose > 0)
+ {
+ ret = X509_check_purpose(x, ctx->purpose,
+ must_be_ca > 0);
+ if ((ret == 0)
+ || ((ctx->flags & X509_V_FLAG_X509_STRICT)
+ && (ret != 1)))
+ {
+ ctx->error = X509_V_ERR_INVALID_PURPOSE;
+ ctx->error_depth = i;
+ ctx->current_cert = x;
+ ok=cb(0,ctx);
+ if (!ok) goto end;
+ }
+ }
/* Check pathlen */
if ((i > 1) && (x->ex_pathlen != -1)
&& (i > (x->ex_pathlen + 1)))
ok=cb(0,ctx);
if (!ok) goto end;
}
+ /* The next certificate must be a CA */
+ must_be_ca = 1;
}
ok = 1;
end:
if(issuer)
{
+ /* Check for cRLSign bit if keyUsage present */
+ if ((issuer->ex_flags & EXFLAG_KUSAGE) &&
+ !(issuer->ex_kusage & KU_CRL_SIGN))
+ {
+ ctx->error = X509_V_ERR_KEYUSAGE_NO_CRL_SIGN;
+ ok = ctx->verify_cb(0, ctx);
+ if(!ok) goto err;
+ }
/* Attempt to get issuer certificate public key */
ikey = X509_get_pubkey(issuer);
{
int idx, ok;
X509_REVOKED rtmp;
+ STACK_OF(X509_EXTENSION) *exts;
+ X509_EXTENSION *ext;
/* Look for serial number of certificate in CRL */
rtmp.serialNumber = X509_get_serialNumber(x);
+ /* Sort revoked into serial number order if not already sorted.
+ * Do this under a lock to avoid race condition.
+ */
+ if (!sk_X509_REVOKED_is_sorted(crl->crl->revoked))
+ {
+ CRYPTO_w_lock(CRYPTO_LOCK_X509_CRL);
+ sk_X509_REVOKED_sort(crl->crl->revoked);
+ CRYPTO_w_unlock(CRYPTO_LOCK_X509_CRL);
+ }
idx = sk_X509_REVOKED_find(crl->crl->revoked, &rtmp);
- /* Not found: OK */
- if(idx == -1) return 1;
- /* Otherwise revoked: want something cleverer than
+ /* If found assume revoked: want something cleverer than
* this to handle entry extensions in V2 CRLs.
*/
- ctx->error = X509_V_ERR_CERT_REVOKED;
- ok = ctx->verify_cb(0, ctx);
- return ok;
+ if(idx >= 0)
+ {
+ ctx->error = X509_V_ERR_CERT_REVOKED;
+ ok = ctx->verify_cb(0, ctx);
+ if (!ok) return 0;
+ }
+
+ if (ctx->flags & X509_V_FLAG_IGNORE_CRITICAL)
+ return 1;
+
+ /* See if we have any critical CRL extensions: since we
+ * currently don't handle any CRL extensions the CRL must be
+ * rejected.
+ * This code accesses the X509_CRL structure directly: applications
+ * shouldn't do this.
+ */
+
+ exts = crl->crl->extensions;
+
+ for (idx = 0; idx < sk_X509_EXTENSION_num(exts); idx++)
+ {
+ ext = sk_X509_EXTENSION_value(exts, idx);
+ if (ext->critical > 0)
+ {
+ ctx->error =
+ X509_V_ERR_UNHANDLED_CRITICAL_CRL_EXTENSION;
+ ok = ctx->verify_cb(0, ctx);
+ if(!ok) return 0;
+ break;
+ }
+ }
+ return 1;
}
static int internal_verify(X509_STORE_CTX *ctx)
atm.length=sizeof(buff2);
atm.data=(unsigned char *)buff2;
- X509_time_adj(&atm,-offset*60, cmp_time);
+ if (X509_time_adj(&atm,-offset*60, cmp_time) == NULL)
+ return 0;
if (ctm->type == V_ASN1_UTCTIME)
{