On Unix, we can use X509_STORE_set_default_paths(store) to load root certificates provided by the system
But on Windows, its certificates aren't provided as a file. So it should be required another way. I wrote a patch * extend ecapi to load a cert and store it to X509Store * new lookup method: by_capi * X509_STORE_set_default_paths also use lookup by_capi Related discussion: http://www.mail-archive.com/[email protected]/msg26956.html Following is the patch: diff --git a/crypto/x509/Makefile b/crypto/x509/Makefile old mode 100644 new mode 100755 index 72c8227..9a8e6c3 --- a/crypto/x509/Makefile +++ b/crypto/x509/Makefile @@ -22,13 +22,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_vpm.c + x509_trs.c by_file.c by_dir.c by_capi.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_vpm.o + x509_trs.o by_file.o by_dir.o by_capi.o x509_vpm.o SRC= $(LIBSRC) @@ -110,6 +110,18 @@ by_file.o: ../../include/openssl/safestack.h ../../include/openssl/sha.h by_file.o: ../../include/openssl/stack.h ../../include/openssl/symhacks.h by_file.o: ../../include/openssl/x509.h ../../include/openssl/x509_vfy.h by_file.o: ../cryptlib.h by_file.c +by_capi.o: ../../e_os.h ../../include/openssl/asn1.h ../../include/openssl/bio.h +by_capi.o: ../../include/openssl/buffer.h ../../include/openssl/crypto.h +by_capi.o: ../../include/openssl/e_os2.h ../../include/openssl/ec.h +by_capi.o: ../../include/openssl/ecdh.h ../../include/openssl/ecdsa.h +by_capi.o: ../../include/openssl/err.h ../../include/openssl/evp.h +by_capi.o: ../../include/openssl/lhash.h ../../include/openssl/obj_mac.h +by_capi.o: ../../include/openssl/objects.h ../../include/openssl/opensslconf.h +by_capi.o: ../../include/openssl/opensslv.h ../../include/openssl/ossl_typ.h +by_capi.o: ../../include/openssl/pkcs7.h ../../include/openssl/safestack.h +by_capi.o: ../../include/openssl/sha.h ../../include/openssl/stack.h +by_capi.o: ../../include/openssl/symhacks.h ../../include/openssl/x509.h +by_capi.o: ../../include/openssl/x509_vfy.h ../cryptlib.h by_capi.c x509_att.o: ../../e_os.h ../../include/openssl/asn1.h x509_att.o: ../../include/openssl/bio.h ../../include/openssl/buffer.h x509_att.o: ../../include/openssl/conf.h ../../include/openssl/crypto.h diff --git a/crypto/x509/by_capi.c b/crypto/x509/by_capi.c new file mode 100755 index 0000000..cde99b0 --- /dev/null +++ b/crypto/x509/by_capi.c @@ -0,0 +1,258 @@ +/* crypto/x509/by_capi.c */ +/* Copyright (C) 1995-1998 Eric Young ([email protected]) + * All rights reserved. + * + * This package is an SSL implementation written + * by Eric Young ([email protected]). + * The implementation was written so as to conform with Netscapes SSL. + * + * This library is free for commercial and non-commercial use as long as + * the following conditions are aheared to. The following conditions + * apply to all code found in this distribution, be it the RC4, RSA, + * lhash, DES, etc., code; not just the SSL code. The SSL documentation + * included with this distribution is covered by the same copyright terms + * except that the holder is Tim Hudson ([email protected]). + * + * Copyright remains Eric Young's, and as such any Copyright notices in + * the code are not to be removed. + * If this package is used in a product, Eric Young should be given attribution + * as the author of the parts of the library used. + * This can be in the form of a textual message at program startup or + * in documentation (online or textual) provided with the package. + * + * 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 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 acknowledgement: + * "This product includes cryptographic software written by + * Eric Young ([email protected])" + * The word 'cryptographic' can be left out if the rouines from the library + * being used are not cryptographic related :-). + * 4. If you include any Windows specific code (or a derivative thereof) from + * the apps directory (application code) you must include an acknowledgement: + * "This product includes software written by Tim Hudson ([email protected])" + * + * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND + * ANY EXPRESS 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 AUTHOR OR 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. + * + * The licence and distribution terms for any publically available version or + * derivative of this code cannot be changed. i.e. this code cannot simply be + * copied and put under another distribution licence + * [including the GNU Public Licence.] + */ + +#include <stdio.h> +#include <time.h> +#include <errno.h> + +#include "cryptlib.h" + +#ifndef NO_SYS_TYPES_H +# include <sys/types.h> +#endif +#ifndef OPENSSL_NO_POSIX_IO +# include <sys/stat.h> +#endif + +#include <openssl/engine.h> +#include <openssl/lhash.h> +#include <openssl/x509.h> + +#define CAPI_LU_MD5 4 +#define CAPI_LU_SHA1 5 +#define CAPI_LU_SUBNAME 6 + +typedef struct lookup_capi_st + { + ENGINE *engine; + } BY_CAPI; + +static int new_capi(X509_LOOKUP *lu); +static void free_capi(X509_LOOKUP *lu); +static int by_capi_ctrl(X509_LOOKUP *ctx, int cmd, const char *argp, long argl, char **ret); +static int get_cert_by_subject(X509_LOOKUP *xl,int type,X509_NAME *name, + X509_OBJECT *ret); +static int get_cert_by_fingerprint(X509_LOOKUP *ctx,int type, + unsigned char *bytes,int len, X509_OBJECT *ret); +X509_LOOKUP_METHOD x509_capi_lookup= + { + "Load certs from Crypto API", + new_capi, /* new */ + free_capi, /* free */ + NULL, /* init */ + NULL, /* shutdown */ + NULL, /* ctrl */ + get_cert_by_subject, /* get_by_subject */ + NULL, /* get_by_issuer_serial */ + NULL, /* get_by_fingerprint */ + NULL, /* get_by_alias */ + }; + +X509_LOOKUP_METHOD *X509_LOOKUP_capi(void) + { + return(&x509_capi_lookup); + } + +static int new_capi(X509_LOOKUP *lu) + { + BY_CAPI *a; + ENGINE *e; + + if ((a=(BY_CAPI *)OPENSSL_malloc(sizeof(BY_CAPI))) == NULL) + return(0); + ENGINE_load_builtin_engines(); + e = ENGINE_by_id("capi"); + if (!e) + return(0); + a->engine = e; + lu->method_data=(char *)a; + return(1); + } + +static void free_capi(X509_LOOKUP *lu) + { + BY_CAPI *a; + + a=(BY_CAPI *)lu->method_data; + if (a->engine != NULL) + { + ENGINE_free(a->engine); + a->engine = NULL; + } + OPENSSL_free(a); + } + +static int get_cert_by_subject(X509_LOOKUP *xl, int type, X509_NAME *name, + X509_OBJECT *ret) + { + BY_CAPI *ctx; + int ok=0, j; + ENGINE *e; + void **ary = NULL; + X509_OBJECT *tmp; + + if (name == NULL) return(0); + + ctx = (BY_CAPI *)xl->method_data; + e = ctx->engine; + if (e == NULL) return(0); + if (!ENGINE_init(e)) + { + ENGINE_free(e); + ctx->engine = NULL; + return(0); + } + + ENGINE_ctrl_cmd_string(e, "store_name", "ROOT", 0); + ENGINE_ctrl_cmd(e, "lookup_method", CAPI_LU_SUBNAME, NULL, NULL, 0); + switch (type) + { + case X509_LU_X509: + ary = OPENSSL_malloc(sizeof(void *) * 2); + if (ary == NULL) goto finish; + ary[0] = name; + ary[1] = xl->store_ctx; + ok = ENGINE_ctrl_cmd(e, "load_certs", 0, ary, NULL, 0); + if (ok < 1) goto finish; + + CRYPTO_r_lock(CRYPTO_LOCK_X509_STORE); + j = sk_X509_OBJECT_num(xl->store_ctx->objs); + if(j > 0) tmp=sk_X509_OBJECT_value(xl->store_ctx->objs,0); + else tmp = NULL; + CRYPTO_r_unlock(CRYPTO_LOCK_X509_STORE); + + if (tmp != NULL) + { + ret->type=tmp->type; + memcpy(&ret->data,&tmp->data,sizeof(ret->data)); + /* If we were going to up the reference count, + * we would need to do it on a perl 'type' + * basis */ + /* CRYPTO_add(&tmp->data.x509->references,1, + CRYPTO_LOCK_X509);*/ + } + break; + + case X509_LU_CRL: + return(0); + + default: + X509err(X509_F_GET_CERT_BY_SUBJECT,X509_R_WRONG_LOOKUP_TYPE); + goto finish; + } + +finish: + if (ary != NULL) + OPENSSL_free(ary); + return(ok); + } + +static int get_cert_by_fingerprint(X509_LOOKUP *xl,int type, + unsigned char *bytes,int len, X509_OBJECT *ret) +{ + BY_CAPI *a; + int ok=0; + ENGINE *e; + void **ary = NULL; + + a = (BY_CAPI *)xl->method_data; + e = a->engine; + if (e == NULL) return(0); + if (!ENGINE_init(e)) + { + ENGINE_free(e); + a->engine = NULL; + return(0); + } + + switch (len) + { + case 16: /* CERT_FIND_MD5_HASH */ + ENGINE_ctrl_cmd_string(e, "lookup_method", NULL, CAPI_LU_MD5); + break; + case 20: /* CERT_FIND_SHA1_HASH */ + ENGINE_ctrl_cmd_string(e, "lookup_method", NULL, CAPI_LU_SHA1); + break; + default: + goto finish; + } + + switch (type) + { + case X509_LU_X509: + ary = OPENSSL_malloc(sizeof(void *) * 2); + if (ary == NULL) + goto finish; + ary[0] = bytes; + ary[1] = xl->store_ctx; + ok = ENGINE_ctrl_cmd(e, "load_cert", 0, ary, NULL, 0); + break; + + case X509_LU_CRL: + /* TODO */ + + default: + X509err(X509_F_GET_CERT_BY_SUBJECT,X509_R_WRONG_LOOKUP_TYPE); + goto finish; + } + +finish: + if (ary != NULL) OPENSSL_free(ary); + return(ok); + } + diff --git a/crypto/x509/x509_d2.c b/crypto/x509/x509_d2.c old mode 100644 new mode 100755 index 51410cf..84a765f --- a/crypto/x509/x509_d2.c +++ b/crypto/x509/x509_d2.c @@ -73,7 +73,11 @@ int X509_STORE_set_default_paths(X509_STORE *ctx) lookup=X509_STORE_add_lookup(ctx,X509_LOOKUP_hash_dir()); if (lookup == NULL) return(0); X509_LOOKUP_add_dir(lookup,NULL,X509_FILETYPE_DEFAULT); - + + lookup=X509_STORE_add_lookup(ctx,X509_LOOKUP_capi()); + if (lookup == NULL) return(0); + X509_LOOKUP_from_capi(lookup,NULL,X509_FILETYPE_DEFAULT); + /* clear any errors */ ERR_clear_error(); diff --git a/crypto/x509/x509_lu.c b/crypto/x509/x509_lu.c old mode 100644 new mode 100755 diff --git a/crypto/x509/x509_vfy.h b/crypto/x509/x509_vfy.h old mode 100644 new mode 100755 index fe09b30..348766f --- a/crypto/x509/x509_vfy.h +++ b/crypto/x509/x509_vfy.h @@ -286,6 +286,7 @@ void X509_STORE_CTX_set_depth(X509_STORE_CTX *ctx, int depth); #define X509_L_FILE_LOAD 1 #define X509_L_ADD_DIR 2 +#define X509_L_FROM_CAPI 3 #define X509_LOOKUP_load_file(x,name,type) \ X509_LOOKUP_ctrl((x),X509_L_FILE_LOAD,(name),(long)(type),NULL) @@ -293,6 +294,9 @@ void X509_STORE_CTX_set_depth(X509_STORE_CTX *ctx, int depth); #define X509_LOOKUP_add_dir(x,name,type) \ X509_LOOKUP_ctrl((x),X509_L_ADD_DIR,(name),(long)(type),NULL) +#define X509_LOOKUP_from_capi(x,name,type) \ + X509_LOOKUP_ctrl((x),X509_L_FROM_CAPI,(name),(long)(type),NULL) + #define X509_V_OK 0 /* illegal error (for uninitialized values, to avoid X509_V_OK): 1 */ @@ -436,6 +440,7 @@ X509_LOOKUP *X509_STORE_add_lookup(X509_STORE *v, X509_LOOKUP_METHOD *m); X509_LOOKUP_METHOD *X509_LOOKUP_hash_dir(void); X509_LOOKUP_METHOD *X509_LOOKUP_file(void); +X509_LOOKUP_METHOD *X509_LOOKUP_capi(void); int X509_STORE_add_cert(X509_STORE *ctx, X509 *x); int X509_STORE_add_crl(X509_STORE *ctx, X509_CRL *x); diff --git a/engines/e_capi.c b/engines/e_capi.c old mode 100644 new mode 100755 index 8da6798..4d01696 --- a/engines/e_capi.c +++ b/engines/e_capi.c @@ -120,10 +120,12 @@ static void CAPI_trace(CAPI_CTX *ctx, char *format, ...); static int capi_list_providers(CAPI_CTX *ctx, BIO *out); static int capi_list_containers(CAPI_CTX *ctx, BIO *out); +static int capi_each_certs(CAPI_CTX *ctx, char *id, void *ptr, int ptype); int capi_list_certs(CAPI_CTX *ctx, BIO *out, char *storename); void capi_free_key(CAPI_KEY *key); -static PCCERT_CONTEXT capi_find_cert(CAPI_CTX *ctx, const char *id, HCERTSTORE hstore); +static PCCERT_CONTEXT capi_find_cert(CAPI_CTX *ctx, const char *id, HCERTSTORE hstore, + PCCERT_CONTEXT cert); CAPI_KEY *capi_find_key(CAPI_CTX *ctx, const char *id); @@ -183,6 +185,10 @@ struct CAPI_CTX_st { #define CAPI_LU_FNAME 2 /* Container name: uses cspname, keytype */ #define CAPI_LU_CONTNAME 3 +#define CAPI_LU_MD5 4 +#define CAPI_LU_SHA1 5 +#define CAPI_LU_SUBNAME 6 +#define CAPI_LU_MAX 6 /* same as above */ int lookup_method; /* Info to dump with dumpcerts option */ /* Issuer and serial name strings */ @@ -225,6 +231,7 @@ static int capi_ctx_set_provname_idx(CAPI_CTX *ctx, int idx); #define CAPI_CMD_LOOKUP_METHOD (ENGINE_CMD_BASE + 11) #define CAPI_CMD_STORE_NAME (ENGINE_CMD_BASE + 12) #define CAPI_CMD_STORE_FLAGS (ENGINE_CMD_BASE + 13) +#define CAPI_CMD_LOAD_CERTS (ENGINE_CMD_BASE + 14) static const ENGINE_CMD_DEFN capi_cmd_defns[] = { {CAPI_CMD_LIST_CERTS, @@ -284,6 +291,10 @@ static const ENGINE_CMD_DEFN capi_cmd_defns[] = { "store_flags", "Certificate store flags: 1 = system store", ENGINE_CMD_FLAG_NUMERIC}, + {CAPI_CMD_LOAD_CERTS, + "load_certs", + "Load certificates in store", + ENGINE_CMD_FLAG_STRING}, {0, NULL, NULL, 0} }; @@ -298,6 +309,8 @@ static int capi_ctrl(ENGINE *e, int cmd, long i, void *p, void (*f)(void)) int ret = 1; CAPI_CTX *ctx; BIO *out; + char *id; + void *ptr; if (capi_idx == -1) { CAPIerr(CAPI_F_CAPI_CTRL, CAPI_R_ENGINE_NOT_INITIALIZED); @@ -315,6 +328,12 @@ static int capi_ctrl(ENGINE *e, int cmd, long i, void *p, void (*f)(void)) ret = capi_list_certs(ctx, out, NULL); break; + case CAPI_CMD_LOAD_CERTS: + id = (char *)(((void **)p)[0]); + ptr = (void *)(((void **)p)[1]); + ret = capi_each_certs(ctx, id, ptr, CAPI_CMD_LOAD_CERTS); + break; + case CAPI_CMD_LOOKUP_CERT: ret = capi_list_certs(ctx, out, p); break; @@ -368,7 +387,7 @@ static int capi_ctrl(ENGINE *e, int cmd, long i, void *p, void (*f)(void)) break; case CAPI_CMD_LOOKUP_METHOD: - if (i < 1 || i > 3) + if (i < CAPI_LU_SUBSTR || CAPI_LU_MAX < i) { CAPIerr(CAPI_F_CAPI_CTRL, CAPI_R_INVALID_LOOKUP_METHOD); return 0; @@ -1331,13 +1350,40 @@ HCERTSTORE capi_open_store(CAPI_CTX *ctx, char *storename) return hstore; } -int capi_list_certs(CAPI_CTX *ctx, BIO *out, char *id) +void capi_store_cert(CAPI_CTX *ctx, X509_STORE *xstore, PCCERT_CONTEXT cert) + { + X509 *x509 = NULL; + x509 = d2i_X509(NULL, (const unsigned char**)&cert->pbCertEncoded, cert->cbCertEncoded); + if (x509) + { + X509_STORE_add_cert(xstore, x509); + X509_free(x509); + } + } + +static int capi_each_certs(CAPI_CTX *ctx, char *id, void *ptr, int ptype) { char *storename; - int idx; - int ret = 1; + int idx, ret = 0, get_all = 1; HCERTSTORE hstore; PCCERT_CONTEXT cert = NULL; + BIO *out = NULL; + X509_STORE *xstore = NULL; + + switch (ptype) + { + case CAPI_CMD_LOOKUP_CERT: + get_all = 0; + case CAPI_CMD_LIST_CERTS: + out = (BIO *)ptr; + break; + + case CAPI_CMD_LOAD_CERTS: + xstore = (X509_STORE *)ptr; + break; + default: + return(0); + } storename = ctx->storename; if (!storename) @@ -1349,14 +1395,17 @@ int capi_list_certs(CAPI_CTX *ctx, BIO *out, char *id) return 0; if (id) { - cert = capi_find_cert(ctx, id, hstore); - if (!cert) + while (cert = capi_find_cert(ctx, id, hstore, cert)) { - ret = 0; - goto err; + if (out) capi_dump_cert(ctx, out, cert); + else if (xstore) capi_store_cert(ctx, xstore, cert); + ret++; + if (!get_all) + { + CertFreeCertificateContext(cert); + break; + } } - capi_dump_cert(ctx, out, cert); - CertFreeCertificateContext(cert); } else { @@ -1366,26 +1415,70 @@ int capi_list_certs(CAPI_CTX *ctx, BIO *out, char *id) cert = CertEnumCertificatesInStore(hstore, cert); if (!cert) break; - BIO_printf(out, "Certificate %d\n", idx); - capi_dump_cert(ctx, out, cert); + ret++; + if (out) + { + BIO_printf(out, "Certificate %d\n", idx); + capi_dump_cert(ctx, out, cert); + } + else if (xstore) + { + capi_store_cert(ctx, xstore, cert); + } } } - err: CertCloseStore(hstore, 0); return ret; } -static PCCERT_CONTEXT capi_find_cert(CAPI_CTX *ctx, const char *id, HCERTSTORE hstore) +int capi_list_certs(CAPI_CTX *ctx, BIO *out, char *id) + { + int r = capi_each_certs(ctx, id, (void *)out, + id ? CAPI_CMD_LOOKUP_CERT : CAPI_CMD_LIST_CERTS); + return r > 0 ? 1 : 0; + } + +static PCCERT_CONTEXT capi_find_cert(CAPI_CTX *ctx, const char *id, HCERTSTORE hstore, + PCCERT_CONTEXT cert) { - PCCERT_CONTEXT cert = NULL; char *fname = NULL; int match; + DWORD dw; + X509_NAME *name; + CRYPT_HASH_BLOB *hb; + CERT_NAME_BLOB *nb; + switch(ctx->lookup_method) { case CAPI_LU_SUBSTR: return CertFindCertificateInStore(hstore, X509_ASN_ENCODING, 0, - CERT_FIND_SUBJECT_STR_A, id, NULL); + CERT_FIND_SUBJECT_STR_A, id, cert); + + case CAPI_LU_SUBNAME: + name = (X509_NAME *)id; + nb = OPENSSL_malloc(sizeof(CERT_NAME_BLOB)); + nb->cbData = name->bytes->length; + nb->pbData = name->bytes->data; + cert = CertFindCertificateInStore(hstore, + X509_ASN_ENCODING, 0, + CERT_FIND_SUBJECT_NAME, nb, cert); + OPENSSL_free(nb); + return cert; + + case CAPI_LU_MD5: + case CAPI_LU_SHA1: + dw = ctx->lookup_method == CAPI_LU_MD5 ? CERT_FIND_MD5_HASH : + CERT_FIND_SHA1_HASH; + hb = OPENSSL_malloc(sizeof(CRYPT_HASH_BLOB)); + if (hb == NULL) return NULL; + hb->pbData = (BYTE *)id; + hb->cbData = ctx->lookup_method == CAPI_LU_MD5 ? 16 : 20; + cert = CertFindCertificateInStore(hstore, + X509_ASN_ENCODING, 0, dw, hb, cert); + OPENSSL_free(hb); + return cert; + case CAPI_LU_FNAME: for(;;) { @@ -1474,7 +1567,7 @@ CAPI_KEY *capi_find_key(CAPI_CTX *ctx, const char *id) hstore = capi_open_store(ctx, NULL); if (!hstore) return NULL; - cert = capi_find_cert(ctx, id, hstore); + cert = capi_find_cert(ctx, id, hstore, NULL); if (cert) { key = capi_get_cert_key(ctx, cert); -- NARUSE, Yui <[email protected]> ______________________________________________________________________ OpenSSL Project http://www.openssl.org Development Mailing List [email protected] Automated List Manager [email protected]
