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.
This commit is contained in:
parent
74ecf9e2bb
commit
51630a3706
22
CHANGES
22
CHANGES
@ -12,15 +12,21 @@
|
|||||||
DSA key was used because it didn't fix the digest.
|
DSA key was used because it didn't fix the digest.
|
||||||
[Steve Henson]
|
[Steve Henson]
|
||||||
|
|
||||||
*) Very preliminary certificate chain verify code. Currently just tests
|
*) Initial certificate chain verify code. Currently tests the untrusted
|
||||||
the untrusted certificates for consistency with the verify purpose
|
certificates for consistency with the verify purpose (which is set
|
||||||
(which is set when the X509_STORE_CTX structure is set up) and checks
|
when the X509_STORE_CTX structure is set up) and checks the pathlength.
|
||||||
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.
|
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
|
Also added X509_STORE_CTX_new() and X509_STORE_CTX_free() functions
|
||||||
which should be used for version portability: especially since the
|
which should be used for version portability: especially since the
|
||||||
|
@ -85,6 +85,7 @@ int MAIN(int argc, char **argv)
|
|||||||
X509_LOOKUP *lookup=NULL;
|
X509_LOOKUP *lookup=NULL;
|
||||||
|
|
||||||
X509_PURPOSE_add_standard();
|
X509_PURPOSE_add_standard();
|
||||||
|
X509_TRUST_add_standard();
|
||||||
X509V3_add_standard_extensions();
|
X509V3_add_standard_extensions();
|
||||||
cert_ctx=X509_STORE_new();
|
cert_ctx=X509_STORE_new();
|
||||||
if (cert_ctx == NULL) goto end;
|
if (cert_ctx == NULL) goto end;
|
||||||
@ -199,6 +200,7 @@ end:
|
|||||||
sk_X509_pop_free(untrusted, X509_free);
|
sk_X509_pop_free(untrusted, X509_free);
|
||||||
X509V3_EXT_cleanup();
|
X509V3_EXT_cleanup();
|
||||||
X509_PURPOSE_cleanup();
|
X509_PURPOSE_cleanup();
|
||||||
|
X509_TRUST_cleanup();
|
||||||
EXIT(ret);
|
EXIT(ret);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -99,13 +99,13 @@ int X509_CERT_AUX_print(BIO *out, X509_CERT_AUX *aux, int indent)
|
|||||||
int i;
|
int i;
|
||||||
if(!aux) return 1;
|
if(!aux) return 1;
|
||||||
if(aux->trust) {
|
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);
|
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) {
|
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);
|
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) {
|
if(aux->othertrust) {
|
||||||
first = 1;
|
first = 1;
|
||||||
BIO_printf(out, "%*sOther Trusted Uses:\n%*s",
|
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) {
|
if(aux->otherreject) {
|
||||||
first = 1;
|
first = 1;
|
||||||
BIO_printf(out, "%*sOther Untrusted Uses:\n%*s",
|
BIO_printf(out, "%*sOther Rejected Uses:\n%*s",
|
||||||
indent, "", indent + 2, "");
|
indent, "", indent + 2, "");
|
||||||
for(i = 0; i < sk_ASN1_OBJECT_num(aux->otherreject); i++) {
|
for(i = 0; i < sk_ASN1_OBJECT_num(aux->otherreject); i++) {
|
||||||
if(!first) BIO_puts(out, ", ");
|
if(!first) BIO_puts(out, ", ");
|
||||||
|
@ -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 121
|
||||||
#define X509_F_X509_REQ_PRINT_FP 122
|
#define X509_F_X509_REQ_PRINT_FP 122
|
||||||
#define X509_F_X509_REQ_TO_X509 123
|
#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_CERT 124
|
||||||
#define X509_F_X509_STORE_ADD_CRL 125
|
#define X509_F_X509_STORE_ADD_CRL 125
|
||||||
#define X509_F_X509_TO_X509_REQ 126
|
#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_UNABLE_TO_GET_CERTS_PUBLIC_KEY 108
|
||||||
#define X509_R_UNKNOWN_KEY_TYPE 117
|
#define X509_R_UNKNOWN_KEY_TYPE 117
|
||||||
#define X509_R_UNKNOWN_NID 109
|
#define X509_R_UNKNOWN_NID 109
|
||||||
|
#define X509_R_UNKNOWN_TRUST_ID 120
|
||||||
#define X509_R_UNSUPPORTED_ALGORITHM 111
|
#define X509_R_UNSUPPORTED_ALGORITHM 111
|
||||||
#define X509_R_WRONG_LOOKUP_TYPE 112
|
#define X509_R_WRONG_LOOKUP_TYPE 112
|
||||||
|
|
||||||
|
@ -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,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_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_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_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_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_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"},
|
{ERR_PACK(0,X509_F_X509_VERIFY_CERT,0), "X509_verify_cert"},
|
||||||
{0,NULL}
|
{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_UNABLE_TO_GET_CERTS_PUBLIC_KEY ,"unable to get certs public key"},
|
||||||
{X509_R_UNKNOWN_KEY_TYPE ,"unknown key type"},
|
{X509_R_UNKNOWN_KEY_TYPE ,"unknown key type"},
|
||||||
{X509_R_UNKNOWN_NID ,"unknown nid"},
|
{X509_R_UNKNOWN_NID ,"unknown nid"},
|
||||||
|
{X509_R_UNKNOWN_TRUST_ID ,"unknown trust id"},
|
||||||
{X509_R_UNSUPPORTED_ALGORITHM ,"unsupported algorithm"},
|
{X509_R_UNSUPPORTED_ALGORITHM ,"unsupported algorithm"},
|
||||||
{X509_R_WRONG_LOOKUP_TYPE ,"wrong lookup type"},
|
{X509_R_WRONG_LOOKUP_TYPE ,"wrong lookup type"},
|
||||||
{0,NULL}
|
{0,NULL}
|
||||||
|
@ -126,6 +126,10 @@ const char *X509_verify_cert_error_string(long n)
|
|||||||
return ("path length constraint exceeded");
|
return ("path length constraint exceeded");
|
||||||
case X509_V_ERR_INVALID_PURPOSE:
|
case X509_V_ERR_INVALID_PURPOSE:
|
||||||
return ("unsupported certificate 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:
|
case X509_V_ERR_APPLICATION_VERIFICATION:
|
||||||
return("application verification failure");
|
return("application verification failure");
|
||||||
default:
|
default:
|
||||||
|
@ -72,6 +72,7 @@
|
|||||||
|
|
||||||
static int null_callback(int ok,X509_STORE_CTX *e);
|
static int null_callback(int ok,X509_STORE_CTX *e);
|
||||||
static int check_chain_purpose(X509_STORE_CTX *ctx);
|
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);
|
static int internal_verify(X509_STORE_CTX *ctx);
|
||||||
const char *X509_version="X.509" OPENSSL_VERSION_PTEXT;
|
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;
|
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 */
|
/* We may as well copy down any DSA parameters that are required */
|
||||||
X509_get_pubkey_parameters(NULL,ctx->chain);
|
X509_get_pubkey_parameters(NULL,ctx->chain);
|
||||||
|
|
||||||
@ -356,6 +363,30 @@ static int check_chain_purpose(X509_STORE_CTX *ctx)
|
|||||||
#endif
|
#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)
|
static int internal_verify(X509_STORE_CTX *ctx)
|
||||||
{
|
{
|
||||||
int i,ok=0,n;
|
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;
|
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)
|
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;
|
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_STACK_OF(X509)
|
||||||
IMPLEMENT_ASN1_SET_OF(X509)
|
IMPLEMENT_ASN1_SET_OF(X509)
|
||||||
|
|
||||||
|
@ -263,6 +263,8 @@ struct x509_store_state_st /* X509_STORE_CTX */
|
|||||||
#define X509_V_ERR_INVALID_CA 24
|
#define X509_V_ERR_INVALID_CA 24
|
||||||
#define X509_V_ERR_PATH_LENGTH_EXCEEDED 25
|
#define X509_V_ERR_PATH_LENGTH_EXCEEDED 25
|
||||||
#define X509_V_ERR_INVALID_PURPOSE 26
|
#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 */
|
/* The application is not happy */
|
||||||
#define X509_V_ERR_APPLICATION_VERIFICATION 50
|
#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);
|
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_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_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);
|
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
|
#ifdef __cplusplus
|
||||||
}
|
}
|
||||||
|
@ -128,10 +128,13 @@ int X509V3_EXT_add_alias(int nid_to, int nid_from)
|
|||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int added_exts = 0;
|
||||||
|
|
||||||
void X509V3_EXT_cleanup(void)
|
void X509V3_EXT_cleanup(void)
|
||||||
{
|
{
|
||||||
sk_pop_free(ext_list, ext_list_free);
|
sk_pop_free(ext_list, ext_list_free);
|
||||||
ext_list = NULL;
|
ext_list = NULL;
|
||||||
|
added_exts = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void ext_list_free(X509V3_EXT_METHOD *ext)
|
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)
|
int X509V3_add_standard_extensions(void)
|
||||||
{
|
{
|
||||||
|
if(added_exts) return 1;
|
||||||
X509V3_EXT_add_list(v3_ns_ia5_list);
|
X509V3_EXT_add_list(v3_ns_ia5_list);
|
||||||
X509V3_EXT_add_list(v3_alt);
|
X509V3_EXT_add_list(v3_alt);
|
||||||
X509V3_EXT_add(&v3_bcons);
|
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_crl_reason);
|
||||||
X509V3_EXT_add(&v3_cpols);
|
X509V3_EXT_add(&v3_cpols);
|
||||||
X509V3_EXT_add(&v3_crld);
|
X509V3_EXT_add(&v3_crld);
|
||||||
|
added_exts = 1;
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -222,7 +222,7 @@ static void x509v3_cache_extensions(X509 *x)
|
|||||||
if(x->ex_flags & EXFLAG_SET) return;
|
if(x->ex_flags & EXFLAG_SET) return;
|
||||||
X509_digest(x, EVP_sha1(), x->sha1_hash, NULL);
|
X509_digest(x, EVP_sha1(), x->sha1_hash, NULL);
|
||||||
/* Does subject name match issuer ? */
|
/* 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;
|
x->ex_flags |= EXFLAG_SS;
|
||||||
/* V1 should mean no extensions ... */
|
/* V1 should mean no extensions ... */
|
||||||
if(!X509_get_version(x)) x->ex_flags |= EXFLAG_V1;
|
if(!X509_get_version(x)) x->ex_flags |= EXFLAG_V1;
|
||||||
|
Loading…
x
Reference in New Issue
Block a user