From 5d7c222db8f26a53c00646cc1dde2bdded38027e Mon Sep 17 00:00:00 2001 From: "Dr. Stephen Henson" Date: Mon, 6 Sep 2004 18:43:01 +0000 Subject: [PATCH] New X509_VERIFY_PARAM structure and associated functionality. This tidies up verify parameters and adds support for integrated policy checking. Add support for policy related command line options. Currently only in smime application. WARNING: experimental code subject to change. --- CHANGES | 8 + apps/Makefile.ssl | 6 +- apps/apps.c | 65 +++++++ apps/apps.h | 1 + apps/smime.c | 80 +++++++- crypto/stack/safestack.h | 21 ++ crypto/x509/Makefile.ssl | 4 +- crypto/x509/x509_lu.c | 28 ++- crypto/x509/x509_txt.c | 9 + crypto/x509/x509_vfy.c | 181 ++++++++++++++---- crypto/x509/x509_vfy.h | 105 ++++++++-- crypto/x509/x509_vpm.c | 400 +++++++++++++++++++++++++++++++++++++++ ssl/ssl.h | 10 +- ssl/ssl_cert.c | 14 +- ssl/ssl_lib.c | 41 +++- 15 files changed, 881 insertions(+), 92 deletions(-) create mode 100644 crypto/x509/x509_vpm.c diff --git a/CHANGES b/CHANGES index 4992f935f3..52d9b4a1b3 100644 --- a/CHANGES +++ b/CHANGES @@ -4,6 +4,14 @@ Changes between 0.9.7e and 0.9.8 [xx XXX xxxx] + *) New structure X509_VERIFY_PARAM which combines current verify parameters, + update associated structures and add various utility functions. + + Add new policy related verify parameters, include policy checking in + standard verify code. Enhance 'smime' application with extra parameters + to support policy checking and print out. + [Steve Henson] + *) Add a new engine to support VIA PadLock ACE extensions in the VIA C3 Nehemiah processors. These extensions support AES encryption in hardware as well as RNG (though RNG support is currently disabled). diff --git a/apps/Makefile.ssl b/apps/Makefile.ssl index 3d75664660..03e2ba34b4 100644 --- a/apps/Makefile.ssl +++ b/apps/Makefile.ssl @@ -62,14 +62,16 @@ E_OBJ= verify.o asn1pars.o req.o dgst.o dh.o dhparam.o enc.o passwd.o gendh.o er rsa.o rsautl.o dsa.o dsaparam.o ec.o ecparam.o \ x509.o genrsa.o gendsa.o s_server.o s_client.o speed.o \ s_time.o $(A_OBJ) $(S_OBJ) $(RAND_OBJ) version.o sess_id.o \ - ciphers.o nseq.o pkcs12.o pkcs8.o spkac.o smime.o rand.o engine.o ocsp.o + ciphers.o nseq.o pkcs12.o pkcs8.o spkac.o smime.o rand.o engine.o \ + ocsp.o E_SRC= verify.c asn1pars.c req.c dgst.c dh.c enc.c passwd.c gendh.c errstr.c ca.c \ pkcs7.c crl2p7.c crl.c \ rsa.c rsautl.c dsa.c dsaparam.c ec.c ecparam.c \ x509.c genrsa.c gendsa.c s_server.c s_client.c speed.c \ s_time.c $(A_SRC) $(S_SRC) $(RAND_SRC) version.c sess_id.c \ - ciphers.c nseq.c pkcs12.c pkcs8.c spkac.c smime.c rand.c engine.c ocsp.c + ciphers.c nseq.c pkcs12.c pkcs8.c spkac.c smime.c rand.c engine.c \ + ocsp.c SRC=$(E_SRC) diff --git a/apps/apps.c b/apps/apps.c index 3c3a11ce4d..6bc3562cdb 100644 --- a/apps/apps.c +++ b/apps/apps.c @@ -2140,3 +2140,68 @@ int WIN32_rename(char *from, char *to) #endif } #endif + +int args_verify(char ***pargs, int *badarg, BIO *err, X509_VERIFY_PARAM **pm) + { + ASN1_OBJECT *otmp = NULL; + unsigned long flags = 0; + char *arg = **pargs, *argn = (*pargs)[1]; + if (!strcmp(arg, "-policy")) + { + if (!argn) + *badarg = 1; + else + { + otmp = OBJ_txt2obj(argn, 0); + if (!otmp) + { + BIO_printf(err, "Invalid Policy \"%s\"\n", + argn); + *badarg = 1; + } + } + (*pargs)++; + } + else if (!strcmp(arg, "-ignore_critical")) + flags |= X509_V_FLAG_IGNORE_CRITICAL; + else if (!strcmp(arg, "-issuer_checks")) + flags |= X509_V_FLAG_CB_ISSUER_CHECK; + else if (!strcmp(arg, "-crl_check")) + flags |= X509_V_FLAG_CRL_CHECK; + else if (!strcmp(arg, "-crl_check_all")) + flags |= X509_V_FLAG_CRL_CHECK|X509_V_FLAG_CRL_CHECK_ALL; + else if (!strcmp(arg, "-policy_check")) + flags |= X509_V_FLAG_POLICY_CHECK; + else if (!strcmp(arg, "-explicit_policy")) + flags |= X509_V_FLAG_EXPLICIT_POLICY; + else if (!strcmp(arg, "-x509_strict")) + flags |= X509_V_FLAG_X509_STRICT; + else if (!strcmp(arg, "-policy_print")) + flags |= X509_V_FLAG_NOTIFY_POLICY; + else + return 0; + + if (*badarg) + { + if (*pm) + X509_VERIFY_PARAM_free(*pm); + *pm = NULL; + return 1; + } + + if (!*pm && !(*pm = X509_VERIFY_PARAM_new())) + { + *badarg = 1; + return 1; + } + + if (otmp) + X509_VERIFY_PARAM_add0_policy(*pm, otmp); + if (flags) + X509_VERIFY_PARAM_set_flags(*pm, flags); + + (*pargs)++; + + return 1; + + } diff --git a/apps/apps.h b/apps/apps.h index e653bf1b46..ede0c462fc 100644 --- a/apps/apps.h +++ b/apps/apps.h @@ -317,6 +317,7 @@ int index_name_cmp(const char **a, const char **b); int parse_yesno(char *str, int def); X509_NAME *parse_name(char *str, long chtype, int multirdn); +int args_verify(char ***pargs, int *badarg, BIO *err, X509_VERIFY_PARAM **pm); #define FORMAT_UNDEF 0 #define FORMAT_ASN1 1 diff --git a/apps/smime.c b/apps/smime.c index 418e03cd66..d193fef7b5 100644 --- a/apps/smime.c +++ b/apps/smime.c @@ -3,7 +3,7 @@ * project. */ /* ==================================================================== - * Copyright (c) 1999-2003 The OpenSSL Project. All rights reserved. + * Copyright (c) 1999-2004 The OpenSSL Project. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -64,10 +64,13 @@ #include #include #include +#include +#include #undef PROG #define PROG smime_main static int save_certs(char *signerfile, STACK_OF(X509) *signers); +static int smime_cb(int ok, X509_STORE_CTX *ctx); #define SMIME_OP 0x10 #define SMIME_ENCRYPT (1 | SMIME_OP) @@ -96,7 +99,7 @@ int MAIN(int argc, char **argv) STACK_OF(X509) *encerts = NULL, *other = NULL; BIO *in = NULL, *out = NULL, *indata = NULL; int badarg = 0; - int flags = PKCS7_DETACHED, store_flags = 0; + int flags = PKCS7_DETACHED; char *to = NULL, *from = NULL, *subject = NULL; char *CAfile = NULL, *CApath = NULL; char *passargin = NULL, *passin = NULL; @@ -108,6 +111,8 @@ int MAIN(int argc, char **argv) char *engine=NULL; #endif + X509_VERIFY_PARAM *vpm = NULL; + args = argv + 1; ret = 1; @@ -172,10 +177,6 @@ int MAIN(int argc, char **argv) flags |= PKCS7_NOOLDMIMETYPE; else if (!strcmp (*args, "-crlfeol")) flags |= PKCS7_CRLFEOL; - else if (!strcmp (*args, "-crl_check")) - store_flags |= X509_V_FLAG_CRL_CHECK; - else if (!strcmp (*args, "-crl_check_all")) - store_flags |= X509_V_FLAG_CRL_CHECK|X509_V_FLAG_CRL_CHECK_ALL; else if (!strcmp(*args,"-rand")) { if (args[1]) { args++; @@ -269,10 +270,14 @@ int MAIN(int argc, char **argv) args++; contfile = *args; } else badarg = 1; - } else badarg = 1; + } else if (args_verify(&args, &badarg, bio_err, &vpm)) + continue; + else + badarg = 1; args++; } + if(operation == SMIME_SIGN) { if(!signerfile) { BIO_printf(bio_err, "No signer certificate specified\n"); @@ -473,7 +478,9 @@ int MAIN(int argc, char **argv) if(operation == SMIME_VERIFY) { if(!(store = setup_verify(bio_err, CAfile, CApath))) goto end; - X509_STORE_set_flags(store, store_flags); + X509_STORE_set_verify_cb_func(store, smime_cb); + if (vpm) + X509_STORE_set1_param(store, vpm); } @@ -569,6 +576,8 @@ end: if(ret) ERR_print_errors(bio_err); sk_X509_pop_free(encerts, X509_free); sk_X509_pop_free(other, X509_free); + if (vpm) + X509_VERIFY_PARAM_free(vpm); X509_STORE_free(store); X509_free(cert); X509_free(recip); @@ -595,3 +604,58 @@ static int save_certs(char *signerfile, STACK_OF(X509) *signers) return 1; } + +static void nodes_print(BIO *out, char *name, STACK_OF(X509_POLICY_NODE) *nodes) + { + X509_POLICY_NODE *node; + int i; + BIO_printf(out, "%s Policies:", name); + if (nodes) + { + BIO_puts(out, "\n"); + for (i = 0; i < sk_X509_POLICY_NODE_num(nodes); i++) + { + node = sk_X509_POLICY_NODE_value(nodes, i); + X509_POLICY_NODE_print(out, node, 2); + } + } + else + BIO_puts(out, " \n"); + } + +static void policies_print(BIO *out, X509_STORE_CTX *ctx) + { + X509_POLICY_TREE *tree; + int explicit; + tree = X509_STORE_CTX_get0_policy_tree(ctx); + explicit = X509_STORE_CTX_get_explicit_policy(ctx); + + BIO_printf(out, "Require explicit Policy: %s\n", + explicit ? "True" : "False"); + + nodes_print(out, "Authority", X509_policy_tree_get0_policies(tree)); + nodes_print(out, "User", X509_policy_tree_get0_user_policies(tree)); + } + +/* Minimal callback just to output policy info (if any) */ + +static int smime_cb(int ok, X509_STORE_CTX *ctx) + { + BIO *out; + int error; + + error = X509_STORE_CTX_get_error(ctx); + + if ((error != X509_V_ERR_NO_EXPLICIT_POLICY) + && ((error != X509_V_OK) || (ok != 2))) + return ok; + + out = BIO_new_fp(stderr, BIO_NOCLOSE); + + policies_print(out, ctx); + + BIO_free(out); + + return ok; + + } diff --git a/crypto/stack/safestack.h b/crypto/stack/safestack.h index e52a859eb3..0b38337d03 100644 --- a/crypto/stack/safestack.h +++ b/crypto/stack/safestack.h @@ -1486,6 +1486,27 @@ STACK_OF(type) \ #define sk_X509_TRUST_pop(st) SKM_sk_pop(X509_TRUST, (st)) #define sk_X509_TRUST_sort(st) SKM_sk_sort(X509_TRUST, (st)) +#define sk_X509_VERIFY_PARAM_new(st) SKM_sk_new(X509_VERIFY_PARAM, (st)) +#define sk_X509_VERIFY_PARAM_new_null() SKM_sk_new_null(X509_VERIFY_PARAM) +#define sk_X509_VERIFY_PARAM_free(st) SKM_sk_free(X509_VERIFY_PARAM, (st)) +#define sk_X509_VERIFY_PARAM_num(st) SKM_sk_num(X509_VERIFY_PARAM, (st)) +#define sk_X509_VERIFY_PARAM_value(st, i) SKM_sk_value(X509_VERIFY_PARAM, (st), (i)) +#define sk_X509_VERIFY_PARAM_set(st, i, val) SKM_sk_set(X509_VERIFY_PARAM, (st), (i), (val)) +#define sk_X509_VERIFY_PARAM_zero(st) SKM_sk_zero(X509_VERIFY_PARAM, (st)) +#define sk_X509_VERIFY_PARAM_push(st, val) SKM_sk_push(X509_VERIFY_PARAM, (st), (val)) +#define sk_X509_VERIFY_PARAM_unshift(st, val) SKM_sk_unshift(X509_VERIFY_PARAM, (st), (val)) +#define sk_X509_VERIFY_PARAM_find(st, val) SKM_sk_find(X509_VERIFY_PARAM, (st), (val)) +#define sk_X509_VERIFY_PARAM_find_ex(st, val) SKM_sk_find_ex(X509_VERIFY_PARAM, (st), (val)) +#define sk_X509_VERIFY_PARAM_delete(st, i) SKM_sk_delete(X509_VERIFY_PARAM, (st), (i)) +#define sk_X509_VERIFY_PARAM_delete_ptr(st, ptr) SKM_sk_delete_ptr(X509_VERIFY_PARAM, (st), (ptr)) +#define sk_X509_VERIFY_PARAM_insert(st, val, i) SKM_sk_insert(X509_VERIFY_PARAM, (st), (val), (i)) +#define sk_X509_VERIFY_PARAM_set_cmp_func(st, cmp) SKM_sk_set_cmp_func(X509_VERIFY_PARAM, (st), (cmp)) +#define sk_X509_VERIFY_PARAM_dup(st) SKM_sk_dup(X509_VERIFY_PARAM, st) +#define sk_X509_VERIFY_PARAM_pop_free(st, free_func) SKM_sk_pop_free(X509_VERIFY_PARAM, (st), (free_func)) +#define sk_X509_VERIFY_PARAM_shift(st) SKM_sk_shift(X509_VERIFY_PARAM, (st)) +#define sk_X509_VERIFY_PARAM_pop(st) SKM_sk_pop(X509_VERIFY_PARAM, (st)) +#define sk_X509_VERIFY_PARAM_sort(st) SKM_sk_sort(X509_VERIFY_PARAM, (st)) + #define d2i_ASN1_SET_OF_ACCESS_DESCRIPTION(st, pp, length, d2i_func, free_func, ex_tag, ex_class) \ SKM_ASN1_SET_OF_d2i(ACCESS_DESCRIPTION, (st), (pp), (length), (d2i_func), (free_func), (ex_tag), (ex_class)) #define i2d_ASN1_SET_OF_ACCESS_DESCRIPTION(st, pp, i2d_func, ex_tag, ex_class, is_set) \ diff --git a/crypto/x509/Makefile.ssl b/crypto/x509/Makefile.ssl index 031b0a1230..26ab668266 100644 --- a/crypto/x509/Makefile.ssl +++ b/crypto/x509/Makefile.ssl @@ -28,13 +28,13 @@ LIBSRC= x509_def.c x509_d2.c x509_r2x.c x509_cmp.c \ x509_set.c x509cset.c x509rset.c x509_err.c \ x509name.c x509_v3.c x509_ext.c x509_att.c \ x509type.c x509_lu.c x_all.c x509_txt.c \ - x509_trs.c by_file.c by_dir.c + x509_trs.c by_file.c by_dir.c x509_vpm.c LIBOBJ= x509_def.o x509_d2.o x509_r2x.o x509_cmp.o \ x509_obj.o x509_req.o x509spki.o x509_vfy.o \ x509_set.o x509cset.o x509rset.o x509_err.o \ x509name.o x509_v3.o x509_ext.o x509_att.o \ x509type.o x509_lu.o x_all.o x509_txt.o \ - x509_trs.o by_file.o by_dir.o + x509_trs.o by_file.o by_dir.o x509_vpm.o SRC= $(LIBSRC) diff --git a/crypto/x509/x509_lu.c b/crypto/x509/x509_lu.c index b780dae5e2..8c7f22b0d9 100644 --- a/crypto/x509/x509_lu.c +++ b/crypto/x509/x509_lu.c @@ -187,10 +187,8 @@ X509_STORE *X509_STORE_new(void) ret->verify=0; ret->verify_cb=0; - ret->purpose = 0; - ret->trust = 0; - - ret->flags = 0; + if ((ret->param = X509_VERIFY_PARAM_new()) == NULL) + return NULL; ret->get_issuer = 0; ret->check_issued = 0; @@ -202,7 +200,6 @@ X509_STORE *X509_STORE_new(void) CRYPTO_new_ex_data(CRYPTO_EX_INDEX_X509_STORE, ret, &ret->ex_data); ret->references=1; - ret->depth=0; return ret; } @@ -244,6 +241,8 @@ void X509_STORE_free(X509_STORE *vfy) sk_X509_OBJECT_pop_free(vfy->objs, cleanup); CRYPTO_free_ex_data(CRYPTO_EX_INDEX_X509_STORE, vfy, &vfy->ex_data); + if (vfy->param) + X509_VERIFY_PARAM_free(vfy->param); OPENSSL_free(vfy); } @@ -538,19 +537,30 @@ int X509_STORE_CTX_get1_issuer(X509 **issuer, X509_STORE_CTX *ctx, X509 *x) return 0; } -void X509_STORE_set_flags(X509_STORE *ctx, long flags) +int X509_STORE_set_flags(X509_STORE *ctx, unsigned long flags) { - ctx->flags |= flags; + return X509_VERIFY_PARAM_set_flags(ctx->param, flags); + } + +int X509_STORE_set_depth(X509_STORE *ctx, int depth) + { + X509_VERIFY_PARAM_set_depth(ctx->param, depth); + return 1; } int X509_STORE_set_purpose(X509_STORE *ctx, int purpose) { - return X509_PURPOSE_set(&ctx->purpose, purpose); + return X509_VERIFY_PARAM_set_purpose(ctx->param, purpose); } int X509_STORE_set_trust(X509_STORE *ctx, int trust) { - return X509_TRUST_set(&ctx->trust, trust); + return X509_VERIFY_PARAM_set_trust(ctx->param, trust); + } + +int X509_STORE_set1_param(X509_STORE *ctx, X509_VERIFY_PARAM *param) + { + return X509_VERIFY_PARAM_set1(ctx->param, param); } IMPLEMENT_STACK_OF(X509_LOOKUP) diff --git a/crypto/x509/x509_txt.c b/crypto/x509/x509_txt.c index e31ebc6741..ddc3b9b355 100644 --- a/crypto/x509/x509_txt.c +++ b/crypto/x509/x509_txt.c @@ -153,6 +153,15 @@ const char *X509_verify_cert_error_string(long n) case X509_V_ERR_UNHANDLED_CRITICAL_CRL_EXTENSION: return("unhandled critical CRL extension"); + case X509_V_ERR_INVALID_EXTENSION: + return("invalid or inconsistent certificate extension"); + + case X509_V_ERR_INVALID_POLICY_EXTENSION: + return("invalid or inconsistent certificate policy extension"); + + case X509_V_ERR_NO_EXPLICIT_POLICY: + return("no explicit policy"); + default: BIO_snprintf(buf,sizeof buf,"error number %ld",n); return(buf); diff --git a/crypto/x509/x509_vfy.c b/crypto/x509/x509_vfy.c index 3e82f95486..4d9b53e997 100644 --- a/crypto/x509/x509_vfy.c +++ b/crypto/x509/x509_vfy.c @@ -77,6 +77,7 @@ static int check_chain_purpose(X509_STORE_CTX *ctx); static int check_trust(X509_STORE_CTX *ctx); static int check_revocation(X509_STORE_CTX *ctx); static int check_cert(X509_STORE_CTX *ctx); +static int check_policy(X509_STORE_CTX *ctx); static int internal_verify(X509_STORE_CTX *ctx); const char *X509_version="X.509" OPENSSL_VERSION_PTEXT; @@ -97,11 +98,12 @@ int X509_verify_cert(X509_STORE_CTX *ctx) { X509 *x,*xtmp,*chain_ss=NULL; X509_NAME *xn; + int bad_chain = 0; + X509_VERIFY_PARAM *param = ctx->param; int depth,i,ok=0; int num; int (*cb)(); STACK_OF(X509) *sktmp=NULL; - if (ctx->cert == NULL) { X509err(X509_F_X509_VERIFY_CERT,X509_R_NO_CERT_SET_FOR_US_TO_VERIFY); @@ -134,7 +136,7 @@ int X509_verify_cert(X509_STORE_CTX *ctx) num=sk_X509_num(ctx->chain); x=sk_X509_value(ctx->chain,num-1); - depth=ctx->depth; + depth=param->depth; for (;;) @@ -201,6 +203,7 @@ int X509_verify_cert(X509_STORE_CTX *ctx) ctx->current_cert=x; ctx->error_depth=i-1; if (ok == 1) X509_free(xtmp); + bad_chain = 1; ok=cb(0,ctx); if (!ok) goto end; } @@ -276,18 +279,19 @@ int X509_verify_cert(X509_STORE_CTX *ctx) } ctx->error_depth=num-1; + bad_chain = 1; ok=cb(0,ctx); if (!ok) goto end; } /* We have the chain complete: now we need to check its purpose */ - if (ctx->purpose > 0) ok = check_chain_purpose(ctx); + if (param->purpose > 0) ok = check_chain_purpose(ctx); if (!ok) goto end; /* The chain extensions are OK: check trust */ - if (ctx->trust > 0) ok = check_trust(ctx); + if (param->trust > 0) ok = check_trust(ctx); if (!ok) goto end; @@ -301,11 +305,17 @@ int X509_verify_cert(X509_STORE_CTX *ctx) ok = ctx->check_revocation(ctx); if(!ok) goto end; - /* At this point, we have a chain and just need to verify it */ + /* At this point, we have a chain and need to verify it */ if (ctx->verify != NULL) ok=ctx->verify(ctx); else ok=internal_verify(ctx); + if(!ok) goto end; + + /* If we get this far evaluate policies */ + if (!bad_chain && (ctx->param->flags & X509_V_FLAG_POLICY_CHECK)) + ok = ctx->check_policy(ctx); + if(!ok) goto end; if (0) { end: @@ -342,7 +352,7 @@ static int check_issued(X509_STORE_CTX *ctx, X509 *x, X509 *issuer) if (ret == X509_V_OK) return 1; /* If we haven't asked for issuer errors don't set ctx */ - if (!(ctx->flags & X509_V_FLAG_CB_ISSUER_CHECK)) + if (!(ctx->param->flags & X509_V_FLAG_CB_ISSUER_CHECK)) return 0; ctx->error = ret; @@ -385,7 +395,7 @@ static int check_chain_purpose(X509_STORE_CTX *ctx) { int ret; x = sk_X509_value(ctx->chain, i); - if (!(ctx->flags & X509_V_FLAG_IGNORE_CRITICAL) + if (!(ctx->param->flags & X509_V_FLAG_IGNORE_CRITICAL) && (x->ex_flags & EXFLAG_CRITICAL)) { ctx->error = X509_V_ERR_UNHANDLED_CRITICAL_EXTENSION; @@ -394,9 +404,9 @@ static int check_chain_purpose(X509_STORE_CTX *ctx) ok=cb(0,ctx); if (!ok) goto end; } - ret = X509_check_purpose(x, ctx->purpose, i); + ret = X509_check_purpose(x, ctx->param->purpose, i); if ((ret == 0) - || ((ctx->flags & X509_V_FLAG_X509_STRICT) + || ((ctx->param->flags & X509_V_FLAG_X509_STRICT) && (ret != 1))) { if (i) @@ -437,7 +447,7 @@ static int check_trust(X509_STORE_CTX *ctx) /* 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, 0); + ok = X509_check_trust(x, ctx->param->trust, 0); if (ok == X509_TRUST_TRUSTED) return 1; ctx->error_depth = i; @@ -454,9 +464,9 @@ static int check_trust(X509_STORE_CTX *ctx) static int check_revocation(X509_STORE_CTX *ctx) { int i, last, ok; - if (!(ctx->flags & X509_V_FLAG_CRL_CHECK)) + if (!(ctx->param->flags & X509_V_FLAG_CRL_CHECK)) return 1; - if (ctx->flags & X509_V_FLAG_CRL_CHECK_ALL) + if (ctx->param->flags & X509_V_FLAG_CRL_CHECK_ALL) last = sk_X509_num(ctx->chain) - 1; else last = 0; @@ -506,8 +516,8 @@ static int check_crl_time(X509_STORE_CTX *ctx, X509_CRL *crl, int notify) time_t *ptime; int i; ctx->current_crl = crl; - if (ctx->flags & X509_V_FLAG_USE_CHECK_TIME) - ptime = &ctx->check_time; + if (ctx->param->flags & X509_V_FLAG_USE_CHECK_TIME) + ptime = &ctx->param->check_time; else ptime = NULL; @@ -707,7 +717,7 @@ static int cert_crl(X509_STORE_CTX *ctx, X509_CRL *crl, X509 *x) if (!ok) return 0; } - if (ctx->flags & X509_V_FLAG_IGNORE_CRITICAL) + if (ctx->param->flags & X509_V_FLAG_IGNORE_CRITICAL) return 1; /* See if we have any critical CRL extensions: since we @@ -734,13 +744,60 @@ static int cert_crl(X509_STORE_CTX *ctx, X509_CRL *crl, X509 *x) return 1; } +static int check_policy(X509_STORE_CTX *ctx) + { + int ret; + ret = X509_policy_check(&ctx->tree, &ctx->explicit, ctx->chain, + ctx->param->policies, ctx->param->flags); + if (ret == 0) + { + X509err(X509_F_X509_VERIFY_CERT,ERR_R_MALLOC_FAILURE); + return 0; + } + /* Invalid or inconsistent extensions */ + if (ret == -1) + { + /* Locate certificates with bad extensions and notify + * callback. + */ + X509 *x; + int i; + for (i = 1; i < sk_X509_num(ctx->chain); i++) + { + x = sk_X509_value(ctx->chain, i); + if (!(x->ex_flags & EXFLAG_INVALID_POLICY)) + continue; + ctx->current_cert = x; + ctx->error = X509_V_ERR_INVALID_POLICY_EXTENSION; + ret = ctx->verify_cb(0, ctx); + } + return 1; + } + if (ret == -2) + { + ctx->current_cert = NULL; + ctx->error = X509_V_ERR_NO_EXPLICIT_POLICY; + return ctx->verify_cb(0, ctx); + } + + if (ctx->param->flags & X509_V_FLAG_NOTIFY_POLICY) + { + ctx->current_cert = NULL; + ctx->error = X509_V_OK; + if (!ctx->verify_cb(2, ctx)) + return 0; + } + + return 1; + } + static int check_cert_time(X509_STORE_CTX *ctx, X509 *x) { time_t *ptime; int i; - if (ctx->flags & X509_V_FLAG_USE_CHECK_TIME) - ptime = &ctx->check_time; + if (ctx->param->flags & X509_V_FLAG_USE_CHECK_TIME) + ptime = &ctx->param->check_time; else ptime = NULL; @@ -1151,8 +1208,8 @@ int X509_STORE_CTX_purpose_inherit(X509_STORE_CTX *ctx, int def_purpose, } } - if (purpose && !ctx->purpose) ctx->purpose = purpose; - if (trust && !ctx->trust) ctx->trust = trust; + if (purpose && !ctx->param->purpose) ctx->param->purpose = purpose; + if (trust && !ctx->param->trust) ctx->param->trust = trust; return 1; } @@ -1178,39 +1235,57 @@ void X509_STORE_CTX_free(X509_STORE_CTX *ctx) int X509_STORE_CTX_init(X509_STORE_CTX *ctx, X509_STORE *store, X509 *x509, STACK_OF(X509) *chain) { + int ret = 1; ctx->ctx=store; ctx->current_method=0; ctx->cert=x509; ctx->untrusted=chain; + ctx->crls = NULL; ctx->last_untrusted=0; - ctx->check_time=0; ctx->other_ctx=NULL; ctx->valid=0; ctx->chain=NULL; - ctx->depth=9; ctx->error=0; + ctx->explicit=0; ctx->error_depth=0; ctx->current_cert=NULL; ctx->current_issuer=NULL; + ctx->tree = NULL; + + ctx->param = X509_VERIFY_PARAM_new(); + + if (!ctx->param) + { + X509err(X509_F_X509_STORE_CTX_INIT,ERR_R_MALLOC_FAILURE); + return 0; + } /* Inherit callbacks and flags from X509_STORE if not set * use defaults. */ + if (store) + ret = X509_VERIFY_PARAM_inherit(ctx->param, store->param); + else + ctx->param->flags |= X509_VP_FLAG_DEFAULT|X509_VP_FLAG_ONCE; + if (store) { - ctx->purpose=store->purpose; - ctx->trust=store->trust; - ctx->flags = store->flags; + ctx->verify_cb = store->verify_cb; ctx->cleanup = store->cleanup; } else - { - ctx->purpose = 0; - ctx->trust = 0; - ctx->flags = 0; ctx->cleanup = 0; + + if (ret) + ret = X509_VERIFY_PARAM_inherit(ctx->param, + X509_VERIFY_PARAM_lookup("default")); + + if (ret == 0) + { + X509err(X509_F_X509_STORE_CTX_INIT,ERR_R_MALLOC_FAILURE); + return 0; } if (store && store->check_issued) @@ -1253,6 +1328,8 @@ int X509_STORE_CTX_init(X509_STORE_CTX *ctx, X509_STORE *store, X509 *x509, else ctx->cert_crl = cert_crl; + ctx->check_policy = check_policy; + /* This memset() can't make any sense anyway, so it's removed. As * X509_STORE_CTX_cleanup does a proper "free" on the ex_data, we put a @@ -1281,6 +1358,9 @@ void X509_STORE_CTX_trusted_stack(X509_STORE_CTX *ctx, STACK_OF(X509) *sk) void X509_STORE_CTX_cleanup(X509_STORE_CTX *ctx) { if (ctx->cleanup) ctx->cleanup(ctx); + X509_VERIFY_PARAM_free(ctx->param); + if (ctx->tree) + X509_policy_tree_free(ctx->tree); if (ctx->chain != NULL) { sk_X509_pop_free(ctx->chain,X509_free); @@ -1290,15 +1370,19 @@ void X509_STORE_CTX_cleanup(X509_STORE_CTX *ctx) memset(&ctx->ex_data,0,sizeof(CRYPTO_EX_DATA)); } -void X509_STORE_CTX_set_flags(X509_STORE_CTX *ctx, long flags) +void X509_STORE_CTX_set_depth(X509_STORE_CTX *ctx, int depth) { - ctx->flags |= flags; + X509_VERIFY_PARAM_set_depth(ctx->param, depth); } -void X509_STORE_CTX_set_time(X509_STORE_CTX *ctx, long flags, time_t t) +void X509_STORE_CTX_set_flags(X509_STORE_CTX *ctx, unsigned long flags) { - ctx->check_time = t; - ctx->flags |= X509_V_FLAG_USE_CHECK_TIME; + X509_VERIFY_PARAM_set_flags(ctx->param, flags); + } + +void X509_STORE_CTX_set_time(X509_STORE_CTX *ctx, unsigned long flags, time_t t) + { + X509_VERIFY_PARAM_set_time(ctx->param, t); } void X509_STORE_CTX_set_verify_cb(X509_STORE_CTX *ctx, @@ -1307,6 +1391,37 @@ void X509_STORE_CTX_set_verify_cb(X509_STORE_CTX *ctx, ctx->verify_cb=verify_cb; } +X509_POLICY_TREE *X509_STORE_CTX_get0_policy_tree(X509_STORE_CTX *ctx) + { + return ctx->tree; + } + +int X509_STORE_CTX_get_explicit_policy(X509_STORE_CTX *ctx) + { + return ctx->explicit; + } + +int X509_STORE_CTX_set_default(X509_STORE_CTX *ctx, const char *name) + { + const X509_VERIFY_PARAM *param; + param = X509_VERIFY_PARAM_lookup(name); + if (!param) + return 0; + return X509_VERIFY_PARAM_inherit(ctx->param, param); + } + +X509_VERIFY_PARAM *X509_STORE_CTX_get0_param(X509_STORE_CTX *ctx) + { + return ctx->param; + } + +void X509_STORE_CTX_set0_param(X509_STORE_CTX *ctx, X509_VERIFY_PARAM *param) + { + if (ctx->param) + X509_VERIFY_PARAM_free(ctx->param); + ctx->param = param; + } + IMPLEMENT_STACK_OF(X509) IMPLEMENT_ASN1_SET_OF(X509) diff --git a/crypto/x509/x509_vfy.h b/crypto/x509/x509_vfy.h index 5a5741df08..d8d34879af 100644 --- a/crypto/x509/x509_vfy.h +++ b/crypto/x509/x509_vfy.h @@ -156,6 +156,25 @@ typedef struct x509_lookup_method_st X509_OBJECT *ret); } X509_LOOKUP_METHOD; +/* This structure hold all parameters associated with a verify operation + * by including an X509_VERIFY_PARAM structure in related structures the + * parameters used can be customized + */ + +typedef struct X509_VERIFY_PARAM_st + { + char *name; + time_t check_time; /* Time to use */ + unsigned long inh_flags; /* Inheritance flags */ + unsigned long flags; /* Various verify flags */ + int purpose; /* purpose to check untrusted certificates */ + int trust; /* trust setting to check */ + int depth; /* Verify depth */ + STACK_OF(ASN1_OBJECT) *policies; /* Permissible policies */ + } X509_VERIFY_PARAM; + +DECLARE_STACK_OF(X509_VERIFY_PARAM) + /* This is used to hold everything. It is used for all certificate * validation. Once we have a certificate chain, the 'verify' * function is then called to actually check the cert chain. */ @@ -168,13 +187,8 @@ struct x509_store_st /* These are external lookup methods */ STACK_OF(X509_LOOKUP) *get_cert_methods; - /* The following fields are not used by X509_STORE but are - * inherited by X509_STORE_CTX when it is initialised. - */ + X509_VERIFY_PARAM *param; - unsigned long flags; /* Various verify flags */ - int purpose; - int trust; /* Callbacks for various operations */ int (*verify)(X509_STORE_CTX *ctx); /* called to verify a certificate */ int (*verify_cb)(int ok,X509_STORE_CTX *ctx); /* error callback */ @@ -188,10 +202,9 @@ struct x509_store_st CRYPTO_EX_DATA ex_data; int references; - int depth; /* how deep to look (still unused -- X509_STORE_CTX's depth is used) */ } /* X509_STORE */; -#define X509_STORE_set_depth(ctx,d) ((ctx)->depth=(d)) +int X509_STORE_set_depth(X509_STORE *store, int depth); #define X509_STORE_set_verify_cb_func(ctx,func) ((ctx)->verify_cb=(func)) #define X509_STORE_set_verify_func(ctx,func) ((ctx)->verify=(func)) @@ -218,11 +231,9 @@ struct x509_store_ctx_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 */ - STACK_OF(X509_CRL) *crls; /* CRLs */ - int purpose; /* purpose to check untrusted certificates */ - int trust; /* trust setting to check */ - time_t check_time; /* time to make verify at */ - unsigned long flags; /* Various verify flags */ + STACK_OF(X509_CRL) *crls; /* set of CRLs passed in */ + + X509_VERIFY_PARAM *param; void *other_ctx; /* Other info for use with get_issuer() */ /* Callbacks for various operations */ @@ -234,13 +245,16 @@ struct x509_store_ctx_st /* X509_STORE_CTX */ int (*get_crl)(X509_STORE_CTX *ctx, X509_CRL **crl, X509 *x); /* retrieve CRL */ int (*check_crl)(X509_STORE_CTX *ctx, X509_CRL *crl); /* Check CRL validity */ int (*cert_crl)(X509_STORE_CTX *ctx, X509_CRL *crl, X509 *x); /* Check certificate against CRL */ + int (*check_policy)(X509_STORE_CTX *ctx); int (*cleanup)(X509_STORE_CTX *ctx); /* The following is built up */ - int depth; /* how far to go looking up certs */ int valid; /* if 0, rebuild chain */ int last_untrusted; /* index of last untrusted cert */ STACK_OF(X509) *chain; /* chain of X509s - built up and trusted */ + X509_POLICY_TREE *tree; /* Valid policy tree */ + + int explicit; /* Require explicit policy value */ /* When something goes wrong, this is why */ int error_depth; @@ -252,7 +266,7 @@ struct x509_store_ctx_st /* X509_STORE_CTX */ CRYPTO_EX_DATA ex_data; } /* X509_STORE_CTX */; -#define X509_STORE_CTX_set_depth(ctx,d) ((ctx)->depth=(d)) +void X509_STORE_CTX_set_depth(X509_STORE_CTX *ctx, int depth); #define X509_STORE_CTX_set_app_data(ctx,data) \ X509_STORE_CTX_set_ex_data(ctx,0,data) @@ -309,6 +323,11 @@ struct x509_store_ctx_st /* X509_STORE_CTX */ #define X509_V_ERR_KEYUSAGE_NO_CRL_SIGN 35 #define X509_V_ERR_UNHANDLED_CRITICAL_CRL_EXTENSION 36 +#define X509_V_ERR_INVALID_EXTENSION 37 +#define X509_V_ERR_INVALID_POLICY_EXTENSION 38 +#define X509_V_ERR_NO_EXPLICIT_POLICY 39 + + /* The application is not happy */ #define X509_V_ERR_APPLICATION_VERIFICATION 50 @@ -330,10 +349,24 @@ struct x509_store_ctx_st /* X509_STORE_CTX */ #define X509_V_FLAG_POLICY_CHECK 0x40 /* Policy variable require-explicit-policy */ #define X509_V_FLAG_EXPLICIT_POLICY 0x80 -/* Policy variable inhibit-policy-mapping */ -#define X509_V_FLAG_INHIBIT_ANY 0x100 /* Policy variable inhibit-any-policy */ +#define X509_V_FLAG_INHIBIT_ANY 0x100 +/* Policy variable inhibit-policy-mapping */ #define X509_V_FLAG_INHIBIT_MAP 0x200 +/* Notify callback that policy is OK */ +#define X509_V_FLAG_NOTIFY_POLICY 0x800 + +#define X509_VP_FLAG_DEFAULT 0x1 +#define X509_VP_FLAG_OVERWRITE 0x2 +#define X509_VP_FLAG_RESET_FLAGS 0x4 +#define X509_VP_FLAG_LOCKED 0x8 +#define X509_VP_FLAG_ONCE 0x10 + +/* Internal use: mask of policy related options */ +#define X509_V_FLAG_POLICY_MASK (X509_V_FLAG_POLICY_CHECK \ + | X509_V_FLAG_EXPLICIT_POLICY \ + | X509_V_FLAG_INHIBIT_ANY \ + | X509_V_FLAG_INHIBIT_MAP) int X509_OBJECT_idx_by_subject(STACK_OF(X509_OBJECT) *h, int type, X509_NAME *name); @@ -344,9 +377,10 @@ void X509_OBJECT_free_contents(X509_OBJECT *a); X509_STORE *X509_STORE_new(void ); void X509_STORE_free(X509_STORE *v); -void X509_STORE_set_flags(X509_STORE *ctx, long flags); +int X509_STORE_set_flags(X509_STORE *ctx, unsigned long flags); int X509_STORE_set_purpose(X509_STORE *ctx, int purpose); int X509_STORE_set_trust(X509_STORE *ctx, int trust); +int X509_STORE_set1_param(X509_STORE *ctx, X509_VERIFY_PARAM *pm); X509_STORE_CTX *X509_STORE_CTX_new(void); @@ -415,10 +449,41 @@ int X509_STORE_CTX_set_purpose(X509_STORE_CTX *ctx, int purpose); int X509_STORE_CTX_set_trust(X509_STORE_CTX *ctx, int trust); int X509_STORE_CTX_purpose_inherit(X509_STORE_CTX *ctx, int def_purpose, int purpose, int trust); -void X509_STORE_CTX_set_flags(X509_STORE_CTX *ctx, long flags); -void X509_STORE_CTX_set_time(X509_STORE_CTX *ctx, long flags, time_t t); +void X509_STORE_CTX_set_flags(X509_STORE_CTX *ctx, unsigned long flags); +void X509_STORE_CTX_set_time(X509_STORE_CTX *ctx, unsigned long flags, + time_t t); void X509_STORE_CTX_set_verify_cb(X509_STORE_CTX *ctx, int (*verify_cb)(int, X509_STORE_CTX *)); + +X509_POLICY_TREE *X509_STORE_CTX_get0_policy_tree(X509_STORE_CTX *ctx); +int X509_STORE_CTX_get_explicit_policy(X509_STORE_CTX *ctx); + +X509_VERIFY_PARAM *X509_STORE_CTX_get0_param(X509_STORE_CTX *ctx); +int X509_STORE_CTX_set_default(X509_STORE_CTX *ctx, const char *name); + +/* X509_VERIFY_PARAM functions */ + +X509_VERIFY_PARAM *X509_VERIFY_PARAM_new(void); +void X509_VERIFY_PARAM_free(X509_VERIFY_PARAM *param); +int X509_VERIFY_PARAM_inherit(X509_VERIFY_PARAM *to, + const X509_VERIFY_PARAM *from); +int X509_VERIFY_PARAM_set1(X509_VERIFY_PARAM *to, + const X509_VERIFY_PARAM *from); +int X509_VERIFY_PARAM_set1_name(X509_VERIFY_PARAM *param, const char *name); +int X509_VERIFY_PARAM_set_flags(X509_VERIFY_PARAM *param, unsigned long flags); +int X509_VERIFY_PARAM_set_purpose(X509_VERIFY_PARAM *param, int purpose); +int X509_VERIFY_PARAM_set_trust(X509_VERIFY_PARAM *param, int trust); +void X509_VERIFY_PARAM_set_depth(X509_VERIFY_PARAM *param, int depth); +void X509_VERIFY_PARAM_set_time(X509_VERIFY_PARAM *param, time_t t); +int X509_VERIFY_PARAM_add0_policy(X509_VERIFY_PARAM *param, + ASN1_OBJECT *policy); +int X509_VERIFY_PARAM_set1_policies(X509_VERIFY_PARAM *param, + STACK_OF(ASN1_OBJECT) *policies); +int X509_VERIFY_PARAM_get_depth(const X509_VERIFY_PARAM *param); + +int X509_VERIFY_PARAM_add0_table(X509_VERIFY_PARAM *param); +const X509_VERIFY_PARAM *X509_VERIFY_PARAM_lookup(const char *name); +void X509_VERIFY_PARAM_table_cleanup(void); int X509_policy_check(X509_POLICY_TREE **ptree, int *pexplicit_policy, STACK_OF(X509) *certs, diff --git a/crypto/x509/x509_vpm.c b/crypto/x509/x509_vpm.c new file mode 100644 index 0000000000..087e8783a8 --- /dev/null +++ b/crypto/x509/x509_vpm.c @@ -0,0 +1,400 @@ +/* x509_vpm.c */ +/* Written by Dr Stephen N Henson (shenson@bigfoot.com) for the OpenSSL + * project 2004. + */ +/* ==================================================================== + * Copyright (c) 2004 The OpenSSL Project. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * 3. All advertising materials mentioning features or use of this + * software must display the following acknowledgment: + * "This product includes software developed by the OpenSSL Project + * for use in the OpenSSL Toolkit. (http://www.OpenSSL.org/)" + * + * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to + * endorse or promote products derived from this software without + * prior written permission. For written permission, please contact + * licensing@OpenSSL.org. + * + * 5. Products derived from this software may not be called "OpenSSL" + * nor may "OpenSSL" appear in their names without prior written + * permission of the OpenSSL Project. + * + * 6. Redistributions of any form whatsoever must retain the following + * acknowledgment: + * "This product includes software developed by the OpenSSL Project + * for use in the OpenSSL Toolkit (http://www.OpenSSL.org/)" + * + * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY + * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE OpenSSL PROJECT OR + * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + * OF THE POSSIBILITY OF SUCH DAMAGE. + * ==================================================================== + * + * This product includes cryptographic software written by Eric Young + * (eay@cryptsoft.com). This product includes software written by Tim + * Hudson (tjh@cryptsoft.com). + * + */ + +#include + +#include "cryptlib.h" +#include +#include +#include +#include +#include + +/* X509_VERIFY_PARAM functions */ + +static void x509_verify_param_zero(X509_VERIFY_PARAM *param) + { + if (!param) + return; + param->name = NULL; + param->purpose = 0; + param->trust = 0; + param->inh_flags = X509_VP_FLAG_DEFAULT; + param->flags = 0; + param->depth = -1; + if (param->policies) + { + sk_ASN1_OBJECT_pop_free(param->policies, ASN1_OBJECT_free); + param->policies = NULL; + } + } + +X509_VERIFY_PARAM *X509_VERIFY_PARAM_new(void) + { + X509_VERIFY_PARAM *param; + param = OPENSSL_malloc(sizeof(X509_VERIFY_PARAM)); + memset(param, 0, sizeof(X509_VERIFY_PARAM)); + x509_verify_param_zero(param); + return param; + } + +void X509_VERIFY_PARAM_free(X509_VERIFY_PARAM *param) + { + x509_verify_param_zero(param); + OPENSSL_free(param); + } + +/* This function determines how parameters are "inherited" from one structure + * to another. There are several different ways this can happen. + * + * 1. If a child structure needs to have its values initialized from a parent + * they are simply copied across. For example SSL_CTX copied to SSL. + * 2. If the structure should take on values only if they are currently unset. + * For example the values in an SSL structure will take appropriate value + * for SSL servers or clients but only if the application has not set new + * ones. + * + * The "inh_flags" field determines how this function behaves. + * + * Normally any values which are set in the default are not copied from the + * destination and verify flags are ORed together. + * + * If X509_VP_FLAG_DEFAULT is set then anything set in the source is copied + * to the destination. Effectively the values in "to" become default values + * which will be used only if nothing new is set in "from". + * + * If X509_VP_FLAG_OVERWRITE is set then all value are copied across whether + * they are set or not. Flags is still Ored though. + * + * If X509_VP_FLAG_RESET_FLAGS is set then the flags value is copied instead + * of ORed. + * + * If X509_VP_FLAG_LOCKED is set then no values are copied. + * + * If X509_VP_FLAG_ONCE is set then the current inh_flags setting is zeroed + * after the next call. + */ + +/* Macro to test if a field should be copied from src to dest */ + +#define test_x509_verify_param_copy(field, def) \ + (to_overwrite || \ + ((src->field != def) && (to_default || (dest->field == def)))) + +/* Macro to test and copy a field if necessary */ + +#define x509_verify_param_copy(field, def) \ + if (test_x509_verify_param_copy(field, def)) \ + dest->field = src->field + + +int X509_VERIFY_PARAM_inherit(X509_VERIFY_PARAM *dest, + const X509_VERIFY_PARAM *src) + { + unsigned long inh_flags; + int to_default, to_overwrite; + if (!src) + return 1; + inh_flags = dest->inh_flags | src->inh_flags; + + if (inh_flags & X509_VP_FLAG_ONCE) + dest->inh_flags = 0; + + if (inh_flags & X509_VP_FLAG_LOCKED) + return 1; + + if (inh_flags & X509_VP_FLAG_DEFAULT) + to_default = 1; + else + to_default = 0; + + if (inh_flags & X509_VP_FLAG_OVERWRITE) + to_overwrite = 1; + else + to_overwrite = 0; + + x509_verify_param_copy(purpose, 0); + x509_verify_param_copy(trust, 0); + x509_verify_param_copy(depth, -1); + + if (inh_flags & X509_VP_FLAG_RESET_FLAGS) + dest->flags = 0; + + dest->flags |= src->flags; + + if (test_x509_verify_param_copy(policies, NULL)) + { + if (!X509_VERIFY_PARAM_set1_policies(dest, src->policies)) + return 0; + } + + return 1; + } + +int X509_VERIFY_PARAM_set1(X509_VERIFY_PARAM *to, + const X509_VERIFY_PARAM *from) + { + to->inh_flags |= X509_VP_FLAG_DEFAULT; + return X509_VERIFY_PARAM_inherit(to, from); + } + +int X509_VERIFY_PARAM_set1_name(X509_VERIFY_PARAM *param, const char *name) + { + if (param->name) + OPENSSL_free(param->name); + param->name = BUF_strdup(name); + if (param->name) + return 1; + return 0; + } + +int X509_VERIFY_PARAM_set_flags(X509_VERIFY_PARAM *param, unsigned long flags) + { + param->flags |= flags; + if (flags & X509_V_FLAG_POLICY_MASK) + param->flags |= X509_V_FLAG_POLICY_CHECK; + return 1; + } + +int X509_VERIFY_PARAM_set_purpose(X509_VERIFY_PARAM *param, int purpose) + { + return X509_PURPOSE_set(¶m->purpose, purpose); + } + +int X509_VERIFY_PARAM_set_trust(X509_VERIFY_PARAM *param, int trust) + { + return X509_TRUST_set(¶m->trust, trust); + } + +void X509_VERIFY_PARAM_set_depth(X509_VERIFY_PARAM *param, int depth) + { + param->depth = depth; + } + +void X509_VERIFY_PARAM_set_time(X509_VERIFY_PARAM *param, time_t t) + { + param->check_time = t; + param->flags |= X509_V_FLAG_USE_CHECK_TIME; + } + +int X509_VERIFY_PARAM_add0_policy(X509_VERIFY_PARAM *param, ASN1_OBJECT *policy) + { + if (!param->policies) + { + param->policies = sk_ASN1_OBJECT_new_null(); + if (!param->policies) + return 0; + } + if (!sk_ASN1_OBJECT_push(param->policies, policy)) + return 0; + return 1; + } + +int X509_VERIFY_PARAM_set1_policies(X509_VERIFY_PARAM *param, + STACK_OF(ASN1_OBJECT) *policies) + { + int i; + ASN1_OBJECT *oid, *doid; + if (!param) + return 0; + if (param->policies) + sk_ASN1_OBJECT_pop_free(param->policies, ASN1_OBJECT_free); + + if (!policies) + { + param->policies = NULL; + return 1; + } + + param->policies = sk_ASN1_OBJECT_new_null(); + if (!param->policies) + return 0; + + for (i = 0; i < sk_ASN1_OBJECT_num(policies); i++) + { + oid = sk_ASN1_OBJECT_value(policies, i); + doid = OBJ_dup(oid); + if (!doid) + return 0; + if (!sk_ASN1_OBJECT_push(param->policies, doid)) + { + ASN1_OBJECT_free(doid); + return 0; + } + } + param->flags |= X509_V_FLAG_POLICY_CHECK; + return 1; + } + +int X509_VERIFY_PARAM_get_depth(const X509_VERIFY_PARAM *param) + { + return param->depth; + } + +/* Default verify parameters: these are used for various + * applications and can be overridden by the user specified table. + * NB: the 'name' field *must* be in alphabetical order because it + * will be searched using OBJ_search. + */ + +static const X509_VERIFY_PARAM default_table[] = { + { + "default", /* X509 default parameters */ + 0, /* Check time */ + 0, /* internal flags */ + 0, /* flags */ + 0, /* purpose */ + 0, /* trust */ + 9, /* depth */ + NULL /* policies */ + }, + { + "pkcs7", /* SSL/TLS client parameters */ + 0, /* Check time */ + 0, /* internal flags */ + 0, /* flags */ + X509_PURPOSE_SMIME_SIGN, /* purpose */ + X509_TRUST_EMAIL, /* trust */ + -1, /* depth */ + NULL /* policies */ + }, + { + "ssl_client", /* SSL/TLS client parameters */ + 0, /* Check time */ + 0, /* internal flags */ + 0, /* flags */ + X509_PURPOSE_SSL_CLIENT, /* purpose */ + X509_TRUST_SSL_CLIENT, /* trust */ + -1, /* depth */ + NULL /* policies */ + }, + { + "ssl_server", /* SSL/TLS server parameters */ + 0, /* Check time */ + 0, /* internal flags */ + 0, /* flags */ + X509_PURPOSE_SSL_SERVER, /* purpose */ + X509_TRUST_SSL_SERVER, /* trust */ + -1, /* depth */ + NULL /* policies */ + }}; + +static STACK_OF(X509_VERIFY_PARAM) *param_table = NULL; + +static int table_cmp(const void *pa, const void *pb) + { + const X509_VERIFY_PARAM *a = pa, *b = pb; + return strcmp(a->name, b->name); + } + +static int param_cmp(const X509_VERIFY_PARAM * const *a, + const X509_VERIFY_PARAM * const *b) + { + return strcmp((*a)->name, (*b)->name); + } + +int X509_VERIFY_PARAM_add0_table(X509_VERIFY_PARAM *param) + { + int idx; + X509_VERIFY_PARAM *ptmp; + if (!param_table) + { + param_table = sk_X509_VERIFY_PARAM_new(param_cmp); + if (!param_table) + return 0; + } + else + { + idx = sk_X509_VERIFY_PARAM_find(param_table, param); + if (idx != -1) + { + ptmp = sk_X509_VERIFY_PARAM_value(param_table, idx); + X509_VERIFY_PARAM_free(ptmp); + sk_X509_VERIFY_PARAM_delete(param_table, idx); + } + } + if (!sk_X509_VERIFY_PARAM_push(param_table, param)) + return 0; + return 1; + } + +const X509_VERIFY_PARAM *X509_VERIFY_PARAM_lookup(const char *name) + { + int idx; + X509_VERIFY_PARAM pm; + pm.name = (char *)name; + if (param_table) + { + idx = sk_X509_VERIFY_PARAM_find(param_table, &pm); + if (idx != -1) + return sk_X509_VERIFY_PARAM_value(param_table, idx); + } + return (const X509_VERIFY_PARAM *) OBJ_bsearch((char *)&pm, + (char *)&default_table, + sizeof(default_table)/sizeof(X509_VERIFY_PARAM), + sizeof(X509_VERIFY_PARAM), + table_cmp); + } + +void X509_VERIFY_PARAM_table_cleanup(void) + { + if (param_table) + sk_X509_VERIFY_PARAM_pop_free(param_table, + X509_VERIFY_PARAM_free); + param_table = NULL; + } diff --git a/ssl/ssl.h b/ssl/ssl.h index 8ff9ab3304..579b9ef1b2 100644 --- a/ssl/ssl.h +++ b/ssl/ssl.h @@ -711,7 +711,6 @@ struct ssl_ctx_st void *msg_callback_arg; int verify_mode; - int verify_depth; unsigned int sid_ctx_length; unsigned char sid_ctx[SSL_MAX_SID_CTX_LENGTH]; int (*default_verify_callback)(int ok,X509_STORE_CTX *ctx); /* called 'verify_callback' in the SSL */ @@ -719,8 +718,12 @@ struct ssl_ctx_st /* Default generate session ID callback. */ GEN_SESSION_CB generate_session_id; + X509_VERIFY_PARAM *param; + +#if 0 int purpose; /* Purpose setting */ int trust; /* Trust setting */ +#endif int quiet_shutdown; }; @@ -861,8 +864,12 @@ struct ssl_st int hit; /* reusing a previous session */ + X509_VERIFY_PARAM *param; + +#if 0 int purpose; /* Purpose setting */ int trust; /* Trust setting */ +#endif /* crypto */ STACK_OF(SSL_CIPHER) *cipher_list; @@ -907,7 +914,6 @@ struct ssl_st /* Used in SSL2 and SSL3 */ int verify_mode; /* 0 don't care about verify failure. * 1 fail if verify fails */ - int verify_depth; int (*verify_callback)(int ok,X509_STORE_CTX *ctx); /* fail if callback returns 0 */ void (*info_callback)(const SSL *ssl,int type,int val); /* optional informational callback */ diff --git a/ssl/ssl_cert.c b/ssl/ssl_cert.c index 4cab28a200..b515c064a8 100644 --- a/ssl/ssl_cert.c +++ b/ssl/ssl_cert.c @@ -483,20 +483,22 @@ int ssl_verify_cert_chain(SSL *s,STACK_OF(X509) *sk) SSLerr(SSL_F_SSL_VERIFY_CERT_CHAIN,ERR_R_X509_LIB); return(0); } + if (s->param) + X509_VERIFY_PARAM_inherit(X509_STORE_CTX_get0_param(&ctx), + s->param); +#if 0 if (SSL_get_verify_depth(s) >= 0) X509_STORE_CTX_set_depth(&ctx, SSL_get_verify_depth(s)); +#endif X509_STORE_CTX_set_ex_data(&ctx,SSL_get_ex_data_X509_STORE_CTX_idx(),s); - /* We need to set the verify purpose. The purpose can be determined by + /* We need to inherit the verify parameters. These can be determined by * the context: if its a server it will verify SSL client certificates * or vice versa. */ - if (s->server) - i = X509_PURPOSE_SSL_CLIENT; - else - i = X509_PURPOSE_SSL_SERVER; - X509_STORE_CTX_purpose_inherit(&ctx, i, s->purpose, s->trust); + X509_STORE_CTX_set_default(&ctx, + s->server ? "ssl_client" : "ssl_server"); if (s->verify_callback) X509_STORE_CTX_set_verify_cb(&ctx, s->verify_callback); diff --git a/ssl/ssl_lib.c b/ssl/ssl_lib.c index 7da3dda900..fb092813e7 100644 --- a/ssl/ssl_lib.c +++ b/ssl/ssl_lib.c @@ -276,14 +276,23 @@ SSL *SSL_new(SSL_CTX *ctx) s->msg_callback=ctx->msg_callback; s->msg_callback_arg=ctx->msg_callback_arg; s->verify_mode=ctx->verify_mode; +#if 0 s->verify_depth=ctx->verify_depth; +#endif s->sid_ctx_length=ctx->sid_ctx_length; OPENSSL_assert(s->sid_ctx_length <= sizeof s->sid_ctx); memcpy(&s->sid_ctx,&ctx->sid_ctx,sizeof(s->sid_ctx)); s->verify_callback=ctx->default_verify_callback; s->generate_session_id=ctx->generate_session_id; + + s->param = X509_VERIFY_PARAM_new(); + if (!s->param) + goto err; + X509_VERIFY_PARAM_inherit(s->param, ctx->param); +#if 0 s->purpose = ctx->purpose; s->trust = ctx->trust; +#endif s->quiet_shutdown=ctx->quiet_shutdown; CRYPTO_add(&ctx->references,1,CRYPTO_LOCK_SSL_CTX); @@ -397,22 +406,22 @@ int SSL_has_matching_session_id(const SSL *ssl, const unsigned char *id, int SSL_CTX_set_purpose(SSL_CTX *s, int purpose) { - return X509_PURPOSE_set(&s->purpose, purpose); + return X509_VERIFY_PARAM_set_purpose(s->param, purpose); } int SSL_set_purpose(SSL *s, int purpose) { - return X509_PURPOSE_set(&s->purpose, purpose); + return X509_VERIFY_PARAM_set_purpose(s->param, purpose); } int SSL_CTX_set_trust(SSL_CTX *s, int trust) { - return X509_TRUST_set(&s->trust, trust); + return X509_VERIFY_PARAM_set_trust(s->param, trust); } int SSL_set_trust(SSL *s, int trust) { - return X509_TRUST_set(&s->trust, trust); + return X509_VERIFY_PARAM_set_trust(s->param, trust); } void SSL_free(SSL *s) @@ -435,6 +444,9 @@ void SSL_free(SSL *s) } #endif + if (s->param) + X509_VERIFY_PARAM_free(s->param); + CRYPTO_free_ex_data(CRYPTO_EX_INDEX_SSL, s, &s->ex_data); if (s->bbio != NULL) @@ -647,7 +659,7 @@ int SSL_get_verify_mode(SSL *s) int SSL_get_verify_depth(SSL *s) { - return(s->verify_depth); + return X509_VERIFY_PARAM_get_depth(s->param); } int (*SSL_get_verify_callback(SSL *s))(int,X509_STORE_CTX *) @@ -662,7 +674,7 @@ int SSL_CTX_get_verify_mode(SSL_CTX *ctx) int SSL_CTX_get_verify_depth(SSL_CTX *ctx) { - return(ctx->verify_depth); + return X509_VERIFY_PARAM_get_depth(ctx->param); } int (*SSL_CTX_get_verify_callback(SSL_CTX *ctx))(int,X509_STORE_CTX *) @@ -680,7 +692,7 @@ void SSL_set_verify(SSL *s,int mode, void SSL_set_verify_depth(SSL *s,int depth) { - s->verify_depth=depth; + X509_VERIFY_PARAM_set_depth(s->param, depth); } void SSL_set_read_ahead(SSL *s,int yes) @@ -1345,7 +1357,9 @@ SSL_CTX *SSL_CTX_new(SSL_METHOD *meth) ret->msg_callback=0; ret->msg_callback_arg=NULL; ret->verify_mode=SSL_VERIFY_NONE; +#if 0 ret->verify_depth=-1; /* Don't impose a limit (but x509_lu.c does) */ +#endif ret->sid_ctx_length=0; ret->default_verify_callback=NULL; if ((ret->cert=ssl_cert_new()) == NULL) @@ -1371,6 +1385,10 @@ SSL_CTX *SSL_CTX_new(SSL_METHOD *meth) goto err2; } + ret->param = X509_VERIFY_PARAM_new(); + if (!ret->param) + goto err; + if ((ret->rsa_md5=EVP_get_digestbyname("ssl2-md5")) == NULL) { SSLerr(SSL_F_SSL_CTX_NEW,SSL_R_UNABLE_TO_LOAD_SSL2_MD5_ROUTINES); @@ -1427,6 +1445,9 @@ void SSL_CTX_free(SSL_CTX *a) } #endif + if (a->param) + X509_VERIFY_PARAM_free(a->param); + /* * Free internal session cache. However: the remove_cb() may reference * the ex_data of SSL_CTX, thus the ex_data store can only be removed @@ -1489,7 +1510,7 @@ void SSL_CTX_set_verify(SSL_CTX *ctx,int mode,int (*cb)(int, X509_STORE_CTX *)) void SSL_CTX_set_verify_depth(SSL_CTX *ctx,int depth) { - ctx->verify_depth=depth; + X509_VERIFY_PARAM_set_depth(ctx->param, depth); } void ssl_set_cert_masks(CERT *c, SSL_CIPHER *cipher) @@ -2117,8 +2138,8 @@ SSL *SSL_dup(SSL *s) ret->rstate=s->rstate; ret->init_num = 0; /* would have to copy ret->init_buf, ret->init_msg, ret->init_num, ret->init_off */ ret->hit=s->hit; - ret->purpose=s->purpose; - ret->trust=s->trust; + + X509_VERIFY_PARAM_inherit(ret->param, s->param); /* dup the cipher_list and cipher_list_by_id stacks */ if (s->cipher_list != NULL) -- 2.25.1