From 51630a37069a0792f2d6ad6ce33e9c5cca27b69c Mon Sep 17 00:00:00 2001 From: "Dr. Stephen Henson" Date: Sat, 27 Nov 1999 19:43:10 +0000 Subject: [PATCH] Add trust setting support to the verify code. It now checks the 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 | 24 ++++++++++++------- apps/verify.c | 2 ++ crypto/asn1/t_x509a.c | 10 ++++---- crypto/x509/x509.h | 2 ++ crypto/x509/x509_err.c | 4 +++- crypto/x509/x509_txt.c | 4 ++++ crypto/x509/x509_vfy.c | 52 +++++++++++++++++++++++++++++++++++++++-- crypto/x509/x509_vfy.h | 5 +++- crypto/x509v3/v3_lib.c | 5 ++++ crypto/x509v3/v3_purp.c | 2 +- 10 files changed, 91 insertions(+), 19 deletions(-) diff --git a/CHANGES b/CHANGES index 3261ecea27..fa00300ebe 100644 --- a/CHANGES +++ b/CHANGES @@ -12,15 +12,21 @@ 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 diff --git a/apps/verify.c b/apps/verify.c index 579d4ea184..8a03e0f290 100644 --- a/apps/verify.c +++ b/apps/verify.c @@ -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); } diff --git a/crypto/asn1/t_x509a.c b/crypto/asn1/t_x509a.c index 5c15d09e43..0e342723aa 100644 --- a/crypto/asn1/t_x509a.c +++ b/crypto/asn1/t_x509a.c @@ -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, ", "); diff --git a/crypto/x509/x509.h b/crypto/x509/x509.h index 227bbaf1ca..534c3d69f7 100644 --- a/crypto/x509/x509.h +++ b/crypto/x509/x509.h @@ -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 diff --git a/crypto/x509/x509_err.c b/crypto/x509/x509_err.c index c185bc02f8..acaa99ffae 100644 --- a/crypto/x509/x509_err.c +++ b/crypto/x509/x509_err.c @@ -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} diff --git a/crypto/x509/x509_txt.c b/crypto/x509/x509_txt.c index b6f61c5e57..209cf53191 100644 --- a/crypto/x509/x509_txt.c +++ b/crypto/x509/x509_txt.c @@ -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: diff --git a/crypto/x509/x509_vfy.c b/crypto/x509/x509_vfy.c index 3d1b38a019..75ab96e506 100644 --- a/crypto/x509/x509_vfy.c +++ b/crypto/x509/x509_vfy.c @@ -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) diff --git a/crypto/x509/x509_vfy.h b/crypto/x509/x509_vfy.h index 47c0b4028c..5e197040fb 100644 --- a/crypto/x509/x509_vfy.h +++ b/crypto/x509/x509_vfy.h @@ -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 } diff --git a/crypto/x509v3/v3_lib.c b/crypto/x509v3/v3_lib.c index edf7a960b3..d6aeaabccd 100644 --- a/crypto/x509v3/v3_lib.c +++ b/crypto/x509v3/v3_lib.c @@ -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; } diff --git a/crypto/x509v3/v3_purp.c b/crypto/x509v3/v3_purp.c index 13120ca516..0eb20d3ef3 100644 --- a/crypto/x509v3/v3_purp.c +++ b/crypto/x509v3/v3_purp.c @@ -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; -- GitLab