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

New options to the -verify program which can be used for chain verification.

Extend the X509_PURPOSE structure to include shortnames for purposed and default
trust ids.

Still need some extendable trust checking code and integration with the SSL and
S/MIME code.
parent 11262391
Loading
Loading
Loading
Loading
+11 −5
Original line number Diff line number Diff line
@@ -7,15 +7,21 @@
  *) Very preliminary certificate chain verify code. Currently just tests
     the untrusted certificates for consistency with the verify purpose
     (which is set when the X509_STORE_CTX structure is set up) and checks
     the pathlength. Totally untested at present: needs some extra
     functionality in the verify program first. There is a
     NO_CHAIN_VERIFY compilation option to keep the old behaviour: this is
     because when it is finally working it will reject chains with
     invalid extensions whereas before it made no checks at all.
     the pathlength. There is a NO_CHAIN_VERIFY compilation option to keep
     the old behaviour: this is because when it is finally working it will
     reject chains with invalid extensions whereas before it made no checks
     at all.

     Still needs some trust checking code.

     Also added X509_STORE_CTX_new() and X509_STORE_CTX_free() functions
     which should be used for version portability: especially since the
     verify structure is likely to change more often now.

     Two new options to the verify program: -untrusted allows a set of
     untrusted certificates to be passed in and -purpose which sets the
     intended purpose of the certificate. If a purpose is set then the
     new chain verify code is used to check extension consistency.
     [Steve Henson]

  *) Support for the authority information access extension.
+8 −7
Original line number Diff line number Diff line
@@ -727,11 +727,12 @@ spkac.o: ../include/openssl/x509.h ../include/openssl/x509_vfy.h apps.h progs.h
verify.o: ../include/openssl/asn1.h ../include/openssl/bio.h
verify.o: ../include/openssl/blowfish.h ../include/openssl/bn.h
verify.o: ../include/openssl/buffer.h ../include/openssl/cast.h
verify.o: ../include/openssl/crypto.h ../include/openssl/des.h
verify.o: ../include/openssl/dh.h ../include/openssl/dsa.h
verify.o: ../include/openssl/e_os.h ../include/openssl/e_os2.h
verify.o: ../include/openssl/err.h ../include/openssl/evp.h
verify.o: ../include/openssl/idea.h ../include/openssl/md2.h
verify.o: ../include/openssl/conf.h ../include/openssl/crypto.h
verify.o: ../include/openssl/des.h ../include/openssl/dh.h
verify.o: ../include/openssl/dsa.h ../include/openssl/e_os.h
verify.o: ../include/openssl/e_os2.h ../include/openssl/err.h
verify.o: ../include/openssl/evp.h ../include/openssl/idea.h
verify.o: ../include/openssl/lhash.h ../include/openssl/md2.h
verify.o: ../include/openssl/md5.h ../include/openssl/mdc2.h
verify.o: ../include/openssl/objects.h ../include/openssl/opensslconf.h
verify.o: ../include/openssl/opensslv.h ../include/openssl/pem.h
@@ -740,8 +741,8 @@ verify.o: ../include/openssl/rc2.h ../include/openssl/rc4.h
verify.o: ../include/openssl/rc5.h ../include/openssl/ripemd.h
verify.o: ../include/openssl/rsa.h ../include/openssl/safestack.h
verify.o: ../include/openssl/sha.h ../include/openssl/stack.h
verify.o: ../include/openssl/x509.h ../include/openssl/x509_vfy.h apps.h
verify.o: progs.h
verify.o: ../include/openssl/x509.h ../include/openssl/x509_vfy.h
verify.o: ../include/openssl/x509v3.h apps.h progs.h
version.o: ../include/openssl/asn1.h ../include/openssl/bio.h
version.o: ../include/openssl/blowfish.h ../include/openssl/bn.h
version.o: ../include/openssl/buffer.h ../include/openssl/cast.h
+3 −2
Original line number Diff line number Diff line
@@ -287,13 +287,14 @@ int MAIN(int argc, char **argv)
	PKCS8_PRIV_KEY_INFO *p8;
	PKCS7 *authsafe;
	X509 *ucert = NULL;
	STACK_OF(X509) *certs;
	STACK_OF(X509) *certs=NULL;
	char *catmp;
	int i;
	unsigned char keyid[EVP_MAX_MD_SIZE];
	unsigned int keyidlen = 0;
	key = PEM_read_bio_PrivateKey(inkey ? inkey : in, NULL, NULL, NULL);
	if (!inkey) (void) BIO_reset(in);
	else BIO_free(inkey);
	if (!key) {
		BIO_printf (bio_err, "Error loading private key\n");
		ERR_print_errors(bio_err);
@@ -364,7 +365,7 @@ int MAIN(int argc, char **argv)
				PKCS12_add_friendlyname(bag, catmp, -1);
		sk_push(bags, (char *)bag);
	}

	sk_X509_pop_free(certs, X509_free);
	if (canames) sk_free(canames);

	if(!noprompt &&
+112 −10
Original line number Diff line number Diff line
@@ -63,22 +63,29 @@
#include <openssl/bio.h>
#include <openssl/err.h>
#include <openssl/x509.h>
#include <openssl/x509v3.h>
#include <openssl/pem.h>

#undef PROG
#define PROG	verify_main

static int MS_CALLBACK cb(int ok, X509_STORE_CTX *ctx);
static int check(X509_STORE *ctx,char *file);
static int check(X509_STORE *ctx,char *file, STACK_OF(X509)*other, int purpose);
static STACK_OF(X509) *load_untrusted(char *file);
static int v_verbose=0;

int MAIN(int argc, char **argv)
	{
	int i,ret=1;
	int purpose = -1;
	char *CApath=NULL,*CAfile=NULL;
	char *untfile = NULL;
	STACK_OF(X509) *untrusted = NULL;
	X509_STORE *cert_ctx=NULL;
	X509_LOOKUP *lookup=NULL;

	X509_PURPOSE_add_standard();
	X509V3_add_standard_extensions();
	cert_ctx=X509_STORE_new();
	if (cert_ctx == NULL) goto end;
	X509_STORE_set_verify_cb_func(cert_ctx,cb);
@@ -107,6 +114,24 @@ int MAIN(int argc, char **argv)
				if (argc-- < 1) goto end;
				CAfile= *(++argv);
				}
			else if (strcmp(*argv,"-purpose") == 0)
				{
				X509_PURPOSE *xptmp;
				if (argc-- < 1) goto end;
				i = X509_PURPOSE_get_by_sname(*(++argv));
				if(i < 0)
					{
					BIO_printf(bio_err, "unrecognised purpose\n");
					goto end;
					}
				xptmp = X509_PURPOSE_iget(i);
				purpose = X509_PURPOSE_get_id(xptmp);
				}
			else if (strcmp(*argv,"-untrusted") == 0)
				{
				if (argc-- < 1) goto end;
				untfile= *(++argv);
				}
			else if (strcmp(*argv,"-help") == 0)
				goto end;
			else if (strcmp(*argv,"-verbose") == 0)
@@ -144,26 +169,45 @@ int MAIN(int argc, char **argv)
		}
	} else X509_LOOKUP_add_dir(lookup,NULL,X509_FILETYPE_DEFAULT);


	ERR_clear_error();
	if (argc < 1) check(cert_ctx,NULL);

	if(untfile) {
		if(!(untrusted = load_untrusted(untfile))) {
			BIO_printf(bio_err, "Error loading untrusted file %s\n", untfile);
			ERR_print_errors(bio_err);
			goto end;
		}
	}

	if (argc < 1) check(cert_ctx, NULL, untrusted, purpose);
	else
		for (i=0; i<argc; i++)
			check(cert_ctx,argv[i]);
			check(cert_ctx,argv[i], untrusted, purpose);
	ret=0;
end:
	if (ret == 1)
	if (ret == 1) {
		BIO_printf(bio_err,"usage: verify [-verbose] [-CApath path] [-CAfile file] cert1 cert2 ...\n");
		BIO_printf(bio_err,"recognised usages:\n");
		for(i = 0; i < X509_PURPOSE_get_count(); i++) {
			X509_PURPOSE *ptmp;
			ptmp = X509_PURPOSE_iget(i);
			BIO_printf(bio_err, "\t%-10s\t%s\n", X509_PURPOSE_iget_sname(ptmp),
								X509_PURPOSE_iget_name(ptmp));
		}
	}
	if (cert_ctx != NULL) X509_STORE_free(cert_ctx);
	sk_X509_pop_free(untrusted, X509_free);
	X509V3_EXT_cleanup();
	X509_PURPOSE_cleanup();
	EXIT(ret);
	}

static int check(X509_STORE *ctx, char *file)
static int check(X509_STORE *ctx, char *file, STACK_OF(X509) *uchain, int purpose)
	{
	X509 *x=NULL;
	BIO *in=NULL;
	int i=0,ret=0;
	X509_STORE_CTX csc;
	X509_STORE_CTX *csc;

	in=BIO_new(BIO_s_file());
	if (in == NULL)
@@ -193,9 +237,16 @@ static int check(X509_STORE *ctx, char *file)
		}
	fprintf(stdout,"%s: ",(file == NULL)?"stdin":file);

	X509_STORE_CTX_init(&csc,ctx,x,NULL);
	i=X509_verify_cert(&csc);
	X509_STORE_CTX_cleanup(&csc);
	csc = X509_STORE_CTX_new();
	if (csc == NULL)
		{
		ERR_print_errors(bio_err);
		goto end;
		}
	X509_STORE_CTX_init(csc,ctx,x,uchain);
	if(purpose >= 0) X509_STORE_CTX_chain_purpose(csc, purpose);
	i=X509_verify_cert(csc);
	X509_STORE_CTX_free(csc);

	ret=0;
end:
@@ -212,6 +263,52 @@ end:
	return(ret);
	}

static STACK_OF(X509) *load_untrusted(char *certfile)
{
	STACK_OF(X509_INFO) *sk=NULL;
	STACK_OF(X509) *stack=NULL, *ret=NULL;
	BIO *in=NULL;
	X509_INFO *xi;

	if(!(stack = sk_X509_new_null())) {
		BIO_printf(bio_err,"memory allocation failure\n");
		goto end;
	}

	if(!(in=BIO_new_file(certfile, "r"))) {
		BIO_printf(bio_err,"error opening the file, %s\n",certfile);
		goto end;
	}

	/* This loads from a file, a stack of x509/crl/pkey sets */
	if(!(sk=PEM_X509_INFO_read_bio(in,NULL,NULL,NULL))) {
		BIO_printf(bio_err,"error reading the file, %s\n",certfile);
		goto end;
	}

	/* scan over it and pull out the certs */
	while (sk_X509_INFO_num(sk))
		{
		xi=sk_X509_INFO_shift(sk);
		if (xi->x509 != NULL)
			{
			sk_X509_push(stack,xi->x509);
			xi->x509=NULL;
			}
		X509_INFO_free(xi);
		}
	if(!sk_X509_num(stack)) {
		BIO_printf(bio_err,"no certificates in file, %s\n",certfile);
		sk_X509_free(stack);
		goto end;
	}
	ret=stack;
end:
	BIO_free(in);
	sk_X509_INFO_free(sk);
	return(ret);
	}

static int MS_CALLBACK cb(int ok, X509_STORE_CTX *ctx)
	{
	char buf[256];
@@ -230,6 +327,11 @@ static int MS_CALLBACK cb(int ok, X509_STORE_CTX *ctx)
		 * the user.
 		 */
		if (ctx->error == X509_V_ERR_DEPTH_ZERO_SELF_SIGNED_CERT) ok=1;
		/* Continue after extension errors too */
		if (ctx->error == X509_V_ERR_INVALID_CA) ok=1;
		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 (!v_verbose)
		ERR_clear_error();
+15 −19
Original line number Diff line number Diff line
@@ -136,14 +136,9 @@ static int sign (X509 *x, EVP_PKEY *pkey,int days,const EVP_MD *digest,
static int x509_certify (X509_STORE *ctx,char *CAfile,const EVP_MD *digest,
			 X509 *x,X509 *xca,EVP_PKEY *pkey,char *serial,
			 int create,int days, LHASH *conf, char *section);
static int efunc(X509_PURPOSE *pt, void *arg);
static int purpose_print(BIO *bio, X509 *cert, X509_PURPOSE *pt);
static int reqfile=0;

typedef struct {
BIO *bio;
X509 *cert;
} X509_PPRINT;

int MAIN(int argc, char **argv)
	{
	int ret=1;
@@ -609,11 +604,14 @@ bad:
				}
			else if (pprint == i)
				{
				X509_PPRINT ptmp;
				ptmp.bio = STDout;
				ptmp.cert = x;
				X509_PURPOSE *ptmp;
				int j;
				BIO_printf(STDout, "Certificate purposes:\n");
				X509_PURPOSE_enum(efunc, &ptmp);
				for(j = 0; j < X509_PURPOSE_get_count(); j++)
					{
					ptmp = X509_PURPOSE_iget(j);
					purpose_print(STDout, x, ptmp);
					}
				}
			else
				if (modulus == i)
@@ -1227,20 +1225,18 @@ err:
	return(0);
	}

static int efunc(X509_PURPOSE *pt, void *arg)
static int purpose_print(BIO *bio, X509 *cert, X509_PURPOSE *pt)
{
	X509_PPRINT *ptmp;
	int id, i, idret;
	char *pname;
	ptmp = arg;
	id = X509_PURPOSE_get_id(pt);
	pname = X509_PURPOSE_get_name(pt);
	pname = X509_PURPOSE_iget_name(pt);
	for(i = 0; i < 2; i++) {
		idret = X509_check_purpose(ptmp->cert, id, i);
		BIO_printf(ptmp->bio, "%s%s : ", pname, i ? " CA" : ""); 
		if(idret == 1) BIO_printf(ptmp->bio, "Yes\n");
		else if (idret == 0) BIO_printf(ptmp->bio, "No\n");
		else BIO_printf(ptmp->bio, "Yes (WARNING code=%d)\n", idret);
		idret = X509_check_purpose(cert, id, i);
		BIO_printf(bio, "%s%s : ", pname, i ? " CA" : ""); 
		if(idret == 1) BIO_printf(bio, "Yes\n");
		else if (idret == 0) BIO_printf(bio, "No\n");
		else BIO_printf(bio, "Yes (WARNING code=%d)\n", idret);
	}
	return 1;
}
Loading