Commit bc7535bc authored by Dr. Stephen Henson's avatar Dr. Stephen Henson
Browse files

Support for AKID in CRLs and partial support for IDP. Overhaul of CRL

handling to support this.
parent 83357f04
Loading
Loading
Loading
Loading
+12 −0
Original line number Original line Diff line number Diff line
@@ -4,6 +4,18 @@


 Changes between 0.9.8d and 0.9.9  [xx XXX xxxx]
 Changes between 0.9.8d and 0.9.9  [xx XXX xxxx]


  *) Partial support for Issuing Distribution Point CRL extension. CRLs
     partitioned by DP are handled but no indirect CRL or reason partitioning
     (yet). Complete overhaul of CRL handling: now the most suitable CRL is
     selected via a scoring technique which handles IDP and AKID in CRLs.
     [Steve Henson]

  *) New X509_STORE_CTX callbacks lookup_crls() and lookup_certs() which
     will ultimately be used for all verify operations: this will remove the
     X509_STORE dependency on certificate verification and allow alternative
     lookup methods.  X509_STORE based implementations of these two callbacks.
     [Steve Henson]

  *) Allow multiple CRLs to exist in an X509_STORE with matching issuer names.
  *) Allow multiple CRLs to exist in an X509_STORE with matching issuer names.
     Modify get_crl() to find a valid (unexpired) CRL if possible.
     Modify get_crl() to find a valid (unexpired) CRL if possible.
     [Steve Henson]
     [Steve Henson]
+4 −0
Original line number Original line Diff line number Diff line
@@ -162,6 +162,10 @@ const char *X509_verify_cert_error_string(long n)
		return("invalid or inconsistent certificate policy extension");
		return("invalid or inconsistent certificate policy extension");
	case X509_V_ERR_NO_EXPLICIT_POLICY:
	case X509_V_ERR_NO_EXPLICIT_POLICY:
		return("no explicit policy");
		return("no explicit policy");
	case X509_V_ERR_DIFFERENT_CRL_SCOPE:
	return("Different CRL scope");
	case X509_V_ERR_UNSUPPORTED_EXTENSION_FEATURE:
	return("Unsupported extension feature");
	default:
	default:
		BIO_snprintf(buf,sizeof buf,"error number %ld",n);
		BIO_snprintf(buf,sizeof buf,"error number %ld",n);
		return(buf);
		return(buf);
+150 −9
Original line number Original line Diff line number Diff line
@@ -78,6 +78,8 @@ static int check_trust(X509_STORE_CTX *ctx);
static int check_revocation(X509_STORE_CTX *ctx);
static int check_revocation(X509_STORE_CTX *ctx);
static int check_cert(X509_STORE_CTX *ctx);
static int check_cert(X509_STORE_CTX *ctx);
static int check_policy(X509_STORE_CTX *ctx);
static int check_policy(X509_STORE_CTX *ctx);
static int crl_akid_check(X509_STORE_CTX *ctx, AUTHORITY_KEYID *akid);
static int idp_check_scope(X509 *x, X509_CRL *crl);
static int internal_verify(X509_STORE_CTX *ctx);
static int internal_verify(X509_STORE_CTX *ctx);
const char *X509_version="X.509" OPENSSL_VERSION_PTEXT;
const char *X509_version="X.509" OPENSSL_VERSION_PTEXT;


@@ -649,30 +651,81 @@ static int check_crl_time(X509_STORE_CTX *ctx, X509_CRL *crl, int notify)
	return 1;
	return 1;
	}
	}


/* Lookup CRLs from the supplied list. Look for matching isser name
/* Based on a set of possible CRLs decide which one is best suited
 * and validity. If we can't find a valid CRL return the last one
 * to handle the current certificate. This is determined by a number
 * with matching name. This gives more meaningful error codes. Otherwise
 * of criteria. If any of the "must" criteria is not satisfied then
 * we'd get a CRL not found error if a CRL existed with matching name but
 * the candidate CRL is rejected. If all "must" and all "should" are
 * was invalid.
 * satisfied the CRL is accepted. If no CRL satisfies all criteria then
 * a "best CRL" is used to provide some meaningful error information.
 *
 * CRL issuer name must match "nm" if not NULL.
 * If IDP is present:
 *   a. it must be consistent.
 *   b. onlyuser, onlyCA, onlyAA should match certificate being checked.
 *   c. indirectCRL must be FALSE.
 *   d. onlysomereason must be absent.
 *   e. if name present a DP in certificate CRLDP must match.
 * If AKID present it should match certificate AKID.
 * Check time should fall between lastUpdate and nextUpdate.
 */
 */


/* IDP name field matches CRLDP or IDP name not present */
#define CRL_SCORE_SCOPE		4
/* AKID present and matches cert, or AKID not present */
#define CRL_SCORE_AKID		2
/* times OK */
#define CRL_SCORE_TIME		1

#define CRL_SCORE_ALL		7

/* IDP flags which cause a CRL to be rejected */

#define IDP_REJECT	(IDP_INVALID|IDP_INDIRECT|IDP_REASONS)

static int get_crl_sk(X509_STORE_CTX *ctx, X509_CRL **pcrl,
static int get_crl_sk(X509_STORE_CTX *ctx, X509_CRL **pcrl,
			X509_NAME *nm, STACK_OF(X509_CRL) *crls)
			X509_NAME *nm, STACK_OF(X509_CRL) *crls)
	{
	{
	int i;
	int i, crl_score, best_score = -1;
	X509_CRL *crl, *best_crl = NULL;
	X509_CRL *crl, *best_crl = NULL;
	for (i = 0; i < sk_X509_CRL_num(crls); i++)
	for (i = 0; i < sk_X509_CRL_num(crls); i++)
		{
		{
		crl_score = 0;
		crl = sk_X509_CRL_value(crls, i);
		crl = sk_X509_CRL_value(crls, i);
		if (nm && X509_NAME_cmp(nm, X509_CRL_get_issuer(crl)))
		if (nm && X509_NAME_cmp(nm, X509_CRL_get_issuer(crl)))
			continue;
			continue;
		if (check_crl_time(ctx, crl, 0))
		if (check_crl_time(ctx, crl, 0))
			crl_score |= CRL_SCORE_TIME;

		if (crl->idp_flags & IDP_PRESENT)
			{
			if (crl->idp_flags & IDP_REJECT)
				continue;
			if (idp_check_scope(ctx->current_cert, crl))
				crl_score |= CRL_SCORE_SCOPE;
			}
		else
			crl_score |= CRL_SCORE_SCOPE;

		if (crl->akid)
			{
			if (crl_akid_check(ctx, crl->akid))
				crl_score |= CRL_SCORE_AKID;
			}
		else
			crl_score |= CRL_SCORE_AKID;

		if (crl_score == CRL_SCORE_ALL)
			{
			{
			*pcrl = crl;
			*pcrl = crl;
			CRYPTO_add(&crl->references, 1, CRYPTO_LOCK_X509_CRL);
			CRYPTO_add(&crl->references, 1, CRYPTO_LOCK_X509_CRL);
			return 1;
			return 1;
			}
			}

		if (crl_score > best_score)
			{
			best_crl = crl;
			best_crl = crl;
			best_score = crl_score;
			}
		}
		}
	if (best_crl)
	if (best_crl)
		{
		{
@@ -683,9 +736,71 @@ static int get_crl_sk(X509_STORE_CTX *ctx, X509_CRL **pcrl,
	return 0;
	return 0;
	}
	}


/* Retrieve CRL corresponding to certificate: currently just a
static int crl_akid_check(X509_STORE_CTX *ctx, AUTHORITY_KEYID *akid)
 * subject lookup: maybe use AKID later...
	{
	int cidx = ctx->error_depth;
	if (cidx != sk_X509_num(ctx->chain) - 1)
		cidx++;
	if (X509_check_akid(sk_X509_value(ctx->chain, cidx), akid) == X509_V_OK)
		return 1;
	return 0;
	}


/* Check IDP name matches at least one CRLDP name */

static int idp_check_scope(X509 *x, X509_CRL *crl)
	{
	int i, j, k;
	GENERAL_NAMES *inames, *dnames;
	if (crl->idp_flags & IDP_ONLYATTR)
		return 0;
	if (x->ex_flags & EXFLAG_CA)
		{
		if (crl->idp_flags & IDP_ONLYUSER)
			return 0;
		}
	else
		{
		if (crl->idp_flags & IDP_ONLYCA)
			return 0;
		}
	if (!crl->idp->distpoint)
		return 1;
	if (crl->idp->distpoint->type != 0)
		return 1;
	if (!x->crldp)
		return 0;
	inames = crl->idp->distpoint->name.fullname;
	for (i = 0; i < sk_GENERAL_NAME_num(inames); i++)
		{
		GENERAL_NAME *igen = sk_GENERAL_NAME_value(inames, i);
		for (j = 0; j < sk_DIST_POINT_num(x->crldp); j++)
			{
			DIST_POINT *dp = sk_DIST_POINT_value(x->crldp, j);
			/* We don't handle these at present */
			if (dp->reasons || dp->CRLissuer)
				continue;
			if (!dp->distpoint || (dp->distpoint->type != 0))
				continue;
			dnames = dp->distpoint->name.fullname;
			for (k = 0; k < sk_GENERAL_NAME_num(dnames); k++)
				{
				GENERAL_NAME *cgen =
					sk_GENERAL_NAME_value(dnames, k);
				if (!GENERAL_NAME_cmp(igen, cgen))
					return 1;
				}
			}
		}
	return 0;
	}

/* Retrieve CRL corresponding to current certificate. Currently only
 * one CRL is retrieved. Multiple CRLs may be needed if we handle
 * CRLs partitioned on reason code later.
 */
 */
	
static int get_crl(X509_STORE_CTX *ctx, X509_CRL **pcrl, X509 *x)
static int get_crl(X509_STORE_CTX *ctx, X509_CRL **pcrl, X509 *x)
	{
	{
	int ok;
	int ok;
@@ -765,6 +880,28 @@ static int check_crl(X509_STORE_CTX *ctx, X509_CRL *crl)
			if(!ok) goto err;
			if(!ok) goto err;
			}
			}


		if (crl->idp_flags & IDP_PRESENT)
			{
			if (crl->idp_flags & IDP_INVALID)
				{
				ctx->error = X509_V_ERR_INVALID_EXTENSION;
				ok = ctx->verify_cb(0, ctx);
				if(!ok) goto err;
				}
			if (crl->idp_flags & (IDP_REASONS|IDP_INDIRECT))
				{
				ctx->error = X509_V_ERR_UNSUPPORTED_EXTENSION_FEATURE;
				ok = ctx->verify_cb(0, ctx);
				if(!ok) goto err;
				}
			if (!idp_check_scope(ctx->current_cert, crl))
				{
				ctx->error = X509_V_ERR_DIFFERENT_CRL_SCOPE;
				ok = ctx->verify_cb(0, ctx);
				if(!ok) goto err;
				}
			}

		/* Attempt to get issuer certificate public key */
		/* Attempt to get issuer certificate public key */
		ikey = X509_get_pubkey(issuer);
		ikey = X509_get_pubkey(issuer);


@@ -843,6 +980,10 @@ static int cert_crl(X509_STORE_CTX *ctx, X509_CRL *crl, X509 *x)
		ext = sk_X509_EXTENSION_value(exts, idx);
		ext = sk_X509_EXTENSION_value(exts, idx);
		if (ext->critical > 0)
		if (ext->critical > 0)
			{
			{
			/* We handle IDP now so permit it */
			if (OBJ_obj2nid(ext->object) ==
				NID_issuing_distribution_point)
				continue;
			ctx->error =
			ctx->error =
				X509_V_ERR_UNHANDLED_CRITICAL_CRL_EXTENSION;
				X509_V_ERR_UNHANDLED_CRITICAL_CRL_EXTENSION;
			ok = ctx->verify_cb(0, ctx);
			ok = ctx->verify_cb(0, ctx);
+2 −0
Original line number Original line Diff line number Diff line
@@ -334,6 +334,8 @@ void X509_STORE_CTX_set_depth(X509_STORE_CTX *ctx, int depth);
#define		X509_V_ERR_INVALID_EXTENSION			41
#define		X509_V_ERR_INVALID_EXTENSION			41
#define		X509_V_ERR_INVALID_POLICY_EXTENSION		42
#define		X509_V_ERR_INVALID_POLICY_EXTENSION		42
#define		X509_V_ERR_NO_EXPLICIT_POLICY			43
#define		X509_V_ERR_NO_EXPLICIT_POLICY			43
#define		X509_V_ERR_DIFFERENT_CRL_SCOPE			44
#define		X509_V_ERR_UNSUPPORTED_EXTENSION_FEATURE	45




/* The application is not happy */
/* The application is not happy */
+49 −32
Original line number Original line Diff line number Diff line
@@ -644,18 +644,41 @@ int X509_check_issued(X509 *issuer, X509 *subject)
				return X509_V_ERR_SUBJECT_ISSUER_MISMATCH;
				return X509_V_ERR_SUBJECT_ISSUER_MISMATCH;
	x509v3_cache_extensions(issuer);
	x509v3_cache_extensions(issuer);
	x509v3_cache_extensions(subject);
	x509v3_cache_extensions(subject);
	if(subject->akid) {

	if(subject->akid)
		{
		int ret = X509_check_akid(issuer, subject->akid);
		if (ret != X509_V_OK)
			return ret;
		}

	if(subject->ex_flags & EXFLAG_PROXY)
		{
		if(ku_reject(issuer, KU_DIGITAL_SIGNATURE))
			return X509_V_ERR_KEYUSAGE_NO_DIGITAL_SIGNATURE;
		}
	else if(ku_reject(issuer, KU_KEY_CERT_SIGN))
		return X509_V_ERR_KEYUSAGE_NO_CERTSIGN;
	return X509_V_OK;
}

int X509_check_akid(X509 *issuer, AUTHORITY_KEYID *akid)
	{

	if(!akid)
		return X509_V_OK;

	/* Check key ids (if present) */
	/* Check key ids (if present) */
		if(subject->akid->keyid && issuer->skid &&
	if(akid->keyid && issuer->skid &&
		 ASN1_OCTET_STRING_cmp(subject->akid->keyid, issuer->skid) )
		 ASN1_OCTET_STRING_cmp(akid->keyid, issuer->skid) )
				return X509_V_ERR_AKID_SKID_MISMATCH;
				return X509_V_ERR_AKID_SKID_MISMATCH;
	/* Check serial number */
	/* Check serial number */
		if(subject->akid->serial &&
	if(akid->serial &&
			ASN1_INTEGER_cmp(X509_get_serialNumber(issuer),
		ASN1_INTEGER_cmp(X509_get_serialNumber(issuer), akid->serial))
						subject->akid->serial))
				return X509_V_ERR_AKID_ISSUER_SERIAL_MISMATCH;
				return X509_V_ERR_AKID_ISSUER_SERIAL_MISMATCH;
	/* Check issuer name */
	/* Check issuer name */
		if(subject->akid->issuer) {
	if(akid->issuer)
		{
		/* Ugh, for some peculiar reason AKID includes
		/* Ugh, for some peculiar reason AKID includes
		 * SEQUENCE OF GeneralName. So look for a DirName.
		 * SEQUENCE OF GeneralName. So look for a DirName.
		 * There may be more than one but we only take any
		 * There may be more than one but we only take any
@@ -665,10 +688,12 @@ int X509_check_issued(X509 *issuer, X509 *subject)
		GENERAL_NAME *gen;
		GENERAL_NAME *gen;
		X509_NAME *nm = NULL;
		X509_NAME *nm = NULL;
		int i;
		int i;
			gens = subject->akid->issuer;
		gens = akid->issuer;
			for(i = 0; i < sk_GENERAL_NAME_num(gens); i++) {
		for(i = 0; i < sk_GENERAL_NAME_num(gens); i++)
			{
			gen = sk_GENERAL_NAME_value(gens, i);
			gen = sk_GENERAL_NAME_value(gens, i);
				if(gen->type == GEN_DIRNAME) {
			if(gen->type == GEN_DIRNAME)
				{
				nm = gen->d.dirn;
				nm = gen->d.dirn;
				break;
				break;
				}
				}
@@ -676,14 +701,6 @@ int X509_check_issued(X509 *issuer, X509 *subject)
		if(nm && X509_NAME_cmp(nm, X509_get_issuer_name(issuer)))
		if(nm && X509_NAME_cmp(nm, X509_get_issuer_name(issuer)))
			return X509_V_ERR_AKID_ISSUER_SERIAL_MISMATCH;
			return X509_V_ERR_AKID_ISSUER_SERIAL_MISMATCH;
		}
		}
	}
	if(subject->ex_flags & EXFLAG_PROXY)
		{
		if(ku_reject(issuer, KU_DIGITAL_SIGNATURE))
			return X509_V_ERR_KEYUSAGE_NO_DIGITAL_SIGNATURE;
		}
	else if(ku_reject(issuer, KU_KEY_CERT_SIGN))
		return X509_V_ERR_KEYUSAGE_NO_CERTSIGN;
	return X509_V_OK;
	return X509_V_OK;
	}
	}
Loading