*BIG* verify code reorganisation.
The old code was painfully primitive and couldn't handle distinct certificates using the same subject name. The new code performs several tests on a candidate issuer certificate based on certificate extensions. It also adds several callbacks to X509_VERIFY_CTX so its behaviour can be customised. Unfortunately some hackery was needed to persuade X509_STORE to tolerate this. This should go away when X509_STORE is replaced, sometime... This must have broken something though :-(
This commit is contained in:
parent
29eb7d9ce0
commit
2f043896d1
51
CHANGES
51
CHANGES
@ -4,6 +4,57 @@
|
|||||||
|
|
||||||
Changes between 0.9.5a and 0.9.6 [xx XXX 2000]
|
Changes between 0.9.5a and 0.9.6 [xx XXX 2000]
|
||||||
|
|
||||||
|
*) Phase 2 verify code reorganisation. The certificate
|
||||||
|
verify code now looks up an issuer certificate by a
|
||||||
|
number of criteria: subject name, authority key id
|
||||||
|
and key usage. It also verifies self signed certificates
|
||||||
|
by the same criteria. The main comparison function is
|
||||||
|
X509_check_issued() which performs these checks.
|
||||||
|
|
||||||
|
Lot of changes were necessary in order to support this
|
||||||
|
without completely rewriting the lookup code.
|
||||||
|
|
||||||
|
Authority and subject key identifier are now cached.
|
||||||
|
|
||||||
|
The LHASH 'certs' is X509_STORE has now been replaced
|
||||||
|
by a STACK_OF(X509_OBJECT). This is mainly because an
|
||||||
|
LHASH can't store or retrieve multiple objects with
|
||||||
|
the same hash value.
|
||||||
|
|
||||||
|
As a result various functions (which were all internal
|
||||||
|
use only) have changed to handle the new X509_STORE
|
||||||
|
structure. This will break anything that messed round
|
||||||
|
with X509_STORE internally.
|
||||||
|
|
||||||
|
The functions X509_STORE_add_cert() now checks for an
|
||||||
|
exact match, rather than just subject name.
|
||||||
|
|
||||||
|
The X509_STORE API doesn't directly support the retrieval
|
||||||
|
of multiple certificates matching a given criteria, however
|
||||||
|
this can be worked round by performing a lookup first
|
||||||
|
(which will fill the cache with candidate certificates)
|
||||||
|
and then examining the cache for matches. This is probably
|
||||||
|
the best we can do without throwing out X509_LOOKUP
|
||||||
|
entirely (maybe later...).
|
||||||
|
|
||||||
|
The X509_VERIFY_CTX structure has been enhanced considerably.
|
||||||
|
|
||||||
|
All certificate lookup operations now go via a get_issuer()
|
||||||
|
callback. Although this currently uses an X509_STORE it
|
||||||
|
can be replaced by custom lookups. This is a simple way
|
||||||
|
to bypass the X509_STORE hackery necessary to make this
|
||||||
|
work and makes it possible to use more efficient techniques
|
||||||
|
in future. A very simple version which uses a simple
|
||||||
|
STACK for its trusted certificate store is also provided
|
||||||
|
using X509_STORE_CTX_trusted_stack().
|
||||||
|
|
||||||
|
The verify_cb() and verify() callbacks now have equivalents
|
||||||
|
in the X509_STORE_CTX structure.
|
||||||
|
|
||||||
|
X509_STORE_CTX also has a 'flags' field which can be used
|
||||||
|
to customise the verify behaviour.
|
||||||
|
[Steve Henson]
|
||||||
|
|
||||||
*) Add new PKCS#7 signing option PKCS7_NOSMIMECAP which
|
*) Add new PKCS#7 signing option PKCS7_NOSMIMECAP which
|
||||||
excludes S/MIME capabilities.
|
excludes S/MIME capabilities.
|
||||||
[Steve Henson]
|
[Steve Henson]
|
||||||
|
@ -111,7 +111,7 @@ my %table=(
|
|||||||
"debug-rse","cc:-DTERMIOS -DL_ENDIAN -pipe -O -g -ggdb3 -Wall::(unknown)::BN_LLONG ${x86_gcc_des} ${x86_gcc_opts}:${x86_elf_asm}",
|
"debug-rse","cc:-DTERMIOS -DL_ENDIAN -pipe -O -g -ggdb3 -Wall::(unknown)::BN_LLONG ${x86_gcc_des} ${x86_gcc_opts}:${x86_elf_asm}",
|
||||||
"debug-bodo", "gcc:-DL_ENDIAN -DBN_DEBUG -DREF_CHECK -DCONF_DEBUG -DBN_CTX_DEBUG -DCRYPTO_MDEBUG_ALL -DBIO_PAIR_DEBUG -g -m486 -pedantic -Wshadow -Wall::-D_REENTRANT::BN_LLONG ${x86_gcc_des} ${x86_gcc_opts}:${x86_elf_asm}",
|
"debug-bodo", "gcc:-DL_ENDIAN -DBN_DEBUG -DREF_CHECK -DCONF_DEBUG -DBN_CTX_DEBUG -DCRYPTO_MDEBUG_ALL -DBIO_PAIR_DEBUG -g -m486 -pedantic -Wshadow -Wall::-D_REENTRANT::BN_LLONG ${x86_gcc_des} ${x86_gcc_opts}:${x86_elf_asm}",
|
||||||
"debug-ulf", "gcc:-DL_ENDIAN -DREF_CHECK -DCONF_DEBUG -DBN_DEBUG -DBN_CTX_DEBUG -DCRYPTO_MDEBUG_ALL -g -O2 -m486 -Wall -Werror -Wshadow -pipe::-D_REENTRANT::${x86_gcc_des} ${x86_gcc_opts}:${x86_elf_asm}",
|
"debug-ulf", "gcc:-DL_ENDIAN -DREF_CHECK -DCONF_DEBUG -DBN_DEBUG -DBN_CTX_DEBUG -DCRYPTO_MDEBUG_ALL -g -O2 -m486 -Wall -Werror -Wshadow -pipe::-D_REENTRANT::${x86_gcc_des} ${x86_gcc_opts}:${x86_elf_asm}",
|
||||||
"debug-steve", "gcc:-DL_ENDIAN -DREF_CHECK -DCONF_DEBUG -DBN_CTX_DEBUG -DCRYPTO_MDEBUG_ALL -DPEDANTIC -g -O2 -m486 -pedantic -Wall -Werror -Wshadow -pipe::-D_REENTRANT::${x86_gcc_des} ${x86_gcc_opts}:${x86_elf_asm}",
|
"debug-steve", "gcc:-DL_ENDIAN -DREF_CHECK -DCONF_DEBUG -DBN_CTX_DEBUG -DDEBUG_SAFESTACK -DCRYPTO_MDEBUG_ALL -DPEDANTIC -g -O2 -m486 -pedantic -Wall -Werror -Wshadow -pipe::-D_REENTRANT::${x86_gcc_des} ${x86_gcc_opts}:${x86_elf_asm}",
|
||||||
"debug-levitte-linux-elf","gcc:-DUSE_ALLOCATING_PRINT -DRL_DEBUG -DREF_CHECK -DCONF_DEBUG -DBN_CTX_DEBUG -DCRYPTO_MDEBUG -DNO_ASM -DL_ENDIAN -DTERMIO -D_POSIX_SOURCE -ggdb -g3 -m486 -pedantic -ansi -Wall -Wshadow -Wid-clash-31 -pipe::-D_REENTRANT:-ldl:::::::::::dlfcn",
|
"debug-levitte-linux-elf","gcc:-DUSE_ALLOCATING_PRINT -DRL_DEBUG -DREF_CHECK -DCONF_DEBUG -DBN_CTX_DEBUG -DCRYPTO_MDEBUG -DNO_ASM -DL_ENDIAN -DTERMIO -D_POSIX_SOURCE -ggdb -g3 -m486 -pedantic -ansi -Wall -Wshadow -Wid-clash-31 -pipe::-D_REENTRANT:-ldl:::::::::::dlfcn",
|
||||||
"dist", "cc:-O::(unknown):::::",
|
"dist", "cc:-O::(unknown):::::",
|
||||||
|
|
||||||
|
@ -70,7 +70,7 @@
|
|||||||
#define PROG verify_main
|
#define PROG verify_main
|
||||||
|
|
||||||
static int MS_CALLBACK cb(int ok, X509_STORE_CTX *ctx);
|
static int MS_CALLBACK cb(int ok, X509_STORE_CTX *ctx);
|
||||||
static int check(X509_STORE *ctx,char *file, STACK_OF(X509)*other, int purpose);
|
static int check(X509_STORE *ctx, char *file, STACK_OF(X509) *uchain, STACK_OF(X509) *tchain, int purpose);
|
||||||
static STACK_OF(X509) *load_untrusted(char *file);
|
static STACK_OF(X509) *load_untrusted(char *file);
|
||||||
static int v_verbose=0;
|
static int v_verbose=0;
|
||||||
|
|
||||||
@ -81,8 +81,8 @@ int MAIN(int argc, char **argv)
|
|||||||
int i,ret=1;
|
int i,ret=1;
|
||||||
int purpose = -1;
|
int purpose = -1;
|
||||||
char *CApath=NULL,*CAfile=NULL;
|
char *CApath=NULL,*CAfile=NULL;
|
||||||
char *untfile = NULL;
|
char *untfile = NULL, *trustfile = NULL;
|
||||||
STACK_OF(X509) *untrusted = NULL;
|
STACK_OF(X509) *untrusted = NULL, *trusted = NULL;
|
||||||
X509_STORE *cert_ctx=NULL;
|
X509_STORE *cert_ctx=NULL;
|
||||||
X509_LOOKUP *lookup=NULL;
|
X509_LOOKUP *lookup=NULL;
|
||||||
|
|
||||||
@ -132,6 +132,11 @@ int MAIN(int argc, char **argv)
|
|||||||
if (argc-- < 1) goto end;
|
if (argc-- < 1) goto end;
|
||||||
untfile= *(++argv);
|
untfile= *(++argv);
|
||||||
}
|
}
|
||||||
|
else if (strcmp(*argv,"-trusted") == 0)
|
||||||
|
{
|
||||||
|
if (argc-- < 1) goto end;
|
||||||
|
trustfile= *(++argv);
|
||||||
|
}
|
||||||
else if (strcmp(*argv,"-help") == 0)
|
else if (strcmp(*argv,"-help") == 0)
|
||||||
goto end;
|
goto end;
|
||||||
else if (strcmp(*argv,"-verbose") == 0)
|
else if (strcmp(*argv,"-verbose") == 0)
|
||||||
@ -179,10 +184,18 @@ int MAIN(int argc, char **argv)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (argc < 1) check(cert_ctx, NULL, untrusted, purpose);
|
if(trustfile) {
|
||||||
|
if(!(trusted = load_untrusted(trustfile))) {
|
||||||
|
BIO_printf(bio_err, "Error loading untrusted file %s\n", trustfile);
|
||||||
|
ERR_print_errors(bio_err);
|
||||||
|
goto end;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (argc < 1) check(cert_ctx, NULL, untrusted, trusted, purpose);
|
||||||
else
|
else
|
||||||
for (i=0; i<argc; i++)
|
for (i=0; i<argc; i++)
|
||||||
check(cert_ctx,argv[i], untrusted, purpose);
|
check(cert_ctx,argv[i], untrusted, trusted, purpose);
|
||||||
ret=0;
|
ret=0;
|
||||||
end:
|
end:
|
||||||
if (ret == 1) {
|
if (ret == 1) {
|
||||||
@ -197,10 +210,11 @@ end:
|
|||||||
}
|
}
|
||||||
if (cert_ctx != NULL) X509_STORE_free(cert_ctx);
|
if (cert_ctx != NULL) X509_STORE_free(cert_ctx);
|
||||||
sk_X509_pop_free(untrusted, X509_free);
|
sk_X509_pop_free(untrusted, X509_free);
|
||||||
|
sk_X509_pop_free(trusted, X509_free);
|
||||||
EXIT(ret);
|
EXIT(ret);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int check(X509_STORE *ctx, char *file, STACK_OF(X509) *uchain, int purpose)
|
static int check(X509_STORE *ctx, char *file, STACK_OF(X509) *uchain, STACK_OF(X509) *tchain, int purpose)
|
||||||
{
|
{
|
||||||
X509 *x=NULL;
|
X509 *x=NULL;
|
||||||
BIO *in=NULL;
|
BIO *in=NULL;
|
||||||
@ -242,6 +256,7 @@ static int check(X509_STORE *ctx, char *file, STACK_OF(X509) *uchain, int purpos
|
|||||||
goto end;
|
goto end;
|
||||||
}
|
}
|
||||||
X509_STORE_CTX_init(csc,ctx,x,uchain);
|
X509_STORE_CTX_init(csc,ctx,x,uchain);
|
||||||
|
if(tchain) X509_STORE_CTX_trusted_stack(csc, tchain);
|
||||||
if(purpose >= 0) X509_STORE_CTX_set_purpose(csc, purpose);
|
if(purpose >= 0) X509_STORE_CTX_set_purpose(csc, purpose);
|
||||||
i=X509_verify_cert(csc);
|
i=X509_verify_cert(csc);
|
||||||
X509_STORE_CTX_free(csc);
|
X509_STORE_CTX_free(csc);
|
||||||
|
@ -61,6 +61,7 @@
|
|||||||
#include <openssl/evp.h>
|
#include <openssl/evp.h>
|
||||||
#include <openssl/asn1_mac.h>
|
#include <openssl/asn1_mac.h>
|
||||||
#include <openssl/x509.h>
|
#include <openssl/x509.h>
|
||||||
|
#include <openssl/x509v3.h>
|
||||||
|
|
||||||
static int x509_meth_num = 0;
|
static int x509_meth_num = 0;
|
||||||
static STACK_OF(CRYPTO_EX_DATA_FUNCS) *x509_meth = NULL;
|
static STACK_OF(CRYPTO_EX_DATA_FUNCS) *x509_meth = NULL;
|
||||||
@ -114,11 +115,13 @@ X509 *X509_new(void)
|
|||||||
ASN1_CTX c;
|
ASN1_CTX c;
|
||||||
|
|
||||||
M_ASN1_New_Malloc(ret,X509);
|
M_ASN1_New_Malloc(ret,X509);
|
||||||
ret->references=1;
|
|
||||||
ret->valid=0;
|
ret->valid=0;
|
||||||
|
ret->references=1;
|
||||||
|
ret->name = NULL;
|
||||||
ret->ex_flags = 0;
|
ret->ex_flags = 0;
|
||||||
ret->ex_pathlen = -1;
|
ret->ex_pathlen = -1;
|
||||||
ret->name=NULL;
|
ret->skid = NULL;
|
||||||
|
ret->akid = NULL;
|
||||||
ret->aux = NULL;
|
ret->aux = NULL;
|
||||||
M_ASN1_New(ret->cert_info,X509_CINF_new);
|
M_ASN1_New(ret->cert_info,X509_CINF_new);
|
||||||
M_ASN1_New(ret->sig_alg,X509_ALGOR_new);
|
M_ASN1_New(ret->sig_alg,X509_ALGOR_new);
|
||||||
@ -152,6 +155,8 @@ void X509_free(X509 *a)
|
|||||||
X509_ALGOR_free(a->sig_alg);
|
X509_ALGOR_free(a->sig_alg);
|
||||||
M_ASN1_BIT_STRING_free(a->signature);
|
M_ASN1_BIT_STRING_free(a->signature);
|
||||||
X509_CERT_AUX_free(a->aux);
|
X509_CERT_AUX_free(a->aux);
|
||||||
|
ASN1_OCTET_STRING_free(a->skid);
|
||||||
|
AUTHORITY_KEYID_free(a->akid);
|
||||||
|
|
||||||
if (a->name != NULL) OPENSSL_free(a->name);
|
if (a->name != NULL) OPENSSL_free(a->name);
|
||||||
OPENSSL_free(a);
|
OPENSSL_free(a);
|
||||||
|
@ -864,6 +864,26 @@ STACK_OF(type) \
|
|||||||
#define sk_X509_NAME_ENTRY_pop(st) SKM_sk_pop(X509_NAME_ENTRY, (st))
|
#define sk_X509_NAME_ENTRY_pop(st) SKM_sk_pop(X509_NAME_ENTRY, (st))
|
||||||
#define sk_X509_NAME_ENTRY_sort(st) SKM_sk_sort(X509_NAME_ENTRY, (st))
|
#define sk_X509_NAME_ENTRY_sort(st) SKM_sk_sort(X509_NAME_ENTRY, (st))
|
||||||
|
|
||||||
|
#define sk_X509_OBJECT_new(st) SKM_sk_new(X509_OBJECT, (st))
|
||||||
|
#define sk_X509_OBJECT_new_null() SKM_sk_new_null(X509_OBJECT)
|
||||||
|
#define sk_X509_OBJECT_free(st) SKM_sk_free(X509_OBJECT, (st))
|
||||||
|
#define sk_X509_OBJECT_num(st) SKM_sk_num(X509_OBJECT, (st))
|
||||||
|
#define sk_X509_OBJECT_value(st, i) SKM_sk_value(X509_OBJECT, (st), (i))
|
||||||
|
#define sk_X509_OBJECT_set(st, i, val) SKM_sk_set(X509_OBJECT, (st), (i), (val))
|
||||||
|
#define sk_X509_OBJECT_zero(st) SKM_sk_zero(X509_OBJECT, (st))
|
||||||
|
#define sk_X509_OBJECT_push(st, val) SKM_sk_push(X509_OBJECT, (st), (val))
|
||||||
|
#define sk_X509_OBJECT_unshift(st, val) SKM_sk_unshift(X509_OBJECT, (st), (val))
|
||||||
|
#define sk_X509_OBJECT_find(st, val) SKM_sk_find(X509_OBJECT, (st), (val))
|
||||||
|
#define sk_X509_OBJECT_delete(st, i) SKM_sk_delete(X509_OBJECT, (st), (i))
|
||||||
|
#define sk_X509_OBJECT_delete_ptr(st, ptr) SKM_sk_delete_ptr(X509_OBJECT, (st), (ptr))
|
||||||
|
#define sk_X509_OBJECT_insert(st, val, i) SKM_sk_insert(X509_OBJECT, (st), (val), (i))
|
||||||
|
#define sk_X509_OBJECT_set_cmp_func(st, cmp) SKM_sk_set_cmp_func(X509_OBJECT, (st), (cmp))
|
||||||
|
#define sk_X509_OBJECT_dup(st) SKM_sk_dup(X509_OBJECT, st)
|
||||||
|
#define sk_X509_OBJECT_pop_free(st, free_func) SKM_sk_pop_free(X509_OBJECT, (st), (free_func))
|
||||||
|
#define sk_X509_OBJECT_shift(st) SKM_sk_shift(X509_OBJECT, (st))
|
||||||
|
#define sk_X509_OBJECT_pop(st) SKM_sk_pop(X509_OBJECT, (st))
|
||||||
|
#define sk_X509_OBJECT_sort(st) SKM_sk_sort(X509_OBJECT, (st))
|
||||||
|
|
||||||
#define sk_X509_PURPOSE_new(st) SKM_sk_new(X509_PURPOSE, (st))
|
#define sk_X509_PURPOSE_new(st) SKM_sk_new(X509_PURPOSE, (st))
|
||||||
#define sk_X509_PURPOSE_new_null() SKM_sk_new_null(X509_PURPOSE)
|
#define sk_X509_PURPOSE_new_null() SKM_sk_new_null(X509_PURPOSE)
|
||||||
#define sk_X509_PURPOSE_free(st) SKM_sk_free(X509_PURPOSE, (st))
|
#define sk_X509_PURPOSE_free(st) SKM_sk_free(X509_PURPOSE, (st))
|
||||||
|
@ -326,7 +326,9 @@ static int get_cert_by_subject(X509_LOOKUP *xl, int type, X509_NAME *name,
|
|||||||
/* we have added it to the cache so now pull
|
/* we have added it to the cache so now pull
|
||||||
* it out again */
|
* it out again */
|
||||||
CRYPTO_r_lock(CRYPTO_LOCK_X509_STORE);
|
CRYPTO_r_lock(CRYPTO_LOCK_X509_STORE);
|
||||||
tmp=(X509_OBJECT *)lh_retrieve(xl->store_ctx->certs,&stmp);
|
j = sk_X509_OBJECT_find(xl->store_ctx->objs,&stmp);
|
||||||
|
if(j != -1) tmp=sk_X509_OBJECT_value(xl->store_ctx->objs,i);
|
||||||
|
else tmp = NULL;
|
||||||
CRYPTO_r_unlock(CRYPTO_LOCK_X509_STORE);
|
CRYPTO_r_unlock(CRYPTO_LOCK_X509_STORE);
|
||||||
|
|
||||||
if (tmp != NULL)
|
if (tmp != NULL)
|
||||||
|
@ -275,6 +275,8 @@ typedef struct x509_st
|
|||||||
unsigned long ex_kusage;
|
unsigned long ex_kusage;
|
||||||
unsigned long ex_xkusage;
|
unsigned long ex_xkusage;
|
||||||
unsigned long ex_nscert;
|
unsigned long ex_nscert;
|
||||||
|
ASN1_OCTET_STRING *skid;
|
||||||
|
struct AUTHORITY_KEYID_st *akid;
|
||||||
#ifndef NO_SHA
|
#ifndef NO_SHA
|
||||||
unsigned char sha1_hash[SHA_DIGEST_LENGTH];
|
unsigned char sha1_hash[SHA_DIGEST_LENGTH];
|
||||||
#endif
|
#endif
|
||||||
|
@ -62,7 +62,6 @@
|
|||||||
#include <openssl/x509.h>
|
#include <openssl/x509.h>
|
||||||
|
|
||||||
static STACK_OF(CRYPTO_EX_DATA_FUNCS) *x509_store_meth=NULL;
|
static STACK_OF(CRYPTO_EX_DATA_FUNCS) *x509_store_meth=NULL;
|
||||||
static STACK_OF(CRYPTO_EX_DATA_FUNCS) *x509_store_ctx_meth=NULL;
|
|
||||||
|
|
||||||
X509_LOOKUP *X509_LOOKUP_new(X509_LOOKUP_METHOD *method)
|
X509_LOOKUP *X509_LOOKUP_new(X509_LOOKUP_METHOD *method)
|
||||||
{
|
{
|
||||||
@ -155,38 +154,20 @@ int X509_LOOKUP_by_alias(X509_LOOKUP *ctx, int type, char *str, int len,
|
|||||||
return(ctx->method->get_by_alias(ctx,type,str,len,ret));
|
return(ctx->method->get_by_alias(ctx,type,str,len,ret));
|
||||||
}
|
}
|
||||||
|
|
||||||
static unsigned long x509_object_hash(X509_OBJECT *a)
|
|
||||||
{
|
|
||||||
unsigned long h;
|
|
||||||
|
|
||||||
switch (a->type)
|
static int x509_object_cmp(const X509_OBJECT * const *a, const X509_OBJECT * const *b)
|
||||||
{
|
|
||||||
case X509_LU_X509:
|
|
||||||
h=X509_NAME_hash(a->data.x509->cert_info->subject);
|
|
||||||
break;
|
|
||||||
case X509_LU_CRL:
|
|
||||||
h=X509_NAME_hash(a->data.crl->crl->issuer);
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
/* abort(); */
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
return(h);
|
|
||||||
}
|
|
||||||
|
|
||||||
static int x509_object_cmp(X509_OBJECT *a, X509_OBJECT *b)
|
|
||||||
{
|
{
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
ret=(a->type - b->type);
|
ret=((*a)->type - (*b)->type);
|
||||||
if (ret) return(ret);
|
if (ret) return(ret);
|
||||||
switch (a->type)
|
switch ((*a)->type)
|
||||||
{
|
{
|
||||||
case X509_LU_X509:
|
case X509_LU_X509:
|
||||||
ret=X509_subject_name_cmp(a->data.x509,b->data.x509);
|
ret=X509_subject_name_cmp((*a)->data.x509,(*b)->data.x509);
|
||||||
break;
|
break;
|
||||||
case X509_LU_CRL:
|
case X509_LU_CRL:
|
||||||
ret=X509_CRL_cmp(a->data.crl,b->data.crl);
|
ret=X509_CRL_cmp((*a)->data.crl,(*b)->data.crl);
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
/* abort(); */
|
/* abort(); */
|
||||||
@ -201,7 +182,7 @@ X509_STORE *X509_STORE_new(void)
|
|||||||
|
|
||||||
if ((ret=(X509_STORE *)OPENSSL_malloc(sizeof(X509_STORE))) == NULL)
|
if ((ret=(X509_STORE *)OPENSSL_malloc(sizeof(X509_STORE))) == NULL)
|
||||||
return(NULL);
|
return(NULL);
|
||||||
ret->certs=lh_new(x509_object_hash,x509_object_cmp);
|
ret->objs = sk_X509_OBJECT_new(x509_object_cmp);
|
||||||
ret->cache=1;
|
ret->cache=1;
|
||||||
ret->get_cert_methods=sk_X509_LOOKUP_new_null();
|
ret->get_cert_methods=sk_X509_LOOKUP_new_null();
|
||||||
ret->verify=NULL;
|
ret->verify=NULL;
|
||||||
@ -247,10 +228,9 @@ void X509_STORE_free(X509_STORE *vfy)
|
|||||||
X509_LOOKUP_free(lu);
|
X509_LOOKUP_free(lu);
|
||||||
}
|
}
|
||||||
sk_X509_LOOKUP_free(sk);
|
sk_X509_LOOKUP_free(sk);
|
||||||
|
sk_X509_OBJECT_pop_free(vfy->objs, cleanup);
|
||||||
|
|
||||||
CRYPTO_free_ex_data(x509_store_meth,vfy,&vfy->ex_data);
|
CRYPTO_free_ex_data(x509_store_meth,vfy,&vfy->ex_data);
|
||||||
lh_doall(vfy->certs,cleanup);
|
|
||||||
lh_free(vfy->certs);
|
|
||||||
OPENSSL_free(vfy);
|
OPENSSL_free(vfy);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -294,7 +274,7 @@ int X509_STORE_get_by_subject(X509_STORE_CTX *vs, int type, X509_NAME *name,
|
|||||||
X509_OBJECT stmp,*tmp;
|
X509_OBJECT stmp,*tmp;
|
||||||
int i,j;
|
int i,j;
|
||||||
|
|
||||||
tmp=X509_OBJECT_retrieve_by_subject(ctx->certs,type,name);
|
tmp=X509_OBJECT_retrieve_by_subject(ctx->objs,type,name);
|
||||||
|
|
||||||
if (tmp == NULL)
|
if (tmp == NULL)
|
||||||
{
|
{
|
||||||
@ -329,6 +309,73 @@ int X509_STORE_get_by_subject(X509_STORE_CTX *vs, int type, X509_NAME *name,
|
|||||||
return(1);
|
return(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int X509_STORE_add_cert(X509_STORE *ctx, X509 *x)
|
||||||
|
{
|
||||||
|
X509_OBJECT *obj;
|
||||||
|
int ret=1;
|
||||||
|
|
||||||
|
if (x == NULL) return(0);
|
||||||
|
obj=(X509_OBJECT *)OPENSSL_malloc(sizeof(X509_OBJECT));
|
||||||
|
if (obj == NULL)
|
||||||
|
{
|
||||||
|
X509err(X509_F_X509_STORE_ADD_CERT,ERR_R_MALLOC_FAILURE);
|
||||||
|
return(0);
|
||||||
|
}
|
||||||
|
obj->type=X509_LU_X509;
|
||||||
|
obj->data.x509=x;
|
||||||
|
|
||||||
|
CRYPTO_w_lock(CRYPTO_LOCK_X509_STORE);
|
||||||
|
|
||||||
|
X509_OBJECT_up_ref_count(obj);
|
||||||
|
|
||||||
|
|
||||||
|
if (X509_OBJECT_retrieve_match(ctx->objs, obj))
|
||||||
|
{
|
||||||
|
X509_OBJECT_free_contents(obj);
|
||||||
|
OPENSSL_free(obj);
|
||||||
|
X509err(X509_F_X509_STORE_ADD_CERT,X509_R_CERT_ALREADY_IN_HASH_TABLE);
|
||||||
|
ret=0;
|
||||||
|
}
|
||||||
|
else sk_X509_OBJECT_push(ctx->objs, obj);
|
||||||
|
|
||||||
|
CRYPTO_w_unlock(CRYPTO_LOCK_X509_STORE);
|
||||||
|
|
||||||
|
return(ret);
|
||||||
|
}
|
||||||
|
|
||||||
|
int X509_STORE_add_crl(X509_STORE *ctx, X509_CRL *x)
|
||||||
|
{
|
||||||
|
X509_OBJECT *obj;
|
||||||
|
int ret=1;
|
||||||
|
|
||||||
|
if (x == NULL) return(0);
|
||||||
|
obj=(X509_OBJECT *)OPENSSL_malloc(sizeof(X509_OBJECT));
|
||||||
|
if (obj == NULL)
|
||||||
|
{
|
||||||
|
X509err(X509_F_X509_STORE_ADD_CRL,ERR_R_MALLOC_FAILURE);
|
||||||
|
return(0);
|
||||||
|
}
|
||||||
|
obj->type=X509_LU_CRL;
|
||||||
|
obj->data.crl=x;
|
||||||
|
|
||||||
|
CRYPTO_w_lock(CRYPTO_LOCK_X509_STORE);
|
||||||
|
|
||||||
|
X509_OBJECT_up_ref_count(obj);
|
||||||
|
|
||||||
|
if (X509_OBJECT_retrieve_match(ctx->objs, obj))
|
||||||
|
{
|
||||||
|
X509_OBJECT_free_contents(obj);
|
||||||
|
OPENSSL_free(obj);
|
||||||
|
X509err(X509_F_X509_STORE_ADD_CRL,X509_R_CERT_ALREADY_IN_HASH_TABLE);
|
||||||
|
ret=0;
|
||||||
|
}
|
||||||
|
else sk_X509_OBJECT_push(ctx->objs, obj);
|
||||||
|
|
||||||
|
CRYPTO_w_unlock(CRYPTO_LOCK_X509_STORE);
|
||||||
|
|
||||||
|
return(ret);
|
||||||
|
}
|
||||||
|
|
||||||
void X509_OBJECT_up_ref_count(X509_OBJECT *a)
|
void X509_OBJECT_up_ref_count(X509_OBJECT *a)
|
||||||
{
|
{
|
||||||
switch (a->type)
|
switch (a->type)
|
||||||
@ -355,10 +402,10 @@ void X509_OBJECT_free_contents(X509_OBJECT *a)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
X509_OBJECT *X509_OBJECT_retrieve_by_subject(LHASH *h, int type,
|
int X509_OBJECT_idx_by_subject(STACK_OF(X509_OBJECT) *h, int type,
|
||||||
X509_NAME *name)
|
X509_NAME *name)
|
||||||
{
|
{
|
||||||
X509_OBJECT stmp,*tmp;
|
X509_OBJECT stmp;
|
||||||
X509 x509_s;
|
X509 x509_s;
|
||||||
X509_CINF cinf_s;
|
X509_CINF cinf_s;
|
||||||
X509_CRL crl_s;
|
X509_CRL crl_s;
|
||||||
@ -379,54 +426,98 @@ X509_OBJECT *X509_OBJECT_retrieve_by_subject(LHASH *h, int type,
|
|||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
/* abort(); */
|
/* abort(); */
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
return sk_X509_OBJECT_find(h,&stmp);
|
||||||
|
}
|
||||||
|
|
||||||
|
X509_OBJECT *X509_OBJECT_retrieve_by_subject(STACK_OF(X509_OBJECT) *h, int type,
|
||||||
|
X509_NAME *name)
|
||||||
|
{
|
||||||
|
int idx;
|
||||||
|
idx = X509_OBJECT_idx_by_subject(h, type, name);
|
||||||
|
if(idx==-1) return NULL;
|
||||||
|
return sk_X509_OBJECT_value(h, idx);
|
||||||
|
}
|
||||||
|
|
||||||
|
X509_OBJECT *X509_OBJECT_retrieve_match(STACK_OF(X509_OBJECT) *h, X509_OBJECT *x)
|
||||||
|
{
|
||||||
|
int idx, i;
|
||||||
|
X509_OBJECT *obj;
|
||||||
|
idx = sk_X509_OBJECT_find(h, x);
|
||||||
|
if(idx == -1) return NULL;
|
||||||
|
if(x->type != X509_LU_X509) return sk_X509_OBJECT_value(h, idx);
|
||||||
|
for(i = idx; i < sk_X509_OBJECT_num(h); i++) {
|
||||||
|
obj = sk_X509_OBJECT_value(h, i);
|
||||||
|
if(x509_object_cmp((const X509_OBJECT **)&obj, (const X509_OBJECT **)&x)) return NULL;
|
||||||
|
if((x->type != X509_LU_X509) || !X509_cmp(obj->data.x509, x->data.x509)) return obj;
|
||||||
|
}
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
tmp=(X509_OBJECT *)lh_retrieve(h,&stmp);
|
|
||||||
return(tmp);
|
|
||||||
}
|
|
||||||
|
|
||||||
X509_STORE_CTX *X509_STORE_CTX_new(void)
|
/* Try to get issuer certificate from store. Due to limitations
|
||||||
{
|
* of the API this can only retrieve a single certificate matching
|
||||||
X509_STORE_CTX *ctx;
|
* a given subject name. However it will fill the cache with all
|
||||||
ctx = (X509_STORE_CTX *)OPENSSL_malloc(sizeof(X509_STORE_CTX));
|
* matching certificates, so we can examine the cache for all
|
||||||
if(ctx) memset(ctx, 0, sizeof(X509_STORE_CTX));
|
* matches.
|
||||||
return ctx;
|
*
|
||||||
}
|
* Return values are:
|
||||||
|
* 1 lookup successful.
|
||||||
|
* 0 certificate not found.
|
||||||
|
* -1 some other error.
|
||||||
|
*/
|
||||||
|
|
||||||
void X509_STORE_CTX_free(X509_STORE_CTX *ctx)
|
|
||||||
{
|
|
||||||
X509_STORE_CTX_cleanup(ctx);
|
|
||||||
OPENSSL_free(ctx);
|
|
||||||
}
|
|
||||||
|
|
||||||
void X509_STORE_CTX_init(X509_STORE_CTX *ctx, X509_STORE *store, X509 *x509,
|
int X509_STORE_CTX_get1_issuer(X509 **issuer, X509_STORE_CTX *ctx, X509 *x)
|
||||||
STACK_OF(X509) *chain)
|
|
||||||
{
|
{
|
||||||
ctx->ctx=store;
|
X509_NAME *xn;
|
||||||
ctx->current_method=0;
|
X509_OBJECT obj, *pobj;
|
||||||
ctx->cert=x509;
|
int i, ok, idx;
|
||||||
ctx->untrusted=chain;
|
xn=X509_get_issuer_name(x);
|
||||||
ctx->last_untrusted=0;
|
ok=X509_STORE_get_by_subject(ctx,X509_LU_X509,xn,&obj);
|
||||||
ctx->purpose=0;
|
if (ok != X509_LU_X509)
|
||||||
ctx->trust=0;
|
{
|
||||||
ctx->valid=0;
|
if (ok == X509_LU_RETRY)
|
||||||
ctx->chain=NULL;
|
{
|
||||||
ctx->depth=9;
|
X509_OBJECT_free_contents(&obj);
|
||||||
ctx->error=0;
|
X509err(X509_F_X509_VERIFY_CERT,X509_R_SHOULD_RETRY);
|
||||||
ctx->current_cert=NULL;
|
return -1;
|
||||||
memset(&(ctx->ex_data),0,sizeof(CRYPTO_EX_DATA));
|
|
||||||
}
|
}
|
||||||
|
else if (ok != X509_LU_FAIL)
|
||||||
|
{
|
||||||
|
X509_OBJECT_free_contents(&obj);
|
||||||
|
/* not good :-(, break anyway */
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
/* If certificate matches all OK */
|
||||||
|
if(ctx->check_issued(ctx, x, obj.data.x509)) {
|
||||||
|
*issuer = obj.data.x509;
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
X509_OBJECT_free_contents(&obj);
|
||||||
|
/* Else find index of first matching cert */
|
||||||
|
idx = X509_OBJECT_idx_by_subject(ctx->ctx->objs, X509_LU_X509, xn);
|
||||||
|
/* This shouldn't normally happen since we already have one match */
|
||||||
|
if(idx == -1) return 0;
|
||||||
|
|
||||||
void X509_STORE_CTX_cleanup(X509_STORE_CTX *ctx)
|
/* Look through all matching certificates for a suitable issuer */
|
||||||
{
|
for(i = idx; i < sk_X509_OBJECT_num(ctx->ctx->objs); i++) {
|
||||||
if (ctx->chain != NULL)
|
pobj = sk_X509_OBJECT_value(ctx->ctx->objs, i);
|
||||||
{
|
/* See if we've ran out of matches */
|
||||||
sk_X509_pop_free(ctx->chain,X509_free);
|
if(pobj->type != X509_LU_X509) return 0;
|
||||||
ctx->chain=NULL;
|
if(X509_NAME_cmp(xn, X509_get_subject_name(pobj->data.x509))) return 0;
|
||||||
|
if(ctx->check_issued(ctx, x, pobj->data.x509)) {
|
||||||
|
*issuer = pobj->data.x509;
|
||||||
|
X509_OBJECT_up_ref_count(pobj);
|
||||||
|
return 1;
|
||||||
}
|
}
|
||||||
CRYPTO_free_ex_data(x509_store_ctx_meth,ctx,&(ctx->ex_data));
|
}
|
||||||
memset(&ctx->ex_data,0,sizeof(CRYPTO_EX_DATA));
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
IMPLEMENT_STACK_OF(X509_LOOKUP)
|
IMPLEMENT_STACK_OF(X509_LOOKUP)
|
||||||
|
IMPLEMENT_STACK_OF(X509_OBJECT)
|
||||||
|
@ -132,6 +132,15 @@ const char *X509_verify_cert_error_string(long n)
|
|||||||
return ("certificate rejected");
|
return ("certificate rejected");
|
||||||
case X509_V_ERR_APPLICATION_VERIFICATION:
|
case X509_V_ERR_APPLICATION_VERIFICATION:
|
||||||
return("application verification failure");
|
return("application verification failure");
|
||||||
|
case X509_V_ERR_SUBJECT_ISSUER_MISMATCH:
|
||||||
|
return("subject issuer mismatch");
|
||||||
|
case X509_V_ERR_AKID_SKID_MISMATCH:
|
||||||
|
return("authority and subject key identifier mismatch");
|
||||||
|
case X509_V_ERR_AKID_ISSUER_SERIAL_MISMATCH:
|
||||||
|
return("authority and issuer serial number mismatch");
|
||||||
|
case X509_V_ERR_KEYUSAGE_NO_CERTSIGN:
|
||||||
|
return("key usage does not include certificate signing");
|
||||||
|
|
||||||
default:
|
default:
|
||||||
sprintf(buf,"error number %ld",n);
|
sprintf(buf,"error number %ld",n);
|
||||||
return(buf);
|
return(buf);
|
||||||
|
@ -71,6 +71,8 @@
|
|||||||
#include <openssl/objects.h>
|
#include <openssl/objects.h>
|
||||||
|
|
||||||
static int null_callback(int ok,X509_STORE_CTX *e);
|
static int null_callback(int ok,X509_STORE_CTX *e);
|
||||||
|
static int check_issued(X509_STORE_CTX *ctx, X509 *x, X509 *issuer);
|
||||||
|
static X509 *find_issuer(X509_STORE_CTX *ctx, STACK_OF(X509) *sk, X509 *x);
|
||||||
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 check_trust(X509_STORE_CTX *ctx);
|
||||||
static int internal_verify(X509_STORE_CTX *ctx);
|
static int internal_verify(X509_STORE_CTX *ctx);
|
||||||
@ -99,7 +101,6 @@ int X509_verify_cert(X509_STORE_CTX *ctx)
|
|||||||
{
|
{
|
||||||
X509 *x,*xtmp,*chain_ss=NULL;
|
X509 *x,*xtmp,*chain_ss=NULL;
|
||||||
X509_NAME *xn;
|
X509_NAME *xn;
|
||||||
X509_OBJECT obj;
|
|
||||||
int depth,i,ok=0;
|
int depth,i,ok=0;
|
||||||
int num;
|
int num;
|
||||||
int (*cb)();
|
int (*cb)();
|
||||||
@ -111,7 +112,7 @@ int X509_verify_cert(X509_STORE_CTX *ctx)
|
|||||||
return(-1);
|
return(-1);
|
||||||
}
|
}
|
||||||
|
|
||||||
cb=ctx->ctx->verify_cb;
|
cb=ctx->verify_cb;
|
||||||
if (cb == NULL) cb=null_callback;
|
if (cb == NULL) cb=null_callback;
|
||||||
|
|
||||||
/* first we make sure the chain we are going to build is
|
/* first we make sure the chain we are going to build is
|
||||||
@ -152,13 +153,12 @@ int X509_verify_cert(X509_STORE_CTX *ctx)
|
|||||||
|
|
||||||
/* If we are self signed, we break */
|
/* If we are self signed, we break */
|
||||||
xn=X509_get_issuer_name(x);
|
xn=X509_get_issuer_name(x);
|
||||||
if (X509_NAME_cmp(X509_get_subject_name(x),xn) == 0)
|
if (ctx->check_issued(ctx, x,x)) break;
|
||||||
break;
|
|
||||||
|
|
||||||
/* If we were passed a cert chain, use it first */
|
/* If we were passed a cert chain, use it first */
|
||||||
if (ctx->untrusted != NULL)
|
if (ctx->untrusted != NULL)
|
||||||
{
|
{
|
||||||
xtmp=X509_find_by_subject(sktmp,xn);
|
xtmp=find_issuer(ctx, sktmp,x);
|
||||||
if (xtmp != NULL)
|
if (xtmp != NULL)
|
||||||
{
|
{
|
||||||
if (!sk_X509_push(ctx->chain,xtmp))
|
if (!sk_X509_push(ctx->chain,xtmp))
|
||||||
@ -183,11 +183,14 @@ int X509_verify_cert(X509_STORE_CTX *ctx)
|
|||||||
* certificates. We now need to add at least one trusted one,
|
* certificates. We now need to add at least one trusted one,
|
||||||
* if possible, otherwise we complain. */
|
* if possible, otherwise we complain. */
|
||||||
|
|
||||||
|
/* Examine last certificate in chain and see if it
|
||||||
|
* is self signed.
|
||||||
|
*/
|
||||||
|
|
||||||
i=sk_X509_num(ctx->chain);
|
i=sk_X509_num(ctx->chain);
|
||||||
x=sk_X509_value(ctx->chain,i-1);
|
x=sk_X509_value(ctx->chain,i-1);
|
||||||
xn = X509_get_subject_name(x);
|
xn = X509_get_subject_name(x);
|
||||||
if (X509_NAME_cmp(xn,X509_get_issuer_name(x))
|
if (ctx->check_issued(ctx, x, x))
|
||||||
== 0)
|
|
||||||
{
|
{
|
||||||
/* we have a self signed certificate */
|
/* we have a self signed certificate */
|
||||||
if (sk_X509_num(ctx->chain) == 1)
|
if (sk_X509_num(ctx->chain) == 1)
|
||||||
@ -196,13 +199,13 @@ int X509_verify_cert(X509_STORE_CTX *ctx)
|
|||||||
* we can find it in the store. We must have an exact
|
* we can find it in the store. We must have an exact
|
||||||
* match to avoid possible impersonation.
|
* match to avoid possible impersonation.
|
||||||
*/
|
*/
|
||||||
ok=X509_STORE_get_by_subject(ctx,X509_LU_X509,xn,&obj);
|
ok = ctx->get_issuer(&xtmp, ctx, x);
|
||||||
if ((ok != X509_LU_X509) || X509_cmp(x, obj.data.x509))
|
if ((ok <= 0) || X509_cmp(x, xtmp))
|
||||||
{
|
{
|
||||||
ctx->error=X509_V_ERR_DEPTH_ZERO_SELF_SIGNED_CERT;
|
ctx->error=X509_V_ERR_DEPTH_ZERO_SELF_SIGNED_CERT;
|
||||||
ctx->current_cert=x;
|
ctx->current_cert=x;
|
||||||
ctx->error_depth=i-1;
|
ctx->error_depth=i-1;
|
||||||
if(ok == X509_LU_X509) X509_OBJECT_free_contents(&obj);
|
if(ok == 1) X509_free(xtmp);
|
||||||
ok=cb(0,ctx);
|
ok=cb(0,ctx);
|
||||||
if (!ok) goto end;
|
if (!ok) goto end;
|
||||||
}
|
}
|
||||||
@ -212,14 +215,14 @@ int X509_verify_cert(X509_STORE_CTX *ctx)
|
|||||||
* so we get any trust settings.
|
* so we get any trust settings.
|
||||||
*/
|
*/
|
||||||
X509_free(x);
|
X509_free(x);
|
||||||
x = obj.data.x509;
|
x = xtmp;
|
||||||
sk_X509_set(ctx->chain, i - 1, x);
|
sk_X509_set(ctx->chain, i - 1, x);
|
||||||
ctx->last_untrusted=0;
|
ctx->last_untrusted=0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
/* worry more about this one elsewhere */
|
/* extract and save self signed certificate for later use */
|
||||||
chain_ss=sk_X509_pop(ctx->chain);
|
chain_ss=sk_X509_pop(ctx->chain);
|
||||||
ctx->last_untrusted--;
|
ctx->last_untrusted--;
|
||||||
num--;
|
num--;
|
||||||
@ -235,30 +238,17 @@ int X509_verify_cert(X509_STORE_CTX *ctx)
|
|||||||
|
|
||||||
/* If we are self signed, we break */
|
/* If we are self signed, we break */
|
||||||
xn=X509_get_issuer_name(x);
|
xn=X509_get_issuer_name(x);
|
||||||
if (X509_NAME_cmp(X509_get_subject_name(x),xn) == 0)
|
if (ctx->check_issued(ctx,x,x)) break;
|
||||||
break;
|
|
||||||
|
|
||||||
ok=X509_STORE_get_by_subject(ctx,X509_LU_X509,xn,&obj);
|
ok = ctx->get_issuer(&xtmp, ctx, x);
|
||||||
if (ok != X509_LU_X509)
|
|
||||||
|
if (ok < 0) return ok;
|
||||||
|
if(ok == 0) break;
|
||||||
|
|
||||||
|
x = xtmp;
|
||||||
|
if (!sk_X509_push(ctx->chain,x))
|
||||||
{
|
{
|
||||||
if (ok == X509_LU_RETRY)
|
X509_free(xtmp);
|
||||||
{
|
|
||||||
X509_OBJECT_free_contents(&obj);
|
|
||||||
X509err(X509_F_X509_VERIFY_CERT,X509_R_SHOULD_RETRY);
|
|
||||||
return(ok);
|
|
||||||
}
|
|
||||||
else if (ok != X509_LU_FAIL)
|
|
||||||
{
|
|
||||||
X509_OBJECT_free_contents(&obj);
|
|
||||||
/* not good :-(, break anyway */
|
|
||||||
return(ok);
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
x=obj.data.x509;
|
|
||||||
if (!sk_X509_push(ctx->chain,obj.data.x509))
|
|
||||||
{
|
|
||||||
X509_OBJECT_free_contents(&obj);
|
|
||||||
X509err(X509_F_X509_VERIFY_CERT,ERR_R_MALLOC_FAILURE);
|
X509err(X509_F_X509_VERIFY_CERT,ERR_R_MALLOC_FAILURE);
|
||||||
return(0);
|
return(0);
|
||||||
}
|
}
|
||||||
@ -267,9 +257,11 @@ int X509_verify_cert(X509_STORE_CTX *ctx)
|
|||||||
|
|
||||||
/* we now have our chain, lets check it... */
|
/* we now have our chain, lets check it... */
|
||||||
xn=X509_get_issuer_name(x);
|
xn=X509_get_issuer_name(x);
|
||||||
if (X509_NAME_cmp(X509_get_subject_name(x),xn) != 0)
|
|
||||||
|
/* Is last certificate looked up self signed? */
|
||||||
|
if (!ctx->check_issued(ctx,x,x))
|
||||||
{
|
{
|
||||||
if ((chain_ss == NULL) || (X509_NAME_cmp(X509_get_subject_name(chain_ss),xn) != 0))
|
if ((chain_ss == NULL) || !ctx->check_issued(ctx, x, chain_ss))
|
||||||
{
|
{
|
||||||
if (ctx->last_untrusted >= num)
|
if (ctx->last_untrusted >= num)
|
||||||
ctx->error=X509_V_ERR_UNABLE_TO_GET_ISSUER_CERT_LOCALLY;
|
ctx->error=X509_V_ERR_UNABLE_TO_GET_ISSUER_CERT_LOCALLY;
|
||||||
@ -308,8 +300,8 @@ int X509_verify_cert(X509_STORE_CTX *ctx)
|
|||||||
X509_get_pubkey_parameters(NULL,ctx->chain);
|
X509_get_pubkey_parameters(NULL,ctx->chain);
|
||||||
|
|
||||||
/* At this point, we have a chain and just need to verify it */
|
/* At this point, we have a chain and just need to verify it */
|
||||||
if (ctx->ctx->verify != NULL)
|
if (ctx->verify != NULL)
|
||||||
ok=ctx->ctx->verify(ctx);
|
ok=ctx->verify(ctx);
|
||||||
else
|
else
|
||||||
ok=internal_verify(ctx);
|
ok=internal_verify(ctx);
|
||||||
if (0)
|
if (0)
|
||||||
@ -322,6 +314,51 @@ end:
|
|||||||
return(ok);
|
return(ok);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* Given a STACK_OF(X509) find the issuer of cert (if any)
|
||||||
|
*/
|
||||||
|
|
||||||
|
static X509 *find_issuer(X509_STORE_CTX *ctx, STACK_OF(X509) *sk, X509 *x)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
X509 *issuer;
|
||||||
|
for(i = 0; i < sk_X509_num(sk); i++) {
|
||||||
|
issuer = sk_X509_value(sk, i);
|
||||||
|
if(ctx->check_issued(ctx, x, issuer)) return issuer;
|
||||||
|
}
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Given a possible certificate and issuer check them */
|
||||||
|
|
||||||
|
static int check_issued(X509_STORE_CTX *ctx, X509 *x, X509 *issuer)
|
||||||
|
{
|
||||||
|
int ret;
|
||||||
|
ret = X509_check_issued(issuer, x);
|
||||||
|
if(ret == X509_V_OK) return 1;
|
||||||
|
else {
|
||||||
|
ctx->error = ret;
|
||||||
|
ctx->current_cert = x;
|
||||||
|
ctx->current_issuer = issuer;
|
||||||
|
if(ctx->flags & X509_V_FLAG_CB_ISSUER_CHECK)
|
||||||
|
return ctx->verify_cb(0, ctx);
|
||||||
|
else return 0;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Alternative lookup method: look from a STACK stored in other_ctx */
|
||||||
|
|
||||||
|
static int get_issuer_sk(X509 **issuer, X509_STORE_CTX *ctx, X509 *x)
|
||||||
|
{
|
||||||
|
*issuer = find_issuer(ctx, ctx->other_ctx, x);
|
||||||
|
if(*issuer) {
|
||||||
|
CRYPTO_add(&(*issuer)->references,1,CRYPTO_LOCK_X509);
|
||||||
|
return 1;
|
||||||
|
} else return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/* Check a certificate chains extensions for consistency
|
/* Check a certificate chains extensions for consistency
|
||||||
* with the supplied purpose
|
* with the supplied purpose
|
||||||
*/
|
*/
|
||||||
@ -334,7 +371,7 @@ static int check_chain_purpose(X509_STORE_CTX *ctx)
|
|||||||
int i, ok=0;
|
int i, ok=0;
|
||||||
X509 *x;
|
X509 *x;
|
||||||
int (*cb)();
|
int (*cb)();
|
||||||
cb=ctx->ctx->verify_cb;
|
cb=ctx->verify_cb;
|
||||||
if (cb == NULL) cb=null_callback;
|
if (cb == NULL) cb=null_callback;
|
||||||
/* Check all untrusted certificates */
|
/* Check all untrusted certificates */
|
||||||
for(i = 0; i < ctx->last_untrusted; i++) {
|
for(i = 0; i < ctx->last_untrusted; i++) {
|
||||||
@ -371,7 +408,7 @@ static int check_trust(X509_STORE_CTX *ctx)
|
|||||||
int i, ok;
|
int i, ok;
|
||||||
X509 *x;
|
X509 *x;
|
||||||
int (*cb)();
|
int (*cb)();
|
||||||
cb=ctx->ctx->verify_cb;
|
cb=ctx->verify_cb;
|
||||||
if (cb == NULL) cb=null_callback;
|
if (cb == NULL) cb=null_callback;
|
||||||
/* For now just check the last certificate in the chain */
|
/* For now just check the last certificate in the chain */
|
||||||
i = sk_X509_num(ctx->chain) - 1;
|
i = sk_X509_num(ctx->chain) - 1;
|
||||||
@ -394,7 +431,7 @@ static int internal_verify(X509_STORE_CTX *ctx)
|
|||||||
EVP_PKEY *pkey=NULL;
|
EVP_PKEY *pkey=NULL;
|
||||||
int (*cb)();
|
int (*cb)();
|
||||||
|
|
||||||
cb=ctx->ctx->verify_cb;
|
cb=ctx->verify_cb;
|
||||||
if (cb == NULL) cb=null_callback;
|
if (cb == NULL) cb=null_callback;
|
||||||
|
|
||||||
n=sk_X509_num(ctx->chain);
|
n=sk_X509_num(ctx->chain);
|
||||||
@ -629,76 +666,6 @@ int X509_get_pubkey_parameters(EVP_PKEY *pkey, STACK_OF(X509) *chain)
|
|||||||
return(1);
|
return(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
int X509_STORE_add_cert(X509_STORE *ctx, X509 *x)
|
|
||||||
{
|
|
||||||
X509_OBJECT *obj,*r;
|
|
||||||
int ret=1;
|
|
||||||
|
|
||||||
if (x == NULL) return(0);
|
|
||||||
obj=(X509_OBJECT *)OPENSSL_malloc(sizeof(X509_OBJECT));
|
|
||||||
if (obj == NULL)
|
|
||||||
{
|
|
||||||
X509err(X509_F_X509_STORE_ADD_CERT,ERR_R_MALLOC_FAILURE);
|
|
||||||
return(0);
|
|
||||||
}
|
|
||||||
obj->type=X509_LU_X509;
|
|
||||||
obj->data.x509=x;
|
|
||||||
|
|
||||||
CRYPTO_w_lock(CRYPTO_LOCK_X509_STORE);
|
|
||||||
|
|
||||||
X509_OBJECT_up_ref_count(obj);
|
|
||||||
|
|
||||||
r=(X509_OBJECT *)lh_insert(ctx->certs,obj);
|
|
||||||
if (r != NULL)
|
|
||||||
{ /* oops, put it back */
|
|
||||||
lh_delete(ctx->certs,obj);
|
|
||||||
X509_OBJECT_free_contents(obj);
|
|
||||||
OPENSSL_free(obj);
|
|
||||||
lh_insert(ctx->certs,r);
|
|
||||||
X509err(X509_F_X509_STORE_ADD_CERT,X509_R_CERT_ALREADY_IN_HASH_TABLE);
|
|
||||||
ret=0;
|
|
||||||
}
|
|
||||||
|
|
||||||
CRYPTO_w_unlock(CRYPTO_LOCK_X509_STORE);
|
|
||||||
|
|
||||||
return(ret);
|
|
||||||
}
|
|
||||||
|
|
||||||
int X509_STORE_add_crl(X509_STORE *ctx, X509_CRL *x)
|
|
||||||
{
|
|
||||||
X509_OBJECT *obj,*r;
|
|
||||||
int ret=1;
|
|
||||||
|
|
||||||
if (x == NULL) return(0);
|
|
||||||
obj=(X509_OBJECT *)OPENSSL_malloc(sizeof(X509_OBJECT));
|
|
||||||
if (obj == NULL)
|
|
||||||
{
|
|
||||||
X509err(X509_F_X509_STORE_ADD_CRL,ERR_R_MALLOC_FAILURE);
|
|
||||||
return(0);
|
|
||||||
}
|
|
||||||
obj->type=X509_LU_CRL;
|
|
||||||
obj->data.crl=x;
|
|
||||||
|
|
||||||
CRYPTO_w_lock(CRYPTO_LOCK_X509_STORE);
|
|
||||||
|
|
||||||
X509_OBJECT_up_ref_count(obj);
|
|
||||||
|
|
||||||
r=(X509_OBJECT *)lh_insert(ctx->certs,obj);
|
|
||||||
if (r != NULL)
|
|
||||||
{ /* oops, put it back */
|
|
||||||
lh_delete(ctx->certs,obj);
|
|
||||||
X509_OBJECT_free_contents(obj);
|
|
||||||
OPENSSL_free(obj);
|
|
||||||
lh_insert(ctx->certs,r);
|
|
||||||
X509err(X509_F_X509_STORE_ADD_CRL,X509_R_CERT_ALREADY_IN_HASH_TABLE);
|
|
||||||
ret=0;
|
|
||||||
}
|
|
||||||
|
|
||||||
CRYPTO_w_unlock(CRYPTO_LOCK_X509_STORE);
|
|
||||||
|
|
||||||
return(ret);
|
|
||||||
}
|
|
||||||
|
|
||||||
int X509_STORE_CTX_get_ex_new_index(long argl, void *argp, CRYPTO_EX_new *new_func,
|
int X509_STORE_CTX_get_ex_new_index(long argl, void *argp, CRYPTO_EX_new *new_func,
|
||||||
CRYPTO_EX_dup *dup_func, CRYPTO_EX_free *free_func)
|
CRYPTO_EX_dup *dup_func, CRYPTO_EX_free *free_func)
|
||||||
{
|
{
|
||||||
@ -828,6 +795,65 @@ int X509_STORE_CTX_purpose_inherit(X509_STORE_CTX *ctx, int def_purpose,
|
|||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
X509_STORE_CTX *X509_STORE_CTX_new(void)
|
||||||
|
{
|
||||||
|
X509_STORE_CTX *ctx;
|
||||||
|
ctx = (X509_STORE_CTX *)OPENSSL_malloc(sizeof(X509_STORE_CTX));
|
||||||
|
if(ctx) memset(ctx, 0, sizeof(X509_STORE_CTX));
|
||||||
|
return ctx;
|
||||||
|
}
|
||||||
|
|
||||||
|
void X509_STORE_CTX_free(X509_STORE_CTX *ctx)
|
||||||
|
{
|
||||||
|
X509_STORE_CTX_cleanup(ctx);
|
||||||
|
OPENSSL_free(ctx);
|
||||||
|
}
|
||||||
|
|
||||||
|
void X509_STORE_CTX_init(X509_STORE_CTX *ctx, X509_STORE *store, X509 *x509,
|
||||||
|
STACK_OF(X509) *chain)
|
||||||
|
{
|
||||||
|
ctx->ctx=store;
|
||||||
|
ctx->current_method=0;
|
||||||
|
ctx->cert=x509;
|
||||||
|
ctx->untrusted=chain;
|
||||||
|
ctx->last_untrusted=0;
|
||||||
|
ctx->purpose=0;
|
||||||
|
ctx->trust=0;
|
||||||
|
ctx->valid=0;
|
||||||
|
ctx->chain=NULL;
|
||||||
|
ctx->depth=9;
|
||||||
|
ctx->error=0;
|
||||||
|
ctx->current_cert=NULL;
|
||||||
|
ctx->current_issuer=NULL;
|
||||||
|
ctx->check_issued = check_issued;
|
||||||
|
ctx->get_issuer = X509_STORE_CTX_get1_issuer;
|
||||||
|
ctx->verify_cb = store->verify_cb;
|
||||||
|
ctx->verify = store->verify;
|
||||||
|
ctx->cleanup = NULL;
|
||||||
|
memset(&(ctx->ex_data),0,sizeof(CRYPTO_EX_DATA));
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Set alternative lookup method: just a STACK of trusted certificates.
|
||||||
|
* This avoids X509_STORE nastiness where it isn't needed.
|
||||||
|
*/
|
||||||
|
|
||||||
|
void X509_STORE_CTX_trusted_stack(X509_STORE_CTX *ctx, STACK_OF(X509) *sk)
|
||||||
|
{
|
||||||
|
ctx->other_ctx = sk;
|
||||||
|
ctx->get_issuer = get_issuer_sk;
|
||||||
|
}
|
||||||
|
|
||||||
|
void X509_STORE_CTX_cleanup(X509_STORE_CTX *ctx)
|
||||||
|
{
|
||||||
|
if(ctx->cleanup) ctx->cleanup(ctx);
|
||||||
|
if (ctx->chain != NULL)
|
||||||
|
{
|
||||||
|
sk_X509_pop_free(ctx->chain,X509_free);
|
||||||
|
ctx->chain=NULL;
|
||||||
|
}
|
||||||
|
CRYPTO_free_ex_data(x509_store_ctx_method,ctx,&(ctx->ex_data));
|
||||||
|
memset(&ctx->ex_data,0,sizeof(CRYPTO_EX_DATA));
|
||||||
|
}
|
||||||
|
|
||||||
IMPLEMENT_STACK_OF(X509)
|
IMPLEMENT_STACK_OF(X509)
|
||||||
IMPLEMENT_ASN1_SET_OF(X509)
|
IMPLEMENT_ASN1_SET_OF(X509)
|
||||||
|
@ -131,6 +131,7 @@ typedef struct x509_object_st
|
|||||||
typedef struct x509_lookup_st X509_LOOKUP;
|
typedef struct x509_lookup_st X509_LOOKUP;
|
||||||
|
|
||||||
DECLARE_STACK_OF(X509_LOOKUP)
|
DECLARE_STACK_OF(X509_LOOKUP)
|
||||||
|
DECLARE_STACK_OF(X509_OBJECT)
|
||||||
|
|
||||||
/* This is a static that defines the function interface */
|
/* This is a static that defines the function interface */
|
||||||
typedef struct x509_lookup_method_st
|
typedef struct x509_lookup_method_st
|
||||||
@ -162,11 +163,7 @@ typedef struct x509_store_st
|
|||||||
{
|
{
|
||||||
/* The following is a cache of trusted certs */
|
/* The following is a cache of trusted certs */
|
||||||
int cache; /* if true, stash any hits */
|
int cache; /* if true, stash any hits */
|
||||||
#ifndef NO_LHASH
|
STACK_OF(X509_OBJECT) *objs; /* Cache of all objects */
|
||||||
LHASH *certs; /* cached certs; */
|
|
||||||
#else
|
|
||||||
char *certs;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
/* These are external lookup methods */
|
/* These are external lookup methods */
|
||||||
STACK_OF(X509_LOOKUP) *get_cert_methods;
|
STACK_OF(X509_LOOKUP) *get_cert_methods;
|
||||||
@ -194,7 +191,7 @@ struct x509_lookup_st
|
|||||||
X509_STORE *store_ctx; /* who owns us */
|
X509_STORE *store_ctx; /* who owns us */
|
||||||
};
|
};
|
||||||
|
|
||||||
/* This is a temporary used when processing cert chains. Since the
|
/* This is a used when verifying cert chains. Since the
|
||||||
* gathering of the cert chain can take some time (and have to be
|
* gathering of the cert chain can take some time (and have to be
|
||||||
* 'retried', this needs to be kept and passed around. */
|
* 'retried', this needs to be kept and passed around. */
|
||||||
struct x509_store_state_st /* X509_STORE_CTX */
|
struct x509_store_state_st /* X509_STORE_CTX */
|
||||||
@ -207,6 +204,16 @@ struct x509_store_state_st /* X509_STORE_CTX */
|
|||||||
STACK_OF(X509) *untrusted; /* chain of X509s - untrusted - passed in */
|
STACK_OF(X509) *untrusted; /* chain of X509s - untrusted - passed in */
|
||||||
int purpose; /* purpose to check untrusted certificates */
|
int purpose; /* purpose to check untrusted certificates */
|
||||||
int trust; /* trust setting to check */
|
int trust; /* trust setting to check */
|
||||||
|
time_t check_time; /* time to make verify at */
|
||||||
|
unsigned long flags; /* Various verify flags */
|
||||||
|
void *other_ctx; /* Other info for use with get_issuer() */
|
||||||
|
|
||||||
|
/* 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 */
|
||||||
|
int (*get_issuer)(X509 **issuer, X509_STORE_CTX *ctx, X509 *x); /* get issuers cert from ctx */
|
||||||
|
int (*check_issued)(X509_STORE_CTX *ctx, X509 *x, X509 *issuer); /* check issued */
|
||||||
|
int (*cleanup)(X509_STORE_CTX *ctx);
|
||||||
|
|
||||||
/* The following is built up */
|
/* The following is built up */
|
||||||
int depth; /* how far to go looking up certs */
|
int depth; /* how far to go looking up certs */
|
||||||
@ -218,6 +225,7 @@ struct x509_store_state_st /* X509_STORE_CTX */
|
|||||||
int error_depth;
|
int error_depth;
|
||||||
int error;
|
int error;
|
||||||
X509 *current_cert;
|
X509 *current_cert;
|
||||||
|
X509 *current_issuer; /* cert currently being tested as valid issuer */
|
||||||
|
|
||||||
CRYPTO_EX_DATA ex_data;
|
CRYPTO_EX_DATA ex_data;
|
||||||
};
|
};
|
||||||
@ -268,10 +276,20 @@ struct x509_store_state_st /* X509_STORE_CTX */
|
|||||||
#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_UNTRUSTED 27
|
||||||
#define X509_V_ERR_CERT_REJECTED 28
|
#define X509_V_ERR_CERT_REJECTED 28
|
||||||
|
/* These are 'informational' when looking for issuer cert */
|
||||||
|
#define X509_V_ERR_SUBJECT_ISSUER_MISMATCH 29
|
||||||
|
#define X509_V_ERR_AKID_SKID_MISMATCH 30
|
||||||
|
#define X509_V_ERR_AKID_ISSUER_SERIAL_MISMATCH 31
|
||||||
|
#define X509_V_ERR_KEYUSAGE_NO_CERTSIGN 32
|
||||||
|
|
||||||
/* The application is not happy */
|
/* The application is not happy */
|
||||||
#define X509_V_ERR_APPLICATION_VERIFICATION 50
|
#define X509_V_ERR_APPLICATION_VERIFICATION 50
|
||||||
|
|
||||||
|
/* Certificate verify flags */
|
||||||
|
|
||||||
|
#define X509_V_FLAG_CB_ISSUER_CHECK 0x1 /* Send issuer+subject checks to verify_cb */
|
||||||
|
#define X509_V_FLAG_USE_CHECK_TIME 0x2 /* Use check time instead of current time */
|
||||||
|
|
||||||
/* These functions are being redefined in another directory,
|
/* These functions are being redefined in another directory,
|
||||||
and clash when the linker is case-insensitive, so let's
|
and clash when the linker is case-insensitive, so let's
|
||||||
hide them a little, by giving them an extra 'o' at the
|
hide them a little, by giving them an extra 'o' at the
|
||||||
@ -287,18 +305,23 @@ struct x509_store_state_st /* X509_STORE_CTX */
|
|||||||
#define X509v3_add_standard_extensions oX509v3_add_standard_extensions
|
#define X509v3_add_standard_extensions oX509v3_add_standard_extensions
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifndef NO_LHASH
|
int X509_OBJECT_idx_by_subject(STACK_OF(X509_OBJECT) *h, int type,
|
||||||
X509_OBJECT *X509_OBJECT_retrieve_by_subject(LHASH *h,int type,X509_NAME *name);
|
X509_NAME *name);
|
||||||
#endif
|
X509_OBJECT *X509_OBJECT_retrieve_by_subject(STACK_OF(X509_OBJECT) *h,int type,X509_NAME *name);
|
||||||
|
X509_OBJECT *X509_OBJECT_retrieve_match(STACK_OF(X509_OBJECT) *h, X509_OBJECT *x);
|
||||||
void X509_OBJECT_up_ref_count(X509_OBJECT *a);
|
void X509_OBJECT_up_ref_count(X509_OBJECT *a);
|
||||||
void X509_OBJECT_free_contents(X509_OBJECT *a);
|
void X509_OBJECT_free_contents(X509_OBJECT *a);
|
||||||
X509_STORE *X509_STORE_new(void );
|
X509_STORE *X509_STORE_new(void );
|
||||||
void X509_STORE_free(X509_STORE *v);
|
void X509_STORE_free(X509_STORE *v);
|
||||||
|
|
||||||
X509_STORE_CTX *X509_STORE_CTX_new(void);
|
X509_STORE_CTX *X509_STORE_CTX_new(void);
|
||||||
|
|
||||||
|
int X509_STORE_CTX_get1_issuer(X509 **issuer, X509_STORE_CTX *ctx, X509 *x);
|
||||||
|
|
||||||
void X509_STORE_CTX_free(X509_STORE_CTX *ctx);
|
void X509_STORE_CTX_free(X509_STORE_CTX *ctx);
|
||||||
void X509_STORE_CTX_init(X509_STORE_CTX *ctx, X509_STORE *store,
|
void X509_STORE_CTX_init(X509_STORE_CTX *ctx, X509_STORE *store,
|
||||||
X509 *x509, STACK_OF(X509) *chain);
|
X509 *x509, STACK_OF(X509) *chain);
|
||||||
|
void X509_STORE_CTX_trusted_stack(X509_STORE_CTX *ctx, STACK_OF(X509) *sk);
|
||||||
void X509_STORE_CTX_cleanup(X509_STORE_CTX *ctx);
|
void X509_STORE_CTX_cleanup(X509_STORE_CTX *ctx);
|
||||||
|
|
||||||
X509_LOOKUP *X509_STORE_add_lookup(X509_STORE *v, X509_LOOKUP_METHOD *m);
|
X509_LOOKUP *X509_STORE_add_lookup(X509_STORE *v, X509_LOOKUP_METHOD *m);
|
||||||
|
@ -59,6 +59,7 @@
|
|||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include "cryptlib.h"
|
#include "cryptlib.h"
|
||||||
#include <openssl/x509v3.h>
|
#include <openssl/x509v3.h>
|
||||||
|
#include <openssl/x509_vfy.h>
|
||||||
|
|
||||||
|
|
||||||
static void x509v3_cache_extensions(X509 *x);
|
static void x509v3_cache_extensions(X509 *x);
|
||||||
@ -255,16 +256,18 @@ int X509_PURPOSE_get_trust(X509_PURPOSE *xp)
|
|||||||
return xp->trust;
|
return xp->trust;
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifndef NO_SHA
|
|
||||||
static void x509v3_cache_extensions(X509 *x)
|
static void x509v3_cache_extensions(X509 *x)
|
||||||
{
|
{
|
||||||
BASIC_CONSTRAINTS *bs;
|
BASIC_CONSTRAINTS *bs;
|
||||||
ASN1_BIT_STRING *usage;
|
ASN1_BIT_STRING *usage;
|
||||||
ASN1_BIT_STRING *ns;
|
ASN1_BIT_STRING *ns;
|
||||||
STACK_OF(ASN1_OBJECT) *extusage;
|
STACK_OF(ASN1_OBJECT) *extusage;
|
||||||
|
|
||||||
int i;
|
int i;
|
||||||
if(x->ex_flags & EXFLAG_SET) return;
|
if(x->ex_flags & EXFLAG_SET) return;
|
||||||
|
#ifndef NO_SHA
|
||||||
X509_digest(x, EVP_sha1(), x->sha1_hash, NULL);
|
X509_digest(x, EVP_sha1(), x->sha1_hash, NULL);
|
||||||
|
#endif
|
||||||
/* 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;
|
||||||
@ -328,9 +331,10 @@ static void x509v3_cache_extensions(X509 *x)
|
|||||||
x->ex_flags |= EXFLAG_NSCERT;
|
x->ex_flags |= EXFLAG_NSCERT;
|
||||||
ASN1_BIT_STRING_free(ns);
|
ASN1_BIT_STRING_free(ns);
|
||||||
}
|
}
|
||||||
|
x->skid =X509_get_ext_d2i(x, NID_subject_key_identifier, NULL, NULL);
|
||||||
|
x->akid =X509_get_ext_d2i(x, NID_authority_key_identifier, NULL, NULL);
|
||||||
x->ex_flags |= EXFLAG_SET;
|
x->ex_flags |= EXFLAG_SET;
|
||||||
}
|
}
|
||||||
#endif
|
|
||||||
|
|
||||||
/* CA checks common to all purposes
|
/* CA checks common to all purposes
|
||||||
* return codes:
|
* return codes:
|
||||||
@ -470,3 +474,60 @@ static int no_check(const X509_PURPOSE *xp, const X509 *x, int ca)
|
|||||||
{
|
{
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Various checks to see if one certificate issued the second.
|
||||||
|
* This can be used to prune a set of possible issuer certificates
|
||||||
|
* which have been looked up using some simple method such as by
|
||||||
|
* subject name.
|
||||||
|
* These are:
|
||||||
|
* 1. Check issuer_name(subject) == subject_name(issuer)
|
||||||
|
* 2. If akid(subject) exists check it matches issuer
|
||||||
|
* 3. If key_usage(issuer) exists check it supports certificate signing
|
||||||
|
* returns 0 for OK, positive for reason for mismatch, reasons match
|
||||||
|
* codes for X509_verify_cert()
|
||||||
|
*/
|
||||||
|
|
||||||
|
int X509_check_issued(X509 *issuer, X509 *subject)
|
||||||
|
{
|
||||||
|
if(X509_NAME_cmp(X509_get_subject_name(issuer),
|
||||||
|
X509_get_issuer_name(subject)))
|
||||||
|
return X509_V_ERR_SUBJECT_ISSUER_MISMATCH;
|
||||||
|
x509v3_cache_extensions(issuer);
|
||||||
|
x509v3_cache_extensions(subject);
|
||||||
|
if(subject->akid) {
|
||||||
|
/* Check key ids (if present) */
|
||||||
|
if(subject->akid->keyid && issuer->skid &&
|
||||||
|
ASN1_OCTET_STRING_cmp(subject->akid->keyid, issuer->skid) )
|
||||||
|
return X509_V_ERR_AKID_SKID_MISMATCH;
|
||||||
|
/* Check serial number */
|
||||||
|
if(subject->akid->serial &&
|
||||||
|
ASN1_INTEGER_cmp(X509_get_serialNumber(issuer),
|
||||||
|
subject->akid->serial))
|
||||||
|
return X509_V_ERR_AKID_ISSUER_SERIAL_MISMATCH;
|
||||||
|
/* Check issuer name */
|
||||||
|
if(subject->akid->issuer) {
|
||||||
|
/* Ugh, for some peculiar reason AKID includes
|
||||||
|
* SEQUENCE OF GeneralName. So look for a DirName.
|
||||||
|
* There may be more than one but we only take any
|
||||||
|
* notice of the first.
|
||||||
|
*/
|
||||||
|
STACK_OF(GENERAL_NAME) *gens;
|
||||||
|
GENERAL_NAME *gen;
|
||||||
|
X509_NAME *nm = NULL;
|
||||||
|
int i;
|
||||||
|
gens = subject->akid->issuer;
|
||||||
|
for(i = 0; i < sk_GENERAL_NAME_num(gens); i++) {
|
||||||
|
gen = sk_GENERAL_NAME_value(gens, i);
|
||||||
|
if(gen->type == GEN_DIRNAME) {
|
||||||
|
nm = gen->d.dirn;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if(nm && X509_NAME_cmp(nm, X509_get_issuer_name(issuer)))
|
||||||
|
return X509_V_ERR_AKID_ISSUER_SERIAL_MISMATCH;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if(ku_reject(issuer, KU_KEY_CERT_SIGN)) return X509_V_ERR_KEYUSAGE_NO_CERTSIGN;
|
||||||
|
return X509_V_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
@ -532,6 +532,7 @@ int X509V3_EXT_print(BIO *out, X509_EXTENSION *ext, int flag, int indent);
|
|||||||
int X509V3_EXT_print_fp(FILE *out, X509_EXTENSION *ext, int flag, int indent);
|
int X509V3_EXT_print_fp(FILE *out, X509_EXTENSION *ext, int flag, int indent);
|
||||||
|
|
||||||
int X509_check_purpose(X509 *x, int id, int ca);
|
int X509_check_purpose(X509 *x, int id, int ca);
|
||||||
|
int X509_check_issued(X509 *issuer, X509 *subject);
|
||||||
int X509_PURPOSE_get_count(void);
|
int X509_PURPOSE_get_count(void);
|
||||||
X509_PURPOSE * X509_PURPOSE_get0(int idx);
|
X509_PURPOSE * X509_PURPOSE_get0(int idx);
|
||||||
int X509_PURPOSE_get_by_sname(char *sname);
|
int X509_PURPOSE_get_by_sname(char *sname);
|
||||||
|
Loading…
x
Reference in New Issue
Block a user