Add trust setting support to the verify code. It now checks the
authorDr. Stephen Henson <steve@openssl.org>
Sat, 27 Nov 1999 19:43:10 +0000 (19:43 +0000)
committerDr. Stephen Henson <steve@openssl.org>
Sat, 27 Nov 1999 19:43:10 +0000 (19:43 +0000)
trust settings of the root CA.

After a few fixes it seems to work OK.

Still need to add support to SSL and S/MIME code though.

CHANGES
apps/verify.c
crypto/asn1/t_x509a.c
crypto/x509/x509.h
crypto/x509/x509_err.c
crypto/x509/x509_txt.c
crypto/x509/x509_vfy.c
crypto/x509/x509_vfy.h
crypto/x509v3/v3_lib.c
crypto/x509v3/v3_purp.c

diff --git a/CHANGES b/CHANGES
index 3261ecea27cd83778ca85bf3dc7c66d2ec862aef..fa00300ebe67f06852cbb0323b885269ceee126a 100644 (file)
--- a/CHANGES
+++ b/CHANGES
      DSA key was used because it didn't fix the digest.
      [Steve Henson]
 
-  *) 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. 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.
-
-     Preliminary untested trust code. 
+  *) Initial certificate chain verify code. Currently 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.
+
+     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 every previous version of OpenSSL and SSLeay
+     made no checks at all.
+
+     Trust code: checks the root CA for the relevant trust settings. Trust
+     settings have an initial value consistent with the verify purpose: e.g.
+     if the verify purpose is for SSL client use it expects the CA to be
+     trusted for SSL client use. However the default value can be changed to
+     permit custom trust settings: one example of this would be to only trust
+     certificates from a specific "secure" set of CAs.
 
      Also added X509_STORE_CTX_new() and X509_STORE_CTX_free() functions
      which should be used for version portability: especially since the
index 579d4ea184463aefff988383298330f4d64390a3..8a03e0f2904c6d1f89ae776f0c9477b305d431d5 100644 (file)
@@ -85,6 +85,7 @@ int MAIN(int argc, char **argv)
        X509_LOOKUP *lookup=NULL;
 
        X509_PURPOSE_add_standard();
+       X509_TRUST_add_standard();
        X509V3_add_standard_extensions();
        cert_ctx=X509_STORE_new();
        if (cert_ctx == NULL) goto end;
@@ -199,6 +200,7 @@ end:
        sk_X509_pop_free(untrusted, X509_free);
        X509V3_EXT_cleanup();
        X509_PURPOSE_cleanup();
+       X509_TRUST_cleanup();
        EXIT(ret);
        }
 
index 5c15d09e43b56b352b22f11adb1f5dbb2ec08770..0e342723aa6072f41458a052b955fe411878bc5c 100644 (file)
@@ -99,13 +99,13 @@ int X509_CERT_AUX_print(BIO *out, X509_CERT_AUX *aux, int indent)
        int i;
        if(!aux) return 1;
        if(aux->trust) {
-               BIO_printf(out, "%*sTrusted for:\n", indent, "");
+               BIO_printf(out, "%*sTrusted Uses:\n", indent, "");
                ASN1_BIT_STRING_name_print(out, aux->trust, tbits, indent + 2);
-       } else BIO_printf(out, "%*sNo Trust Settings\n", indent + 2, "");
+       } else BIO_printf(out, "%*sNo Trusted Uses.\n", indent, "");
        if(aux->reject) {
-               BIO_printf(out, "%*sUntrusted for:\n", indent, "");
+               BIO_printf(out, "%*sRejected Uses:\n", indent, "");
                ASN1_BIT_STRING_name_print(out, aux->reject, tbits, indent + 2);
-       } else BIO_printf(out, "%*sNo Untrusted Settings\n", indent + 2, "");
+       } else BIO_printf(out, "%*sNo Rejected Uses.\n", indent, "");
        if(aux->othertrust) {
                first = 1;
                BIO_printf(out, "%*sOther Trusted Uses:\n%*s",
@@ -121,7 +121,7 @@ int X509_CERT_AUX_print(BIO *out, X509_CERT_AUX *aux, int indent)
        }
        if(aux->otherreject) {
                first = 1;
-               BIO_printf(out, "%*sOther Untrusted Uses:\n%*s",
+               BIO_printf(out, "%*sOther Rejected Uses:\n%*s",
                                                indent, "", indent + 2, "");
                for(i = 0; i < sk_ASN1_OBJECT_num(aux->otherreject); i++) {
                        if(!first) BIO_puts(out, ", ");
index 227bbaf1ca269b65897a15490e82e4a230954bdc..534c3d69f77bbd19358e71330947af1914c265f9 100644 (file)
@@ -1098,6 +1098,7 @@ int X509_TRUST_get_trust(X509_TRUST *xp);
 #define X509_F_X509_REQ_PRINT                           121
 #define X509_F_X509_REQ_PRINT_FP                        122
 #define X509_F_X509_REQ_TO_X509                                 123
+#define X509_F_X509_SET_PURPOSE_AND_TRUST               134
 #define X509_F_X509_STORE_ADD_CERT                      124
 #define X509_F_X509_STORE_ADD_CRL                       125
 #define X509_F_X509_TO_X509_REQ                                 126
@@ -1122,6 +1123,7 @@ int X509_TRUST_get_trust(X509_TRUST *xp);
 #define X509_R_UNABLE_TO_GET_CERTS_PUBLIC_KEY           108
 #define X509_R_UNKNOWN_KEY_TYPE                                 117
 #define X509_R_UNKNOWN_NID                              109
+#define X509_R_UNKNOWN_TRUST_ID                                 120
 #define X509_R_UNSUPPORTED_ALGORITHM                    111
 #define X509_R_WRONG_LOOKUP_TYPE                        112
 
index c185bc02f81046d59cee4784d5277d284fee77bd..acaa99ffae53416093f85982617b1e9e3db6fd72 100644 (file)
@@ -91,10 +91,11 @@ static ERR_STRING_DATA X509_str_functs[]=
 {ERR_PACK(0,X509_F_X509_REQ_PRINT,0),  "X509_REQ_print"},
 {ERR_PACK(0,X509_F_X509_REQ_PRINT_FP,0),       "X509_REQ_print_fp"},
 {ERR_PACK(0,X509_F_X509_REQ_TO_X509,0),        "X509_REQ_to_X509"},
+{ERR_PACK(0,X509_F_X509_SET_PURPOSE_AND_TRUST,0),      "X509_set_purpose_and_trust"},
 {ERR_PACK(0,X509_F_X509_STORE_ADD_CERT,0),     "X509_STORE_add_cert"},
 {ERR_PACK(0,X509_F_X509_STORE_ADD_CRL,0),      "X509_STORE_add_crl"},
 {ERR_PACK(0,X509_F_X509_TO_X509_REQ,0),        "X509_to_X509_REQ"},
-{ERR_PACK(0,X509_F_X509_TRUST_ADD,0),  "X509_TRUST_ADD"},
+{ERR_PACK(0,X509_F_X509_TRUST_ADD,0),  "X509_TRUST_add"},
 {ERR_PACK(0,X509_F_X509_VERIFY_CERT,0),        "X509_verify_cert"},
 {0,NULL}
        };
@@ -118,6 +119,7 @@ static ERR_STRING_DATA X509_str_reasons[]=
 {X509_R_UNABLE_TO_GET_CERTS_PUBLIC_KEY   ,"unable to get certs public key"},
 {X509_R_UNKNOWN_KEY_TYPE                 ,"unknown key type"},
 {X509_R_UNKNOWN_NID                      ,"unknown nid"},
+{X509_R_UNKNOWN_TRUST_ID                 ,"unknown trust id"},
 {X509_R_UNSUPPORTED_ALGORITHM            ,"unsupported algorithm"},
 {X509_R_WRONG_LOOKUP_TYPE                ,"wrong lookup type"},
 {0,NULL}
index b6f61c5e5742980bccefb4ce5696675a129513bc..209cf5319135dfbc778aa93580d655a531578446 100644 (file)
@@ -126,6 +126,10 @@ const char *X509_verify_cert_error_string(long n)
                return ("path length constraint exceeded");
        case X509_V_ERR_INVALID_PURPOSE:
                return ("unsupported certificate purpose");
+       case X509_V_ERR_CERT_UNTRUSTED:
+               return ("certificate not trusted");
+       case X509_V_ERR_CERT_REJECTED:
+               return ("certificate rejected");
        case X509_V_ERR_APPLICATION_VERIFICATION:
                return("application verification failure");
        default:
index 3d1b38a0194c99b0b43da00523656cf39559e2b1..75ab96e506ee3b8888c669f3e264034fd687e92a 100644 (file)
@@ -72,6 +72,7 @@
 
 static int null_callback(int ok,X509_STORE_CTX *e);
 static int check_chain_purpose(X509_STORE_CTX *ctx);
+static int check_trust(X509_STORE_CTX *ctx);
 static int internal_verify(X509_STORE_CTX *ctx);
 const char *X509_version="X.509" OPENSSL_VERSION_PTEXT;
 
@@ -297,6 +298,12 @@ int X509_verify_cert(X509_STORE_CTX *ctx)
 
        if(!ok) goto end;
 
+       /* The chain extensions are OK: check trust */
+
+       if(ctx->trust_purpose > 0) ok = check_trust(ctx);
+
+       if(!ok) goto end;
+
        /* We may as well copy down any DSA parameters that are required */
        X509_get_pubkey_parameters(NULL,ctx->chain);
 
@@ -356,6 +363,30 @@ static int check_chain_purpose(X509_STORE_CTX *ctx)
 #endif
 }
 
+static int check_trust(X509_STORE_CTX *ctx)
+{
+#ifdef NO_CHAIN_VERIFY
+       return 1;
+#else
+       int i, ok;
+       X509 *x;
+       int (*cb)();
+       cb=ctx->ctx->verify_cb;
+       if (cb == NULL) cb=null_callback;
+/* For now just check the last certificate in the chain */
+       i = sk_X509_num(ctx->chain) - 1;
+       x = sk_X509_value(ctx->chain, i);
+       ok = X509_check_trust(x, ctx->trust_purpose, 0);
+       if(ok == X509_TRUST_TRUSTED) return 1;
+       ctx->error_depth = sk_X509_num(ctx->chain) - 1;
+       ctx->current_cert = x;
+       if(ok == X509_TRUST_REJECTED) ctx->error = X509_V_ERR_CERT_REJECTED;
+       else ctx->error = X509_V_ERR_CERT_UNTRUSTED;
+       ok = cb(0, ctx);
+       return(ok);
+#endif
+}
+
 static int internal_verify(X509_STORE_CTX *ctx)
        {
        int i,ok=0,n;
@@ -696,9 +727,10 @@ 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)
+int X509_STORE_CTX_chain_purpose(X509_STORE_CTX *ctx, int purpose)
        {
-       ctx->chain_purpose = purpose;
+               return X509_set_purpose_and_trust(purpose,
+                               &ctx->chain_purpose, &ctx->trust_purpose);
        }
 
 void X509_STORE_CTX_trust_purpose(X509_STORE_CTX *ctx, int purpose)
@@ -706,6 +738,22 @@ void X509_STORE_CTX_trust_purpose(X509_STORE_CTX *ctx, int purpose)
        ctx->trust_purpose = purpose;
        }
 
+int X509_set_purpose_and_trust(int id, int *purp, int *trust)
+{
+       X509_PURPOSE *ptmp;
+       int idx;
+       idx = X509_PURPOSE_get_by_id(id);
+       if(idx == -1) {
+               X509err(X509_F_X509_SET_PURPOSE_AND_TRUST,
+                                       X509_R_UNKNOWN_TRUST_ID);
+               return 0;
+       }
+       ptmp = X509_PURPOSE_iget(idx);
+       if(purp) *purp = id;
+       if(trust) *trust = ptmp->trust_id;
+       return 1;
+}
+
 IMPLEMENT_STACK_OF(X509)
 IMPLEMENT_ASN1_SET_OF(X509)
 
index 47c0b4028c09b4c172e95b47f3525757da9bb12a..5e197040fb6865929bf6acc6ca476bdf39cb2e40 100644 (file)
@@ -263,6 +263,8 @@ struct x509_store_state_st      /* X509_STORE_CTX */
 #define                X509_V_ERR_INVALID_CA                           24
 #define                X509_V_ERR_PATH_LENGTH_EXCEEDED                 25
 #define                X509_V_ERR_INVALID_PURPOSE                      26
+#define                X509_V_ERR_CERT_UNTRUSTED                       27
+#define                X509_V_ERR_CERT_REJECTED                        28
 
 /* The application is not happy */
 #define                X509_V_ERR_APPLICATION_VERIFICATION             50
@@ -347,8 +349,9 @@ 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);
+int X509_STORE_CTX_chain_purpose(X509_STORE_CTX *ctx, int purpose);
 void X509_STORE_CTX_trust_purpose(X509_STORE_CTX *ctx, int purpose);
+int X509_set_purpose_and_trust(int id, int *purp, int *trust);
 
 #ifdef  __cplusplus
 }
index edf7a960b38a4cfb8fb99a0b06aa4bbb55575f63..d6aeaabccddfd83af8a7cc1edf746aba00d10dfc 100644 (file)
@@ -128,10 +128,13 @@ int X509V3_EXT_add_alias(int nid_to, int nid_from)
        return 1;
 }
 
+static int added_exts = 0;
+
 void X509V3_EXT_cleanup(void)
 {
        sk_pop_free(ext_list, ext_list_free);
        ext_list = NULL;
+       added_exts = 0;
 }
 
 static void ext_list_free(X509V3_EXT_METHOD *ext)
@@ -147,6 +150,7 @@ extern X509V3_EXT_METHOD v3_crl_num, v3_crl_reason, v3_cpols, v3_crld;
 
 int X509V3_add_standard_extensions(void)
 {
+       if(added_exts) return 1;
        X509V3_EXT_add_list(v3_ns_ia5_list);
        X509V3_EXT_add_list(v3_alt);
        X509V3_EXT_add(&v3_bcons);
@@ -162,6 +166,7 @@ int X509V3_add_standard_extensions(void)
        X509V3_EXT_add(&v3_crl_reason);
        X509V3_EXT_add(&v3_cpols);
        X509V3_EXT_add(&v3_crld);
+       added_exts = 1;
        return 1;
 }
 
index 13120ca516bef35ff130b208a3ff2c0258fbea56..0eb20d3ef3d5f3b45d7688fae9576a65ab7ac81e 100644 (file)
@@ -222,7 +222,7 @@ static void x509v3_cache_extensions(X509 *x)
        if(x->ex_flags & EXFLAG_SET) return;
        X509_digest(x, EVP_sha1(), x->sha1_hash, NULL);
        /* Does subject name match issuer ? */
-       if(X509_NAME_cmp(X509_get_subject_name(x), X509_get_issuer_name(x)))
+       if(!X509_NAME_cmp(X509_get_subject_name(x), X509_get_issuer_name(x)))
                         x->ex_flags |= EXFLAG_SS;
        /* V1 should mean no extensions ... */
        if(!X509_get_version(x)) x->ex_flags |= EXFLAG_V1;