Initial CRL based revocation checking.
diff --git a/CHANGES b/CHANGES
index 2d32583..c49d03a 100644
--- a/CHANGES
+++ b/CHANGES
@@ -11,6 +11,21 @@
          *) applies to 0.9.6a (/0.9.6b) and 0.9.7
          +) applies to 0.9.7 only
 
+  +) Initial CRL based revocation checking. If the CRL checking flag(s)
+     are set then the CRL is looked up in the X509_STORE structure and
+     its validity and signature checked, then if the certificate is found
+     in the CRL the verify fails with a revoked error.
+
+     Various new CRL related callbacks added to X509_STORE_CTX structure.
+
+     Command line options added to 'verify' application to support this.
+
+     This needs some additional work, such as being able to handle multiple
+     CRLs with different times, extension based lookup (rather than just
+     by subject name) and ultimately more complete V2 CRL extension
+     handling.
+     [Steve Henson]
+
   +) Add a general user interface API.  This is designed to replace things
      like des_read_password and friends (backward compatibility functions
      using this new API are provided).  The purpose is to remove prompting
diff --git a/apps/verify.c b/apps/verify.c
index f384de6..0802728 100644
--- a/apps/verify.c
+++ b/apps/verify.c
@@ -73,7 +73,7 @@
 static int MS_CALLBACK cb(int ok, X509_STORE_CTX *ctx);
 static int check(X509_STORE *ctx, char *file, STACK_OF(X509) *uchain, STACK_OF(X509) *tchain, int purpose);
 static STACK_OF(X509) *load_untrusted(char *file);
-static int v_verbose=0, issuer_checks = 0;
+static int v_verbose=0, vflags = 0;
 
 int MAIN(int, char **);
 
@@ -148,7 +148,11 @@
 			else if (strcmp(*argv,"-help") == 0)
 				goto end;
 			else if (strcmp(*argv,"-issuer_checks") == 0)
-				issuer_checks=1;
+				vflags |= X509_V_FLAG_CB_ISSUER_CHECK;
+			else if (strcmp(*argv,"-crl_check") == 0)
+				vflags |= X509_V_FLAG_CRL_CHECK;
+			else if (strcmp(*argv,"-crl_check_all") == 0)
+				vflags |= X509_V_FLAG_CRL_CHECK|X509_V_FLAG_CRL_CHECK_ALL;
 			else if (strcmp(*argv,"-verbose") == 0)
 				v_verbose=1;
 			else if (argv[0][0] == '-')
@@ -227,7 +231,7 @@
 	ret=0;
 end:
 	if (ret == 1) {
-		BIO_printf(bio_err,"usage: verify [-verbose] [-CApath path] [-CAfile file] [-purpose purpose] [-engine e] cert1 cert2 ...\n");
+		BIO_printf(bio_err,"usage: verify [-verbose] [-CApath path] [-CAfile file] [-purpose purpose] [-crl_check] [-engine e] cert1 cert2 ...\n");
 		BIO_printf(bio_err,"recognized usages:\n");
 		for(i = 0; i < X509_PURPOSE_get_count(); i++) {
 			X509_PURPOSE *ptmp;
@@ -286,8 +290,7 @@
 	X509_STORE_CTX_init(csc,ctx,x,uchain);
 	if(tchain) X509_STORE_CTX_trusted_stack(csc, tchain);
 	if(purpose >= 0) X509_STORE_CTX_set_purpose(csc, purpose);
-	if(issuer_checks)
-		X509_STORE_CTX_set_flags(csc, X509_V_FLAG_CB_ISSUER_CHECK);
+	X509_STORE_CTX_set_flags(csc, vflags);
 	i=X509_verify_cert(csc);
 	X509_STORE_CTX_free(csc);
 
@@ -375,6 +378,8 @@
 		if (ctx->error == X509_V_ERR_PATH_LENGTH_EXCEEDED) ok=1;
 		if (ctx->error == X509_V_ERR_INVALID_PURPOSE) ok=1;
 		if (ctx->error == X509_V_ERR_DEPTH_ZERO_SELF_SIGNED_CERT) ok=1;
+		if (ctx->error == X509_V_ERR_CRL_HAS_EXPIRED) ok=1;
+		if (ctx->error == X509_V_ERR_CRL_NOT_YET_VALID) ok=1;
 		}
 	if (!v_verbose)
 		ERR_clear_error();
diff --git a/crypto/x509/x509_txt.c b/crypto/x509/x509_txt.c
index cfb478d..417be41 100644
--- a/crypto/x509/x509_txt.c
+++ b/crypto/x509/x509_txt.c
@@ -83,7 +83,7 @@
 	case X509_V_ERR_UNABLE_TO_DECRYPT_CERT_SIGNATURE:
 		return("unable to decrypt certificate's signature");
 	case X509_V_ERR_UNABLE_TO_DECRYPT_CRL_SIGNATURE:
-		return("unable to decrypt CRL's's signature");
+		return("unable to decrypt CRL's signature");
 	case X509_V_ERR_UNABLE_TO_DECODE_ISSUER_PUBLIC_KEY:
 		return("unable to decode issuer public key");
 	case X509_V_ERR_CERT_SIGNATURE_FAILURE:
@@ -141,6 +141,9 @@
 	case X509_V_ERR_KEYUSAGE_NO_CERTSIGN:
 		return("key usage does not include certificate signing");
 
+	case X509_V_ERR_UNABLE_TO_GET_CRL_ISSUER:
+		return("unable to get CRL issuer certificate");
+
 	default:
 		sprintf(buf,"error number %ld",n);
 		return(buf);
diff --git a/crypto/x509/x509_vfy.c b/crypto/x509/x509_vfy.c
index 298016b..c8fa53d 100644
--- a/crypto/x509/x509_vfy.c
+++ b/crypto/x509/x509_vfy.c
@@ -75,6 +75,8 @@
 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_trust(X509_STORE_CTX *ctx);
+static int check_revocation(X509_STORE_CTX *ctx);
+static int check_cert(X509_STORE_CTX *ctx);
 static int internal_verify(X509_STORE_CTX *ctx);
 const char *X509_version="X.509" OPENSSL_VERSION_PTEXT;
 
@@ -296,6 +298,13 @@
 	/* We may as well copy down any DSA parameters that are required */
 	X509_get_pubkey_parameters(NULL,ctx->chain);
 
+	/* Check revocation status: we do this after copying parameters
+	 * because they may be needed for CRL signature verification.
+	 */
+
+	ok = ctx->check_revocation(ctx);
+	if(!ok) goto end;
+
 	/* At this point, we have a chain and just need to verify it */
 	if (ctx->verify != NULL)
 		ok=ctx->verify(ctx);
@@ -425,7 +434,7 @@
 	ok = X509_check_trust(x, ctx->trust, 0);
 	if (ok == X509_TRUST_TRUSTED)
 		return 1;
-	ctx->error_depth = sk_X509_num(ctx->chain) - 1;
+	ctx->error_depth = i;
 	ctx->current_cert = x;
 	if (ok == X509_TRUST_REJECTED)
 		ctx->error = X509_V_ERR_CERT_REJECTED;
@@ -436,6 +445,196 @@
 #endif
 }
 
+static int check_revocation(X509_STORE_CTX *ctx)
+	{
+	int i, last, ok;
+	if (!(ctx->flags & X509_V_FLAG_CRL_CHECK))
+		return 1;
+	if (ctx->flags & X509_V_FLAG_CRL_CHECK_ALL)
+		last = 0;
+	else
+		last = sk_X509_num(ctx->chain) - 1;
+	for(i = 0; i <= last; i++)
+		{
+		ctx->error_depth = i;
+		ok = check_cert(ctx);
+		if (!ok) return ok;
+		}
+	return 1;
+	}
+
+static int check_cert(X509_STORE_CTX *ctx)
+	{
+	X509_CRL *crl = NULL;
+	X509 *x;
+	int ok, cnum;
+	cnum = ctx->error_depth;
+	x = sk_X509_value(ctx->chain, cnum);
+	ctx->current_cert = x;
+	/* Try to retrieve relevant CRL */
+	ok = ctx->get_crl(ctx, &crl, x);
+	/* If error looking up CRL, nothing we can do except
+	 * notify callback
+	 */
+	if(!ok)
+		{
+		ctx->error = X509_V_ERR_UNABLE_TO_GET_CRL;
+		if (ctx->verify_cb)
+			ok = ctx->verify_cb(0, ctx);
+		goto err;
+		}
+	ctx->current_crl = crl;
+	ok = ctx->check_crl(ctx, crl);
+	if (!ok) goto err;
+	ok = ctx->cert_crl(ctx, crl, x);
+	err:
+	ctx->current_crl = NULL;
+	X509_CRL_free(crl);
+	return ok;
+
+	}
+
+/* Retrieve CRL corresponding to certificate: currently just a
+ * subject lookup: maybe use AKID later...
+ * Also might look up any included CRLs too (e.g PKCS#7 signedData).
+ */
+static int get_crl(X509_STORE_CTX *ctx, X509_CRL **crl, X509 *x)
+	{
+	int ok;
+	X509_OBJECT xobj;
+	ok = X509_STORE_get_by_subject(ctx, X509_LU_CRL, X509_get_issuer_name(x), &xobj);
+	if (!ok) return 0;
+	*crl = xobj.data.crl;
+	return 1;
+	}
+
+/* Check CRL validity */
+static int check_crl(X509_STORE_CTX *ctx, X509_CRL *crl)
+	{
+	X509 *issuer = NULL;
+	EVP_PKEY *ikey = NULL;
+	int ok = 0, chnum, cnum, i;
+	time_t *ptime;
+	cnum = ctx->error_depth;
+	chnum = sk_X509_num(ctx->chain) - 1;
+	/* Find CRL issuer: if not last certificate then issuer
+	 * is next certificate in chain.
+	 */
+	if(cnum < chnum)
+		issuer = sk_X509_value(ctx->chain, cnum + 1);
+	else
+		{
+		issuer = sk_X509_value(ctx->chain, chnum);
+		/* If not self signed, can't check signature */
+		if(!ctx->check_issued(ctx, issuer, issuer))
+			{
+			ctx->error = X509_V_ERR_UNABLE_TO_GET_CRL_ISSUER;
+			if(ctx->verify_cb)
+				ok = ctx->verify_cb(0, ctx);
+			if(!ok) goto err;
+			}
+		}
+
+	if(issuer)
+		{
+
+		/* Attempt to get issuer certificate public key */
+		ikey = X509_get_pubkey(issuer);
+
+		if(!ikey)
+			{
+			ctx->error=X509_V_ERR_UNABLE_TO_DECODE_ISSUER_PUBLIC_KEY;
+			if(ctx->verify_cb)
+				ok = ctx->verify_cb(0, ctx);
+			if (!ok) goto err;
+			}
+		else
+			{
+			/* Verify CRL signature */
+			if(X509_CRL_verify(crl, ikey) <= 0)
+				{
+				ctx->error=X509_V_ERR_CRL_SIGNATURE_FAILURE;
+				if(ctx->verify_cb)
+					ok = ctx->verify_cb(0, ctx);
+				if (!ok) goto err;
+				}
+			}
+		}
+
+	/* OK, CRL signature valid check times */
+	if (ctx->flags & X509_V_FLAG_USE_CHECK_TIME)
+		ptime = &ctx->check_time;
+	else
+		ptime = NULL;
+
+	i=X509_cmp_time(X509_CRL_get_lastUpdate(crl), ptime);
+	if (i == 0)
+		{
+		ctx->error=X509_V_ERR_ERROR_IN_CRL_LAST_UPDATE_FIELD;
+		ok= 0;
+		if(ctx->verify_cb)
+			ok = ctx->verify_cb(0, ctx);
+		if (!ok) goto err;
+		}
+
+	if (i > 0)
+		{
+		ctx->error=X509_V_ERR_CRL_NOT_YET_VALID;
+		ok= 0;
+		if(ctx->verify_cb)
+			ok = ctx->verify_cb(0, ctx);
+		if (!ok) goto err;
+		}
+
+	if(X509_CRL_get_nextUpdate(crl))
+		{
+		i=X509_cmp_time(X509_CRL_get_nextUpdate(crl), ptime);
+
+		if (i == 0)
+			{
+			ctx->error=X509_V_ERR_ERROR_IN_CRL_NEXT_UPDATE_FIELD;
+			ok= 0;
+			if(ctx->verify_cb)
+				ok = ctx->verify_cb(0, ctx);
+			if (!ok) goto err;
+			}
+
+		if (i < 0)
+			{
+			ctx->error=X509_V_ERR_CRL_HAS_EXPIRED;
+			ok= 0;
+			if(ctx->verify_cb)
+				ok = ctx->verify_cb(0, ctx);
+			if (!ok) goto err;
+			}
+		}
+
+	ok = 1;
+
+	err:
+	EVP_PKEY_free(ikey);
+	return ok;
+	}
+
+/* Check certificate against CRL */
+static int cert_crl(X509_STORE_CTX *ctx, X509_CRL *crl, X509 *x)
+	{
+	int idx, ok;
+	X509_REVOKED rtmp;
+	/* Look for serial number of certificate in CRL */
+	rtmp.serialNumber = X509_get_serialNumber(x);
+	idx = sk_X509_REVOKED_find(crl->crl->revoked, &rtmp);
+	/* Not found: OK */
+	if(idx == -1) return 1;
+	/* Otherwise revoked: want something cleverer than
+	 * this to handle entry extensions in V2 CRLs.
+	 */
+	ctx->error = X509_V_ERR_CERT_REVOKED;
+	if (ctx->verify_cb)
+		ok = ctx->verify_cb(0, ctx);
+	return ok;
+	}
+
 static int internal_verify(X509_STORE_CTX *ctx)
 	{
 	int i,ok=0,n;
@@ -885,6 +1084,10 @@
 	ctx->get_issuer = X509_STORE_CTX_get1_issuer;
 	ctx->verify_cb = store->verify_cb;
 	ctx->verify = store->verify;
+	ctx->check_revocation = check_revocation;
+	ctx->get_crl = get_crl;
+	ctx->check_crl = check_crl;
+	ctx->cert_crl = cert_crl;
 	ctx->cleanup = 0;
 	memset(&(ctx->ex_data),0,sizeof(CRYPTO_EX_DATA));
 	}
diff --git a/crypto/x509/x509_vfy.h b/crypto/x509/x509_vfy.h
index 3ae8a90..22b6c95 100644
--- a/crypto/x509/x509_vfy.h
+++ b/crypto/x509/x509_vfy.h
@@ -214,6 +214,10 @@
 	int (*verify_cb)(int ok,X509_STORE_CTX *ctx);		/* error callback */
 	int (*get_issuer)(X509 **issuer, X509_STORE_CTX *ctx, X509 *x);	/* get issuers cert from ctx */
 	int (*check_issued)(X509_STORE_CTX *ctx, X509 *x, X509 *issuer); /* check issued */
+	int (*check_revocation)(X509_STORE_CTX *ctx); /* Check revocation status of chain */
+	int (*get_crl)(X509_STORE_CTX *ctx, X509_CRL **crl, X509 *x); /* retrieve CRL */
+	int (*check_crl)(X509_STORE_CTX *ctx, X509_CRL *crl); /* Check CRL validity */
+	int (*cert_crl)(X509_STORE_CTX *ctx, X509_CRL *crl, X509 *x); /* Check certificate against CRL */
 	int (*cleanup)(X509_STORE_CTX *ctx);
 
 	/* The following is built up */
@@ -227,6 +231,7 @@
 	int error;
 	X509 *current_cert;
 	X509 *current_issuer;	/* cert currently being tested as valid issuer */
+	X509_CRL *current_crl;	/* current CRL */
 
 	CRYPTO_EX_DATA ex_data;
 	};
@@ -283,6 +288,8 @@
 #define		X509_V_ERR_AKID_ISSUER_SERIAL_MISMATCH		31
 #define		X509_V_ERR_KEYUSAGE_NO_CERTSIGN			32
 
+#define		X509_V_ERR_UNABLE_TO_GET_CRL_ISSUER		33
+
 /* The application is not happy */
 #define		X509_V_ERR_APPLICATION_VERIFICATION		50
 
@@ -290,6 +297,8 @@
 
 #define	X509_V_FLAG_CB_ISSUER_CHECK		0x1	/* Send issuer+subject checks to verify_cb */
 #define	X509_V_FLAG_USE_CHECK_TIME		0x2	/* Use check time instead of current time */
+#define	X509_V_FLAG_CRL_CHECK			0x4	/* Lookup CRLs */
+#define	X509_V_FLAG_CRL_CHECK_ALL		0x8	/* Lookup CRLs for whole chain */
 
 int X509_OBJECT_idx_by_subject(STACK_OF(X509_OBJECT) *h, int type,
 	     X509_NAME *name);
diff --git a/ssl/s3_both.c b/ssl/s3_both.c
index 3e98cb0..b4d1b84 100644
--- a/ssl/s3_both.c
+++ b/ssl/s3_both.c
@@ -512,6 +512,7 @@
 		{
 	case X509_V_ERR_UNABLE_TO_GET_ISSUER_CERT:
 	case X509_V_ERR_UNABLE_TO_GET_CRL:
+	case X509_V_ERR_UNABLE_TO_GET_CRL_ISSUER:
 		al=SSL_AD_UNKNOWN_CA;
 		break;
 	case X509_V_ERR_UNABLE_TO_DECRYPT_CERT_SIGNATURE: