Initial OCSP certificate verify. Not complete,
authorDr. Stephen Henson <steve@openssl.org>
Wed, 17 Jan 2001 01:31:34 +0000 (01:31 +0000)
committerDr. Stephen Henson <steve@openssl.org>
Wed, 17 Jan 2001 01:31:34 +0000 (01:31 +0000)
it just supports a "trusted OCSP global root CA".

13 files changed:
CHANGES
apps/apps.c
apps/apps.h
apps/ocsp.c
apps/smime.c
crypto/ocsp/ocsp.h
crypto/ocsp/ocsp_err.c
crypto/ocsp/ocsp_lib.c
crypto/ocsp/ocsp_vfy.c
crypto/x509/x509.h
crypto/x509/x509_trs.c
crypto/x509v3/v3_purp.c
crypto/x509v3/x509v3.h

diff --git a/CHANGES b/CHANGES
index c111153..d0e2699 100644 (file)
--- a/CHANGES
+++ b/CHANGES
@@ -3,6 +3,16 @@
 
  Changes between 0.9.6 and 0.9.7  [xx XXX 2000]
 
+  *) Initial OCSP certificate verification added to OCSP_basic_verify()
+     and related routines. This uses the standard OpenSSL certificate
+     verify routines to perform initial checks (just CA validity) and
+     to obtain the certificate chain. Then additional checks will be
+     performed on the chain. Currently the root CA is checked to see
+     if it is explicitly trusted for OCSP signing. This is used to set
+     a root CA as a global signing root: that is any certificate that
+     chains to that CA is an acceptable OCSP signing certificate.
+     [Steve Henson]
+
   *) New '-extfile ...' option to 'openssl ca' for reading X.509v3
      extensions from a separate configuration file.
      As when reading extensions from the main configuration file,
index ca3f557..bdd8c71 100644 (file)
@@ -837,3 +837,32 @@ void print_name(BIO *out, char *title, X509_NAME *nm, unsigned long lflags)
        }
 }
 
+X509_STORE *setup_verify(BIO *bp, char *CAfile, char *CApath)
+{
+       X509_STORE *store;
+       X509_LOOKUP *lookup;
+       if(!(store = X509_STORE_new())) goto end;
+       lookup=X509_STORE_add_lookup(store,X509_LOOKUP_file());
+       if (lookup == NULL) goto end;
+       if (CAfile) {
+               if(!X509_LOOKUP_load_file(lookup,CAfile,X509_FILETYPE_PEM)) {
+                       BIO_printf(bp, "Error loading file %s\n", CAfile);
+                       goto end;
+               }
+       } else X509_LOOKUP_load_file(lookup,NULL,X509_FILETYPE_DEFAULT);
+               
+       lookup=X509_STORE_add_lookup(store,X509_LOOKUP_hash_dir());
+       if (lookup == NULL) goto end;
+       if (CApath) {
+               if(!X509_LOOKUP_add_dir(lookup,CApath,X509_FILETYPE_PEM)) {
+                       BIO_printf(bp, "Error loading directory %s\n", CApath);
+                       goto end;
+               }
+       } else X509_LOOKUP_add_dir(lookup,NULL,X509_FILETYPE_DEFAULT);
+
+       ERR_clear_error();
+       return store;
+       end:
+       X509_STORE_free(store);
+       return NULL;
+}
index 11133cb..2da89e2 100644 (file)
@@ -158,6 +158,7 @@ X509 *load_cert(BIO *err, char *file, int format);
 EVP_PKEY *load_key(BIO *err, char *file, int format, char *pass, ENGINE *e);
 EVP_PKEY *load_pubkey(BIO *err, char *file, int format, ENGINE *e);
 STACK_OF(X509) *load_certs(BIO *err, char *file, int format);
+X509_STORE *setup_verify(BIO *bp, char *CAfile, char *CApath);
 
 #define FORMAT_UNDEF    0
 #define FORMAT_ASN1     1
index cfd4f18..3125583 100644 (file)
@@ -82,14 +82,18 @@ int MAIN(int argc, char **argv)
        int add_nonce = 1;
        OCSP_REQUEST *req = NULL;
        OCSP_RESPONSE *resp = NULL;
+       OCSP_BASICRESP *bs = NULL;
        X509 *issuer = NULL, *cert = NULL;
        X509 *signer = NULL;
        EVP_PKEY *key = NULL;
        BIO *cbio = NULL, *derbio = NULL;
        BIO *out = NULL;
        int req_text = 0, resp_text = 0;
+       char *CAfile = NULL, *CApath = NULL;
+       X509_STORE *store = NULL;
        int ret = 1;
        int badarg = 0;
+       int i;
        if (bio_err == NULL) bio_err = BIO_new_fp(stderr, BIO_NOCLOSE);
        ERR_load_crypto_strings();
        args = argv + 1;
@@ -153,6 +157,24 @@ int MAIN(int argc, char **argv)
                                }
                        else badarg = 1;
                        }
+               else if (!strcmp (*args, "-CAfile"))
+                       {
+                       if (args[1])
+                               {
+                               args++;
+                               CAfile = *args;
+                               }
+                       else badarg = 1;
+                       }
+               else if (!strcmp (*args, "-CApath"))
+                       {
+                       if (args[1])
+                               {
+                               args++;
+                               CApath = *args;
+                               }
+                       else badarg = 1;
+                       }
                 else if (!strcmp(*args, "-signkey"))
                        {
                        if (args[1])
@@ -386,11 +408,25 @@ int MAIN(int argc, char **argv)
 
        if (resp_text) OCSP_RESPONSE_print(out, resp, 0);
 
+       store = setup_verify(bio_err, CAfile, CApath);
+       if(!store) goto end;
+
+       bs = OCSP_response_get1_basic(resp);
+
+       i = OCSP_basic_verify(bs, NULL, store, 0);
+
+       if(i <= 0)
+               {
+               BIO_printf(bio_err, "Response verify error (%d)\n", i);
+               ERR_print_errors(bio_err);
+               }
+
        ret = 0;
 
 end:
        ERR_print_errors(bio_err);
        X509_free(signer);
+       X509_STORE_free(store);
        EVP_PKEY_free(key);
        X509_free(issuer);
        X509_free(cert);
@@ -398,6 +434,7 @@ end:
        BIO_free(out);
        OCSP_REQUEST_free(req);
        OCSP_RESPONSE_free(resp);
+       OCSP_BASICRESP_free(bs);
 
        EXIT(ret);
 }
index 0a16bbc..e0d31b2 100644 (file)
@@ -68,7 +68,6 @@
 
 #undef PROG
 #define PROG smime_main
-static X509_STORE *setup_verify(char *CAfile, char *CApath);
 static int save_certs(char *signerfile, STACK_OF(X509) *signers);
 
 #define SMIME_OP       0x10
@@ -431,7 +430,7 @@ int MAIN(int argc, char **argv)
        }
 
        if(operation == SMIME_VERIFY) {
-               if(!(store = setup_verify(CAfile, CApath))) goto end;
+               if(!(store = setup_verify(bio_err, CAfile, CApath))) goto end;
        }
 
        ret = 3;
@@ -530,36 +529,6 @@ end:
        return (ret);
 }
 
-static X509_STORE *setup_verify(char *CAfile, char *CApath)
-{
-       X509_STORE *store;
-       X509_LOOKUP *lookup;
-       if(!(store = X509_STORE_new())) goto end;
-       lookup=X509_STORE_add_lookup(store,X509_LOOKUP_file());
-       if (lookup == NULL) goto end;
-       if (CAfile) {
-               if(!X509_LOOKUP_load_file(lookup,CAfile,X509_FILETYPE_PEM)) {
-                       BIO_printf(bio_err, "Error loading file %s\n", CAfile);
-                       goto end;
-               }
-       } else X509_LOOKUP_load_file(lookup,NULL,X509_FILETYPE_DEFAULT);
-               
-       lookup=X509_STORE_add_lookup(store,X509_LOOKUP_hash_dir());
-       if (lookup == NULL) goto end;
-       if (CApath) {
-               if(!X509_LOOKUP_add_dir(lookup,CApath,X509_FILETYPE_PEM)) {
-                       BIO_printf(bio_err, "Error loading directory %s\n", CApath);
-                       goto end;
-               }
-       } else X509_LOOKUP_add_dir(lookup,NULL,X509_FILETYPE_DEFAULT);
-
-       ERR_clear_error();
-       return store;
-       end:
-       X509_STORE_free(store);
-       return NULL;
-}
-
 static int save_certs(char *signerfile, STACK_OF(X509) *signers)
 {
        int i;
index 60b843a..1cb6ead 100644 (file)
@@ -79,6 +79,12 @@ extern "C" {
 #define OCSP_NOCERTS                   0x1
 #define OCSP_NOINTERN                  0x2
 #define OCSP_NOSIGS                    0x4
+#define OCSP_NOCHAIN                   0x8
+#define OCSP_NOVERIFY                  0x10
+#define OCSP_NOEXPLICIT                        0x20
+#define OCSP_NOCASIGN                  0x40
+#define OCSP_NODELEGATED               0x80
+#define OCSP_NOCHECKS                  0x100
 
 /*   CertID ::= SEQUENCE {
  *       hashAlgorithm            AlgorithmIdentifier,
@@ -434,6 +440,7 @@ int OCSP_resp_find_status(OCSP_BASICRESP *bs, OCSP_CERTID *id, int *status,
 
 int OCSP_request_verify(OCSP_REQUEST *req, EVP_PKEY *pkey);
 
+int OCSP_id_issuer_cmp(OCSP_CERTID *a, OCSP_CERTID *b);
 int OCSP_id_cmp(OCSP_CERTID *a, OCSP_CERTID *b);
 
 OCSP_BASICRESP *OCSP_basic_response_new(int tag,
@@ -565,6 +572,7 @@ void ERR_load_OCSP_strings(void);
 /* Reason codes. */
 #define OCSP_R_BAD_DATA                                         108
 #define OCSP_R_BAD_TAG                                  100
+#define OCSP_R_CERTIFICATE_VERIFY_ERROR                         126
 #define OCSP_R_DIGEST_ERR                               101
 #define OCSP_R_FAILED_TO_OPEN                           109
 #define OCSP_R_FAILED_TO_READ                           110
@@ -579,6 +587,7 @@ void ERR_load_OCSP_strings(void);
 #define OCSP_R_NO_RESPONSE_DATA                                 104
 #define OCSP_R_NO_SIGNATURE                             105
 #define OCSP_R_REVOKED_NO_TIME                          106
+#define OCSP_R_ROOT_CA_NOT_TRUSTED                      127
 #define OCSP_R_SERVER_READ_ERROR                        116
 #define OCSP_R_SERVER_RESPONSE_ERROR                    117
 #define OCSP_R_SERVER_RESPONSE_PARSE_ERROR              118
index 70a2756..f4335d2 100644 (file)
@@ -87,6 +87,7 @@ static ERR_STRING_DATA OCSP_str_reasons[]=
        {
 {OCSP_R_BAD_DATA                         ,"bad data"},
 {OCSP_R_BAD_TAG                          ,"bad tag"},
+{OCSP_R_CERTIFICATE_VERIFY_ERROR         ,"certificate verify error"},
 {OCSP_R_DIGEST_ERR                       ,"digest err"},
 {OCSP_R_FAILED_TO_OPEN                   ,"failed to open"},
 {OCSP_R_FAILED_TO_READ                   ,"failed to read"},
@@ -101,6 +102,7 @@ static ERR_STRING_DATA OCSP_str_reasons[]=
 {OCSP_R_NO_RESPONSE_DATA                 ,"no response data"},
 {OCSP_R_NO_SIGNATURE                     ,"no signature"},
 {OCSP_R_REVOKED_NO_TIME                  ,"revoked no time"},
+{OCSP_R_ROOT_CA_NOT_TRUSTED              ,"root ca not trusted"},
 {OCSP_R_SERVER_READ_ERROR                ,"server read error"},
 {OCSP_R_SERVER_RESPONSE_ERROR            ,"server response error"},
 {OCSP_R_SERVER_RESPONSE_PARSE_ERROR      ,"server response parse error"},
index f9d2978..bdd4cfc 100644 (file)
@@ -163,14 +163,21 @@ err:
        return NULL;
        }
 
-int OCSP_id_cmp(OCSP_CERTID *a, OCSP_CERTID *b)
+
+int OCSP_id_issuer_cmp(OCSP_CERTID *a, OCSP_CERTID *b)
        {
        int ret;
        ret = OBJ_cmp(a->hashAlgorithm->algorithm, b->hashAlgorithm->algorithm);
        if (ret) return ret;
        ret = ASN1_OCTET_STRING_cmp(a->issuerNameHash, b->issuerNameHash);
        if (ret) return ret;
-       ret = ASN1_OCTET_STRING_cmp(a->issuerKeyHash, b->issuerKeyHash);
+       return ASN1_OCTET_STRING_cmp(a->issuerKeyHash, b->issuerKeyHash);
+       }
+
+int OCSP_id_cmp(OCSP_CERTID *a, OCSP_CERTID *b)
+       {
+       int ret;
+       ret = OCSP_id_issuer_cmp(a, b);
        if (ret) return ret;
        return ASN1_INTEGER_cmp(a->serialNumber, b->serialNumber);
        }
index 2ea3f4a..6110825 100644 (file)
@@ -68,13 +68,15 @@ static X509 *ocsp_find_signer_sk(STACK_OF(X509) *certs, OCSP_RESPID *id);
 int OCSP_basic_verify(OCSP_BASICRESP *bs, STACK_OF(X509) *certs,
                                X509_STORE *st, unsigned long flags)
        {
-       X509 *signer;
-       int ret;
+       X509 *signer, *x;
+       STACK_OF(X509) *chain = NULL;
+       X509_STORE_CTX ctx;
+       int i, ret = 0;
        signer = ocsp_find_signer(bs, certs, st, flags);
        if (!signer)
                {
                OCSPerr(OCSP_F_OCSP_BASIC_VERIFY, OCSP_R_SIGNER_CERTIFICATE_NOT_FOUND);
-               return 0;
+               goto end;
                }
        if(!(flags & OCSP_NOSIGS))
                {
@@ -85,9 +87,62 @@ int OCSP_basic_verify(OCSP_BASICRESP *bs, STACK_OF(X509) *certs,
                if(ret <= 0)
                        {
                        OCSPerr(OCSP_F_OCSP_BASIC_VERIFY, OCSP_R_SIGNATURE_FAILURE);
-                       return 0;
+                       goto end;
                        }
                }
+       if(!(flags & OCSP_NOVERIFY))
+               {
+               if(flags & OCSP_NOCHAIN)
+                       X509_STORE_CTX_init(&ctx, st, signer, NULL);
+               else
+                       X509_STORE_CTX_init(&ctx, st, signer, bs->certs);
+
+               X509_STORE_CTX_set_purpose(&ctx, X509_PURPOSE_OCSP_HELPER);
+               ret = X509_verify_cert(&ctx);
+               chain = X509_STORE_CTX_get1_chain(&ctx);
+               X509_STORE_CTX_cleanup(&ctx);
+                if (ret <= 0)
+                       {
+                       i = X509_STORE_CTX_get_error(&ctx);     
+                       OCSPerr(OCSP_F_OCSP_BASIC_VERIFY,OCSP_R_CERTIFICATE_VERIFY_ERROR);
+                       ERR_add_error_data(2, "Verify error:",
+                                       X509_verify_cert_error_string(i));
+                        goto end;
+                       }
+               if(flags & OCSP_NOCHECKS)
+                       {
+                       ret = 1;
+                       goto end;
+                       }
+               /* At this point we have a valid certificate chain
+                * need to verify it against the OCSP criteria.
+                */
+#if 0
+               if(ocsp_check_issuer(bs, chain, flags))
+                       {
+                       ret = 1;
+                       goto end;
+                       }
+#endif
+
+               /* Easy case: explicitly trusted. Get root CA and
+                * check for explicit trust
+                */
+               if(flags & OCSP_NOEXPLICIT) goto end;
+
+               x = sk_X509_value(chain, sk_X509_num(chain) - 1);
+               if(X509_check_trust(x, NID_OCSP_sign, 0) != X509_TRUST_TRUSTED)
+                       {
+                       OCSPerr(OCSP_F_OCSP_BASIC_VERIFY,OCSP_R_ROOT_CA_NOT_TRUSTED);
+                       goto end;
+                       }
+               ret = 1;
+               }
+               
+
+
+       end:
+       if(chain) sk_X509_pop_free(chain, X509_free);
        return 1;
        }
 
index 332cad5..4b19572 100644 (file)
@@ -300,10 +300,11 @@ DECLARE_STACK_OF(X509_TRUST)
 #define X509_TRUST_SSL_SERVER  3
 #define X509_TRUST_EMAIL       4
 #define X509_TRUST_OBJECT_SIGN 5
+#define X509_TRUST_OCSP_SIGN   6
 
 /* Keep these up to date! */
 #define X509_TRUST_MIN         1
-#define X509_TRUST_MAX         5
+#define X509_TRUST_MAX         6
 
 
 /* trust_flags values */
index a7b1543..0de252c 100644 (file)
@@ -66,6 +66,7 @@ static int tr_cmp(const X509_TRUST * const *a,
 static void trtable_free(X509_TRUST *p);
 
 static int trust_1oidany(X509_TRUST *trust, X509 *x, int flags);
+static int trust_1oid(X509_TRUST *trust, X509 *x, int flags);
 static int trust_compat(X509_TRUST *trust, X509 *x, int flags);
 
 static int obj_trust(int id, X509 *x, int flags);
@@ -81,6 +82,7 @@ static X509_TRUST trstandard[] = {
 {X509_TRUST_SSL_CLIENT, 0, trust_1oidany, "SSL Client", NID_client_auth, NULL},
 {X509_TRUST_SSL_SERVER, 0, trust_1oidany, "SSL Client", NID_server_auth, NULL},
 {X509_TRUST_EMAIL, 0, trust_1oidany, "S/MIME email", NID_email_protect, NULL},
+{X509_TRUST_OCSP_SIGN, 0, trust_1oid, "OCSP responder", NID_OCSP_sign, NULL}
 };
 
 #define X509_TRUST_COUNT       (sizeof(trstandard)/sizeof(X509_TRUST))
@@ -235,6 +237,12 @@ static int trust_1oidany(X509_TRUST *trust, X509 *x, int flags)
        return trust_compat(trust, x, flags);
 }
 
+static int trust_1oid(X509_TRUST *trust, X509 *x, int flags)
+{
+       if(x->aux) return obj_trust(trust->arg1, x, flags);
+       return X509_TRUST_UNTRUSTED;
+}
+
 static int trust_compat(X509_TRUST *trust, X509 *x, int flags)
 {
        X509_check_purpose(x, -1, 0);
index 717e23d..9d67bd9 100644 (file)
@@ -61,7 +61,6 @@
 #include <openssl/x509v3.h>
 #include <openssl/x509_vfy.h>
 
-
 static void x509v3_cache_extensions(X509 *x);
 
 static int ca_check(const X509 *x);
@@ -74,6 +73,7 @@ static int check_purpose_smime_sign(const X509_PURPOSE *xp, const X509 *x, int c
 static int check_purpose_smime_encrypt(const X509_PURPOSE *xp, const X509 *x, int ca);
 static int check_purpose_crl_sign(const X509_PURPOSE *xp, const X509 *x, int ca);
 static int no_check(const X509_PURPOSE *xp, const X509 *x, int ca);
+static int ocsp_helper(const X509_PURPOSE *xp, const X509 *x, int ca);
 
 static int xp_cmp(const X509_PURPOSE * const *a,
                const X509_PURPOSE * const *b);
@@ -87,6 +87,7 @@ static X509_PURPOSE xstandard[] = {
        {X509_PURPOSE_SMIME_ENCRYPT, X509_TRUST_EMAIL, 0, check_purpose_smime_encrypt, "S/MIME encryption", "smimeencrypt", NULL},
        {X509_PURPOSE_CRL_SIGN, X509_TRUST_COMPAT, 0, check_purpose_crl_sign, "CRL signing", "crlsign", NULL},
        {X509_PURPOSE_ANY, X509_TRUST_DEFAULT, 0, no_check, "Any Purpose", "any", NULL},
+       {X509_PURPOSE_OCSP_HELPER, X509_TRUST_COMPAT, 0, ocsp_helper, "OCSP helper", "ocsphelper", NULL},
 };
 
 #define X509_PURPOSE_COUNT (sizeof(xstandard)/sizeof(X509_PURPOSE))
@@ -144,7 +145,6 @@ int X509_PURPOSE_get_by_sname(char *sname)
        return -1;
 }
 
-
 int X509_PURPOSE_get_by_id(int purpose)
 {
        X509_PURPOSE tmp;
@@ -320,6 +320,15 @@ static void x509v3_cache_extensions(X509 *x)
                                case NID_ms_sgc:
                                case NID_ns_sgc:
                                x->ex_xkusage |= XKU_SGC;
+                               break;
+
+                               case NID_OCSP_sign:
+                               x->ex_xkusage |= XKU_OCSP_SIGN;
+                               break;
+
+                               case NID_time_stamp:
+                               x->ex_xkusage |= XKU_TIMESTAMP;
+                               break;
                        }
                }
                sk_ASN1_OBJECT_pop_free(extusage, ASN1_OBJECT_free);
@@ -470,6 +479,27 @@ static int check_purpose_crl_sign(const X509_PURPOSE *xp, const X509 *x, int ca)
        return 1;
 }
 
+/* OCSP helper: this is *not* a full OCSP check. It just checks that
+ * each CA is valid. Additional checks must be made on the chain.
+ */
+
+static int ocsp_helper(const X509_PURPOSE *xp, const X509 *x, int ca)
+{
+       /* Must be a valid CA */
+       if(ca) {
+               int ca_ret;
+               ca_ret = ca_check(x);
+               if(ca_ret != 2) return ca_ret;
+               if(x->ex_flags & EXFLAG_NSCERT) {
+                       if(x->ex_nscert & NS_ANY_CA) return ca_ret;
+                       return 0;
+               }
+               return 0;
+       }
+       /* leaf certificate is checked in OCSP_verify() */
+       return 1;
+}
+
 static int no_check(const X509_PURPOSE *xp, const X509 *x, int ca)
 {
        return 1;
index 8bf67bc..29421b7 100644 (file)
@@ -342,12 +342,15 @@ DECLARE_ASN1_SET_OF(POLICYINFO)
 #define NS_SSL_CA              0x04
 #define NS_SMIME_CA            0x02
 #define NS_OBJSIGN_CA          0x01
+#define NS_ANY_CA              (NS_SSL_CA|NS_SMIME_CA|NS_OBJSIGN_CA)
 
 #define XKU_SSL_SERVER         0x1     
 #define XKU_SSL_CLIENT         0x2
 #define XKU_SMIME              0x4
 #define XKU_CODE_SIGN          0x8
 #define XKU_SGC                        0x10
+#define XKU_OCSP_SIGN          0x20
+#define XKU_TIMESTAMP          0x40
 
 #define X509_PURPOSE_DYNAMIC   0x1
 #define X509_PURPOSE_DYNAMIC_NAME      0x2
@@ -370,9 +373,10 @@ typedef struct x509_purpose_st {
 #define X509_PURPOSE_SMIME_ENCRYPT     5
 #define X509_PURPOSE_CRL_SIGN          6
 #define X509_PURPOSE_ANY               7
+#define X509_PURPOSE_OCSP_HELPER       8
 
 #define X509_PURPOSE_MIN               1
-#define X509_PURPOSE_MAX               7
+#define X509_PURPOSE_MAX               8
 
 /* Flags for X509V3_EXT_print() */