Initial chain verify code: not tested probably not working
authorDr. Stephen Henson <steve@openssl.org>
Wed, 24 Nov 1999 01:31:49 +0000 (01:31 +0000)
committerDr. Stephen Henson <steve@openssl.org>
Wed, 24 Nov 1999 01:31:49 +0000 (01:31 +0000)
at present. However nothing enables it yet so this doesn't
matter :-)

CHANGES
crypto/x509/x509_lu.c
crypto/x509/x509_txt.c
crypto/x509/x509_vfy.c
crypto/x509/x509_vfy.h

diff --git a/CHANGES b/CHANGES
index 870847d..493f7e6 100644 (file)
--- a/CHANGES
+++ b/CHANGES
@@ -4,8 +4,21 @@
 
  Changes between 0.9.4 and 0.9.5  [xx XXX 1999]
 
-  *) Support for the authority information access extension. Not
-     very well tested yet.
+  *) 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.
+
+     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.
+     [Steve Henson]
+
+  *) Support for the authority information access extension.
      [Steve Henson]
 
   *) Modify RSA and DSA PEM read routines to transparently handle
index 18bfecb..82e7fa5 100644 (file)
@@ -381,6 +381,17 @@ X509_OBJECT *X509_OBJECT_retrieve_by_subject(LHASH *h, int type,
        return(tmp);
        }
 
+X509_STORE_CTX *X509_STORE_CTX_new(void)
+{
+       return (X509_STORE_CTX *)Malloc(sizeof(X509_STORE_CTX));
+}
+
+void X509_STORE_CTX_free(X509_STORE_CTX *ctx)
+{
+       X509_STORE_CTX_cleanup(ctx);
+       Free(ctx);
+}
+
 void X509_STORE_CTX_init(X509_STORE_CTX *ctx, X509_STORE *store, X509 *x509,
             STACK_OF(X509) *chain)
        {
@@ -389,6 +400,8 @@ void X509_STORE_CTX_init(X509_STORE_CTX *ctx, X509_STORE *store, X509 *x509,
        ctx->cert=x509;
        ctx->untrusted=chain;
        ctx->last_untrusted=0;
+       ctx->chain_purpose=0;
+       ctx->trust_purpose=0;
        ctx->valid=0;
        ctx->chain=NULL;
        ctx->depth=9;
index 60c48f1..b6f61c5 100644 (file)
@@ -120,6 +120,12 @@ const char *X509_verify_cert_error_string(long n)
                return("certificate chain too long");
        case X509_V_ERR_CERT_REVOKED:
                return("certificate revoked");
+       case X509_V_ERR_INVALID_CA:
+               return ("invalid CA certificate");
+       case X509_V_ERR_PATH_LENGTH_EXCEEDED:
+               return ("path length constraint exceeded");
+       case X509_V_ERR_INVALID_PURPOSE:
+               return ("unsupported certificate purpose");
        case X509_V_ERR_APPLICATION_VERIFICATION:
                return("application verification failure");
        default:
index 97984ca..3d1b38a 100644 (file)
 #include <openssl/evp.h>
 #include <openssl/asn1.h>
 #include <openssl/x509.h>
+#include <openssl/x509v3.h>
 #include <openssl/objects.h>
 
 static int null_callback(int ok,X509_STORE_CTX *e);
+static int check_chain_purpose(X509_STORE_CTX *ctx);
 static int internal_verify(X509_STORE_CTX *ctx);
 const char *X509_version="X.509" OPENSSL_VERSION_PTEXT;
 
@@ -290,6 +292,11 @@ int X509_verify_cert(X509_STORE_CTX *ctx)
                if (!ok) goto end;
                }
 
+       /* We have the chain complete: now we need to check its purpose */
+       if(ctx->chain_purpose > 0) ok = check_chain_purpose(ctx);
+
+       if(!ok) goto end;
+
        /* We may as well copy down any DSA parameters that are required */
        X509_get_pubkey_parameters(NULL,ctx->chain);
 
@@ -308,6 +315,47 @@ end:
        return(ok);
        }
 
+/* Check a certificate chains extensions for consistency
+ * with the supplied purpose
+ */
+
+static int check_chain_purpose(X509_STORE_CTX *ctx)
+{
+#ifdef NO_CHAIN_VERIFY
+       return 1;
+#else
+       int i, ok=0;
+       X509 *x;
+       int (*cb)();
+       cb=ctx->ctx->verify_cb;
+       if (cb == NULL) cb=null_callback;
+       /* Check all untrusted certificates */
+       for(i = 0; i < ctx->last_untrusted; i++) {
+               x = sk_X509_value(ctx->chain, i);
+               if(!X509_check_purpose(x, ctx->chain_purpose, i)) {
+                       if(i) ctx->error = X509_V_ERR_INVALID_CA;
+                       else 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))) {
+                       ctx->error = X509_V_ERR_PATH_LENGTH_EXCEEDED;
+                       ctx->error_depth = i;
+                       ctx->current_cert = x;
+                       ok=cb(0,ctx);
+                       if(!ok) goto end;
+               }
+       }
+       ok = 1;
+       end:
+       return(ok);
+#endif
+}
+
 static int internal_verify(X509_STORE_CTX *ctx)
        {
        int i,ok=0,n;
@@ -648,6 +696,16 @@ void X509_STORE_CTX_set_chain(X509_STORE_CTX *ctx, STACK_OF(X509) *sk)
        ctx->untrusted=sk;
        }
 
+void X509_STORE_CTX_chain_purpose(X509_STORE_CTX *ctx, int purpose)
+       {
+       ctx->chain_purpose = purpose;
+       }
+
+void X509_STORE_CTX_trust_purpose(X509_STORE_CTX *ctx, int purpose)
+       {
+       ctx->trust_purpose = purpose;
+       }
+
 IMPLEMENT_STACK_OF(X509)
 IMPLEMENT_ASN1_SET_OF(X509)
 
index 9891a69..47c0b40 100644 (file)
@@ -202,6 +202,8 @@ struct x509_store_state_st      /* X509_STORE_CTX */
        /* The following are set by the caller */
        X509 *cert;             /* The cert to check */
        STACK_OF(X509) *untrusted;      /* chain of X509s - untrusted - passed in */
+       int chain_purpose;              /* purpose to check untrusted certificates */
+       int trust_purpose;              /* trust setting to check */
 
        /* The following is built up */
        int depth;              /* how far to go looking up certs */
@@ -258,6 +260,9 @@ struct x509_store_state_st      /* X509_STORE_CTX */
 #define                X509_V_ERR_UNABLE_TO_VERIFY_LEAF_SIGNATURE      21
 #define                X509_V_ERR_CERT_CHAIN_TOO_LONG                  22
 #define                X509_V_ERR_CERT_REVOKED                         23
+#define                X509_V_ERR_INVALID_CA                           24
+#define                X509_V_ERR_PATH_LENGTH_EXCEEDED                 25
+#define                X509_V_ERR_INVALID_PURPOSE                      26
 
 /* The application is not happy */
 #define                X509_V_ERR_APPLICATION_VERIFICATION             50
@@ -285,6 +290,8 @@ void X509_OBJECT_free_contents(X509_OBJECT *a);
 X509_STORE *X509_STORE_new(void );
 void X509_STORE_free(X509_STORE *v);
 
+X509_STORE_CTX *X509_STORE_CTX_new(void);
+void X509_STORE_CTX_free(X509_STORE_CTX *ctx);
 void X509_STORE_CTX_init(X509_STORE_CTX *ctx, X509_STORE *store,
                         X509 *x509, STACK_OF(X509) *chain);
 void X509_STORE_CTX_cleanup(X509_STORE_CTX *ctx);
@@ -340,6 +347,8 @@ X509 *      X509_STORE_CTX_get_current_cert(X509_STORE_CTX *ctx);
 STACK_OF(X509) *X509_STORE_CTX_get_chain(X509_STORE_CTX *ctx);
 void   X509_STORE_CTX_set_cert(X509_STORE_CTX *c,X509 *x);
 void   X509_STORE_CTX_set_chain(X509_STORE_CTX *c,STACK_OF(X509) *sk);
+void X509_STORE_CTX_chain_purpose(X509_STORE_CTX *ctx, int purpose);
+void X509_STORE_CTX_trust_purpose(X509_STORE_CTX *ctx, int purpose);
 
 #ifdef  __cplusplus
 }