e_capi.c revision 246772
1183234Ssimon/* engines/e_capi.c */ 2183234Ssimon/* Written by Dr Stephen N Henson (steve@openssl.org) for the OpenSSL 3183234Ssimon * project. 4183234Ssimon */ 5183234Ssimon/* ==================================================================== 6183234Ssimon * Copyright (c) 2008 The OpenSSL Project. All rights reserved. 7183234Ssimon * 8183234Ssimon * Redistribution and use in source and binary forms, with or without 9183234Ssimon * modification, are permitted provided that the following conditions 10183234Ssimon * are met: 11183234Ssimon * 12183234Ssimon * 1. Redistributions of source code must retain the above copyright 13183234Ssimon * notice, this list of conditions and the following disclaimer. 14183234Ssimon * 15183234Ssimon * 2. Redistributions in binary form must reproduce the above copyright 16183234Ssimon * notice, this list of conditions and the following disclaimer in 17183234Ssimon * the documentation and/or other materials provided with the 18183234Ssimon * distribution. 19183234Ssimon * 20183234Ssimon * 3. All advertising materials mentioning features or use of this 21183234Ssimon * software must display the following acknowledgment: 22183234Ssimon * "This product includes software developed by the OpenSSL Project 23183234Ssimon * for use in the OpenSSL Toolkit. (http://www.OpenSSL.org/)" 24183234Ssimon * 25183234Ssimon * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to 26183234Ssimon * endorse or promote products derived from this software without 27183234Ssimon * prior written permission. For written permission, please contact 28183234Ssimon * licensing@OpenSSL.org. 29183234Ssimon * 30183234Ssimon * 5. Products derived from this software may not be called "OpenSSL" 31183234Ssimon * nor may "OpenSSL" appear in their names without prior written 32183234Ssimon * permission of the OpenSSL Project. 33183234Ssimon * 34183234Ssimon * 6. Redistributions of any form whatsoever must retain the following 35183234Ssimon * acknowledgment: 36183234Ssimon * "This product includes software developed by the OpenSSL Project 37183234Ssimon * for use in the OpenSSL Toolkit (http://www.OpenSSL.org/)" 38183234Ssimon * 39183234Ssimon * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY 40183234Ssimon * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 41183234Ssimon * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 42183234Ssimon * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE OpenSSL PROJECT OR 43183234Ssimon * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 44183234Ssimon * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 45183234Ssimon * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 46183234Ssimon * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 47183234Ssimon * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, 48183234Ssimon * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 49183234Ssimon * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED 50183234Ssimon * OF THE POSSIBILITY OF SUCH DAMAGE. 51183234Ssimon * ==================================================================== 52183234Ssimon */ 53183234Ssimon 54183234Ssimon 55183234Ssimon#include <stdio.h> 56183234Ssimon#include <string.h> 57183234Ssimon#include <openssl/crypto.h> 58183234Ssimon#include <openssl/buffer.h> 59183234Ssimon#include <openssl/bn.h> 60183234Ssimon 61183234Ssimon#ifdef OPENSSL_SYS_WIN32 62183234Ssimon#ifndef OPENSSL_NO_CAPIENG 63183234Ssimon 64205128Ssimon#include <openssl/rsa.h> 65183234Ssimon 66183234Ssimon#include <windows.h> 67183234Ssimon 68183234Ssimon#ifndef _WIN32_WINNT 69183234Ssimon#define _WIN32_WINNT 0x0400 70183234Ssimon#endif 71183234Ssimon 72183234Ssimon#include <wincrypt.h> 73183234Ssimon 74238405Sjkim/* 75238405Sjkim * This module uses several "new" interfaces, among which is 76238405Sjkim * CertGetCertificateContextProperty. CERT_KEY_PROV_INFO_PROP_ID is 77238405Sjkim * one of possible values you can pass to function in question. By 78238405Sjkim * checking if it's defined we can see if wincrypt.h and accompanying 79238405Sjkim * crypt32.lib are in shape. The native MingW32 headers up to and 80238405Sjkim * including __W32API_VERSION 3.14 lack of struct DSSPUBKEY and the 81238405Sjkim * defines CERT_STORE_PROV_SYSTEM_A and CERT_STORE_READONLY_FLAG, 82238405Sjkim * so we check for these too and avoid compiling. 83238405Sjkim * Yes, it's rather "weak" test and if compilation fails, 84238405Sjkim * then re-configure with -DOPENSSL_NO_CAPIENG. 85238405Sjkim */ 86238405Sjkim#if defined(CERT_KEY_PROV_INFO_PROP_ID) && \ 87238405Sjkim defined(CERT_STORE_PROV_SYSTEM_A) && \ 88238405Sjkim defined(CERT_STORE_READONLY_FLAG) 89238405Sjkim# define __COMPILE_CAPIENG 90238405Sjkim#endif /* CERT_KEY_PROV_INFO_PROP_ID */ 91238405Sjkim#endif /* OPENSSL_NO_CAPIENG */ 92238405Sjkim#endif /* OPENSSL_SYS_WIN32 */ 93238405Sjkim 94238405Sjkim#ifdef __COMPILE_CAPIENG 95238405Sjkim 96183234Ssimon#undef X509_EXTENSIONS 97183234Ssimon#undef X509_CERT_PAIR 98183234Ssimon 99183234Ssimon/* Definitions which may be missing from earlier version of headers */ 100183234Ssimon#ifndef CERT_STORE_OPEN_EXISTING_FLAG 101183234Ssimon#define CERT_STORE_OPEN_EXISTING_FLAG 0x00004000 102183234Ssimon#endif 103183234Ssimon 104183234Ssimon#ifndef CERT_STORE_CREATE_NEW_FLAG 105183234Ssimon#define CERT_STORE_CREATE_NEW_FLAG 0x00002000 106183234Ssimon#endif 107183234Ssimon 108206046Ssimon#ifndef CERT_SYSTEM_STORE_CURRENT_USER 109206046Ssimon#define CERT_SYSTEM_STORE_CURRENT_USER 0x00010000 110206046Ssimon#endif 111206046Ssimon 112183234Ssimon#include <openssl/engine.h> 113183234Ssimon#include <openssl/pem.h> 114183234Ssimon#include <openssl/x509v3.h> 115183234Ssimon 116183234Ssimon#include "e_capi_err.h" 117183234Ssimon#include "e_capi_err.c" 118183234Ssimon 119183234Ssimon 120183234Ssimonstatic const char *engine_capi_id = "capi"; 121183234Ssimonstatic const char *engine_capi_name = "CryptoAPI ENGINE"; 122183234Ssimon 123183234Ssimontypedef struct CAPI_CTX_st CAPI_CTX; 124183234Ssimontypedef struct CAPI_KEY_st CAPI_KEY; 125183234Ssimon 126183234Ssimonstatic void capi_addlasterror(void); 127183234Ssimonstatic void capi_adderror(DWORD err); 128183234Ssimon 129183234Ssimonstatic void CAPI_trace(CAPI_CTX *ctx, char *format, ...); 130183234Ssimon 131183234Ssimonstatic int capi_list_providers(CAPI_CTX *ctx, BIO *out); 132183234Ssimonstatic int capi_list_containers(CAPI_CTX *ctx, BIO *out); 133183234Ssimonint capi_list_certs(CAPI_CTX *ctx, BIO *out, char *storename); 134183234Ssimonvoid capi_free_key(CAPI_KEY *key); 135183234Ssimon 136183234Ssimonstatic PCCERT_CONTEXT capi_find_cert(CAPI_CTX *ctx, const char *id, HCERTSTORE hstore); 137183234Ssimon 138183234SsimonCAPI_KEY *capi_find_key(CAPI_CTX *ctx, const char *id); 139183234Ssimon 140183234Ssimonstatic EVP_PKEY *capi_load_privkey(ENGINE *eng, const char *key_id, 141183234Ssimon UI_METHOD *ui_method, void *callback_data); 142183234Ssimonstatic int capi_rsa_sign(int dtype, const unsigned char *m, unsigned int m_len, 143183234Ssimon unsigned char *sigret, unsigned int *siglen, const RSA *rsa); 144183234Ssimonstatic int capi_rsa_priv_enc(int flen, const unsigned char *from, 145183234Ssimon unsigned char *to, RSA *rsa, int padding); 146183234Ssimonstatic int capi_rsa_priv_dec(int flen, const unsigned char *from, 147183234Ssimon unsigned char *to, RSA *rsa, int padding); 148183234Ssimonstatic int capi_rsa_free(RSA *rsa); 149183234Ssimon 150183234Ssimonstatic DSA_SIG *capi_dsa_do_sign(const unsigned char *digest, int dlen, 151183234Ssimon DSA *dsa); 152183234Ssimonstatic int capi_dsa_free(DSA *dsa); 153183234Ssimon 154183234Ssimonstatic int capi_load_ssl_client_cert(ENGINE *e, SSL *ssl, 155183234Ssimon STACK_OF(X509_NAME) *ca_dn, X509 **pcert, EVP_PKEY **pkey, 156183234Ssimon STACK_OF(X509) **pother, UI_METHOD *ui_method, void *callback_data); 157183234Ssimon 158183234Ssimonstatic int cert_select_simple(ENGINE *e, SSL *ssl, STACK_OF(X509) *certs); 159183234Ssimon#ifdef OPENSSL_CAPIENG_DIALOG 160183234Ssimonstatic int cert_select_dialog(ENGINE *e, SSL *ssl, STACK_OF(X509) *certs); 161183234Ssimon#endif 162183234Ssimon 163183234Ssimontypedef PCCERT_CONTEXT (WINAPI *CERTDLG)(HCERTSTORE, HWND, LPCWSTR, 164183234Ssimon LPCWSTR, DWORD, DWORD, 165183234Ssimon void *); 166183234Ssimontypedef HWND (WINAPI *GETCONSWIN)(void); 167183234Ssimon 168183234Ssimon/* This structure contains CAPI ENGINE specific data: 169183234Ssimon * it contains various global options and affects how 170183234Ssimon * other functions behave. 171183234Ssimon */ 172183234Ssimon 173183234Ssimon#define CAPI_DBG_TRACE 2 174183234Ssimon#define CAPI_DBG_ERROR 1 175183234Ssimon 176183234Ssimonstruct CAPI_CTX_st { 177183234Ssimon int debug_level; 178183234Ssimon char *debug_file; 179183234Ssimon /* Parameters to use for container lookup */ 180183234Ssimon DWORD keytype; 181205128Ssimon LPSTR cspname; 182183234Ssimon DWORD csptype; 183183234Ssimon /* Certificate store name to use */ 184205128Ssimon LPSTR storename; 185205128Ssimon LPSTR ssl_client_store; 186183234Ssimon /* System store flags */ 187183234Ssimon DWORD store_flags; 188183234Ssimon 189183234Ssimon/* Lookup string meanings in load_private_key */ 190183234Ssimon/* Substring of subject: uses "storename" */ 191205128Ssimon#define CAPI_LU_SUBSTR 1 192183234Ssimon/* Friendly name: uses storename */ 193205128Ssimon#define CAPI_LU_FNAME 2 194183234Ssimon/* Container name: uses cspname, keytype */ 195205128Ssimon#define CAPI_LU_CONTNAME 3 196183234Ssimon int lookup_method; 197183234Ssimon/* Info to dump with dumpcerts option */ 198183234Ssimon/* Issuer and serial name strings */ 199183234Ssimon#define CAPI_DMP_SUMMARY 0x1 200183234Ssimon/* Friendly name */ 201183234Ssimon#define CAPI_DMP_FNAME 0x2 202183234Ssimon/* Full X509_print dump */ 203183234Ssimon#define CAPI_DMP_FULL 0x4 204183234Ssimon/* Dump PEM format certificate */ 205183234Ssimon#define CAPI_DMP_PEM 0x8 206183234Ssimon/* Dump pseudo key (if possible) */ 207183234Ssimon#define CAPI_DMP_PSKEY 0x10 208183234Ssimon/* Dump key info (if possible) */ 209183234Ssimon#define CAPI_DMP_PKEYINFO 0x20 210183234Ssimon 211183234Ssimon DWORD dump_flags; 212183234Ssimon int (*client_cert_select)(ENGINE *e, SSL *ssl, STACK_OF(X509) *certs); 213183234Ssimon 214183234Ssimon CERTDLG certselectdlg; 215183234Ssimon GETCONSWIN getconswindow; 216183234Ssimon}; 217183234Ssimon 218183234Ssimon 219183234Ssimonstatic CAPI_CTX *capi_ctx_new(); 220183234Ssimonstatic void capi_ctx_free(CAPI_CTX *ctx); 221183234Ssimonstatic int capi_ctx_set_provname(CAPI_CTX *ctx, LPSTR pname, DWORD type, int check); 222183234Ssimonstatic int capi_ctx_set_provname_idx(CAPI_CTX *ctx, int idx); 223183234Ssimon 224183234Ssimon#define CAPI_CMD_LIST_CERTS ENGINE_CMD_BASE 225183234Ssimon#define CAPI_CMD_LOOKUP_CERT (ENGINE_CMD_BASE + 1) 226183234Ssimon#define CAPI_CMD_DEBUG_LEVEL (ENGINE_CMD_BASE + 2) 227183234Ssimon#define CAPI_CMD_DEBUG_FILE (ENGINE_CMD_BASE + 3) 228183234Ssimon#define CAPI_CMD_KEYTYPE (ENGINE_CMD_BASE + 4) 229183234Ssimon#define CAPI_CMD_LIST_CSPS (ENGINE_CMD_BASE + 5) 230183234Ssimon#define CAPI_CMD_SET_CSP_IDX (ENGINE_CMD_BASE + 6) 231183234Ssimon#define CAPI_CMD_SET_CSP_NAME (ENGINE_CMD_BASE + 7) 232183234Ssimon#define CAPI_CMD_SET_CSP_TYPE (ENGINE_CMD_BASE + 8) 233183234Ssimon#define CAPI_CMD_LIST_CONTAINERS (ENGINE_CMD_BASE + 9) 234183234Ssimon#define CAPI_CMD_LIST_OPTIONS (ENGINE_CMD_BASE + 10) 235183234Ssimon#define CAPI_CMD_LOOKUP_METHOD (ENGINE_CMD_BASE + 11) 236183234Ssimon#define CAPI_CMD_STORE_NAME (ENGINE_CMD_BASE + 12) 237183234Ssimon#define CAPI_CMD_STORE_FLAGS (ENGINE_CMD_BASE + 13) 238183234Ssimon 239183234Ssimonstatic const ENGINE_CMD_DEFN capi_cmd_defns[] = { 240183234Ssimon {CAPI_CMD_LIST_CERTS, 241183234Ssimon "list_certs", 242183234Ssimon "List all certificates in store", 243183234Ssimon ENGINE_CMD_FLAG_NO_INPUT}, 244183234Ssimon {CAPI_CMD_LOOKUP_CERT, 245183234Ssimon "lookup_cert", 246183234Ssimon "Lookup and output certificates", 247183234Ssimon ENGINE_CMD_FLAG_STRING}, 248183234Ssimon {CAPI_CMD_DEBUG_LEVEL, 249183234Ssimon "debug_level", 250183234Ssimon "debug level (1=errors, 2=trace)", 251183234Ssimon ENGINE_CMD_FLAG_NUMERIC}, 252183234Ssimon {CAPI_CMD_DEBUG_FILE, 253183234Ssimon "debug_file", 254183234Ssimon "debugging filename)", 255183234Ssimon ENGINE_CMD_FLAG_STRING}, 256183234Ssimon {CAPI_CMD_KEYTYPE, 257183234Ssimon "key_type", 258183234Ssimon "Key type: 1=AT_KEYEXCHANGE (default), 2=AT_SIGNATURE", 259183234Ssimon ENGINE_CMD_FLAG_NUMERIC}, 260183234Ssimon {CAPI_CMD_LIST_CSPS, 261183234Ssimon "list_csps", 262183234Ssimon "List all CSPs", 263183234Ssimon ENGINE_CMD_FLAG_NO_INPUT}, 264183234Ssimon {CAPI_CMD_SET_CSP_IDX, 265183234Ssimon "csp_idx", 266183234Ssimon "Set CSP by index", 267183234Ssimon ENGINE_CMD_FLAG_NUMERIC}, 268183234Ssimon {CAPI_CMD_SET_CSP_NAME, 269183234Ssimon "csp_name", 270183234Ssimon "Set CSP name, (default CSP used if not specified)", 271183234Ssimon ENGINE_CMD_FLAG_STRING}, 272183234Ssimon {CAPI_CMD_SET_CSP_TYPE, 273183234Ssimon "csp_type", 274183234Ssimon "Set CSP type, (default RSA_PROV_FULL)", 275183234Ssimon ENGINE_CMD_FLAG_NUMERIC}, 276183234Ssimon {CAPI_CMD_LIST_CONTAINERS, 277183234Ssimon "list_containers", 278183234Ssimon "list container names", 279183234Ssimon ENGINE_CMD_FLAG_NO_INPUT}, 280183234Ssimon {CAPI_CMD_LIST_OPTIONS, 281183234Ssimon "list_options", 282183234Ssimon "Set list options (1=summary,2=friendly name, 4=full printout, 8=PEM output, 16=XXX, " 283183234Ssimon "32=private key info)", 284183234Ssimon ENGINE_CMD_FLAG_NUMERIC}, 285183234Ssimon {CAPI_CMD_LOOKUP_METHOD, 286183234Ssimon "lookup_method", 287183234Ssimon "Set key lookup method (1=substring, 2=friendlyname, 3=container name)", 288183234Ssimon ENGINE_CMD_FLAG_NUMERIC}, 289183234Ssimon {CAPI_CMD_STORE_NAME, 290183234Ssimon "store_name", 291183234Ssimon "certificate store name, default \"MY\"", 292183234Ssimon ENGINE_CMD_FLAG_STRING}, 293183234Ssimon {CAPI_CMD_STORE_FLAGS, 294183234Ssimon "store_flags", 295183234Ssimon "Certificate store flags: 1 = system store", 296183234Ssimon ENGINE_CMD_FLAG_NUMERIC}, 297183234Ssimon 298183234Ssimon {0, NULL, NULL, 0} 299183234Ssimon }; 300183234Ssimon 301183234Ssimonstatic int capi_idx = -1; 302183234Ssimonstatic int rsa_capi_idx = -1; 303183234Ssimonstatic int dsa_capi_idx = -1; 304183234Ssimonstatic int cert_capi_idx = -1; 305183234Ssimon 306183234Ssimonstatic int capi_ctrl(ENGINE *e, int cmd, long i, void *p, void (*f)(void)) 307183234Ssimon { 308183234Ssimon int ret = 1; 309183234Ssimon CAPI_CTX *ctx; 310183234Ssimon BIO *out; 311183234Ssimon if (capi_idx == -1) 312183234Ssimon { 313183234Ssimon CAPIerr(CAPI_F_CAPI_CTRL, CAPI_R_ENGINE_NOT_INITIALIZED); 314183234Ssimon return 0; 315183234Ssimon } 316183234Ssimon ctx = ENGINE_get_ex_data(e, capi_idx); 317183234Ssimon out = BIO_new_fp(stdout, BIO_NOCLOSE); 318183234Ssimon switch (cmd) 319183234Ssimon { 320183234Ssimon case CAPI_CMD_LIST_CSPS: 321183234Ssimon ret = capi_list_providers(ctx, out); 322183234Ssimon break; 323183234Ssimon 324183234Ssimon case CAPI_CMD_LIST_CERTS: 325183234Ssimon ret = capi_list_certs(ctx, out, NULL); 326183234Ssimon break; 327183234Ssimon 328183234Ssimon case CAPI_CMD_LOOKUP_CERT: 329183234Ssimon ret = capi_list_certs(ctx, out, p); 330183234Ssimon break; 331183234Ssimon 332183234Ssimon case CAPI_CMD_LIST_CONTAINERS: 333183234Ssimon ret = capi_list_containers(ctx, out); 334183234Ssimon break; 335183234Ssimon 336183234Ssimon case CAPI_CMD_STORE_NAME: 337183234Ssimon if (ctx->storename) 338183234Ssimon OPENSSL_free(ctx->storename); 339183234Ssimon ctx->storename = BUF_strdup(p); 340183234Ssimon CAPI_trace(ctx, "Setting store name to %s\n", p); 341183234Ssimon break; 342183234Ssimon 343183234Ssimon case CAPI_CMD_STORE_FLAGS: 344183234Ssimon if (i & 1) 345183234Ssimon { 346183234Ssimon ctx->store_flags |= CERT_SYSTEM_STORE_LOCAL_MACHINE; 347183234Ssimon ctx->store_flags &= ~CERT_SYSTEM_STORE_CURRENT_USER; 348183234Ssimon } 349183234Ssimon else 350183234Ssimon { 351183234Ssimon ctx->store_flags |= CERT_SYSTEM_STORE_CURRENT_USER; 352183234Ssimon ctx->store_flags &= ~CERT_SYSTEM_STORE_LOCAL_MACHINE; 353183234Ssimon } 354183234Ssimon CAPI_trace(ctx, "Setting flags to %d\n", i); 355183234Ssimon break; 356183234Ssimon 357183234Ssimon case CAPI_CMD_DEBUG_LEVEL: 358183234Ssimon ctx->debug_level = (int)i; 359183234Ssimon CAPI_trace(ctx, "Setting debug level to %d\n", ctx->debug_level); 360183234Ssimon break; 361183234Ssimon 362183234Ssimon case CAPI_CMD_DEBUG_FILE: 363183234Ssimon ctx->debug_file = BUF_strdup(p); 364183234Ssimon CAPI_trace(ctx, "Setting debug file to %s\n", ctx->debug_file); 365183234Ssimon break; 366183234Ssimon 367183234Ssimon case CAPI_CMD_KEYTYPE: 368183234Ssimon ctx->keytype = i; 369183234Ssimon CAPI_trace(ctx, "Setting key type to %d\n", ctx->keytype); 370183234Ssimon break; 371183234Ssimon 372183234Ssimon case CAPI_CMD_SET_CSP_IDX: 373183234Ssimon ret = capi_ctx_set_provname_idx(ctx, i); 374183234Ssimon break; 375183234Ssimon 376183234Ssimon case CAPI_CMD_LIST_OPTIONS: 377183234Ssimon ctx->dump_flags = i; 378183234Ssimon break; 379183234Ssimon 380183234Ssimon case CAPI_CMD_LOOKUP_METHOD: 381183234Ssimon if (i < 1 || i > 3) 382183234Ssimon { 383183234Ssimon CAPIerr(CAPI_F_CAPI_CTRL, CAPI_R_INVALID_LOOKUP_METHOD); 384183234Ssimon return 0; 385183234Ssimon } 386183234Ssimon ctx->lookup_method = i; 387183234Ssimon break; 388183234Ssimon 389183234Ssimon case CAPI_CMD_SET_CSP_NAME: 390183234Ssimon ret = capi_ctx_set_provname(ctx, p, ctx->csptype, 1); 391183234Ssimon break; 392183234Ssimon 393183234Ssimon case CAPI_CMD_SET_CSP_TYPE: 394183234Ssimon ctx->csptype = i; 395183234Ssimon break; 396183234Ssimon 397183234Ssimon default: 398183234Ssimon CAPIerr(CAPI_F_CAPI_CTRL, CAPI_R_UNKNOWN_COMMAND); 399183234Ssimon ret = 0; 400183234Ssimon } 401183234Ssimon 402183234Ssimon BIO_free(out); 403183234Ssimon return ret; 404183234Ssimon 405183234Ssimon } 406183234Ssimon 407183234Ssimonstatic RSA_METHOD capi_rsa_method = 408183234Ssimon { 409183234Ssimon "CryptoAPI RSA method", 410183234Ssimon 0, /* pub_enc */ 411183234Ssimon 0, /* pub_dec */ 412183234Ssimon capi_rsa_priv_enc, /* priv_enc */ 413183234Ssimon capi_rsa_priv_dec, /* priv_dec */ 414183234Ssimon 0, /* rsa_mod_exp */ 415183234Ssimon 0, /* bn_mod_exp */ 416183234Ssimon 0, /* init */ 417183234Ssimon capi_rsa_free, /* finish */ 418183234Ssimon RSA_FLAG_SIGN_VER, /* flags */ 419183234Ssimon NULL, /* app_data */ 420183234Ssimon capi_rsa_sign, /* rsa_sign */ 421183234Ssimon 0 /* rsa_verify */ 422183234Ssimon }; 423183234Ssimon 424183234Ssimonstatic DSA_METHOD capi_dsa_method = 425183234Ssimon { 426183234Ssimon "CryptoAPI DSA method", 427183234Ssimon capi_dsa_do_sign, /* dsa_do_sign */ 428183234Ssimon 0, /* dsa_sign_setup */ 429183234Ssimon 0, /* dsa_do_verify */ 430183234Ssimon 0, /* dsa_mod_exp */ 431183234Ssimon 0, /* bn_mod_exp */ 432183234Ssimon 0, /* init */ 433183234Ssimon capi_dsa_free, /* finish */ 434183234Ssimon 0, /* flags */ 435183234Ssimon NULL, /* app_data */ 436183234Ssimon 0, /* dsa_paramgen */ 437183234Ssimon 0 /* dsa_keygen */ 438183234Ssimon }; 439183234Ssimon 440183234Ssimonstatic int capi_init(ENGINE *e) 441183234Ssimon { 442183234Ssimon CAPI_CTX *ctx; 443183234Ssimon const RSA_METHOD *ossl_rsa_meth; 444183234Ssimon const DSA_METHOD *ossl_dsa_meth; 445183234Ssimon 446237657Sjkim if (capi_idx < 0) 447237657Sjkim { 448237657Sjkim capi_idx = ENGINE_get_ex_new_index(0, NULL, NULL, NULL, 0); 449237657Sjkim if (capi_idx < 0) 450237657Sjkim goto memerr; 451237657Sjkim 452237657Sjkim cert_capi_idx = X509_get_ex_new_index(0, NULL, NULL, NULL, 0); 453237657Sjkim 454237657Sjkim /* Setup RSA_METHOD */ 455237657Sjkim rsa_capi_idx = RSA_get_ex_new_index(0, NULL, NULL, NULL, 0); 456237657Sjkim ossl_rsa_meth = RSA_PKCS1_SSLeay(); 457237657Sjkim capi_rsa_method.rsa_pub_enc = ossl_rsa_meth->rsa_pub_enc; 458237657Sjkim capi_rsa_method.rsa_pub_dec = ossl_rsa_meth->rsa_pub_dec; 459237657Sjkim capi_rsa_method.rsa_mod_exp = ossl_rsa_meth->rsa_mod_exp; 460237657Sjkim capi_rsa_method.bn_mod_exp = ossl_rsa_meth->bn_mod_exp; 461237657Sjkim 462237657Sjkim /* Setup DSA Method */ 463237657Sjkim dsa_capi_idx = DSA_get_ex_new_index(0, NULL, NULL, NULL, 0); 464237657Sjkim ossl_dsa_meth = DSA_OpenSSL(); 465237657Sjkim capi_dsa_method.dsa_do_verify = ossl_dsa_meth->dsa_do_verify; 466237657Sjkim capi_dsa_method.dsa_mod_exp = ossl_dsa_meth->dsa_mod_exp; 467237657Sjkim capi_dsa_method.bn_mod_exp = ossl_dsa_meth->bn_mod_exp; 468237657Sjkim } 469237657Sjkim 470183234Ssimon ctx = capi_ctx_new(); 471237657Sjkim if (!ctx) 472183234Ssimon goto memerr; 473183234Ssimon 474183234Ssimon ENGINE_set_ex_data(e, capi_idx, ctx); 475183234Ssimon 476183234Ssimon#ifdef OPENSSL_CAPIENG_DIALOG 477183234Ssimon { 478183234Ssimon HMODULE cryptui = LoadLibrary(TEXT("CRYPTUI.DLL")); 479205128Ssimon HMODULE kernel = GetModuleHandle(TEXT("KERNEL32.DLL")); 480183234Ssimon if (cryptui) 481183234Ssimon ctx->certselectdlg = (CERTDLG)GetProcAddress(cryptui, "CryptUIDlgSelectCertificateFromStore"); 482183234Ssimon if (kernel) 483183234Ssimon ctx->getconswindow = (GETCONSWIN)GetProcAddress(kernel, "GetConsoleWindow"); 484183234Ssimon if (cryptui && !OPENSSL_isservice()) 485183234Ssimon ctx->client_cert_select = cert_select_dialog; 486183234Ssimon } 487183234Ssimon#endif 488183234Ssimon 489183234Ssimon 490183234Ssimon return 1; 491183234Ssimon 492183234Ssimon memerr: 493183234Ssimon CAPIerr(CAPI_F_CAPI_INIT, ERR_R_MALLOC_FAILURE); 494183234Ssimon return 0; 495183234Ssimon 496183234Ssimon return 1; 497183234Ssimon } 498183234Ssimon 499183234Ssimonstatic int capi_destroy(ENGINE *e) 500183234Ssimon { 501183234Ssimon ERR_unload_CAPI_strings(); 502183234Ssimon return 1; 503183234Ssimon } 504183234Ssimon 505183234Ssimonstatic int capi_finish(ENGINE *e) 506183234Ssimon { 507183234Ssimon CAPI_CTX *ctx; 508183234Ssimon ctx = ENGINE_get_ex_data(e, capi_idx); 509183234Ssimon capi_ctx_free(ctx); 510183234Ssimon ENGINE_set_ex_data(e, capi_idx, NULL); 511183234Ssimon return 1; 512183234Ssimon } 513183234Ssimon 514183234Ssimon 515183234Ssimon/* CryptoAPI key application data. This contains 516183234Ssimon * a handle to the private key container (for sign operations) 517183234Ssimon * and a handle to the key (for decrypt operations). 518183234Ssimon */ 519183234Ssimon 520183234Ssimonstruct CAPI_KEY_st 521183234Ssimon { 522183234Ssimon /* Associated certificate context (if any) */ 523183234Ssimon PCCERT_CONTEXT pcert; 524183234Ssimon HCRYPTPROV hprov; 525183234Ssimon HCRYPTKEY key; 526183234Ssimon DWORD keyspec; 527183234Ssimon }; 528183234Ssimon 529183234Ssimonstatic int bind_capi(ENGINE *e) 530183234Ssimon { 531183234Ssimon if (!ENGINE_set_id(e, engine_capi_id) 532183234Ssimon || !ENGINE_set_name(e, engine_capi_name) 533238405Sjkim || !ENGINE_set_flags(e, ENGINE_FLAGS_NO_REGISTER_ALL) 534183234Ssimon || !ENGINE_set_init_function(e, capi_init) 535183234Ssimon || !ENGINE_set_finish_function(e, capi_finish) 536183234Ssimon || !ENGINE_set_destroy_function(e, capi_destroy) 537183234Ssimon || !ENGINE_set_RSA(e, &capi_rsa_method) 538183234Ssimon || !ENGINE_set_DSA(e, &capi_dsa_method) 539183234Ssimon || !ENGINE_set_load_privkey_function(e, capi_load_privkey) 540183234Ssimon || !ENGINE_set_load_ssl_client_cert_function(e, 541183234Ssimon capi_load_ssl_client_cert) 542183234Ssimon || !ENGINE_set_cmd_defns(e, capi_cmd_defns) 543183234Ssimon || !ENGINE_set_ctrl_function(e, capi_ctrl)) 544183234Ssimon return 0; 545183234Ssimon ERR_load_CAPI_strings(); 546183234Ssimon 547183234Ssimon return 1; 548183234Ssimon 549183234Ssimon } 550183234Ssimon 551183234Ssimon#ifndef OPENSSL_NO_DYNAMIC_ENGINE 552183234Ssimonstatic int bind_helper(ENGINE *e, const char *id) 553183234Ssimon { 554183234Ssimon if(id && (strcmp(id, engine_capi_id) != 0)) 555183234Ssimon return 0; 556183234Ssimon if(!bind_capi(e)) 557183234Ssimon return 0; 558183234Ssimon return 1; 559183234Ssimon } 560183234SsimonIMPLEMENT_DYNAMIC_CHECK_FN() 561183234SsimonIMPLEMENT_DYNAMIC_BIND_FN(bind_helper) 562183234Ssimon#else 563183234Ssimonstatic ENGINE *engine_capi(void) 564183234Ssimon { 565183234Ssimon ENGINE *ret = ENGINE_new(); 566183234Ssimon if(!ret) 567183234Ssimon return NULL; 568183234Ssimon if(!bind_capi(ret)) 569183234Ssimon { 570183234Ssimon ENGINE_free(ret); 571183234Ssimon return NULL; 572183234Ssimon } 573183234Ssimon return ret; 574183234Ssimon } 575183234Ssimon 576183234Ssimonvoid ENGINE_load_capi(void) 577183234Ssimon { 578183234Ssimon /* Copied from eng_[openssl|dyn].c */ 579183234Ssimon ENGINE *toadd = engine_capi(); 580183234Ssimon if(!toadd) return; 581183234Ssimon ENGINE_add(toadd); 582183234Ssimon ENGINE_free(toadd); 583183234Ssimon ERR_clear_error(); 584183234Ssimon } 585183234Ssimon#endif 586183234Ssimon 587183234Ssimon 588183234Ssimonstatic int lend_tobn(BIGNUM *bn, unsigned char *bin, int binlen) 589183234Ssimon { 590183234Ssimon int i; 591183234Ssimon /* Reverse buffer in place: since this is a keyblob structure 592183234Ssimon * that will be freed up after conversion anyway it doesn't 593183234Ssimon * matter if we change it. 594183234Ssimon */ 595183234Ssimon for(i = 0; i < binlen / 2; i++) 596183234Ssimon { 597183234Ssimon unsigned char c; 598183234Ssimon c = bin[i]; 599183234Ssimon bin[i] = bin[binlen - i - 1]; 600183234Ssimon bin[binlen - i - 1] = c; 601183234Ssimon } 602183234Ssimon 603183234Ssimon if (!BN_bin2bn(bin, binlen, bn)) 604183234Ssimon return 0; 605183234Ssimon return 1; 606183234Ssimon } 607183234Ssimon 608183234Ssimon/* Given a CAPI_KEY get an EVP_PKEY structure */ 609183234Ssimon 610183234Ssimonstatic EVP_PKEY *capi_get_pkey(ENGINE *eng, CAPI_KEY *key) 611183234Ssimon { 612183234Ssimon unsigned char *pubkey = NULL; 613183234Ssimon DWORD len; 614183234Ssimon BLOBHEADER *bh; 615183234Ssimon RSA *rkey = NULL; 616183234Ssimon DSA *dkey = NULL; 617183234Ssimon EVP_PKEY *ret = NULL; 618183234Ssimon if (!CryptExportKey(key->key, 0, PUBLICKEYBLOB, 0, NULL, &len)) 619183234Ssimon { 620183234Ssimon CAPIerr(CAPI_F_CAPI_GET_PKEY, CAPI_R_PUBKEY_EXPORT_LENGTH_ERROR); 621183234Ssimon capi_addlasterror(); 622183234Ssimon return NULL; 623183234Ssimon } 624183234Ssimon 625183234Ssimon pubkey = OPENSSL_malloc(len); 626183234Ssimon 627183234Ssimon if (!pubkey) 628183234Ssimon goto memerr; 629183234Ssimon 630183234Ssimon if (!CryptExportKey(key->key, 0, PUBLICKEYBLOB, 0, pubkey, &len)) 631183234Ssimon { 632183234Ssimon CAPIerr(CAPI_F_CAPI_GET_PKEY, CAPI_R_PUBKEY_EXPORT_ERROR); 633183234Ssimon capi_addlasterror(); 634183234Ssimon goto err; 635183234Ssimon } 636183234Ssimon 637183234Ssimon bh = (BLOBHEADER *)pubkey; 638183234Ssimon if (bh->bType != PUBLICKEYBLOB) 639183234Ssimon { 640183234Ssimon CAPIerr(CAPI_F_CAPI_GET_PKEY, CAPI_R_INVALID_PUBLIC_KEY_BLOB); 641183234Ssimon goto err; 642183234Ssimon } 643183234Ssimon if (bh->aiKeyAlg == CALG_RSA_SIGN || bh->aiKeyAlg == CALG_RSA_KEYX) 644183234Ssimon { 645183234Ssimon RSAPUBKEY *rp; 646183234Ssimon DWORD rsa_modlen; 647183234Ssimon unsigned char *rsa_modulus; 648183234Ssimon rp = (RSAPUBKEY *)(bh + 1); 649183234Ssimon if (rp->magic != 0x31415352) 650183234Ssimon { 651183234Ssimon char magstr[10]; 652183234Ssimon BIO_snprintf(magstr, 10, "%lx", rp->magic); 653183234Ssimon CAPIerr(CAPI_F_CAPI_GET_PKEY, CAPI_R_INVALID_RSA_PUBLIC_KEY_BLOB_MAGIC_NUMBER); 654183234Ssimon ERR_add_error_data(2, "magic=0x", magstr); 655183234Ssimon goto err; 656183234Ssimon } 657183234Ssimon rsa_modulus = (unsigned char *)(rp + 1); 658183234Ssimon rkey = RSA_new_method(eng); 659183234Ssimon if (!rkey) 660183234Ssimon goto memerr; 661183234Ssimon 662183234Ssimon rkey->e = BN_new(); 663183234Ssimon rkey->n = BN_new(); 664183234Ssimon 665183234Ssimon if (!rkey->e || !rkey->n) 666183234Ssimon goto memerr; 667183234Ssimon 668183234Ssimon if (!BN_set_word(rkey->e, rp->pubexp)) 669183234Ssimon goto memerr; 670183234Ssimon 671183234Ssimon rsa_modlen = rp->bitlen / 8; 672183234Ssimon if (!lend_tobn(rkey->n, rsa_modulus, rsa_modlen)) 673183234Ssimon goto memerr; 674183234Ssimon 675183234Ssimon RSA_set_ex_data(rkey, rsa_capi_idx, key); 676183234Ssimon 677183234Ssimon if (!(ret = EVP_PKEY_new())) 678183234Ssimon goto memerr; 679183234Ssimon 680183234Ssimon EVP_PKEY_assign_RSA(ret, rkey); 681183234Ssimon rkey = NULL; 682183234Ssimon 683183234Ssimon } 684183234Ssimon else if (bh->aiKeyAlg == CALG_DSS_SIGN) 685183234Ssimon { 686183234Ssimon DSSPUBKEY *dp; 687183234Ssimon DWORD dsa_plen; 688183234Ssimon unsigned char *btmp; 689183234Ssimon dp = (DSSPUBKEY *)(bh + 1); 690183234Ssimon if (dp->magic != 0x31535344) 691183234Ssimon { 692183234Ssimon char magstr[10]; 693183234Ssimon BIO_snprintf(magstr, 10, "%lx", dp->magic); 694183234Ssimon CAPIerr(CAPI_F_CAPI_GET_PKEY, CAPI_R_INVALID_DSA_PUBLIC_KEY_BLOB_MAGIC_NUMBER); 695183234Ssimon ERR_add_error_data(2, "magic=0x", magstr); 696183234Ssimon goto err; 697183234Ssimon } 698183234Ssimon dsa_plen = dp->bitlen / 8; 699183234Ssimon btmp = (unsigned char *)(dp + 1); 700183234Ssimon dkey = DSA_new_method(eng); 701183234Ssimon if (!dkey) 702183234Ssimon goto memerr; 703183234Ssimon dkey->p = BN_new(); 704183234Ssimon dkey->q = BN_new(); 705183234Ssimon dkey->g = BN_new(); 706183234Ssimon dkey->pub_key = BN_new(); 707183234Ssimon if (!dkey->p || !dkey->q || !dkey->g || !dkey->pub_key) 708183234Ssimon goto memerr; 709183234Ssimon if (!lend_tobn(dkey->p, btmp, dsa_plen)) 710183234Ssimon goto memerr; 711183234Ssimon btmp += dsa_plen; 712183234Ssimon if (!lend_tobn(dkey->q, btmp, 20)) 713183234Ssimon goto memerr; 714183234Ssimon btmp += 20; 715183234Ssimon if (!lend_tobn(dkey->g, btmp, dsa_plen)) 716183234Ssimon goto memerr; 717183234Ssimon btmp += dsa_plen; 718183234Ssimon if (!lend_tobn(dkey->pub_key, btmp, dsa_plen)) 719183234Ssimon goto memerr; 720183234Ssimon btmp += dsa_plen; 721183234Ssimon 722183234Ssimon DSA_set_ex_data(dkey, dsa_capi_idx, key); 723183234Ssimon 724183234Ssimon if (!(ret = EVP_PKEY_new())) 725183234Ssimon goto memerr; 726183234Ssimon 727183234Ssimon EVP_PKEY_assign_DSA(ret, dkey); 728183234Ssimon dkey = NULL; 729183234Ssimon } 730183234Ssimon else 731183234Ssimon { 732183234Ssimon char algstr[10]; 733183234Ssimon BIO_snprintf(algstr, 10, "%lx", bh->aiKeyAlg); 734183234Ssimon CAPIerr(CAPI_F_CAPI_GET_PKEY, CAPI_R_UNSUPPORTED_PUBLIC_KEY_ALGORITHM); 735183234Ssimon ERR_add_error_data(2, "aiKeyAlg=0x", algstr); 736183234Ssimon goto err; 737183234Ssimon } 738183234Ssimon 739183234Ssimon 740183234Ssimon err: 741183234Ssimon if (pubkey) 742183234Ssimon OPENSSL_free(pubkey); 743183234Ssimon if (!ret) 744183234Ssimon { 745183234Ssimon if (rkey) 746183234Ssimon RSA_free(rkey); 747183234Ssimon if (dkey) 748183234Ssimon DSA_free(dkey); 749183234Ssimon } 750183234Ssimon 751183234Ssimon return ret; 752183234Ssimon 753183234Ssimonmemerr: 754183234Ssimon CAPIerr(CAPI_F_CAPI_GET_PKEY, ERR_R_MALLOC_FAILURE); 755183234Ssimon goto err; 756183234Ssimon 757183234Ssimon } 758183234Ssimon 759183234Ssimonstatic EVP_PKEY *capi_load_privkey(ENGINE *eng, const char *key_id, 760183234Ssimon UI_METHOD *ui_method, void *callback_data) 761183234Ssimon { 762183234Ssimon CAPI_CTX *ctx; 763183234Ssimon CAPI_KEY *key; 764183234Ssimon EVP_PKEY *ret; 765183234Ssimon ctx = ENGINE_get_ex_data(eng, capi_idx); 766183234Ssimon 767183234Ssimon if (!ctx) 768183234Ssimon { 769183234Ssimon CAPIerr(CAPI_F_CAPI_LOAD_PRIVKEY, CAPI_R_CANT_FIND_CAPI_CONTEXT); 770183234Ssimon return NULL; 771183234Ssimon } 772183234Ssimon 773183234Ssimon key = capi_find_key(ctx, key_id); 774183234Ssimon 775183234Ssimon if (!key) 776183234Ssimon return NULL; 777183234Ssimon 778183234Ssimon ret = capi_get_pkey(eng, key); 779183234Ssimon 780183234Ssimon if (!ret) 781183234Ssimon capi_free_key(key); 782183234Ssimon return ret; 783183234Ssimon 784183234Ssimon } 785183234Ssimon 786183234Ssimon/* CryptoAPI RSA operations */ 787183234Ssimon 788183234Ssimonint capi_rsa_priv_enc(int flen, const unsigned char *from, 789183234Ssimon unsigned char *to, RSA *rsa, int padding) 790183234Ssimon { 791183234Ssimon CAPIerr(CAPI_F_CAPI_RSA_PRIV_ENC, CAPI_R_FUNCTION_NOT_SUPPORTED); 792183234Ssimon return -1; 793183234Ssimon } 794183234Ssimon 795183234Ssimonint capi_rsa_sign(int dtype, const unsigned char *m, unsigned int m_len, 796183234Ssimon unsigned char *sigret, unsigned int *siglen, const RSA *rsa) 797183234Ssimon { 798183234Ssimon ALG_ID alg; 799183234Ssimon HCRYPTHASH hash; 800183234Ssimon DWORD slen; 801183234Ssimon unsigned int i; 802183234Ssimon int ret = -1; 803183234Ssimon CAPI_KEY *capi_key; 804183234Ssimon CAPI_CTX *ctx; 805183234Ssimon 806183234Ssimon ctx = ENGINE_get_ex_data(rsa->engine, capi_idx); 807183234Ssimon 808183234Ssimon CAPI_trace(ctx, "Called CAPI_rsa_sign()\n"); 809183234Ssimon 810183234Ssimon capi_key = RSA_get_ex_data(rsa, rsa_capi_idx); 811183234Ssimon if (!capi_key) 812183234Ssimon { 813183234Ssimon CAPIerr(CAPI_F_CAPI_RSA_SIGN, CAPI_R_CANT_GET_KEY); 814183234Ssimon return -1; 815183234Ssimon } 816183234Ssimon/* Convert the signature type to a CryptoAPI algorithm ID */ 817183234Ssimon switch(dtype) 818183234Ssimon { 819183234Ssimon case NID_sha1: 820183234Ssimon alg = CALG_SHA1; 821183234Ssimon break; 822183234Ssimon 823183234Ssimon case NID_md5: 824183234Ssimon alg = CALG_MD5; 825183234Ssimon break; 826183234Ssimon 827183234Ssimon case NID_md5_sha1: 828183234Ssimon alg = CALG_SSL3_SHAMD5; 829183234Ssimon break; 830183234Ssimon default: 831183234Ssimon { 832183234Ssimon char algstr[10]; 833183234Ssimon BIO_snprintf(algstr, 10, "%lx", dtype); 834183234Ssimon CAPIerr(CAPI_F_CAPI_RSA_SIGN, CAPI_R_UNSUPPORTED_ALGORITHM_NID); 835183234Ssimon ERR_add_error_data(2, "NID=0x", algstr); 836183234Ssimon return -1; 837183234Ssimon } 838183234Ssimon } 839183234Ssimon 840183234Ssimon 841183234Ssimon 842183234Ssimon/* Create the hash object */ 843183234Ssimon if(!CryptCreateHash(capi_key->hprov, alg, 0, 0, &hash)) 844183234Ssimon { 845183234Ssimon CAPIerr(CAPI_F_CAPI_RSA_SIGN, CAPI_R_CANT_CREATE_HASH_OBJECT); 846183234Ssimon capi_addlasterror(); 847183234Ssimon return -1; 848183234Ssimon } 849183234Ssimon/* Set the hash value to the value passed */ 850183234Ssimon 851183234Ssimon if(!CryptSetHashParam(hash, HP_HASHVAL, (unsigned char *)m, 0)) 852183234Ssimon { 853183234Ssimon CAPIerr(CAPI_F_CAPI_RSA_SIGN, CAPI_R_CANT_SET_HASH_VALUE); 854183234Ssimon capi_addlasterror(); 855183234Ssimon goto err; 856183234Ssimon } 857183234Ssimon 858183234Ssimon 859183234Ssimon/* Finally sign it */ 860183234Ssimon slen = RSA_size(rsa); 861205128Ssimon if(!CryptSignHashA(hash, capi_key->keyspec, NULL, 0, sigret, &slen)) 862183234Ssimon { 863183234Ssimon CAPIerr(CAPI_F_CAPI_RSA_SIGN, CAPI_R_ERROR_SIGNING_HASH); 864183234Ssimon capi_addlasterror(); 865183234Ssimon goto err; 866183234Ssimon } 867183234Ssimon else 868183234Ssimon { 869183234Ssimon ret = 1; 870183234Ssimon /* Inplace byte reversal of signature */ 871183234Ssimon for(i = 0; i < slen / 2; i++) 872183234Ssimon { 873183234Ssimon unsigned char c; 874183234Ssimon c = sigret[i]; 875183234Ssimon sigret[i] = sigret[slen - i - 1]; 876183234Ssimon sigret[slen - i - 1] = c; 877183234Ssimon } 878183234Ssimon *siglen = slen; 879183234Ssimon } 880183234Ssimon 881183234Ssimon /* Now cleanup */ 882183234Ssimon 883183234Ssimonerr: 884183234Ssimon CryptDestroyHash(hash); 885183234Ssimon 886183234Ssimon return ret; 887183234Ssimon } 888183234Ssimon 889183234Ssimonint capi_rsa_priv_dec(int flen, const unsigned char *from, 890183234Ssimon unsigned char *to, RSA *rsa, int padding) 891183234Ssimon { 892183234Ssimon int i; 893183234Ssimon unsigned char *tmpbuf; 894183234Ssimon CAPI_KEY *capi_key; 895183234Ssimon CAPI_CTX *ctx; 896183234Ssimon ctx = ENGINE_get_ex_data(rsa->engine, capi_idx); 897183234Ssimon 898183234Ssimon CAPI_trace(ctx, "Called capi_rsa_priv_dec()\n"); 899183234Ssimon 900183234Ssimon 901183234Ssimon capi_key = RSA_get_ex_data(rsa, rsa_capi_idx); 902183234Ssimon if (!capi_key) 903183234Ssimon { 904183234Ssimon CAPIerr(CAPI_F_CAPI_RSA_PRIV_DEC, CAPI_R_CANT_GET_KEY); 905183234Ssimon return -1; 906183234Ssimon } 907183234Ssimon 908183234Ssimon if(padding != RSA_PKCS1_PADDING) 909183234Ssimon { 910183234Ssimon char errstr[10]; 911183234Ssimon BIO_snprintf(errstr, 10, "%d", padding); 912183234Ssimon CAPIerr(CAPI_F_CAPI_RSA_PRIV_DEC, CAPI_R_UNSUPPORTED_PADDING); 913183234Ssimon ERR_add_error_data(2, "padding=", errstr); 914183234Ssimon return -1; 915183234Ssimon } 916183234Ssimon 917183234Ssimon /* Create temp reverse order version of input */ 918183234Ssimon if(!(tmpbuf = OPENSSL_malloc(flen)) ) 919183234Ssimon { 920183234Ssimon CAPIerr(CAPI_F_CAPI_RSA_PRIV_DEC, ERR_R_MALLOC_FAILURE); 921183234Ssimon return -1; 922183234Ssimon } 923183234Ssimon for(i = 0; i < flen; i++) 924183234Ssimon tmpbuf[flen - i - 1] = from[i]; 925183234Ssimon 926183234Ssimon /* Finally decrypt it */ 927183234Ssimon if(!CryptDecrypt(capi_key->key, 0, TRUE, 0, tmpbuf, &flen)) 928183234Ssimon { 929183234Ssimon CAPIerr(CAPI_F_CAPI_RSA_PRIV_DEC, CAPI_R_DECRYPT_ERROR); 930183234Ssimon capi_addlasterror(); 931183234Ssimon OPENSSL_free(tmpbuf); 932183234Ssimon return -1; 933183234Ssimon } 934183234Ssimon else memcpy(to, tmpbuf, flen); 935183234Ssimon 936183234Ssimon OPENSSL_free(tmpbuf); 937183234Ssimon 938183234Ssimon return flen; 939183234Ssimon } 940183234Ssimon 941183234Ssimonstatic int capi_rsa_free(RSA *rsa) 942183234Ssimon { 943183234Ssimon CAPI_KEY *capi_key; 944183234Ssimon capi_key = RSA_get_ex_data(rsa, rsa_capi_idx); 945183234Ssimon capi_free_key(capi_key); 946183234Ssimon RSA_set_ex_data(rsa, rsa_capi_idx, 0); 947183234Ssimon return 1; 948183234Ssimon } 949183234Ssimon 950183234Ssimon/* CryptoAPI DSA operations */ 951183234Ssimon 952183234Ssimonstatic DSA_SIG *capi_dsa_do_sign(const unsigned char *digest, int dlen, 953183234Ssimon DSA *dsa) 954183234Ssimon { 955183234Ssimon HCRYPTHASH hash; 956183234Ssimon DWORD slen; 957183234Ssimon DSA_SIG *ret = NULL; 958183234Ssimon CAPI_KEY *capi_key; 959183234Ssimon CAPI_CTX *ctx; 960183234Ssimon unsigned char csigbuf[40]; 961183234Ssimon 962183234Ssimon ctx = ENGINE_get_ex_data(dsa->engine, capi_idx); 963183234Ssimon 964183234Ssimon CAPI_trace(ctx, "Called CAPI_dsa_do_sign()\n"); 965183234Ssimon 966183234Ssimon capi_key = DSA_get_ex_data(dsa, dsa_capi_idx); 967183234Ssimon 968183234Ssimon if (!capi_key) 969183234Ssimon { 970183234Ssimon CAPIerr(CAPI_F_CAPI_DSA_DO_SIGN, CAPI_R_CANT_GET_KEY); 971183234Ssimon return NULL; 972183234Ssimon } 973183234Ssimon 974183234Ssimon if (dlen != 20) 975183234Ssimon { 976183234Ssimon CAPIerr(CAPI_F_CAPI_DSA_DO_SIGN, CAPI_R_INVALID_DIGEST_LENGTH); 977183234Ssimon return NULL; 978183234Ssimon } 979183234Ssimon 980183234Ssimon /* Create the hash object */ 981183234Ssimon if(!CryptCreateHash(capi_key->hprov, CALG_SHA1, 0, 0, &hash)) 982183234Ssimon { 983183234Ssimon CAPIerr(CAPI_F_CAPI_DSA_DO_SIGN, CAPI_R_CANT_CREATE_HASH_OBJECT); 984183234Ssimon capi_addlasterror(); 985183234Ssimon return NULL; 986183234Ssimon } 987183234Ssimon 988183234Ssimon /* Set the hash value to the value passed */ 989183234Ssimon if(!CryptSetHashParam(hash, HP_HASHVAL, (unsigned char *)digest, 0)) 990183234Ssimon { 991183234Ssimon CAPIerr(CAPI_F_CAPI_DSA_DO_SIGN, CAPI_R_CANT_SET_HASH_VALUE); 992183234Ssimon capi_addlasterror(); 993183234Ssimon goto err; 994183234Ssimon } 995183234Ssimon 996183234Ssimon 997183234Ssimon /* Finally sign it */ 998183234Ssimon slen = sizeof(csigbuf); 999205128Ssimon if(!CryptSignHashA(hash, capi_key->keyspec, NULL, 0, csigbuf, &slen)) 1000183234Ssimon { 1001183234Ssimon CAPIerr(CAPI_F_CAPI_DSA_DO_SIGN, CAPI_R_ERROR_SIGNING_HASH); 1002183234Ssimon capi_addlasterror(); 1003183234Ssimon goto err; 1004183234Ssimon } 1005183234Ssimon else 1006183234Ssimon { 1007183234Ssimon ret = DSA_SIG_new(); 1008183234Ssimon if (!ret) 1009183234Ssimon goto err; 1010183234Ssimon ret->r = BN_new(); 1011183234Ssimon ret->s = BN_new(); 1012183234Ssimon if (!ret->r || !ret->s) 1013183234Ssimon goto err; 1014183234Ssimon if (!lend_tobn(ret->r, csigbuf, 20) 1015183234Ssimon || !lend_tobn(ret->s, csigbuf + 20, 20)) 1016183234Ssimon { 1017183234Ssimon DSA_SIG_free(ret); 1018183234Ssimon ret = NULL; 1019183234Ssimon goto err; 1020183234Ssimon } 1021183234Ssimon } 1022183234Ssimon 1023183234Ssimon /* Now cleanup */ 1024183234Ssimon 1025183234Ssimonerr: 1026183234Ssimon OPENSSL_cleanse(csigbuf, 40); 1027183234Ssimon CryptDestroyHash(hash); 1028183234Ssimon return ret; 1029183234Ssimon } 1030183234Ssimon 1031183234Ssimonstatic int capi_dsa_free(DSA *dsa) 1032183234Ssimon { 1033183234Ssimon CAPI_KEY *capi_key; 1034183234Ssimon capi_key = DSA_get_ex_data(dsa, dsa_capi_idx); 1035183234Ssimon capi_free_key(capi_key); 1036183234Ssimon DSA_set_ex_data(dsa, dsa_capi_idx, 0); 1037183234Ssimon return 1; 1038183234Ssimon } 1039183234Ssimon 1040183234Ssimonstatic void capi_vtrace(CAPI_CTX *ctx, int level, char *format, va_list argptr) 1041183234Ssimon { 1042183234Ssimon BIO *out; 1043183234Ssimon 1044183234Ssimon if (!ctx || (ctx->debug_level < level) || (!ctx->debug_file)) 1045183234Ssimon return; 1046183234Ssimon out = BIO_new_file(ctx->debug_file, "a+"); 1047183234Ssimon BIO_vprintf(out, format, argptr); 1048183234Ssimon BIO_free(out); 1049183234Ssimon } 1050183234Ssimon 1051183234Ssimonstatic void CAPI_trace(CAPI_CTX *ctx, char *format, ...) 1052183234Ssimon { 1053183234Ssimon va_list args; 1054183234Ssimon va_start(args, format); 1055183234Ssimon capi_vtrace(ctx, CAPI_DBG_TRACE, format, args); 1056183234Ssimon va_end(args); 1057183234Ssimon } 1058183234Ssimon 1059183234Ssimonstatic void capi_addlasterror(void) 1060183234Ssimon { 1061183234Ssimon capi_adderror(GetLastError()); 1062183234Ssimon } 1063183234Ssimon 1064183234Ssimonstatic void capi_adderror(DWORD err) 1065183234Ssimon { 1066183234Ssimon char errstr[10]; 1067183234Ssimon BIO_snprintf(errstr, 10, "%lX", err); 1068183234Ssimon ERR_add_error_data(2, "Error code= 0x", errstr); 1069183234Ssimon } 1070183234Ssimon 1071183234Ssimonstatic char *wide_to_asc(LPWSTR wstr) 1072183234Ssimon { 1073183234Ssimon char *str; 1074205128Ssimon int len_0,sz; 1075205128Ssimon 1076183234Ssimon if (!wstr) 1077183234Ssimon return NULL; 1078205128Ssimon len_0 = (int)wcslen(wstr)+1; /* WideCharToMultiByte expects int */ 1079205128Ssimon sz = WideCharToMultiByte(CP_ACP,0,wstr,len_0,NULL,0,NULL,NULL); 1080205128Ssimon if (!sz) 1081205128Ssimon { 1082205128Ssimon CAPIerr(CAPI_F_WIDE_TO_ASC, CAPI_R_WIN32_ERROR); 1083205128Ssimon return NULL; 1084205128Ssimon } 1085205128Ssimon str = OPENSSL_malloc(sz); 1086183234Ssimon if (!str) 1087183234Ssimon { 1088183234Ssimon CAPIerr(CAPI_F_WIDE_TO_ASC, ERR_R_MALLOC_FAILURE); 1089183234Ssimon return NULL; 1090183234Ssimon } 1091205128Ssimon if (!WideCharToMultiByte(CP_ACP,0,wstr,len_0,str,sz,NULL,NULL)) 1092205128Ssimon { 1093205128Ssimon OPENSSL_free(str); 1094205128Ssimon CAPIerr(CAPI_F_WIDE_TO_ASC, CAPI_R_WIN32_ERROR); 1095205128Ssimon return NULL; 1096205128Ssimon } 1097183234Ssimon return str; 1098183234Ssimon } 1099183234Ssimon 1100183234Ssimonstatic int capi_get_provname(CAPI_CTX *ctx, LPSTR *pname, DWORD *ptype, DWORD idx) 1101183234Ssimon { 1102183234Ssimon LPSTR name; 1103183234Ssimon DWORD len, err; 1104183234Ssimon CAPI_trace(ctx, "capi_get_provname, index=%d\n", idx); 1105205128Ssimon if (!CryptEnumProvidersA(idx, NULL, 0, ptype, NULL, &len)) 1106183234Ssimon { 1107183234Ssimon err = GetLastError(); 1108183234Ssimon if (err == ERROR_NO_MORE_ITEMS) 1109183234Ssimon return 2; 1110183234Ssimon CAPIerr(CAPI_F_CAPI_GET_PROVNAME, CAPI_R_CRYPTENUMPROVIDERS_ERROR); 1111183234Ssimon capi_adderror(err); 1112183234Ssimon return 0; 1113183234Ssimon } 1114183234Ssimon name = OPENSSL_malloc(len); 1115205128Ssimon if (!CryptEnumProvidersA(idx, NULL, 0, ptype, name, &len)) 1116183234Ssimon { 1117183234Ssimon err = GetLastError(); 1118183234Ssimon if (err == ERROR_NO_MORE_ITEMS) 1119183234Ssimon return 2; 1120183234Ssimon CAPIerr(CAPI_F_CAPI_GET_PROVNAME, CAPI_R_CRYPTENUMPROVIDERS_ERROR); 1121183234Ssimon capi_adderror(err); 1122183234Ssimon return 0; 1123183234Ssimon } 1124183234Ssimon *pname = name; 1125183234Ssimon CAPI_trace(ctx, "capi_get_provname, returned name=%s, type=%d\n", name, *ptype); 1126183234Ssimon 1127183234Ssimon return 1; 1128183234Ssimon } 1129183234Ssimon 1130183234Ssimonstatic int capi_list_providers(CAPI_CTX *ctx, BIO *out) 1131183234Ssimon { 1132183234Ssimon DWORD idx, ptype; 1133183234Ssimon int ret; 1134205128Ssimon LPSTR provname = NULL; 1135183234Ssimon CAPI_trace(ctx, "capi_list_providers\n"); 1136183234Ssimon BIO_printf(out, "Available CSPs:\n"); 1137183234Ssimon for(idx = 0; ; idx++) 1138183234Ssimon { 1139183234Ssimon ret = capi_get_provname(ctx, &provname, &ptype, idx); 1140183234Ssimon if (ret == 2) 1141183234Ssimon break; 1142183234Ssimon if (ret == 0) 1143183234Ssimon break; 1144183234Ssimon BIO_printf(out, "%d. %s, type %d\n", idx, provname, ptype); 1145183234Ssimon OPENSSL_free(provname); 1146183234Ssimon } 1147183234Ssimon return 1; 1148183234Ssimon } 1149183234Ssimon 1150183234Ssimonstatic int capi_list_containers(CAPI_CTX *ctx, BIO *out) 1151183234Ssimon { 1152183234Ssimon int ret = 1; 1153183234Ssimon HCRYPTPROV hprov; 1154183234Ssimon DWORD err, idx, flags, buflen = 0, clen; 1155183234Ssimon LPSTR cname; 1156183234Ssimon CAPI_trace(ctx, "Listing containers CSP=%s, type = %d\n", ctx->cspname, ctx->csptype); 1157205128Ssimon if (!CryptAcquireContextA(&hprov, NULL, ctx->cspname, ctx->csptype, CRYPT_VERIFYCONTEXT)) 1158183234Ssimon { 1159183234Ssimon CAPIerr(CAPI_F_CAPI_LIST_CONTAINERS, CAPI_R_CRYPTACQUIRECONTEXT_ERROR); 1160183234Ssimon capi_addlasterror(); 1161183234Ssimon return 0; 1162183234Ssimon } 1163183234Ssimon if (!CryptGetProvParam(hprov, PP_ENUMCONTAINERS, NULL, &buflen, CRYPT_FIRST)) 1164183234Ssimon { 1165183234Ssimon CAPIerr(CAPI_F_CAPI_LIST_CONTAINERS, CAPI_R_ENUMCONTAINERS_ERROR); 1166183234Ssimon capi_addlasterror(); 1167237657Sjkim CryptReleaseContext(hprov, 0); 1168183234Ssimon return 0; 1169183234Ssimon } 1170183234Ssimon CAPI_trace(ctx, "Got max container len %d\n", buflen); 1171183234Ssimon if (buflen == 0) 1172183234Ssimon buflen = 1024; 1173183234Ssimon cname = OPENSSL_malloc(buflen); 1174183234Ssimon if (!cname) 1175183234Ssimon { 1176183234Ssimon CAPIerr(CAPI_F_CAPI_LIST_CONTAINERS, ERR_R_MALLOC_FAILURE); 1177183234Ssimon goto err; 1178183234Ssimon } 1179183234Ssimon 1180183234Ssimon for (idx = 0;;idx++) 1181183234Ssimon { 1182183234Ssimon clen = buflen; 1183183234Ssimon cname[0] = 0; 1184183234Ssimon 1185183234Ssimon if (idx == 0) 1186183234Ssimon flags = CRYPT_FIRST; 1187183234Ssimon else 1188183234Ssimon flags = 0; 1189183234Ssimon if(!CryptGetProvParam(hprov, PP_ENUMCONTAINERS, cname, &clen, flags)) 1190183234Ssimon { 1191183234Ssimon err = GetLastError(); 1192183234Ssimon if (err == ERROR_NO_MORE_ITEMS) 1193183234Ssimon goto done; 1194183234Ssimon CAPIerr(CAPI_F_CAPI_LIST_CONTAINERS, CAPI_R_ENUMCONTAINERS_ERROR); 1195183234Ssimon capi_adderror(err); 1196183234Ssimon goto err; 1197183234Ssimon } 1198183234Ssimon CAPI_trace(ctx, "Container name %s, len=%d, index=%d, flags=%d\n", cname, clen, idx, flags); 1199183234Ssimon if (!cname[0] && (clen == buflen)) 1200183234Ssimon { 1201183234Ssimon CAPI_trace(ctx, "Enumerate bug: using workaround\n"); 1202183234Ssimon goto done; 1203183234Ssimon } 1204183234Ssimon BIO_printf(out, "%d. %s\n", idx, cname); 1205183234Ssimon } 1206183234Ssimon err: 1207183234Ssimon 1208183234Ssimon ret = 0; 1209183234Ssimon 1210183234Ssimon done: 1211183234Ssimon if (cname) 1212183234Ssimon OPENSSL_free(cname); 1213183234Ssimon CryptReleaseContext(hprov, 0); 1214183234Ssimon 1215183234Ssimon return ret; 1216183234Ssimon } 1217183234Ssimon 1218183234SsimonCRYPT_KEY_PROV_INFO *capi_get_prov_info(CAPI_CTX *ctx, PCCERT_CONTEXT cert) 1219183234Ssimon { 1220183234Ssimon DWORD len; 1221183234Ssimon CRYPT_KEY_PROV_INFO *pinfo; 1222183234Ssimon 1223183234Ssimon if(!CertGetCertificateContextProperty(cert, CERT_KEY_PROV_INFO_PROP_ID, NULL, &len)) 1224183234Ssimon return NULL; 1225183234Ssimon pinfo = OPENSSL_malloc(len); 1226183234Ssimon if (!pinfo) 1227183234Ssimon { 1228183234Ssimon CAPIerr(CAPI_F_CAPI_GET_PROV_INFO, ERR_R_MALLOC_FAILURE); 1229183234Ssimon return NULL; 1230183234Ssimon } 1231183234Ssimon if(!CertGetCertificateContextProperty(cert, CERT_KEY_PROV_INFO_PROP_ID, pinfo, &len)) 1232183234Ssimon { 1233183234Ssimon CAPIerr(CAPI_F_CAPI_GET_PROV_INFO, CAPI_R_ERROR_GETTING_KEY_PROVIDER_INFO); 1234183234Ssimon capi_addlasterror(); 1235183234Ssimon OPENSSL_free(pinfo); 1236183234Ssimon return NULL; 1237183234Ssimon } 1238183234Ssimon return pinfo; 1239183234Ssimon } 1240183234Ssimon 1241183234Ssimonstatic void capi_dump_prov_info(CAPI_CTX *ctx, BIO *out, CRYPT_KEY_PROV_INFO *pinfo) 1242183234Ssimon { 1243183234Ssimon char *provname = NULL, *contname = NULL; 1244183234Ssimon if (!pinfo) 1245183234Ssimon { 1246183234Ssimon BIO_printf(out, " No Private Key\n"); 1247183234Ssimon return; 1248183234Ssimon } 1249183234Ssimon provname = wide_to_asc(pinfo->pwszProvName); 1250183234Ssimon contname = wide_to_asc(pinfo->pwszContainerName); 1251183234Ssimon if (!provname || !contname) 1252183234Ssimon goto err; 1253183234Ssimon 1254183234Ssimon BIO_printf(out, " Private Key Info:\n"); 1255183234Ssimon BIO_printf(out, " Provider Name: %s, Provider Type %d\n", provname, pinfo->dwProvType); 1256183234Ssimon BIO_printf(out, " Container Name: %s, Key Type %d\n", contname, pinfo->dwKeySpec); 1257183234Ssimon err: 1258183234Ssimon if (provname) 1259183234Ssimon OPENSSL_free(provname); 1260183234Ssimon if (contname) 1261183234Ssimon OPENSSL_free(contname); 1262183234Ssimon } 1263183234Ssimon 1264183234Ssimonchar * capi_cert_get_fname(CAPI_CTX *ctx, PCCERT_CONTEXT cert) 1265183234Ssimon { 1266183234Ssimon LPWSTR wfname; 1267183234Ssimon DWORD dlen; 1268183234Ssimon 1269183234Ssimon CAPI_trace(ctx, "capi_cert_get_fname\n"); 1270183234Ssimon if (!CertGetCertificateContextProperty(cert, CERT_FRIENDLY_NAME_PROP_ID, NULL, &dlen)) 1271183234Ssimon return NULL; 1272183234Ssimon wfname = OPENSSL_malloc(dlen); 1273183234Ssimon if (CertGetCertificateContextProperty(cert, CERT_FRIENDLY_NAME_PROP_ID, wfname, &dlen)) 1274183234Ssimon { 1275183234Ssimon char *fname = wide_to_asc(wfname); 1276183234Ssimon OPENSSL_free(wfname); 1277183234Ssimon return fname; 1278183234Ssimon } 1279183234Ssimon CAPIerr(CAPI_F_CAPI_CERT_GET_FNAME, CAPI_R_ERROR_GETTING_FRIENDLY_NAME); 1280183234Ssimon capi_addlasterror(); 1281183234Ssimon 1282183234Ssimon OPENSSL_free(wfname); 1283183234Ssimon return NULL; 1284183234Ssimon } 1285183234Ssimon 1286183234Ssimon 1287183234Ssimonvoid capi_dump_cert(CAPI_CTX *ctx, BIO *out, PCCERT_CONTEXT cert) 1288183234Ssimon { 1289183234Ssimon X509 *x; 1290183234Ssimon unsigned char *p; 1291183234Ssimon unsigned long flags = ctx->dump_flags; 1292183234Ssimon if (flags & CAPI_DMP_FNAME) 1293183234Ssimon { 1294183234Ssimon char *fname; 1295183234Ssimon fname = capi_cert_get_fname(ctx, cert); 1296183234Ssimon if (fname) 1297183234Ssimon { 1298183234Ssimon BIO_printf(out, " Friendly Name \"%s\"\n", fname); 1299183234Ssimon OPENSSL_free(fname); 1300183234Ssimon } 1301183234Ssimon else 1302183234Ssimon BIO_printf(out, " <No Friendly Name>\n"); 1303183234Ssimon } 1304183234Ssimon 1305183234Ssimon p = cert->pbCertEncoded; 1306183234Ssimon x = d2i_X509(NULL, &p, cert->cbCertEncoded); 1307183234Ssimon if (!x) 1308183234Ssimon BIO_printf(out, " <Can't parse certificate>\n"); 1309183234Ssimon if (flags & CAPI_DMP_SUMMARY) 1310183234Ssimon { 1311183234Ssimon BIO_printf(out, " Subject: "); 1312183234Ssimon X509_NAME_print_ex(out, X509_get_subject_name(x), 0, XN_FLAG_ONELINE); 1313183234Ssimon BIO_printf(out, "\n Issuer: "); 1314183234Ssimon X509_NAME_print_ex(out, X509_get_issuer_name(x), 0, XN_FLAG_ONELINE); 1315183234Ssimon BIO_printf(out, "\n"); 1316183234Ssimon } 1317183234Ssimon if (flags & CAPI_DMP_FULL) 1318183234Ssimon X509_print_ex(out, x, XN_FLAG_ONELINE,0); 1319183234Ssimon 1320183234Ssimon if (flags & CAPI_DMP_PKEYINFO) 1321183234Ssimon { 1322183234Ssimon CRYPT_KEY_PROV_INFO *pinfo; 1323183234Ssimon pinfo = capi_get_prov_info(ctx, cert); 1324183234Ssimon capi_dump_prov_info(ctx, out, pinfo); 1325183234Ssimon if (pinfo) 1326183234Ssimon OPENSSL_free(pinfo); 1327183234Ssimon } 1328183234Ssimon 1329183234Ssimon if (flags & CAPI_DMP_PEM) 1330183234Ssimon PEM_write_bio_X509(out, x); 1331183234Ssimon X509_free(x); 1332183234Ssimon } 1333183234Ssimon 1334183234SsimonHCERTSTORE capi_open_store(CAPI_CTX *ctx, char *storename) 1335183234Ssimon { 1336183234Ssimon HCERTSTORE hstore; 1337183234Ssimon 1338183234Ssimon if (!storename) 1339183234Ssimon storename = ctx->storename; 1340183234Ssimon if (!storename) 1341183234Ssimon storename = "MY"; 1342183234Ssimon CAPI_trace(ctx, "Opening certificate store %s\n", storename); 1343183234Ssimon 1344183234Ssimon hstore = CertOpenStore(CERT_STORE_PROV_SYSTEM_A, 0, 0, 1345183234Ssimon ctx->store_flags, storename); 1346183234Ssimon if (!hstore) 1347183234Ssimon { 1348183234Ssimon CAPIerr(CAPI_F_CAPI_OPEN_STORE, CAPI_R_ERROR_OPENING_STORE); 1349183234Ssimon capi_addlasterror(); 1350183234Ssimon } 1351183234Ssimon return hstore; 1352183234Ssimon } 1353183234Ssimon 1354183234Ssimonint capi_list_certs(CAPI_CTX *ctx, BIO *out, char *id) 1355183234Ssimon { 1356183234Ssimon char *storename; 1357183234Ssimon int idx; 1358183234Ssimon int ret = 1; 1359183234Ssimon HCERTSTORE hstore; 1360183234Ssimon PCCERT_CONTEXT cert = NULL; 1361183234Ssimon 1362183234Ssimon storename = ctx->storename; 1363183234Ssimon if (!storename) 1364183234Ssimon storename = "MY"; 1365183234Ssimon CAPI_trace(ctx, "Listing certs for store %s\n", storename); 1366183234Ssimon 1367183234Ssimon hstore = capi_open_store(ctx, storename); 1368183234Ssimon if (!hstore) 1369183234Ssimon return 0; 1370183234Ssimon if (id) 1371183234Ssimon { 1372183234Ssimon cert = capi_find_cert(ctx, id, hstore); 1373183234Ssimon if (!cert) 1374183234Ssimon { 1375183234Ssimon ret = 0; 1376183234Ssimon goto err; 1377183234Ssimon } 1378183234Ssimon capi_dump_cert(ctx, out, cert); 1379183234Ssimon CertFreeCertificateContext(cert); 1380183234Ssimon } 1381183234Ssimon else 1382183234Ssimon { 1383183234Ssimon for(idx = 0;;idx++) 1384183234Ssimon { 1385183234Ssimon LPWSTR fname = NULL; 1386183234Ssimon cert = CertEnumCertificatesInStore(hstore, cert); 1387183234Ssimon if (!cert) 1388183234Ssimon break; 1389183234Ssimon BIO_printf(out, "Certificate %d\n", idx); 1390183234Ssimon capi_dump_cert(ctx, out, cert); 1391183234Ssimon } 1392183234Ssimon } 1393183234Ssimon err: 1394183234Ssimon CertCloseStore(hstore, 0); 1395183234Ssimon return ret; 1396183234Ssimon } 1397183234Ssimon 1398183234Ssimonstatic PCCERT_CONTEXT capi_find_cert(CAPI_CTX *ctx, const char *id, HCERTSTORE hstore) 1399183234Ssimon { 1400183234Ssimon PCCERT_CONTEXT cert = NULL; 1401183234Ssimon char *fname = NULL; 1402183234Ssimon int match; 1403183234Ssimon switch(ctx->lookup_method) 1404183234Ssimon { 1405183234Ssimon case CAPI_LU_SUBSTR: 1406183234Ssimon return CertFindCertificateInStore(hstore, 1407183234Ssimon X509_ASN_ENCODING, 0, 1408183234Ssimon CERT_FIND_SUBJECT_STR_A, id, NULL); 1409183234Ssimon case CAPI_LU_FNAME: 1410183234Ssimon for(;;) 1411183234Ssimon { 1412183234Ssimon cert = CertEnumCertificatesInStore(hstore, cert); 1413183234Ssimon if (!cert) 1414183234Ssimon return NULL; 1415183234Ssimon fname = capi_cert_get_fname(ctx, cert); 1416183234Ssimon if (fname) 1417183234Ssimon { 1418183234Ssimon if (strcmp(fname, id)) 1419183234Ssimon match = 0; 1420183234Ssimon else 1421183234Ssimon match = 1; 1422183234Ssimon OPENSSL_free(fname); 1423183234Ssimon if (match) 1424183234Ssimon return cert; 1425183234Ssimon } 1426183234Ssimon } 1427183234Ssimon default: 1428183234Ssimon return NULL; 1429183234Ssimon } 1430183234Ssimon } 1431183234Ssimon 1432183234Ssimonstatic CAPI_KEY *capi_get_key(CAPI_CTX *ctx, const char *contname, char *provname, DWORD ptype, DWORD keyspec) 1433183234Ssimon { 1434183234Ssimon CAPI_KEY *key; 1435246772Sjkim DWORD dwFlags = 0; 1436183234Ssimon key = OPENSSL_malloc(sizeof(CAPI_KEY)); 1437183234Ssimon CAPI_trace(ctx, "capi_get_key, contname=%s, provname=%s, type=%d\n", 1438183234Ssimon contname, provname, ptype); 1439246772Sjkim if(ctx->store_flags & CERT_SYSTEM_STORE_LOCAL_MACHINE) 1440246772Sjkim dwFlags = CRYPT_MACHINE_KEYSET; 1441246772Sjkim if (!CryptAcquireContextA(&key->hprov, contname, provname, ptype, dwFlags)) 1442183234Ssimon { 1443183234Ssimon CAPIerr(CAPI_F_CAPI_GET_KEY, CAPI_R_CRYPTACQUIRECONTEXT_ERROR); 1444183234Ssimon capi_addlasterror(); 1445183234Ssimon goto err; 1446183234Ssimon } 1447183234Ssimon if (!CryptGetUserKey(key->hprov, keyspec, &key->key)) 1448183234Ssimon { 1449183234Ssimon CAPIerr(CAPI_F_CAPI_GET_KEY, CAPI_R_GETUSERKEY_ERROR); 1450183234Ssimon capi_addlasterror(); 1451183234Ssimon CryptReleaseContext(key->hprov, 0); 1452183234Ssimon goto err; 1453183234Ssimon } 1454183234Ssimon key->keyspec = keyspec; 1455183234Ssimon key->pcert = NULL; 1456183234Ssimon return key; 1457183234Ssimon 1458183234Ssimon err: 1459183234Ssimon OPENSSL_free(key); 1460183234Ssimon return NULL; 1461183234Ssimon } 1462183234Ssimon 1463183234Ssimonstatic CAPI_KEY *capi_get_cert_key(CAPI_CTX *ctx, PCCERT_CONTEXT cert) 1464183234Ssimon { 1465183234Ssimon CAPI_KEY *key = NULL; 1466183234Ssimon CRYPT_KEY_PROV_INFO *pinfo = NULL; 1467183234Ssimon char *provname = NULL, *contname = NULL; 1468183234Ssimon pinfo = capi_get_prov_info(ctx, cert); 1469183234Ssimon if (!pinfo) 1470183234Ssimon goto err; 1471183234Ssimon provname = wide_to_asc(pinfo->pwszProvName); 1472183234Ssimon contname = wide_to_asc(pinfo->pwszContainerName); 1473183234Ssimon if (!provname || !contname) 1474183234Ssimon goto err; 1475183234Ssimon key = capi_get_key(ctx, contname, provname, 1476183234Ssimon pinfo->dwProvType, pinfo->dwKeySpec); 1477183234Ssimon 1478183234Ssimon err: 1479183234Ssimon if (pinfo) 1480183234Ssimon OPENSSL_free(pinfo); 1481183234Ssimon if (provname) 1482183234Ssimon OPENSSL_free(provname); 1483183234Ssimon if (contname) 1484183234Ssimon OPENSSL_free(contname); 1485183234Ssimon return key; 1486183234Ssimon } 1487183234Ssimon 1488183234SsimonCAPI_KEY *capi_find_key(CAPI_CTX *ctx, const char *id) 1489183234Ssimon { 1490183234Ssimon PCCERT_CONTEXT cert; 1491183234Ssimon HCERTSTORE hstore; 1492183234Ssimon CAPI_KEY *key = NULL; 1493183234Ssimon switch (ctx->lookup_method) 1494183234Ssimon { 1495183234Ssimon case CAPI_LU_SUBSTR: 1496183234Ssimon case CAPI_LU_FNAME: 1497183234Ssimon hstore = capi_open_store(ctx, NULL); 1498183234Ssimon if (!hstore) 1499183234Ssimon return NULL; 1500183234Ssimon cert = capi_find_cert(ctx, id, hstore); 1501183234Ssimon if (cert) 1502183234Ssimon { 1503183234Ssimon key = capi_get_cert_key(ctx, cert); 1504183234Ssimon CertFreeCertificateContext(cert); 1505183234Ssimon } 1506183234Ssimon CertCloseStore(hstore, 0); 1507183234Ssimon break; 1508183234Ssimon 1509183234Ssimon case CAPI_LU_CONTNAME: 1510183234Ssimon key = capi_get_key(ctx, id, ctx->cspname, ctx->csptype, 1511183234Ssimon ctx->keytype); 1512183234Ssimon break; 1513183234Ssimon } 1514183234Ssimon 1515183234Ssimon return key; 1516183234Ssimon } 1517183234Ssimon 1518183234Ssimonvoid capi_free_key(CAPI_KEY *key) 1519183234Ssimon { 1520183234Ssimon if (!key) 1521183234Ssimon return; 1522183234Ssimon CryptDestroyKey(key->key); 1523183234Ssimon CryptReleaseContext(key->hprov, 0); 1524183234Ssimon if (key->pcert) 1525183234Ssimon CertFreeCertificateContext(key->pcert); 1526183234Ssimon OPENSSL_free(key); 1527183234Ssimon } 1528183234Ssimon 1529183234Ssimon 1530183234Ssimon/* Initialize a CAPI_CTX structure */ 1531183234Ssimon 1532183234Ssimonstatic CAPI_CTX *capi_ctx_new() 1533183234Ssimon { 1534183234Ssimon CAPI_CTX *ctx; 1535183234Ssimon ctx = OPENSSL_malloc(sizeof(CAPI_CTX)); 1536183234Ssimon if (!ctx) 1537183234Ssimon { 1538183234Ssimon CAPIerr(CAPI_F_CAPI_CTX_NEW, ERR_R_MALLOC_FAILURE); 1539183234Ssimon return NULL; 1540183234Ssimon } 1541183234Ssimon ctx->cspname = NULL; 1542183234Ssimon ctx->csptype = PROV_RSA_FULL; 1543183234Ssimon ctx->dump_flags = CAPI_DMP_SUMMARY|CAPI_DMP_FNAME; 1544183234Ssimon ctx->keytype = AT_KEYEXCHANGE; 1545183234Ssimon ctx->storename = NULL; 1546183234Ssimon ctx->ssl_client_store = NULL; 1547183234Ssimon ctx->store_flags = CERT_STORE_OPEN_EXISTING_FLAG | 1548183234Ssimon CERT_STORE_READONLY_FLAG | 1549183234Ssimon CERT_SYSTEM_STORE_CURRENT_USER; 1550183234Ssimon ctx->lookup_method = CAPI_LU_SUBSTR; 1551183234Ssimon ctx->debug_level = 0; 1552183234Ssimon ctx->debug_file = NULL; 1553183234Ssimon ctx->client_cert_select = cert_select_simple; 1554183234Ssimon return ctx; 1555183234Ssimon } 1556183234Ssimon 1557183234Ssimonstatic void capi_ctx_free(CAPI_CTX *ctx) 1558183234Ssimon { 1559183234Ssimon CAPI_trace(ctx, "Calling capi_ctx_free with %lx\n", ctx); 1560183234Ssimon if (!ctx) 1561183234Ssimon return; 1562183234Ssimon if (ctx->cspname) 1563183234Ssimon OPENSSL_free(ctx->cspname); 1564183234Ssimon if (ctx->debug_file) 1565183234Ssimon OPENSSL_free(ctx->debug_file); 1566183234Ssimon if (ctx->storename) 1567183234Ssimon OPENSSL_free(ctx->storename); 1568183234Ssimon if (ctx->ssl_client_store) 1569183234Ssimon OPENSSL_free(ctx->ssl_client_store); 1570183234Ssimon OPENSSL_free(ctx); 1571183234Ssimon } 1572183234Ssimon 1573183234Ssimonstatic int capi_ctx_set_provname(CAPI_CTX *ctx, LPSTR pname, DWORD type, int check) 1574183234Ssimon { 1575183234Ssimon CAPI_trace(ctx, "capi_ctx_set_provname, name=%s, type=%d\n", pname, type); 1576183234Ssimon if (check) 1577183234Ssimon { 1578183234Ssimon HCRYPTPROV hprov; 1579205128Ssimon if (!CryptAcquireContextA(&hprov, NULL, pname, type, 1580183234Ssimon CRYPT_VERIFYCONTEXT)) 1581183234Ssimon { 1582183234Ssimon CAPIerr(CAPI_F_CAPI_CTX_SET_PROVNAME, CAPI_R_CRYPTACQUIRECONTEXT_ERROR); 1583183234Ssimon capi_addlasterror(); 1584183234Ssimon return 0; 1585183234Ssimon } 1586183234Ssimon CryptReleaseContext(hprov, 0); 1587183234Ssimon } 1588237657Sjkim if (ctx->cspname) 1589237657Sjkim OPENSSL_free(ctx->cspname); 1590183234Ssimon ctx->cspname = BUF_strdup(pname); 1591183234Ssimon ctx->csptype = type; 1592183234Ssimon return 1; 1593183234Ssimon } 1594183234Ssimon 1595183234Ssimonstatic int capi_ctx_set_provname_idx(CAPI_CTX *ctx, int idx) 1596183234Ssimon { 1597183234Ssimon LPSTR pname; 1598183234Ssimon DWORD type; 1599237657Sjkim int res; 1600183234Ssimon if (capi_get_provname(ctx, &pname, &type, idx) != 1) 1601183234Ssimon return 0; 1602237657Sjkim res = capi_ctx_set_provname(ctx, pname, type, 0); 1603237657Sjkim OPENSSL_free(pname); 1604237657Sjkim return res; 1605183234Ssimon } 1606183234Ssimon 1607183234Ssimonstatic int cert_issuer_match(STACK_OF(X509_NAME) *ca_dn, X509 *x) 1608183234Ssimon { 1609183234Ssimon int i; 1610183234Ssimon X509_NAME *nm; 1611183234Ssimon /* Special case: empty list: match anything */ 1612183234Ssimon if (sk_X509_NAME_num(ca_dn) <= 0) 1613183234Ssimon return 1; 1614183234Ssimon for (i = 0; i < sk_X509_NAME_num(ca_dn); i++) 1615183234Ssimon { 1616183234Ssimon nm = sk_X509_NAME_value(ca_dn, i); 1617183234Ssimon if (!X509_NAME_cmp(nm, X509_get_issuer_name(x))) 1618183234Ssimon return 1; 1619183234Ssimon } 1620183234Ssimon return 0; 1621183234Ssimon } 1622183234Ssimon 1623183234Ssimon 1624183234Ssimon 1625183234Ssimonstatic int capi_load_ssl_client_cert(ENGINE *e, SSL *ssl, 1626183234Ssimon STACK_OF(X509_NAME) *ca_dn, X509 **pcert, EVP_PKEY **pkey, 1627183234Ssimon STACK_OF(X509) **pother, UI_METHOD *ui_method, void *callback_data) 1628183234Ssimon { 1629183234Ssimon STACK_OF(X509) *certs = NULL; 1630183234Ssimon X509 *x; 1631183234Ssimon char *storename; 1632183234Ssimon const char *p; 1633183234Ssimon int i, client_cert_idx; 1634183234Ssimon HCERTSTORE hstore; 1635183234Ssimon PCCERT_CONTEXT cert = NULL, excert = NULL; 1636183234Ssimon CAPI_CTX *ctx; 1637183234Ssimon CAPI_KEY *key; 1638183234Ssimon ctx = ENGINE_get_ex_data(e, capi_idx); 1639183234Ssimon 1640183234Ssimon *pcert = NULL; 1641183234Ssimon *pkey = NULL; 1642183234Ssimon 1643183234Ssimon storename = ctx->ssl_client_store; 1644183234Ssimon if (!storename) 1645183234Ssimon storename = "MY"; 1646183234Ssimon 1647183234Ssimon hstore = capi_open_store(ctx, storename); 1648183234Ssimon if (!hstore) 1649183234Ssimon return 0; 1650183234Ssimon /* Enumerate all certificates collect any matches */ 1651183234Ssimon for(i = 0;;i++) 1652183234Ssimon { 1653183234Ssimon cert = CertEnumCertificatesInStore(hstore, cert); 1654183234Ssimon if (!cert) 1655183234Ssimon break; 1656183234Ssimon p = cert->pbCertEncoded; 1657183234Ssimon x = d2i_X509(NULL, &p, cert->cbCertEncoded); 1658183234Ssimon if (!x) 1659183234Ssimon { 1660183234Ssimon CAPI_trace(ctx, "Can't Parse Certificate %d\n", i); 1661183234Ssimon continue; 1662183234Ssimon } 1663183234Ssimon if (cert_issuer_match(ca_dn, x) 1664183234Ssimon && X509_check_purpose(x, X509_PURPOSE_SSL_CLIENT, 0)) 1665183234Ssimon { 1666183234Ssimon key = capi_get_cert_key(ctx, cert); 1667183234Ssimon if (!key) 1668183234Ssimon { 1669183234Ssimon X509_free(x); 1670183234Ssimon continue; 1671183234Ssimon } 1672183234Ssimon /* Match found: attach extra data to it so 1673183234Ssimon * we can retrieve the key later. 1674183234Ssimon */ 1675183234Ssimon excert = CertDuplicateCertificateContext(cert); 1676183234Ssimon key->pcert = excert; 1677183234Ssimon X509_set_ex_data(x, cert_capi_idx, key); 1678183234Ssimon 1679183234Ssimon if (!certs) 1680183234Ssimon certs = sk_X509_new_null(); 1681183234Ssimon 1682183234Ssimon sk_X509_push(certs, x); 1683183234Ssimon } 1684183234Ssimon else 1685183234Ssimon X509_free(x); 1686183234Ssimon 1687183234Ssimon } 1688183234Ssimon 1689183234Ssimon if (cert) 1690183234Ssimon CertFreeCertificateContext(cert); 1691183234Ssimon if (hstore) 1692183234Ssimon CertCloseStore(hstore, 0); 1693183234Ssimon 1694183234Ssimon if (!certs) 1695183234Ssimon return 0; 1696183234Ssimon 1697183234Ssimon 1698183234Ssimon /* Select the appropriate certificate */ 1699183234Ssimon 1700183234Ssimon client_cert_idx = ctx->client_cert_select(e, ssl, certs); 1701183234Ssimon 1702183234Ssimon /* Set the selected certificate and free the rest */ 1703183234Ssimon 1704183234Ssimon for(i = 0; i < sk_X509_num(certs); i++) 1705183234Ssimon { 1706183234Ssimon x = sk_X509_value(certs, i); 1707183234Ssimon if (i == client_cert_idx) 1708183234Ssimon *pcert = x; 1709183234Ssimon else 1710183234Ssimon { 1711183234Ssimon key = X509_get_ex_data(x, cert_capi_idx); 1712183234Ssimon capi_free_key(key); 1713183234Ssimon X509_free(x); 1714183234Ssimon } 1715183234Ssimon } 1716183234Ssimon 1717183234Ssimon sk_X509_free(certs); 1718183234Ssimon 1719183234Ssimon if (!*pcert) 1720183234Ssimon return 0; 1721183234Ssimon 1722183234Ssimon /* Setup key for selected certificate */ 1723183234Ssimon 1724183234Ssimon key = X509_get_ex_data(*pcert, cert_capi_idx); 1725183234Ssimon *pkey = capi_get_pkey(e, key); 1726183234Ssimon X509_set_ex_data(*pcert, cert_capi_idx, NULL); 1727183234Ssimon 1728183234Ssimon return 1; 1729183234Ssimon 1730183234Ssimon } 1731183234Ssimon 1732183234Ssimon 1733183234Ssimon/* Simple client cert selection function: always select first */ 1734183234Ssimon 1735183234Ssimonstatic int cert_select_simple(ENGINE *e, SSL *ssl, STACK_OF(X509) *certs) 1736183234Ssimon { 1737183234Ssimon return 0; 1738183234Ssimon } 1739183234Ssimon 1740183234Ssimon#ifdef OPENSSL_CAPIENG_DIALOG 1741183234Ssimon 1742183234Ssimon/* More complex cert selection function, using standard function 1743183234Ssimon * CryptUIDlgSelectCertificateFromStore() to produce a dialog box. 1744183234Ssimon */ 1745183234Ssimon 1746183234Ssimon/* Definitions which are in cryptuiapi.h but this is not present in older 1747183234Ssimon * versions of headers. 1748183234Ssimon */ 1749183234Ssimon 1750183234Ssimon#ifndef CRYPTUI_SELECT_LOCATION_COLUMN 1751183234Ssimon#define CRYPTUI_SELECT_LOCATION_COLUMN 0x000000010 1752183234Ssimon#define CRYPTUI_SELECT_INTENDEDUSE_COLUMN 0x000000004 1753183234Ssimon#endif 1754183234Ssimon 1755183234Ssimon#define dlg_title L"OpenSSL Application SSL Client Certificate Selection" 1756183234Ssimon#define dlg_prompt L"Select a certificate to use for authentication" 1757183234Ssimon#define dlg_columns CRYPTUI_SELECT_LOCATION_COLUMN \ 1758183234Ssimon |CRYPTUI_SELECT_INTENDEDUSE_COLUMN 1759183234Ssimon 1760183234Ssimonstatic int cert_select_dialog(ENGINE *e, SSL *ssl, STACK_OF(X509) *certs) 1761183234Ssimon { 1762183234Ssimon X509 *x; 1763183234Ssimon HCERTSTORE dstore; 1764183234Ssimon PCCERT_CONTEXT cert; 1765183234Ssimon CAPI_CTX *ctx; 1766183234Ssimon CAPI_KEY *key; 1767183234Ssimon HWND hwnd; 1768183234Ssimon int i, idx = -1; 1769183234Ssimon if (sk_X509_num(certs) == 1) 1770183234Ssimon return 0; 1771183234Ssimon ctx = ENGINE_get_ex_data(e, capi_idx); 1772183234Ssimon /* Create an in memory store of certificates */ 1773183234Ssimon dstore = CertOpenStore(CERT_STORE_PROV_MEMORY, 0, 0, 1774183234Ssimon CERT_STORE_CREATE_NEW_FLAG, NULL); 1775183234Ssimon if (!dstore) 1776183234Ssimon { 1777183234Ssimon CAPIerr(CAPI_F_CERT_SELECT_DIALOG, CAPI_R_ERROR_CREATING_STORE); 1778183234Ssimon capi_addlasterror(); 1779183234Ssimon goto err; 1780183234Ssimon } 1781183234Ssimon /* Add all certificates to store */ 1782183234Ssimon for(i = 0; i < sk_X509_num(certs); i++) 1783183234Ssimon { 1784183234Ssimon x = sk_X509_value(certs, i); 1785183234Ssimon key = X509_get_ex_data(x, cert_capi_idx); 1786183234Ssimon 1787183234Ssimon if (!CertAddCertificateContextToStore(dstore, key->pcert, 1788183234Ssimon CERT_STORE_ADD_NEW, NULL)) 1789183234Ssimon { 1790183234Ssimon CAPIerr(CAPI_F_CERT_SELECT_DIALOG, CAPI_R_ERROR_ADDING_CERT); 1791183234Ssimon capi_addlasterror(); 1792183234Ssimon goto err; 1793183234Ssimon } 1794183234Ssimon 1795183234Ssimon } 1796183234Ssimon hwnd = GetForegroundWindow(); 1797183234Ssimon if (!hwnd) 1798183234Ssimon hwnd = GetActiveWindow(); 1799183234Ssimon if (!hwnd && ctx->getconswindow) 1800183234Ssimon hwnd = ctx->getconswindow(); 1801183234Ssimon /* Call dialog to select one */ 1802183234Ssimon cert = ctx->certselectdlg(dstore, hwnd, dlg_title, dlg_prompt, 1803183234Ssimon dlg_columns, 0, NULL); 1804183234Ssimon 1805183234Ssimon /* Find matching cert from list */ 1806183234Ssimon if (cert) 1807183234Ssimon { 1808183234Ssimon for(i = 0; i < sk_X509_num(certs); i++) 1809183234Ssimon { 1810183234Ssimon x = sk_X509_value(certs, i); 1811183234Ssimon key = X509_get_ex_data(x, cert_capi_idx); 1812183234Ssimon if (CertCompareCertificate( 1813183234Ssimon X509_ASN_ENCODING | PKCS_7_ASN_ENCODING, 1814183234Ssimon cert->pCertInfo, 1815183234Ssimon key->pcert->pCertInfo)) 1816183234Ssimon { 1817183234Ssimon idx = i; 1818183234Ssimon break; 1819183234Ssimon } 1820183234Ssimon } 1821183234Ssimon } 1822183234Ssimon 1823183234Ssimon err: 1824183234Ssimon if (dstore) 1825183234Ssimon CertCloseStore(dstore, 0); 1826183234Ssimon return idx; 1827183234Ssimon 1828183234Ssimon } 1829183234Ssimon#endif 1830183234Ssimon 1831238405Sjkim#else /* !__COMPILE_CAPIENG */ 1832183234Ssimon#include <openssl/engine.h> 1833183234Ssimon#ifndef OPENSSL_NO_DYNAMIC_ENGINE 1834183234SsimonOPENSSL_EXPORT 1835238405Sjkimint bind_engine(ENGINE *e, const char *id, const dynamic_fns *fns); 1836238405SjkimOPENSSL_EXPORT 1837183234Ssimonint bind_engine(ENGINE *e, const char *id, const dynamic_fns *fns) { return 0; } 1838183234SsimonIMPLEMENT_DYNAMIC_CHECK_FN() 1839238405Sjkim#else 1840238405Sjkimvoid ENGINE_load_capi(void){} 1841183234Ssimon#endif 1842183234Ssimon#endif 1843