1183234Ssimon/* engines/e_capi.c */ 2280297Sjkim/* 3280297Sjkim * Written by Dr Stephen N Henson (steve@openssl.org) for the OpenSSL 4183234Ssimon * project. 5183234Ssimon */ 6183234Ssimon/* ==================================================================== 7340704Sjkim * Copyright (c) 2008-2018 The OpenSSL Project. All rights reserved. 8183234Ssimon * 9183234Ssimon * Redistribution and use in source and binary forms, with or without 10183234Ssimon * modification, are permitted provided that the following conditions 11183234Ssimon * are met: 12183234Ssimon * 13183234Ssimon * 1. Redistributions of source code must retain the above copyright 14280297Sjkim * notice, this list of conditions and the following disclaimer. 15183234Ssimon * 16183234Ssimon * 2. Redistributions in binary form must reproduce the above copyright 17183234Ssimon * notice, this list of conditions and the following disclaimer in 18183234Ssimon * the documentation and/or other materials provided with the 19183234Ssimon * distribution. 20183234Ssimon * 21183234Ssimon * 3. All advertising materials mentioning features or use of this 22183234Ssimon * software must display the following acknowledgment: 23183234Ssimon * "This product includes software developed by the OpenSSL Project 24183234Ssimon * for use in the OpenSSL Toolkit. (http://www.OpenSSL.org/)" 25183234Ssimon * 26183234Ssimon * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to 27183234Ssimon * endorse or promote products derived from this software without 28183234Ssimon * prior written permission. For written permission, please contact 29183234Ssimon * licensing@OpenSSL.org. 30183234Ssimon * 31183234Ssimon * 5. Products derived from this software may not be called "OpenSSL" 32183234Ssimon * nor may "OpenSSL" appear in their names without prior written 33183234Ssimon * permission of the OpenSSL Project. 34183234Ssimon * 35183234Ssimon * 6. Redistributions of any form whatsoever must retain the following 36183234Ssimon * acknowledgment: 37183234Ssimon * "This product includes software developed by the OpenSSL Project 38183234Ssimon * for use in the OpenSSL Toolkit (http://www.OpenSSL.org/)" 39183234Ssimon * 40183234Ssimon * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY 41183234Ssimon * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 42183234Ssimon * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 43183234Ssimon * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE OpenSSL PROJECT OR 44183234Ssimon * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 45183234Ssimon * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 46183234Ssimon * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 47183234Ssimon * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 48183234Ssimon * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, 49183234Ssimon * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 50183234Ssimon * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED 51183234Ssimon * OF THE POSSIBILITY OF SUCH DAMAGE. 52183234Ssimon * ==================================================================== 53183234Ssimon */ 54183234Ssimon 55183234Ssimon#include <stdio.h> 56183234Ssimon#include <string.h> 57290207Sjkim#include <stdlib.h> 58290207Sjkim 59183234Ssimon#include <openssl/crypto.h> 60183234Ssimon 61183234Ssimon#ifdef OPENSSL_SYS_WIN32 62280297Sjkim# ifndef OPENSSL_NO_CAPIENG 63183234Ssimon 64290207Sjkim# include <openssl/buffer.h> 65290207Sjkim# include <openssl/bn.h> 66280297Sjkim# include <openssl/rsa.h> 67183234Ssimon 68280297Sjkim# ifndef _WIN32_WINNT 69280297Sjkim# define _WIN32_WINNT 0x0400 70280297Sjkim# endif 71183234Ssimon 72290207Sjkim# include <windows.h> 73280297Sjkim# include <wincrypt.h> 74290207Sjkim# include <malloc.h> 75290207Sjkim# ifndef alloca 76290207Sjkim# define alloca _alloca 77290207Sjkim# endif 78183234Ssimon 79238405Sjkim/* 80238405Sjkim * This module uses several "new" interfaces, among which is 81238405Sjkim * CertGetCertificateContextProperty. CERT_KEY_PROV_INFO_PROP_ID is 82238405Sjkim * one of possible values you can pass to function in question. By 83238405Sjkim * checking if it's defined we can see if wincrypt.h and accompanying 84238405Sjkim * crypt32.lib are in shape. The native MingW32 headers up to and 85238405Sjkim * including __W32API_VERSION 3.14 lack of struct DSSPUBKEY and the 86238405Sjkim * defines CERT_STORE_PROV_SYSTEM_A and CERT_STORE_READONLY_FLAG, 87238405Sjkim * so we check for these too and avoid compiling. 88238405Sjkim * Yes, it's rather "weak" test and if compilation fails, 89238405Sjkim * then re-configure with -DOPENSSL_NO_CAPIENG. 90238405Sjkim */ 91280297Sjkim# if defined(CERT_KEY_PROV_INFO_PROP_ID) && \ 92238405Sjkim defined(CERT_STORE_PROV_SYSTEM_A) && \ 93238405Sjkim defined(CERT_STORE_READONLY_FLAG) 94280297Sjkim# define __COMPILE_CAPIENG 95280297Sjkim# endif /* CERT_KEY_PROV_INFO_PROP_ID */ 96280297Sjkim# endif /* OPENSSL_NO_CAPIENG */ 97280297Sjkim#endif /* OPENSSL_SYS_WIN32 */ 98238405Sjkim 99238405Sjkim#ifdef __COMPILE_CAPIENG 100238405Sjkim 101280297Sjkim# undef X509_EXTENSIONS 102280297Sjkim# undef X509_CERT_PAIR 103183234Ssimon 104183234Ssimon/* Definitions which may be missing from earlier version of headers */ 105280297Sjkim# ifndef CERT_STORE_OPEN_EXISTING_FLAG 106280297Sjkim# define CERT_STORE_OPEN_EXISTING_FLAG 0x00004000 107280297Sjkim# endif 108183234Ssimon 109280297Sjkim# ifndef CERT_STORE_CREATE_NEW_FLAG 110280297Sjkim# define CERT_STORE_CREATE_NEW_FLAG 0x00002000 111280297Sjkim# endif 112183234Ssimon 113280297Sjkim# ifndef CERT_SYSTEM_STORE_CURRENT_USER 114280297Sjkim# define CERT_SYSTEM_STORE_CURRENT_USER 0x00010000 115280297Sjkim# endif 116206046Ssimon 117296279Sjkim# ifndef ALG_SID_SHA_256 118296279Sjkim# define ALG_SID_SHA_256 12 119296279Sjkim# endif 120296279Sjkim# ifndef ALG_SID_SHA_384 121296279Sjkim# define ALG_SID_SHA_384 13 122296279Sjkim# endif 123296279Sjkim# ifndef ALG_SID_SHA_512 124296279Sjkim# define ALG_SID_SHA_512 14 125296279Sjkim# endif 126296279Sjkim 127296279Sjkim# ifndef CALG_SHA_256 128296279Sjkim# define CALG_SHA_256 (ALG_CLASS_HASH | ALG_TYPE_ANY | ALG_SID_SHA_256) 129296279Sjkim# endif 130296279Sjkim# ifndef CALG_SHA_384 131296279Sjkim# define CALG_SHA_384 (ALG_CLASS_HASH | ALG_TYPE_ANY | ALG_SID_SHA_384) 132296279Sjkim# endif 133296279Sjkim# ifndef CALG_SHA_512 134296279Sjkim# define CALG_SHA_512 (ALG_CLASS_HASH | ALG_TYPE_ANY | ALG_SID_SHA_512) 135296279Sjkim# endif 136296279Sjkim 137280297Sjkim# include <openssl/engine.h> 138280297Sjkim# include <openssl/pem.h> 139280297Sjkim# include <openssl/x509v3.h> 140183234Ssimon 141280297Sjkim# include "e_capi_err.h" 142280297Sjkim# include "e_capi_err.c" 143183234Ssimon 144183234Ssimonstatic const char *engine_capi_id = "capi"; 145183234Ssimonstatic const char *engine_capi_name = "CryptoAPI ENGINE"; 146183234Ssimon 147183234Ssimontypedef struct CAPI_CTX_st CAPI_CTX; 148183234Ssimontypedef struct CAPI_KEY_st CAPI_KEY; 149183234Ssimon 150183234Ssimonstatic void capi_addlasterror(void); 151183234Ssimonstatic void capi_adderror(DWORD err); 152183234Ssimon 153280297Sjkimstatic void CAPI_trace(CAPI_CTX * ctx, char *format, ...); 154183234Ssimon 155280297Sjkimstatic int capi_list_providers(CAPI_CTX * ctx, BIO *out); 156280297Sjkimstatic int capi_list_containers(CAPI_CTX * ctx, BIO *out); 157280297Sjkimint capi_list_certs(CAPI_CTX * ctx, BIO *out, char *storename); 158280297Sjkimvoid capi_free_key(CAPI_KEY * key); 159183234Ssimon 160280297Sjkimstatic PCCERT_CONTEXT capi_find_cert(CAPI_CTX * ctx, const char *id, 161280297Sjkim HCERTSTORE hstore); 162183234Ssimon 163280297SjkimCAPI_KEY *capi_find_key(CAPI_CTX * ctx, const char *id); 164183234Ssimon 165183234Ssimonstatic EVP_PKEY *capi_load_privkey(ENGINE *eng, const char *key_id, 166280297Sjkim UI_METHOD *ui_method, void *callback_data); 167280297Sjkimstatic int capi_rsa_sign(int dtype, const unsigned char *m, 168280297Sjkim unsigned int m_len, unsigned char *sigret, 169280297Sjkim unsigned int *siglen, const RSA *rsa); 170183234Ssimonstatic int capi_rsa_priv_enc(int flen, const unsigned char *from, 171280297Sjkim unsigned char *to, RSA *rsa, int padding); 172183234Ssimonstatic int capi_rsa_priv_dec(int flen, const unsigned char *from, 173280297Sjkim unsigned char *to, RSA *rsa, int padding); 174183234Ssimonstatic int capi_rsa_free(RSA *rsa); 175183234Ssimon 176183234Ssimonstatic DSA_SIG *capi_dsa_do_sign(const unsigned char *digest, int dlen, 177280297Sjkim DSA *dsa); 178183234Ssimonstatic int capi_dsa_free(DSA *dsa); 179183234Ssimon 180183234Ssimonstatic int capi_load_ssl_client_cert(ENGINE *e, SSL *ssl, 181280297Sjkim STACK_OF(X509_NAME) *ca_dn, X509 **pcert, 182280297Sjkim EVP_PKEY **pkey, STACK_OF(X509) **pother, 183280297Sjkim UI_METHOD *ui_method, 184280297Sjkim void *callback_data); 185183234Ssimon 186183234Ssimonstatic int cert_select_simple(ENGINE *e, SSL *ssl, STACK_OF(X509) *certs); 187280297Sjkim# ifdef OPENSSL_CAPIENG_DIALOG 188183234Ssimonstatic int cert_select_dialog(ENGINE *e, SSL *ssl, STACK_OF(X509) *certs); 189280297Sjkim# endif 190183234Ssimon 191280297Sjkimtypedef PCCERT_CONTEXT(WINAPI *CERTDLG) (HCERTSTORE, HWND, LPCWSTR, 192280297Sjkim LPCWSTR, DWORD, DWORD, void *); 193280297Sjkimtypedef HWND(WINAPI *GETCONSWIN) (void); 194183234Ssimon 195280297Sjkim/* 196280297Sjkim * This structure contains CAPI ENGINE specific data: it contains various 197280297Sjkim * global options and affects how other functions behave. 198183234Ssimon */ 199183234Ssimon 200280297Sjkim# define CAPI_DBG_TRACE 2 201280297Sjkim# define CAPI_DBG_ERROR 1 202183234Ssimon 203183234Ssimonstruct CAPI_CTX_st { 204280297Sjkim int debug_level; 205280297Sjkim char *debug_file; 206280297Sjkim /* Parameters to use for container lookup */ 207280297Sjkim DWORD keytype; 208280297Sjkim LPSTR cspname; 209280297Sjkim DWORD csptype; 210280297Sjkim /* Certificate store name to use */ 211280297Sjkim LPSTR storename; 212280297Sjkim LPSTR ssl_client_store; 213280297Sjkim /* System store flags */ 214280297Sjkim DWORD store_flags; 215183234Ssimon/* Lookup string meanings in load_private_key */ 216183234Ssimon/* Substring of subject: uses "storename" */ 217280297Sjkim# define CAPI_LU_SUBSTR 1 218183234Ssimon/* Friendly name: uses storename */ 219280297Sjkim# define CAPI_LU_FNAME 2 220183234Ssimon/* Container name: uses cspname, keytype */ 221280297Sjkim# define CAPI_LU_CONTNAME 3 222280297Sjkim int lookup_method; 223183234Ssimon/* Info to dump with dumpcerts option */ 224183234Ssimon/* Issuer and serial name strings */ 225280297Sjkim# define CAPI_DMP_SUMMARY 0x1 226183234Ssimon/* Friendly name */ 227280297Sjkim# define CAPI_DMP_FNAME 0x2 228183234Ssimon/* Full X509_print dump */ 229280297Sjkim# define CAPI_DMP_FULL 0x4 230183234Ssimon/* Dump PEM format certificate */ 231280297Sjkim# define CAPI_DMP_PEM 0x8 232183234Ssimon/* Dump pseudo key (if possible) */ 233280297Sjkim# define CAPI_DMP_PSKEY 0x10 234183234Ssimon/* Dump key info (if possible) */ 235280297Sjkim# define CAPI_DMP_PKEYINFO 0x20 236280297Sjkim DWORD dump_flags; 237280297Sjkim int (*client_cert_select) (ENGINE *e, SSL *ssl, STACK_OF(X509) *certs); 238280297Sjkim CERTDLG certselectdlg; 239280297Sjkim GETCONSWIN getconswindow; 240183234Ssimon}; 241183234Ssimon 242183234Ssimonstatic CAPI_CTX *capi_ctx_new(); 243280297Sjkimstatic void capi_ctx_free(CAPI_CTX * ctx); 244280297Sjkimstatic int capi_ctx_set_provname(CAPI_CTX * ctx, LPSTR pname, DWORD type, 245280297Sjkim int check); 246280297Sjkimstatic int capi_ctx_set_provname_idx(CAPI_CTX * ctx, int idx); 247183234Ssimon 248280297Sjkim# define CAPI_CMD_LIST_CERTS ENGINE_CMD_BASE 249280297Sjkim# define CAPI_CMD_LOOKUP_CERT (ENGINE_CMD_BASE + 1) 250280297Sjkim# define CAPI_CMD_DEBUG_LEVEL (ENGINE_CMD_BASE + 2) 251280297Sjkim# define CAPI_CMD_DEBUG_FILE (ENGINE_CMD_BASE + 3) 252280297Sjkim# define CAPI_CMD_KEYTYPE (ENGINE_CMD_BASE + 4) 253280297Sjkim# define CAPI_CMD_LIST_CSPS (ENGINE_CMD_BASE + 5) 254280297Sjkim# define CAPI_CMD_SET_CSP_IDX (ENGINE_CMD_BASE + 6) 255280297Sjkim# define CAPI_CMD_SET_CSP_NAME (ENGINE_CMD_BASE + 7) 256280297Sjkim# define CAPI_CMD_SET_CSP_TYPE (ENGINE_CMD_BASE + 8) 257280297Sjkim# define CAPI_CMD_LIST_CONTAINERS (ENGINE_CMD_BASE + 9) 258280297Sjkim# define CAPI_CMD_LIST_OPTIONS (ENGINE_CMD_BASE + 10) 259280297Sjkim# define CAPI_CMD_LOOKUP_METHOD (ENGINE_CMD_BASE + 11) 260280297Sjkim# define CAPI_CMD_STORE_NAME (ENGINE_CMD_BASE + 12) 261280297Sjkim# define CAPI_CMD_STORE_FLAGS (ENGINE_CMD_BASE + 13) 262183234Ssimon 263183234Ssimonstatic const ENGINE_CMD_DEFN capi_cmd_defns[] = { 264280297Sjkim {CAPI_CMD_LIST_CERTS, 265280297Sjkim "list_certs", 266280297Sjkim "List all certificates in store", 267280297Sjkim ENGINE_CMD_FLAG_NO_INPUT}, 268280297Sjkim {CAPI_CMD_LOOKUP_CERT, 269280297Sjkim "lookup_cert", 270280297Sjkim "Lookup and output certificates", 271280297Sjkim ENGINE_CMD_FLAG_STRING}, 272280297Sjkim {CAPI_CMD_DEBUG_LEVEL, 273280297Sjkim "debug_level", 274280297Sjkim "debug level (1=errors, 2=trace)", 275280297Sjkim ENGINE_CMD_FLAG_NUMERIC}, 276280297Sjkim {CAPI_CMD_DEBUG_FILE, 277280297Sjkim "debug_file", 278280297Sjkim "debugging filename)", 279280297Sjkim ENGINE_CMD_FLAG_STRING}, 280280297Sjkim {CAPI_CMD_KEYTYPE, 281280297Sjkim "key_type", 282280297Sjkim "Key type: 1=AT_KEYEXCHANGE (default), 2=AT_SIGNATURE", 283280297Sjkim ENGINE_CMD_FLAG_NUMERIC}, 284280297Sjkim {CAPI_CMD_LIST_CSPS, 285280297Sjkim "list_csps", 286280297Sjkim "List all CSPs", 287280297Sjkim ENGINE_CMD_FLAG_NO_INPUT}, 288280297Sjkim {CAPI_CMD_SET_CSP_IDX, 289280297Sjkim "csp_idx", 290280297Sjkim "Set CSP by index", 291280297Sjkim ENGINE_CMD_FLAG_NUMERIC}, 292280297Sjkim {CAPI_CMD_SET_CSP_NAME, 293280297Sjkim "csp_name", 294280297Sjkim "Set CSP name, (default CSP used if not specified)", 295280297Sjkim ENGINE_CMD_FLAG_STRING}, 296280297Sjkim {CAPI_CMD_SET_CSP_TYPE, 297280297Sjkim "csp_type", 298280297Sjkim "Set CSP type, (default RSA_PROV_FULL)", 299280297Sjkim ENGINE_CMD_FLAG_NUMERIC}, 300280297Sjkim {CAPI_CMD_LIST_CONTAINERS, 301280297Sjkim "list_containers", 302280297Sjkim "list container names", 303280297Sjkim ENGINE_CMD_FLAG_NO_INPUT}, 304280297Sjkim {CAPI_CMD_LIST_OPTIONS, 305280297Sjkim "list_options", 306280297Sjkim "Set list options (1=summary,2=friendly name, 4=full printout, 8=PEM output, 16=XXX, " 307280297Sjkim "32=private key info)", 308280297Sjkim ENGINE_CMD_FLAG_NUMERIC}, 309280297Sjkim {CAPI_CMD_LOOKUP_METHOD, 310280297Sjkim "lookup_method", 311280297Sjkim "Set key lookup method (1=substring, 2=friendlyname, 3=container name)", 312280297Sjkim ENGINE_CMD_FLAG_NUMERIC}, 313280297Sjkim {CAPI_CMD_STORE_NAME, 314280297Sjkim "store_name", 315280297Sjkim "certificate store name, default \"MY\"", 316280297Sjkim ENGINE_CMD_FLAG_STRING}, 317280297Sjkim {CAPI_CMD_STORE_FLAGS, 318280297Sjkim "store_flags", 319280297Sjkim "Certificate store flags: 1 = system store", 320280297Sjkim ENGINE_CMD_FLAG_NUMERIC}, 321183234Ssimon 322280297Sjkim {0, NULL, NULL, 0} 323280297Sjkim}; 324183234Ssimon 325183234Ssimonstatic int capi_idx = -1; 326183234Ssimonstatic int rsa_capi_idx = -1; 327183234Ssimonstatic int dsa_capi_idx = -1; 328183234Ssimonstatic int cert_capi_idx = -1; 329183234Ssimon 330280297Sjkimstatic int capi_ctrl(ENGINE *e, int cmd, long i, void *p, void (*f) (void)) 331280297Sjkim{ 332280297Sjkim int ret = 1; 333280297Sjkim CAPI_CTX *ctx; 334280297Sjkim BIO *out; 335280297Sjkim if (capi_idx == -1) { 336280297Sjkim CAPIerr(CAPI_F_CAPI_CTRL, CAPI_R_ENGINE_NOT_INITIALIZED); 337280297Sjkim return 0; 338280297Sjkim } 339280297Sjkim ctx = ENGINE_get_ex_data(e, capi_idx); 340280297Sjkim out = BIO_new_fp(stdout, BIO_NOCLOSE); 341280297Sjkim switch (cmd) { 342280297Sjkim case CAPI_CMD_LIST_CSPS: 343280297Sjkim ret = capi_list_providers(ctx, out); 344280297Sjkim break; 345183234Ssimon 346280297Sjkim case CAPI_CMD_LIST_CERTS: 347280297Sjkim ret = capi_list_certs(ctx, out, NULL); 348280297Sjkim break; 349183234Ssimon 350280297Sjkim case CAPI_CMD_LOOKUP_CERT: 351280297Sjkim ret = capi_list_certs(ctx, out, p); 352280297Sjkim break; 353183234Ssimon 354280297Sjkim case CAPI_CMD_LIST_CONTAINERS: 355280297Sjkim ret = capi_list_containers(ctx, out); 356280297Sjkim break; 357183234Ssimon 358280297Sjkim case CAPI_CMD_STORE_NAME: 359280297Sjkim if (ctx->storename) 360280297Sjkim OPENSSL_free(ctx->storename); 361280297Sjkim ctx->storename = BUF_strdup(p); 362280297Sjkim CAPI_trace(ctx, "Setting store name to %s\n", p); 363280297Sjkim break; 364183234Ssimon 365280297Sjkim case CAPI_CMD_STORE_FLAGS: 366280297Sjkim if (i & 1) { 367280297Sjkim ctx->store_flags |= CERT_SYSTEM_STORE_LOCAL_MACHINE; 368280297Sjkim ctx->store_flags &= ~CERT_SYSTEM_STORE_CURRENT_USER; 369280297Sjkim } else { 370280297Sjkim ctx->store_flags |= CERT_SYSTEM_STORE_CURRENT_USER; 371280297Sjkim ctx->store_flags &= ~CERT_SYSTEM_STORE_LOCAL_MACHINE; 372280297Sjkim } 373280297Sjkim CAPI_trace(ctx, "Setting flags to %d\n", i); 374280297Sjkim break; 375183234Ssimon 376280297Sjkim case CAPI_CMD_DEBUG_LEVEL: 377280297Sjkim ctx->debug_level = (int)i; 378280297Sjkim CAPI_trace(ctx, "Setting debug level to %d\n", ctx->debug_level); 379280297Sjkim break; 380183234Ssimon 381280297Sjkim case CAPI_CMD_DEBUG_FILE: 382280297Sjkim ctx->debug_file = BUF_strdup(p); 383280297Sjkim CAPI_trace(ctx, "Setting debug file to %s\n", ctx->debug_file); 384280297Sjkim break; 385183234Ssimon 386280297Sjkim case CAPI_CMD_KEYTYPE: 387280297Sjkim ctx->keytype = i; 388280297Sjkim CAPI_trace(ctx, "Setting key type to %d\n", ctx->keytype); 389280297Sjkim break; 390183234Ssimon 391280297Sjkim case CAPI_CMD_SET_CSP_IDX: 392280297Sjkim ret = capi_ctx_set_provname_idx(ctx, i); 393280297Sjkim break; 394183234Ssimon 395280297Sjkim case CAPI_CMD_LIST_OPTIONS: 396280297Sjkim ctx->dump_flags = i; 397280297Sjkim break; 398183234Ssimon 399280297Sjkim case CAPI_CMD_LOOKUP_METHOD: 400280297Sjkim if (i < 1 || i > 3) { 401280297Sjkim CAPIerr(CAPI_F_CAPI_CTRL, CAPI_R_INVALID_LOOKUP_METHOD); 402280297Sjkim return 0; 403280297Sjkim } 404280297Sjkim ctx->lookup_method = i; 405280297Sjkim break; 406183234Ssimon 407280297Sjkim case CAPI_CMD_SET_CSP_NAME: 408280297Sjkim ret = capi_ctx_set_provname(ctx, p, ctx->csptype, 1); 409280297Sjkim break; 410183234Ssimon 411280297Sjkim case CAPI_CMD_SET_CSP_TYPE: 412280297Sjkim ctx->csptype = i; 413280297Sjkim break; 414183234Ssimon 415280297Sjkim default: 416280297Sjkim CAPIerr(CAPI_F_CAPI_CTRL, CAPI_R_UNKNOWN_COMMAND); 417280297Sjkim ret = 0; 418280297Sjkim } 419183234Ssimon 420280297Sjkim BIO_free(out); 421280297Sjkim return ret; 422183234Ssimon 423280297Sjkim} 424183234Ssimon 425280297Sjkimstatic RSA_METHOD capi_rsa_method = { 426280297Sjkim "CryptoAPI RSA method", 427280297Sjkim 0, /* pub_enc */ 428280297Sjkim 0, /* pub_dec */ 429280297Sjkim capi_rsa_priv_enc, /* priv_enc */ 430280297Sjkim capi_rsa_priv_dec, /* priv_dec */ 431280297Sjkim 0, /* rsa_mod_exp */ 432280297Sjkim 0, /* bn_mod_exp */ 433280297Sjkim 0, /* init */ 434280297Sjkim capi_rsa_free, /* finish */ 435280297Sjkim RSA_FLAG_SIGN_VER, /* flags */ 436280297Sjkim NULL, /* app_data */ 437280297Sjkim capi_rsa_sign, /* rsa_sign */ 438280297Sjkim 0 /* rsa_verify */ 439280297Sjkim}; 440183234Ssimon 441280297Sjkimstatic DSA_METHOD capi_dsa_method = { 442280297Sjkim "CryptoAPI DSA method", 443280297Sjkim capi_dsa_do_sign, /* dsa_do_sign */ 444280297Sjkim 0, /* dsa_sign_setup */ 445280297Sjkim 0, /* dsa_do_verify */ 446280297Sjkim 0, /* dsa_mod_exp */ 447280297Sjkim 0, /* bn_mod_exp */ 448280297Sjkim 0, /* init */ 449280297Sjkim capi_dsa_free, /* finish */ 450280297Sjkim 0, /* flags */ 451280297Sjkim NULL, /* app_data */ 452280297Sjkim 0, /* dsa_paramgen */ 453280297Sjkim 0 /* dsa_keygen */ 454280297Sjkim}; 455183234Ssimon 456183234Ssimonstatic int capi_init(ENGINE *e) 457280297Sjkim{ 458280297Sjkim CAPI_CTX *ctx; 459280297Sjkim const RSA_METHOD *ossl_rsa_meth; 460280297Sjkim const DSA_METHOD *ossl_dsa_meth; 461183234Ssimon 462280297Sjkim if (capi_idx < 0) { 463280297Sjkim capi_idx = ENGINE_get_ex_new_index(0, NULL, NULL, NULL, 0); 464280297Sjkim if (capi_idx < 0) 465280297Sjkim goto memerr; 466237657Sjkim 467280297Sjkim cert_capi_idx = X509_get_ex_new_index(0, NULL, NULL, NULL, 0); 468237657Sjkim 469280297Sjkim /* Setup RSA_METHOD */ 470280297Sjkim rsa_capi_idx = RSA_get_ex_new_index(0, NULL, NULL, NULL, 0); 471280297Sjkim ossl_rsa_meth = RSA_PKCS1_SSLeay(); 472280297Sjkim capi_rsa_method.rsa_pub_enc = ossl_rsa_meth->rsa_pub_enc; 473280297Sjkim capi_rsa_method.rsa_pub_dec = ossl_rsa_meth->rsa_pub_dec; 474280297Sjkim capi_rsa_method.rsa_mod_exp = ossl_rsa_meth->rsa_mod_exp; 475280297Sjkim capi_rsa_method.bn_mod_exp = ossl_rsa_meth->bn_mod_exp; 476237657Sjkim 477280297Sjkim /* Setup DSA Method */ 478280297Sjkim dsa_capi_idx = DSA_get_ex_new_index(0, NULL, NULL, NULL, 0); 479280297Sjkim ossl_dsa_meth = DSA_OpenSSL(); 480280297Sjkim capi_dsa_method.dsa_do_verify = ossl_dsa_meth->dsa_do_verify; 481280297Sjkim capi_dsa_method.dsa_mod_exp = ossl_dsa_meth->dsa_mod_exp; 482280297Sjkim capi_dsa_method.bn_mod_exp = ossl_dsa_meth->bn_mod_exp; 483280297Sjkim } 484237657Sjkim 485280297Sjkim ctx = capi_ctx_new(); 486280297Sjkim if (!ctx) 487280297Sjkim goto memerr; 488183234Ssimon 489280297Sjkim ENGINE_set_ex_data(e, capi_idx, ctx); 490183234Ssimon 491280297Sjkim# ifdef OPENSSL_CAPIENG_DIALOG 492280297Sjkim { 493280297Sjkim HMODULE cryptui = LoadLibrary(TEXT("CRYPTUI.DLL")); 494280297Sjkim HMODULE kernel = GetModuleHandle(TEXT("KERNEL32.DLL")); 495280297Sjkim if (cryptui) 496280297Sjkim ctx->certselectdlg = 497280297Sjkim (CERTDLG) GetProcAddress(cryptui, 498280297Sjkim "CryptUIDlgSelectCertificateFromStore"); 499280297Sjkim if (kernel) 500280297Sjkim ctx->getconswindow = 501280297Sjkim (GETCONSWIN) GetProcAddress(kernel, "GetConsoleWindow"); 502280297Sjkim if (cryptui && !OPENSSL_isservice()) 503280297Sjkim ctx->client_cert_select = cert_select_dialog; 504280297Sjkim } 505280297Sjkim# endif 506183234Ssimon 507280297Sjkim return 1; 508183234Ssimon 509280297Sjkim memerr: 510280297Sjkim CAPIerr(CAPI_F_CAPI_INIT, ERR_R_MALLOC_FAILURE); 511280297Sjkim return 0; 512183234Ssimon 513280297Sjkim return 1; 514280297Sjkim} 515183234Ssimon 516183234Ssimonstatic int capi_destroy(ENGINE *e) 517280297Sjkim{ 518280297Sjkim ERR_unload_CAPI_strings(); 519280297Sjkim return 1; 520280297Sjkim} 521183234Ssimon 522183234Ssimonstatic int capi_finish(ENGINE *e) 523280297Sjkim{ 524280297Sjkim CAPI_CTX *ctx; 525280297Sjkim ctx = ENGINE_get_ex_data(e, capi_idx); 526280297Sjkim capi_ctx_free(ctx); 527280297Sjkim ENGINE_set_ex_data(e, capi_idx, NULL); 528280297Sjkim return 1; 529280297Sjkim} 530183234Ssimon 531280297Sjkim/* 532280297Sjkim * CryptoAPI key application data. This contains a handle to the private key 533280297Sjkim * container (for sign operations) and a handle to the key (for decrypt 534280297Sjkim * operations). 535183234Ssimon */ 536183234Ssimon 537280297Sjkimstruct CAPI_KEY_st { 538280297Sjkim /* Associated certificate context (if any) */ 539280297Sjkim PCCERT_CONTEXT pcert; 540280297Sjkim HCRYPTPROV hprov; 541280297Sjkim HCRYPTKEY key; 542280297Sjkim DWORD keyspec; 543280297Sjkim}; 544183234Ssimon 545183234Ssimonstatic int bind_capi(ENGINE *e) 546280297Sjkim{ 547280297Sjkim if (!ENGINE_set_id(e, engine_capi_id) 548280297Sjkim || !ENGINE_set_name(e, engine_capi_name) 549280297Sjkim || !ENGINE_set_flags(e, ENGINE_FLAGS_NO_REGISTER_ALL) 550280297Sjkim || !ENGINE_set_init_function(e, capi_init) 551280297Sjkim || !ENGINE_set_finish_function(e, capi_finish) 552280297Sjkim || !ENGINE_set_destroy_function(e, capi_destroy) 553280297Sjkim || !ENGINE_set_RSA(e, &capi_rsa_method) 554280297Sjkim || !ENGINE_set_DSA(e, &capi_dsa_method) 555280297Sjkim || !ENGINE_set_load_privkey_function(e, capi_load_privkey) 556280297Sjkim || !ENGINE_set_load_ssl_client_cert_function(e, 557280297Sjkim capi_load_ssl_client_cert) 558280297Sjkim || !ENGINE_set_cmd_defns(e, capi_cmd_defns) 559280297Sjkim || !ENGINE_set_ctrl_function(e, capi_ctrl)) 560280297Sjkim return 0; 561280297Sjkim ERR_load_CAPI_strings(); 562183234Ssimon 563280297Sjkim return 1; 564183234Ssimon 565280297Sjkim} 566183234Ssimon 567280297Sjkim# ifndef OPENSSL_NO_DYNAMIC_ENGINE 568183234Ssimonstatic int bind_helper(ENGINE *e, const char *id) 569280297Sjkim{ 570280297Sjkim if (id && (strcmp(id, engine_capi_id) != 0)) 571280297Sjkim return 0; 572280297Sjkim if (!bind_capi(e)) 573280297Sjkim return 0; 574280297Sjkim return 1; 575280297Sjkim} 576280297Sjkim 577183234SsimonIMPLEMENT_DYNAMIC_CHECK_FN() 578280297Sjkim IMPLEMENT_DYNAMIC_BIND_FN(bind_helper) 579280297Sjkim# else 580183234Ssimonstatic ENGINE *engine_capi(void) 581280297Sjkim{ 582280297Sjkim ENGINE *ret = ENGINE_new(); 583280297Sjkim if (!ret) 584280297Sjkim return NULL; 585280297Sjkim if (!bind_capi(ret)) { 586280297Sjkim ENGINE_free(ret); 587280297Sjkim return NULL; 588280297Sjkim } 589280297Sjkim return ret; 590280297Sjkim} 591183234Ssimon 592183234Ssimonvoid ENGINE_load_capi(void) 593280297Sjkim{ 594280297Sjkim /* Copied from eng_[openssl|dyn].c */ 595280297Sjkim ENGINE *toadd = engine_capi(); 596280297Sjkim if (!toadd) 597280297Sjkim return; 598280297Sjkim ENGINE_add(toadd); 599280297Sjkim ENGINE_free(toadd); 600280297Sjkim ERR_clear_error(); 601280297Sjkim} 602280297Sjkim# endif 603183234Ssimon 604183234Ssimonstatic int lend_tobn(BIGNUM *bn, unsigned char *bin, int binlen) 605280297Sjkim{ 606280297Sjkim int i; 607280297Sjkim /* 608280297Sjkim * Reverse buffer in place: since this is a keyblob structure that will 609280297Sjkim * be freed up after conversion anyway it doesn't matter if we change 610280297Sjkim * it. 611280297Sjkim */ 612280297Sjkim for (i = 0; i < binlen / 2; i++) { 613280297Sjkim unsigned char c; 614280297Sjkim c = bin[i]; 615280297Sjkim bin[i] = bin[binlen - i - 1]; 616280297Sjkim bin[binlen - i - 1] = c; 617280297Sjkim } 618183234Ssimon 619280297Sjkim if (!BN_bin2bn(bin, binlen, bn)) 620280297Sjkim return 0; 621280297Sjkim return 1; 622280297Sjkim} 623183234Ssimon 624183234Ssimon/* Given a CAPI_KEY get an EVP_PKEY structure */ 625183234Ssimon 626280297Sjkimstatic EVP_PKEY *capi_get_pkey(ENGINE *eng, CAPI_KEY * key) 627280297Sjkim{ 628280297Sjkim unsigned char *pubkey = NULL; 629280297Sjkim DWORD len; 630280297Sjkim BLOBHEADER *bh; 631280297Sjkim RSA *rkey = NULL; 632280297Sjkim DSA *dkey = NULL; 633280297Sjkim EVP_PKEY *ret = NULL; 634280297Sjkim if (!CryptExportKey(key->key, 0, PUBLICKEYBLOB, 0, NULL, &len)) { 635280297Sjkim CAPIerr(CAPI_F_CAPI_GET_PKEY, CAPI_R_PUBKEY_EXPORT_LENGTH_ERROR); 636280297Sjkim capi_addlasterror(); 637280297Sjkim return NULL; 638280297Sjkim } 639183234Ssimon 640280297Sjkim pubkey = OPENSSL_malloc(len); 641183234Ssimon 642280297Sjkim if (!pubkey) 643280297Sjkim goto memerr; 644183234Ssimon 645280297Sjkim if (!CryptExportKey(key->key, 0, PUBLICKEYBLOB, 0, pubkey, &len)) { 646280297Sjkim CAPIerr(CAPI_F_CAPI_GET_PKEY, CAPI_R_PUBKEY_EXPORT_ERROR); 647280297Sjkim capi_addlasterror(); 648280297Sjkim goto err; 649280297Sjkim } 650183234Ssimon 651280297Sjkim bh = (BLOBHEADER *) pubkey; 652280297Sjkim if (bh->bType != PUBLICKEYBLOB) { 653280297Sjkim CAPIerr(CAPI_F_CAPI_GET_PKEY, CAPI_R_INVALID_PUBLIC_KEY_BLOB); 654280297Sjkim goto err; 655280297Sjkim } 656280297Sjkim if (bh->aiKeyAlg == CALG_RSA_SIGN || bh->aiKeyAlg == CALG_RSA_KEYX) { 657280297Sjkim RSAPUBKEY *rp; 658280297Sjkim DWORD rsa_modlen; 659280297Sjkim unsigned char *rsa_modulus; 660280297Sjkim rp = (RSAPUBKEY *) (bh + 1); 661280297Sjkim if (rp->magic != 0x31415352) { 662280297Sjkim char magstr[10]; 663280297Sjkim BIO_snprintf(magstr, 10, "%lx", rp->magic); 664280297Sjkim CAPIerr(CAPI_F_CAPI_GET_PKEY, 665280297Sjkim CAPI_R_INVALID_RSA_PUBLIC_KEY_BLOB_MAGIC_NUMBER); 666280297Sjkim ERR_add_error_data(2, "magic=0x", magstr); 667280297Sjkim goto err; 668280297Sjkim } 669280297Sjkim rsa_modulus = (unsigned char *)(rp + 1); 670280297Sjkim rkey = RSA_new_method(eng); 671280297Sjkim if (!rkey) 672280297Sjkim goto memerr; 673183234Ssimon 674280297Sjkim rkey->e = BN_new(); 675280297Sjkim rkey->n = BN_new(); 676183234Ssimon 677280297Sjkim if (!rkey->e || !rkey->n) 678280297Sjkim goto memerr; 679183234Ssimon 680280297Sjkim if (!BN_set_word(rkey->e, rp->pubexp)) 681280297Sjkim goto memerr; 682183234Ssimon 683280297Sjkim rsa_modlen = rp->bitlen / 8; 684280297Sjkim if (!lend_tobn(rkey->n, rsa_modulus, rsa_modlen)) 685280297Sjkim goto memerr; 686183234Ssimon 687280297Sjkim RSA_set_ex_data(rkey, rsa_capi_idx, key); 688183234Ssimon 689280297Sjkim if (!(ret = EVP_PKEY_new())) 690280297Sjkim goto memerr; 691183234Ssimon 692280297Sjkim EVP_PKEY_assign_RSA(ret, rkey); 693280297Sjkim rkey = NULL; 694183234Ssimon 695280297Sjkim } else if (bh->aiKeyAlg == CALG_DSS_SIGN) { 696280297Sjkim DSSPUBKEY *dp; 697280297Sjkim DWORD dsa_plen; 698280297Sjkim unsigned char *btmp; 699280297Sjkim dp = (DSSPUBKEY *) (bh + 1); 700280297Sjkim if (dp->magic != 0x31535344) { 701280297Sjkim char magstr[10]; 702280297Sjkim BIO_snprintf(magstr, 10, "%lx", dp->magic); 703280297Sjkim CAPIerr(CAPI_F_CAPI_GET_PKEY, 704280297Sjkim CAPI_R_INVALID_DSA_PUBLIC_KEY_BLOB_MAGIC_NUMBER); 705280297Sjkim ERR_add_error_data(2, "magic=0x", magstr); 706280297Sjkim goto err; 707280297Sjkim } 708280297Sjkim dsa_plen = dp->bitlen / 8; 709280297Sjkim btmp = (unsigned char *)(dp + 1); 710280297Sjkim dkey = DSA_new_method(eng); 711280297Sjkim if (!dkey) 712280297Sjkim goto memerr; 713280297Sjkim dkey->p = BN_new(); 714280297Sjkim dkey->q = BN_new(); 715280297Sjkim dkey->g = BN_new(); 716280297Sjkim dkey->pub_key = BN_new(); 717280297Sjkim if (!dkey->p || !dkey->q || !dkey->g || !dkey->pub_key) 718280297Sjkim goto memerr; 719280297Sjkim if (!lend_tobn(dkey->p, btmp, dsa_plen)) 720280297Sjkim goto memerr; 721280297Sjkim btmp += dsa_plen; 722280297Sjkim if (!lend_tobn(dkey->q, btmp, 20)) 723280297Sjkim goto memerr; 724280297Sjkim btmp += 20; 725280297Sjkim if (!lend_tobn(dkey->g, btmp, dsa_plen)) 726280297Sjkim goto memerr; 727280297Sjkim btmp += dsa_plen; 728280297Sjkim if (!lend_tobn(dkey->pub_key, btmp, dsa_plen)) 729280297Sjkim goto memerr; 730280297Sjkim btmp += dsa_plen; 731183234Ssimon 732280297Sjkim DSA_set_ex_data(dkey, dsa_capi_idx, key); 733183234Ssimon 734280297Sjkim if (!(ret = EVP_PKEY_new())) 735280297Sjkim goto memerr; 736183234Ssimon 737280297Sjkim EVP_PKEY_assign_DSA(ret, dkey); 738280297Sjkim dkey = NULL; 739280297Sjkim } else { 740280297Sjkim char algstr[10]; 741280297Sjkim BIO_snprintf(algstr, 10, "%lx", bh->aiKeyAlg); 742280297Sjkim CAPIerr(CAPI_F_CAPI_GET_PKEY, 743280297Sjkim CAPI_R_UNSUPPORTED_PUBLIC_KEY_ALGORITHM); 744280297Sjkim ERR_add_error_data(2, "aiKeyAlg=0x", algstr); 745280297Sjkim goto err; 746280297Sjkim } 747183234Ssimon 748280297Sjkim err: 749280297Sjkim if (pubkey) 750280297Sjkim OPENSSL_free(pubkey); 751280297Sjkim if (!ret) { 752280297Sjkim if (rkey) 753280297Sjkim RSA_free(rkey); 754280297Sjkim if (dkey) 755280297Sjkim DSA_free(dkey); 756280297Sjkim } 757183234Ssimon 758280297Sjkim return ret; 759183234Ssimon 760280297Sjkim memerr: 761280297Sjkim CAPIerr(CAPI_F_CAPI_GET_PKEY, ERR_R_MALLOC_FAILURE); 762280297Sjkim goto err; 763183234Ssimon 764280297Sjkim} 765183234Ssimon 766183234Ssimonstatic EVP_PKEY *capi_load_privkey(ENGINE *eng, const char *key_id, 767280297Sjkim UI_METHOD *ui_method, void *callback_data) 768280297Sjkim{ 769280297Sjkim CAPI_CTX *ctx; 770280297Sjkim CAPI_KEY *key; 771280297Sjkim EVP_PKEY *ret; 772280297Sjkim ctx = ENGINE_get_ex_data(eng, capi_idx); 773183234Ssimon 774280297Sjkim if (!ctx) { 775280297Sjkim CAPIerr(CAPI_F_CAPI_LOAD_PRIVKEY, CAPI_R_CANT_FIND_CAPI_CONTEXT); 776280297Sjkim return NULL; 777280297Sjkim } 778183234Ssimon 779280297Sjkim key = capi_find_key(ctx, key_id); 780183234Ssimon 781280297Sjkim if (!key) 782280297Sjkim return NULL; 783183234Ssimon 784280297Sjkim ret = capi_get_pkey(eng, key); 785183234Ssimon 786280297Sjkim if (!ret) 787280297Sjkim capi_free_key(key); 788280297Sjkim return ret; 789183234Ssimon 790280297Sjkim} 791183234Ssimon 792183234Ssimon/* CryptoAPI RSA operations */ 793183234Ssimon 794183234Ssimonint capi_rsa_priv_enc(int flen, const unsigned char *from, 795280297Sjkim unsigned char *to, RSA *rsa, int padding) 796280297Sjkim{ 797280297Sjkim CAPIerr(CAPI_F_CAPI_RSA_PRIV_ENC, CAPI_R_FUNCTION_NOT_SUPPORTED); 798280297Sjkim return -1; 799280297Sjkim} 800183234Ssimon 801183234Ssimonint capi_rsa_sign(int dtype, const unsigned char *m, unsigned int m_len, 802280297Sjkim unsigned char *sigret, unsigned int *siglen, const RSA *rsa) 803280297Sjkim{ 804280297Sjkim ALG_ID alg; 805280297Sjkim HCRYPTHASH hash; 806280297Sjkim DWORD slen; 807280297Sjkim unsigned int i; 808280297Sjkim int ret = -1; 809280297Sjkim CAPI_KEY *capi_key; 810280297Sjkim CAPI_CTX *ctx; 811183234Ssimon 812280297Sjkim ctx = ENGINE_get_ex_data(rsa->engine, capi_idx); 813183234Ssimon 814280297Sjkim CAPI_trace(ctx, "Called CAPI_rsa_sign()\n"); 815183234Ssimon 816280297Sjkim capi_key = RSA_get_ex_data(rsa, rsa_capi_idx); 817280297Sjkim if (!capi_key) { 818280297Sjkim CAPIerr(CAPI_F_CAPI_RSA_SIGN, CAPI_R_CANT_GET_KEY); 819280297Sjkim return -1; 820280297Sjkim } 821183234Ssimon/* Convert the signature type to a CryptoAPI algorithm ID */ 822280297Sjkim switch (dtype) { 823296279Sjkim case NID_sha256: 824296279Sjkim alg = CALG_SHA_256; 825296279Sjkim break; 826296279Sjkim 827296279Sjkim case NID_sha384: 828296279Sjkim alg = CALG_SHA_384; 829296279Sjkim break; 830296279Sjkim 831296279Sjkim case NID_sha512: 832296279Sjkim alg = CALG_SHA_512; 833296279Sjkim break; 834296279Sjkim 835280297Sjkim case NID_sha1: 836280297Sjkim alg = CALG_SHA1; 837280297Sjkim break; 838183234Ssimon 839280297Sjkim case NID_md5: 840280297Sjkim alg = CALG_MD5; 841280297Sjkim break; 842183234Ssimon 843280297Sjkim case NID_md5_sha1: 844280297Sjkim alg = CALG_SSL3_SHAMD5; 845280297Sjkim break; 846280297Sjkim default: 847280297Sjkim { 848280297Sjkim char algstr[10]; 849280297Sjkim BIO_snprintf(algstr, 10, "%lx", dtype); 850280297Sjkim CAPIerr(CAPI_F_CAPI_RSA_SIGN, CAPI_R_UNSUPPORTED_ALGORITHM_NID); 851280297Sjkim ERR_add_error_data(2, "NID=0x", algstr); 852280297Sjkim return -1; 853280297Sjkim } 854280297Sjkim } 855183234Ssimon 856183234Ssimon/* Create the hash object */ 857280297Sjkim if (!CryptCreateHash(capi_key->hprov, alg, 0, 0, &hash)) { 858280297Sjkim CAPIerr(CAPI_F_CAPI_RSA_SIGN, CAPI_R_CANT_CREATE_HASH_OBJECT); 859280297Sjkim capi_addlasterror(); 860280297Sjkim return -1; 861280297Sjkim } 862183234Ssimon/* Set the hash value to the value passed */ 863183234Ssimon 864280297Sjkim if (!CryptSetHashParam(hash, HP_HASHVAL, (unsigned char *)m, 0)) { 865280297Sjkim CAPIerr(CAPI_F_CAPI_RSA_SIGN, CAPI_R_CANT_SET_HASH_VALUE); 866280297Sjkim capi_addlasterror(); 867280297Sjkim goto err; 868280297Sjkim } 869183234Ssimon 870183234Ssimon/* Finally sign it */ 871280297Sjkim slen = RSA_size(rsa); 872290207Sjkim if (!CryptSignHash(hash, capi_key->keyspec, NULL, 0, sigret, &slen)) { 873280297Sjkim CAPIerr(CAPI_F_CAPI_RSA_SIGN, CAPI_R_ERROR_SIGNING_HASH); 874280297Sjkim capi_addlasterror(); 875280297Sjkim goto err; 876280297Sjkim } else { 877280297Sjkim ret = 1; 878280297Sjkim /* Inplace byte reversal of signature */ 879280297Sjkim for (i = 0; i < slen / 2; i++) { 880280297Sjkim unsigned char c; 881280297Sjkim c = sigret[i]; 882280297Sjkim sigret[i] = sigret[slen - i - 1]; 883280297Sjkim sigret[slen - i - 1] = c; 884280297Sjkim } 885280297Sjkim *siglen = slen; 886280297Sjkim } 887183234Ssimon 888280297Sjkim /* Now cleanup */ 889183234Ssimon 890280297Sjkim err: 891280297Sjkim CryptDestroyHash(hash); 892183234Ssimon 893280297Sjkim return ret; 894280297Sjkim} 895183234Ssimon 896183234Ssimonint capi_rsa_priv_dec(int flen, const unsigned char *from, 897280297Sjkim unsigned char *to, RSA *rsa, int padding) 898280297Sjkim{ 899280297Sjkim int i; 900280297Sjkim unsigned char *tmpbuf; 901280297Sjkim CAPI_KEY *capi_key; 902280297Sjkim CAPI_CTX *ctx; 903340704Sjkim DWORD flags = 0; 904340704Sjkim 905280297Sjkim ctx = ENGINE_get_ex_data(rsa->engine, capi_idx); 906183234Ssimon 907280297Sjkim CAPI_trace(ctx, "Called capi_rsa_priv_dec()\n"); 908183234Ssimon 909280297Sjkim capi_key = RSA_get_ex_data(rsa, rsa_capi_idx); 910280297Sjkim if (!capi_key) { 911280297Sjkim CAPIerr(CAPI_F_CAPI_RSA_PRIV_DEC, CAPI_R_CANT_GET_KEY); 912280297Sjkim return -1; 913280297Sjkim } 914183234Ssimon 915340704Sjkim switch (padding) { 916340704Sjkim case RSA_PKCS1_PADDING: 917340704Sjkim /* Nothing to do */ 918340704Sjkim break; 919340704Sjkim#ifdef CRYPT_DECRYPT_RSA_NO_PADDING_CHECK 920340704Sjkim case RSA_NO_PADDING: 921340704Sjkim flags = CRYPT_DECRYPT_RSA_NO_PADDING_CHECK; 922340704Sjkim break; 923340704Sjkim#endif 924340704Sjkim default: 925340704Sjkim { 926340704Sjkim char errstr[10]; 927340704Sjkim BIO_snprintf(errstr, 10, "%d", padding); 928340704Sjkim CAPIerr(CAPI_F_CAPI_RSA_PRIV_DEC, CAPI_R_UNSUPPORTED_PADDING); 929340704Sjkim ERR_add_error_data(2, "padding=", errstr); 930340704Sjkim return -1; 931340704Sjkim } 932280297Sjkim } 933183234Ssimon 934280297Sjkim /* Create temp reverse order version of input */ 935280297Sjkim if (!(tmpbuf = OPENSSL_malloc(flen))) { 936280297Sjkim CAPIerr(CAPI_F_CAPI_RSA_PRIV_DEC, ERR_R_MALLOC_FAILURE); 937280297Sjkim return -1; 938280297Sjkim } 939280297Sjkim for (i = 0; i < flen; i++) 940280297Sjkim tmpbuf[flen - i - 1] = from[i]; 941183234Ssimon 942280297Sjkim /* Finally decrypt it */ 943340704Sjkim if (!CryptDecrypt(capi_key->key, 0, TRUE, flags, tmpbuf, &flen)) { 944280297Sjkim CAPIerr(CAPI_F_CAPI_RSA_PRIV_DEC, CAPI_R_DECRYPT_ERROR); 945280297Sjkim capi_addlasterror(); 946340704Sjkim OPENSSL_cleanse(tmpbuf, flen); 947280297Sjkim OPENSSL_free(tmpbuf); 948280297Sjkim return -1; 949340704Sjkim } else { 950280297Sjkim memcpy(to, tmpbuf, flen); 951340704Sjkim } 952183234Ssimon 953340704Sjkim OPENSSL_cleanse(tmpbuf, flen); 954280297Sjkim OPENSSL_free(tmpbuf); 955183234Ssimon 956280297Sjkim return flen; 957280297Sjkim} 958183234Ssimon 959183234Ssimonstatic int capi_rsa_free(RSA *rsa) 960280297Sjkim{ 961280297Sjkim CAPI_KEY *capi_key; 962280297Sjkim capi_key = RSA_get_ex_data(rsa, rsa_capi_idx); 963280297Sjkim capi_free_key(capi_key); 964280297Sjkim RSA_set_ex_data(rsa, rsa_capi_idx, 0); 965280297Sjkim return 1; 966280297Sjkim} 967183234Ssimon 968183234Ssimon/* CryptoAPI DSA operations */ 969183234Ssimon 970183234Ssimonstatic DSA_SIG *capi_dsa_do_sign(const unsigned char *digest, int dlen, 971280297Sjkim DSA *dsa) 972280297Sjkim{ 973280297Sjkim HCRYPTHASH hash; 974280297Sjkim DWORD slen; 975280297Sjkim DSA_SIG *ret = NULL; 976280297Sjkim CAPI_KEY *capi_key; 977280297Sjkim CAPI_CTX *ctx; 978280297Sjkim unsigned char csigbuf[40]; 979183234Ssimon 980280297Sjkim ctx = ENGINE_get_ex_data(dsa->engine, capi_idx); 981183234Ssimon 982280297Sjkim CAPI_trace(ctx, "Called CAPI_dsa_do_sign()\n"); 983183234Ssimon 984280297Sjkim capi_key = DSA_get_ex_data(dsa, dsa_capi_idx); 985183234Ssimon 986280297Sjkim if (!capi_key) { 987280297Sjkim CAPIerr(CAPI_F_CAPI_DSA_DO_SIGN, CAPI_R_CANT_GET_KEY); 988280297Sjkim return NULL; 989280297Sjkim } 990183234Ssimon 991280297Sjkim if (dlen != 20) { 992280297Sjkim CAPIerr(CAPI_F_CAPI_DSA_DO_SIGN, CAPI_R_INVALID_DIGEST_LENGTH); 993280297Sjkim return NULL; 994280297Sjkim } 995183234Ssimon 996280297Sjkim /* Create the hash object */ 997280297Sjkim if (!CryptCreateHash(capi_key->hprov, CALG_SHA1, 0, 0, &hash)) { 998280297Sjkim CAPIerr(CAPI_F_CAPI_DSA_DO_SIGN, CAPI_R_CANT_CREATE_HASH_OBJECT); 999280297Sjkim capi_addlasterror(); 1000280297Sjkim return NULL; 1001280297Sjkim } 1002183234Ssimon 1003280297Sjkim /* Set the hash value to the value passed */ 1004280297Sjkim if (!CryptSetHashParam(hash, HP_HASHVAL, (unsigned char *)digest, 0)) { 1005280297Sjkim CAPIerr(CAPI_F_CAPI_DSA_DO_SIGN, CAPI_R_CANT_SET_HASH_VALUE); 1006280297Sjkim capi_addlasterror(); 1007280297Sjkim goto err; 1008280297Sjkim } 1009183234Ssimon 1010280297Sjkim /* Finally sign it */ 1011280297Sjkim slen = sizeof(csigbuf); 1012290207Sjkim if (!CryptSignHash(hash, capi_key->keyspec, NULL, 0, csigbuf, &slen)) { 1013280297Sjkim CAPIerr(CAPI_F_CAPI_DSA_DO_SIGN, CAPI_R_ERROR_SIGNING_HASH); 1014280297Sjkim capi_addlasterror(); 1015280297Sjkim goto err; 1016280297Sjkim } else { 1017280297Sjkim ret = DSA_SIG_new(); 1018280297Sjkim if (!ret) 1019280297Sjkim goto err; 1020280297Sjkim ret->r = BN_new(); 1021280297Sjkim ret->s = BN_new(); 1022280297Sjkim if (!ret->r || !ret->s) 1023280297Sjkim goto err; 1024280297Sjkim if (!lend_tobn(ret->r, csigbuf, 20) 1025280297Sjkim || !lend_tobn(ret->s, csigbuf + 20, 20)) { 1026280297Sjkim DSA_SIG_free(ret); 1027280297Sjkim ret = NULL; 1028280297Sjkim goto err; 1029280297Sjkim } 1030280297Sjkim } 1031183234Ssimon 1032280297Sjkim /* Now cleanup */ 1033183234Ssimon 1034280297Sjkim err: 1035280297Sjkim OPENSSL_cleanse(csigbuf, 40); 1036280297Sjkim CryptDestroyHash(hash); 1037280297Sjkim return ret; 1038280297Sjkim} 1039183234Ssimon 1040183234Ssimonstatic int capi_dsa_free(DSA *dsa) 1041280297Sjkim{ 1042280297Sjkim CAPI_KEY *capi_key; 1043280297Sjkim capi_key = DSA_get_ex_data(dsa, dsa_capi_idx); 1044280297Sjkim capi_free_key(capi_key); 1045280297Sjkim DSA_set_ex_data(dsa, dsa_capi_idx, 0); 1046280297Sjkim return 1; 1047280297Sjkim} 1048183234Ssimon 1049280297Sjkimstatic void capi_vtrace(CAPI_CTX * ctx, int level, char *format, 1050280297Sjkim va_list argptr) 1051280297Sjkim{ 1052280297Sjkim BIO *out; 1053183234Ssimon 1054280297Sjkim if (!ctx || (ctx->debug_level < level) || (!ctx->debug_file)) 1055280297Sjkim return; 1056280297Sjkim out = BIO_new_file(ctx->debug_file, "a+"); 1057280297Sjkim BIO_vprintf(out, format, argptr); 1058280297Sjkim BIO_free(out); 1059280297Sjkim} 1060183234Ssimon 1061280297Sjkimstatic void CAPI_trace(CAPI_CTX * ctx, char *format, ...) 1062280297Sjkim{ 1063280297Sjkim va_list args; 1064280297Sjkim va_start(args, format); 1065280297Sjkim capi_vtrace(ctx, CAPI_DBG_TRACE, format, args); 1066280297Sjkim va_end(args); 1067280297Sjkim} 1068183234Ssimon 1069183234Ssimonstatic void capi_addlasterror(void) 1070280297Sjkim{ 1071280297Sjkim capi_adderror(GetLastError()); 1072280297Sjkim} 1073183234Ssimon 1074183234Ssimonstatic void capi_adderror(DWORD err) 1075280297Sjkim{ 1076280297Sjkim char errstr[10]; 1077280297Sjkim BIO_snprintf(errstr, 10, "%lX", err); 1078280297Sjkim ERR_add_error_data(2, "Error code= 0x", errstr); 1079280297Sjkim} 1080183234Ssimon 1081290207Sjkimstatic char *wide_to_asc(LPCWSTR wstr) 1082280297Sjkim{ 1083280297Sjkim char *str; 1084280297Sjkim int len_0, sz; 1085205128Ssimon 1086280297Sjkim if (!wstr) 1087280297Sjkim return NULL; 1088280297Sjkim len_0 = (int)wcslen(wstr) + 1; /* WideCharToMultiByte expects int */ 1089280297Sjkim sz = WideCharToMultiByte(CP_ACP, 0, wstr, len_0, NULL, 0, NULL, NULL); 1090280297Sjkim if (!sz) { 1091280297Sjkim CAPIerr(CAPI_F_WIDE_TO_ASC, CAPI_R_WIN32_ERROR); 1092280297Sjkim return NULL; 1093280297Sjkim } 1094280297Sjkim str = OPENSSL_malloc(sz); 1095280297Sjkim if (!str) { 1096280297Sjkim CAPIerr(CAPI_F_WIDE_TO_ASC, ERR_R_MALLOC_FAILURE); 1097280297Sjkim return NULL; 1098280297Sjkim } 1099280297Sjkim if (!WideCharToMultiByte(CP_ACP, 0, wstr, len_0, str, sz, NULL, NULL)) { 1100280297Sjkim OPENSSL_free(str); 1101280297Sjkim CAPIerr(CAPI_F_WIDE_TO_ASC, CAPI_R_WIN32_ERROR); 1102280297Sjkim return NULL; 1103280297Sjkim } 1104280297Sjkim return str; 1105280297Sjkim} 1106183234Ssimon 1107280297Sjkimstatic int capi_get_provname(CAPI_CTX * ctx, LPSTR * pname, DWORD * ptype, 1108280297Sjkim DWORD idx) 1109280297Sjkim{ 1110280297Sjkim DWORD len, err; 1111290207Sjkim LPTSTR name; 1112280297Sjkim CAPI_trace(ctx, "capi_get_provname, index=%d\n", idx); 1113290207Sjkim if (!CryptEnumProviders(idx, NULL, 0, ptype, NULL, &len)) { 1114280297Sjkim err = GetLastError(); 1115280297Sjkim if (err == ERROR_NO_MORE_ITEMS) 1116280297Sjkim return 2; 1117280297Sjkim CAPIerr(CAPI_F_CAPI_GET_PROVNAME, CAPI_R_CRYPTENUMPROVIDERS_ERROR); 1118280297Sjkim capi_adderror(err); 1119280297Sjkim return 0; 1120280297Sjkim } 1121290207Sjkim if (sizeof(TCHAR) != sizeof(char)) 1122290207Sjkim name = alloca(len); 1123290207Sjkim else 1124290207Sjkim name = OPENSSL_malloc(len); 1125306195Sjkim if (name == NULL) { 1126306195Sjkim CAPIerr(CAPI_F_CAPI_GET_PROVNAME, ERR_R_MALLOC_FAILURE); 1127306195Sjkim return 0; 1128306195Sjkim } 1129290207Sjkim if (!CryptEnumProviders(idx, NULL, 0, ptype, name, &len)) { 1130280297Sjkim err = GetLastError(); 1131280297Sjkim if (err == ERROR_NO_MORE_ITEMS) 1132280297Sjkim return 2; 1133280297Sjkim CAPIerr(CAPI_F_CAPI_GET_PROVNAME, CAPI_R_CRYPTENUMPROVIDERS_ERROR); 1134280297Sjkim capi_adderror(err); 1135280297Sjkim return 0; 1136280297Sjkim } 1137290207Sjkim if (sizeof(TCHAR) != sizeof(char)) 1138290207Sjkim *pname = wide_to_asc((WCHAR *)name); 1139290207Sjkim else 1140290207Sjkim *pname = (char *)name; 1141290207Sjkim CAPI_trace(ctx, "capi_get_provname, returned name=%s, type=%d\n", *pname, 1142280297Sjkim *ptype); 1143183234Ssimon 1144280297Sjkim return 1; 1145280297Sjkim} 1146183234Ssimon 1147280297Sjkimstatic int capi_list_providers(CAPI_CTX * ctx, BIO *out) 1148280297Sjkim{ 1149280297Sjkim DWORD idx, ptype; 1150280297Sjkim int ret; 1151280297Sjkim LPSTR provname = NULL; 1152280297Sjkim CAPI_trace(ctx, "capi_list_providers\n"); 1153280297Sjkim BIO_printf(out, "Available CSPs:\n"); 1154280297Sjkim for (idx = 0;; idx++) { 1155280297Sjkim ret = capi_get_provname(ctx, &provname, &ptype, idx); 1156280297Sjkim if (ret == 2) 1157280297Sjkim break; 1158280297Sjkim if (ret == 0) 1159280297Sjkim break; 1160280297Sjkim BIO_printf(out, "%d. %s, type %d\n", idx, provname, ptype); 1161280297Sjkim OPENSSL_free(provname); 1162280297Sjkim } 1163280297Sjkim return 1; 1164280297Sjkim} 1165183234Ssimon 1166280297Sjkimstatic int capi_list_containers(CAPI_CTX * ctx, BIO *out) 1167280297Sjkim{ 1168280297Sjkim int ret = 1; 1169280297Sjkim HCRYPTPROV hprov; 1170280297Sjkim DWORD err, idx, flags, buflen = 0, clen; 1171280297Sjkim LPSTR cname; 1172290207Sjkim LPTSTR cspname = NULL; 1173290207Sjkim 1174280297Sjkim CAPI_trace(ctx, "Listing containers CSP=%s, type = %d\n", ctx->cspname, 1175280297Sjkim ctx->csptype); 1176290207Sjkim if (ctx->cspname && sizeof(TCHAR) != sizeof(char)) { 1177290207Sjkim if ((clen = 1178290207Sjkim MultiByteToWideChar(CP_ACP, 0, ctx->cspname, -1, NULL, 0))) { 1179290207Sjkim cspname = alloca(clen * sizeof(WCHAR)); 1180290207Sjkim MultiByteToWideChar(CP_ACP, 0, ctx->cspname, -1, (WCHAR *)cspname, 1181290207Sjkim clen); 1182290207Sjkim } 1183290207Sjkim if (!cspname) { 1184290207Sjkim CAPIerr(CAPI_F_CAPI_LIST_CONTAINERS, ERR_R_MALLOC_FAILURE); 1185290207Sjkim capi_addlasterror(); 1186290207Sjkim return 0; 1187290207Sjkim } 1188290207Sjkim } else 1189290207Sjkim cspname = (TCHAR *)ctx->cspname; 1190290207Sjkim if (!CryptAcquireContext 1191290207Sjkim (&hprov, NULL, cspname, ctx->csptype, CRYPT_VERIFYCONTEXT)) { 1192280297Sjkim CAPIerr(CAPI_F_CAPI_LIST_CONTAINERS, 1193280297Sjkim CAPI_R_CRYPTACQUIRECONTEXT_ERROR); 1194280297Sjkim capi_addlasterror(); 1195280297Sjkim return 0; 1196280297Sjkim } 1197280297Sjkim if (!CryptGetProvParam 1198280297Sjkim (hprov, PP_ENUMCONTAINERS, NULL, &buflen, CRYPT_FIRST)) { 1199280297Sjkim CAPIerr(CAPI_F_CAPI_LIST_CONTAINERS, CAPI_R_ENUMCONTAINERS_ERROR); 1200280297Sjkim capi_addlasterror(); 1201280297Sjkim CryptReleaseContext(hprov, 0); 1202280297Sjkim return 0; 1203280297Sjkim } 1204280297Sjkim CAPI_trace(ctx, "Got max container len %d\n", buflen); 1205280297Sjkim if (buflen == 0) 1206280297Sjkim buflen = 1024; 1207280297Sjkim cname = OPENSSL_malloc(buflen); 1208280297Sjkim if (!cname) { 1209280297Sjkim CAPIerr(CAPI_F_CAPI_LIST_CONTAINERS, ERR_R_MALLOC_FAILURE); 1210280297Sjkim goto err; 1211280297Sjkim } 1212183234Ssimon 1213280297Sjkim for (idx = 0;; idx++) { 1214280297Sjkim clen = buflen; 1215280297Sjkim cname[0] = 0; 1216183234Ssimon 1217280297Sjkim if (idx == 0) 1218280297Sjkim flags = CRYPT_FIRST; 1219280297Sjkim else 1220280297Sjkim flags = 0; 1221290207Sjkim if (!CryptGetProvParam 1222290207Sjkim (hprov, PP_ENUMCONTAINERS, (BYTE *) cname, &clen, flags)) { 1223280297Sjkim err = GetLastError(); 1224280297Sjkim if (err == ERROR_NO_MORE_ITEMS) 1225280297Sjkim goto done; 1226280297Sjkim CAPIerr(CAPI_F_CAPI_LIST_CONTAINERS, CAPI_R_ENUMCONTAINERS_ERROR); 1227280297Sjkim capi_adderror(err); 1228280297Sjkim goto err; 1229280297Sjkim } 1230280297Sjkim CAPI_trace(ctx, "Container name %s, len=%d, index=%d, flags=%d\n", 1231280297Sjkim cname, clen, idx, flags); 1232280297Sjkim if (!cname[0] && (clen == buflen)) { 1233280297Sjkim CAPI_trace(ctx, "Enumerate bug: using workaround\n"); 1234280297Sjkim goto done; 1235280297Sjkim } 1236280297Sjkim BIO_printf(out, "%d. %s\n", idx, cname); 1237280297Sjkim } 1238280297Sjkim err: 1239183234Ssimon 1240280297Sjkim ret = 0; 1241183234Ssimon 1242280297Sjkim done: 1243280297Sjkim if (cname) 1244280297Sjkim OPENSSL_free(cname); 1245280297Sjkim CryptReleaseContext(hprov, 0); 1246183234Ssimon 1247280297Sjkim return ret; 1248280297Sjkim} 1249183234Ssimon 1250280297SjkimCRYPT_KEY_PROV_INFO *capi_get_prov_info(CAPI_CTX * ctx, PCCERT_CONTEXT cert) 1251280297Sjkim{ 1252280297Sjkim DWORD len; 1253280297Sjkim CRYPT_KEY_PROV_INFO *pinfo; 1254183234Ssimon 1255280297Sjkim if (!CertGetCertificateContextProperty 1256280297Sjkim (cert, CERT_KEY_PROV_INFO_PROP_ID, NULL, &len)) 1257280297Sjkim return NULL; 1258280297Sjkim pinfo = OPENSSL_malloc(len); 1259280297Sjkim if (!pinfo) { 1260280297Sjkim CAPIerr(CAPI_F_CAPI_GET_PROV_INFO, ERR_R_MALLOC_FAILURE); 1261280297Sjkim return NULL; 1262280297Sjkim } 1263280297Sjkim if (!CertGetCertificateContextProperty 1264280297Sjkim (cert, CERT_KEY_PROV_INFO_PROP_ID, pinfo, &len)) { 1265280297Sjkim CAPIerr(CAPI_F_CAPI_GET_PROV_INFO, 1266280297Sjkim CAPI_R_ERROR_GETTING_KEY_PROVIDER_INFO); 1267280297Sjkim capi_addlasterror(); 1268280297Sjkim OPENSSL_free(pinfo); 1269280297Sjkim return NULL; 1270280297Sjkim } 1271280297Sjkim return pinfo; 1272280297Sjkim} 1273183234Ssimon 1274280297Sjkimstatic void capi_dump_prov_info(CAPI_CTX * ctx, BIO *out, 1275280297Sjkim CRYPT_KEY_PROV_INFO * pinfo) 1276280297Sjkim{ 1277280297Sjkim char *provname = NULL, *contname = NULL; 1278280297Sjkim if (!pinfo) { 1279280297Sjkim BIO_printf(out, " No Private Key\n"); 1280280297Sjkim return; 1281280297Sjkim } 1282280297Sjkim provname = wide_to_asc(pinfo->pwszProvName); 1283280297Sjkim contname = wide_to_asc(pinfo->pwszContainerName); 1284280297Sjkim if (!provname || !contname) 1285280297Sjkim goto err; 1286183234Ssimon 1287280297Sjkim BIO_printf(out, " Private Key Info:\n"); 1288280297Sjkim BIO_printf(out, " Provider Name: %s, Provider Type %d\n", provname, 1289280297Sjkim pinfo->dwProvType); 1290280297Sjkim BIO_printf(out, " Container Name: %s, Key Type %d\n", contname, 1291280297Sjkim pinfo->dwKeySpec); 1292280297Sjkim err: 1293280297Sjkim if (provname) 1294280297Sjkim OPENSSL_free(provname); 1295280297Sjkim if (contname) 1296280297Sjkim OPENSSL_free(contname); 1297280297Sjkim} 1298183234Ssimon 1299280297Sjkimchar *capi_cert_get_fname(CAPI_CTX * ctx, PCCERT_CONTEXT cert) 1300280297Sjkim{ 1301280297Sjkim LPWSTR wfname; 1302280297Sjkim DWORD dlen; 1303183234Ssimon 1304280297Sjkim CAPI_trace(ctx, "capi_cert_get_fname\n"); 1305280297Sjkim if (!CertGetCertificateContextProperty 1306280297Sjkim (cert, CERT_FRIENDLY_NAME_PROP_ID, NULL, &dlen)) 1307280297Sjkim return NULL; 1308280297Sjkim wfname = OPENSSL_malloc(dlen); 1309306195Sjkim if (wfname == NULL) { 1310306195Sjkim CAPIerr(CAPI_F_CAPI_CERT_GET_FNAME, ERR_R_MALLOC_FAILURE); 1311306195Sjkim return NULL; 1312306195Sjkim } 1313280297Sjkim if (CertGetCertificateContextProperty 1314280297Sjkim (cert, CERT_FRIENDLY_NAME_PROP_ID, wfname, &dlen)) { 1315280297Sjkim char *fname = wide_to_asc(wfname); 1316280297Sjkim OPENSSL_free(wfname); 1317280297Sjkim return fname; 1318280297Sjkim } 1319280297Sjkim CAPIerr(CAPI_F_CAPI_CERT_GET_FNAME, CAPI_R_ERROR_GETTING_FRIENDLY_NAME); 1320280297Sjkim capi_addlasterror(); 1321183234Ssimon 1322280297Sjkim OPENSSL_free(wfname); 1323280297Sjkim return NULL; 1324280297Sjkim} 1325183234Ssimon 1326280297Sjkimvoid capi_dump_cert(CAPI_CTX * ctx, BIO *out, PCCERT_CONTEXT cert) 1327280297Sjkim{ 1328280297Sjkim X509 *x; 1329280297Sjkim unsigned char *p; 1330280297Sjkim unsigned long flags = ctx->dump_flags; 1331280297Sjkim if (flags & CAPI_DMP_FNAME) { 1332280297Sjkim char *fname; 1333280297Sjkim fname = capi_cert_get_fname(ctx, cert); 1334280297Sjkim if (fname) { 1335280297Sjkim BIO_printf(out, " Friendly Name \"%s\"\n", fname); 1336280297Sjkim OPENSSL_free(fname); 1337280297Sjkim } else 1338280297Sjkim BIO_printf(out, " <No Friendly Name>\n"); 1339280297Sjkim } 1340183234Ssimon 1341280297Sjkim p = cert->pbCertEncoded; 1342280297Sjkim x = d2i_X509(NULL, &p, cert->cbCertEncoded); 1343280297Sjkim if (!x) 1344280297Sjkim BIO_printf(out, " <Can't parse certificate>\n"); 1345280297Sjkim if (flags & CAPI_DMP_SUMMARY) { 1346280297Sjkim BIO_printf(out, " Subject: "); 1347280297Sjkim X509_NAME_print_ex(out, X509_get_subject_name(x), 0, XN_FLAG_ONELINE); 1348280297Sjkim BIO_printf(out, "\n Issuer: "); 1349280297Sjkim X509_NAME_print_ex(out, X509_get_issuer_name(x), 0, XN_FLAG_ONELINE); 1350280297Sjkim BIO_printf(out, "\n"); 1351280297Sjkim } 1352280297Sjkim if (flags & CAPI_DMP_FULL) 1353280297Sjkim X509_print_ex(out, x, XN_FLAG_ONELINE, 0); 1354183234Ssimon 1355280297Sjkim if (flags & CAPI_DMP_PKEYINFO) { 1356280297Sjkim CRYPT_KEY_PROV_INFO *pinfo; 1357280297Sjkim pinfo = capi_get_prov_info(ctx, cert); 1358280297Sjkim capi_dump_prov_info(ctx, out, pinfo); 1359280297Sjkim if (pinfo) 1360280297Sjkim OPENSSL_free(pinfo); 1361280297Sjkim } 1362183234Ssimon 1363280297Sjkim if (flags & CAPI_DMP_PEM) 1364280297Sjkim PEM_write_bio_X509(out, x); 1365280297Sjkim X509_free(x); 1366280297Sjkim} 1367183234Ssimon 1368280297SjkimHCERTSTORE capi_open_store(CAPI_CTX * ctx, char *storename) 1369280297Sjkim{ 1370280297Sjkim HCERTSTORE hstore; 1371183234Ssimon 1372280297Sjkim if (!storename) 1373280297Sjkim storename = ctx->storename; 1374280297Sjkim if (!storename) 1375280297Sjkim storename = "MY"; 1376280297Sjkim CAPI_trace(ctx, "Opening certificate store %s\n", storename); 1377183234Ssimon 1378280297Sjkim hstore = CertOpenStore(CERT_STORE_PROV_SYSTEM_A, 0, 0, 1379280297Sjkim ctx->store_flags, storename); 1380280297Sjkim if (!hstore) { 1381280297Sjkim CAPIerr(CAPI_F_CAPI_OPEN_STORE, CAPI_R_ERROR_OPENING_STORE); 1382280297Sjkim capi_addlasterror(); 1383280297Sjkim } 1384280297Sjkim return hstore; 1385280297Sjkim} 1386183234Ssimon 1387280297Sjkimint capi_list_certs(CAPI_CTX * ctx, BIO *out, char *id) 1388280297Sjkim{ 1389280297Sjkim char *storename; 1390280297Sjkim int idx; 1391280297Sjkim int ret = 1; 1392280297Sjkim HCERTSTORE hstore; 1393280297Sjkim PCCERT_CONTEXT cert = NULL; 1394183234Ssimon 1395280297Sjkim storename = ctx->storename; 1396280297Sjkim if (!storename) 1397280297Sjkim storename = "MY"; 1398280297Sjkim CAPI_trace(ctx, "Listing certs for store %s\n", storename); 1399183234Ssimon 1400280297Sjkim hstore = capi_open_store(ctx, storename); 1401280297Sjkim if (!hstore) 1402280297Sjkim return 0; 1403280297Sjkim if (id) { 1404280297Sjkim cert = capi_find_cert(ctx, id, hstore); 1405280297Sjkim if (!cert) { 1406280297Sjkim ret = 0; 1407280297Sjkim goto err; 1408280297Sjkim } 1409280297Sjkim capi_dump_cert(ctx, out, cert); 1410280297Sjkim CertFreeCertificateContext(cert); 1411280297Sjkim } else { 1412280297Sjkim for (idx = 0;; idx++) { 1413280297Sjkim cert = CertEnumCertificatesInStore(hstore, cert); 1414280297Sjkim if (!cert) 1415280297Sjkim break; 1416280297Sjkim BIO_printf(out, "Certificate %d\n", idx); 1417280297Sjkim capi_dump_cert(ctx, out, cert); 1418280297Sjkim } 1419280297Sjkim } 1420280297Sjkim err: 1421280297Sjkim CertCloseStore(hstore, 0); 1422280297Sjkim return ret; 1423280297Sjkim} 1424183234Ssimon 1425280297Sjkimstatic PCCERT_CONTEXT capi_find_cert(CAPI_CTX * ctx, const char *id, 1426280297Sjkim HCERTSTORE hstore) 1427280297Sjkim{ 1428280297Sjkim PCCERT_CONTEXT cert = NULL; 1429280297Sjkim char *fname = NULL; 1430280297Sjkim int match; 1431280297Sjkim switch (ctx->lookup_method) { 1432280297Sjkim case CAPI_LU_SUBSTR: 1433280297Sjkim return CertFindCertificateInStore(hstore, 1434280297Sjkim X509_ASN_ENCODING, 0, 1435280297Sjkim CERT_FIND_SUBJECT_STR_A, id, NULL); 1436280297Sjkim case CAPI_LU_FNAME: 1437280297Sjkim for (;;) { 1438280297Sjkim cert = CertEnumCertificatesInStore(hstore, cert); 1439280297Sjkim if (!cert) 1440280297Sjkim return NULL; 1441280297Sjkim fname = capi_cert_get_fname(ctx, cert); 1442280297Sjkim if (fname) { 1443280297Sjkim if (strcmp(fname, id)) 1444280297Sjkim match = 0; 1445280297Sjkim else 1446280297Sjkim match = 1; 1447280297Sjkim OPENSSL_free(fname); 1448280297Sjkim if (match) 1449280297Sjkim return cert; 1450280297Sjkim } 1451280297Sjkim } 1452280297Sjkim default: 1453280297Sjkim return NULL; 1454280297Sjkim } 1455280297Sjkim} 1456183234Ssimon 1457290207Sjkimstatic CAPI_KEY *capi_get_key(CAPI_CTX * ctx, const TCHAR *contname, 1458290207Sjkim TCHAR *provname, DWORD ptype, DWORD keyspec) 1459280297Sjkim{ 1460280297Sjkim CAPI_KEY *key; 1461280297Sjkim DWORD dwFlags = 0; 1462280297Sjkim key = OPENSSL_malloc(sizeof(CAPI_KEY)); 1463306195Sjkim if (key == NULL) { 1464306195Sjkim CAPIerr(CAPI_F_CAPI_GET_KEY, ERR_R_MALLOC_FAILURE); 1465306195Sjkim capi_addlasterror(); 1466306195Sjkim goto err; 1467306195Sjkim } 1468290207Sjkim if (sizeof(TCHAR) == sizeof(char)) 1469290207Sjkim CAPI_trace(ctx, "capi_get_key, contname=%s, provname=%s, type=%d\n", 1470290207Sjkim contname, provname, ptype); 1471290207Sjkim else if (ctx && ctx->debug_level >= CAPI_DBG_TRACE && ctx->debug_file) { 1472290207Sjkim /* above 'if' is optimization to minimize malloc-ations */ 1473290207Sjkim char *_contname = wide_to_asc((WCHAR *)contname); 1474290207Sjkim char *_provname = wide_to_asc((WCHAR *)provname); 1475290207Sjkim 1476290207Sjkim CAPI_trace(ctx, "capi_get_key, contname=%s, provname=%s, type=%d\n", 1477290207Sjkim _contname, _provname, ptype); 1478290207Sjkim if (_provname) 1479290207Sjkim OPENSSL_free(_provname); 1480290207Sjkim if (_contname) 1481290207Sjkim OPENSSL_free(_contname); 1482290207Sjkim } 1483280297Sjkim if (ctx->store_flags & CERT_SYSTEM_STORE_LOCAL_MACHINE) 1484246772Sjkim dwFlags = CRYPT_MACHINE_KEYSET; 1485290207Sjkim if (!CryptAcquireContext(&key->hprov, contname, provname, ptype, dwFlags)) { 1486280297Sjkim CAPIerr(CAPI_F_CAPI_GET_KEY, CAPI_R_CRYPTACQUIRECONTEXT_ERROR); 1487280297Sjkim capi_addlasterror(); 1488280297Sjkim goto err; 1489280297Sjkim } 1490280297Sjkim if (!CryptGetUserKey(key->hprov, keyspec, &key->key)) { 1491280297Sjkim CAPIerr(CAPI_F_CAPI_GET_KEY, CAPI_R_GETUSERKEY_ERROR); 1492280297Sjkim capi_addlasterror(); 1493280297Sjkim CryptReleaseContext(key->hprov, 0); 1494280297Sjkim goto err; 1495280297Sjkim } 1496280297Sjkim key->keyspec = keyspec; 1497280297Sjkim key->pcert = NULL; 1498280297Sjkim return key; 1499183234Ssimon 1500280297Sjkim err: 1501280297Sjkim OPENSSL_free(key); 1502280297Sjkim return NULL; 1503280297Sjkim} 1504183234Ssimon 1505280297Sjkimstatic CAPI_KEY *capi_get_cert_key(CAPI_CTX * ctx, PCCERT_CONTEXT cert) 1506280297Sjkim{ 1507280297Sjkim CAPI_KEY *key = NULL; 1508280297Sjkim CRYPT_KEY_PROV_INFO *pinfo = NULL; 1509280297Sjkim char *provname = NULL, *contname = NULL; 1510280297Sjkim pinfo = capi_get_prov_info(ctx, cert); 1511280297Sjkim if (!pinfo) 1512280297Sjkim goto err; 1513290207Sjkim if (sizeof(TCHAR) != sizeof(char)) 1514290207Sjkim key = capi_get_key(ctx, (TCHAR *)pinfo->pwszContainerName, 1515290207Sjkim (TCHAR *)pinfo->pwszProvName, 1516290207Sjkim pinfo->dwProvType, pinfo->dwKeySpec); 1517290207Sjkim else { 1518290207Sjkim provname = wide_to_asc(pinfo->pwszProvName); 1519290207Sjkim contname = wide_to_asc(pinfo->pwszContainerName); 1520290207Sjkim if (!provname || !contname) 1521290207Sjkim goto err; 1522290207Sjkim key = capi_get_key(ctx, (TCHAR *)contname, (TCHAR *)provname, 1523290207Sjkim pinfo->dwProvType, pinfo->dwKeySpec); 1524290207Sjkim } 1525183234Ssimon 1526280297Sjkim err: 1527280297Sjkim if (pinfo) 1528280297Sjkim OPENSSL_free(pinfo); 1529280297Sjkim if (provname) 1530280297Sjkim OPENSSL_free(provname); 1531280297Sjkim if (contname) 1532280297Sjkim OPENSSL_free(contname); 1533280297Sjkim return key; 1534280297Sjkim} 1535183234Ssimon 1536280297SjkimCAPI_KEY *capi_find_key(CAPI_CTX * ctx, const char *id) 1537280297Sjkim{ 1538280297Sjkim PCCERT_CONTEXT cert; 1539280297Sjkim HCERTSTORE hstore; 1540280297Sjkim CAPI_KEY *key = NULL; 1541280297Sjkim switch (ctx->lookup_method) { 1542280297Sjkim case CAPI_LU_SUBSTR: 1543280297Sjkim case CAPI_LU_FNAME: 1544280297Sjkim hstore = capi_open_store(ctx, NULL); 1545280297Sjkim if (!hstore) 1546280297Sjkim return NULL; 1547280297Sjkim cert = capi_find_cert(ctx, id, hstore); 1548280297Sjkim if (cert) { 1549280297Sjkim key = capi_get_cert_key(ctx, cert); 1550280297Sjkim CertFreeCertificateContext(cert); 1551280297Sjkim } 1552280297Sjkim CertCloseStore(hstore, 0); 1553280297Sjkim break; 1554183234Ssimon 1555280297Sjkim case CAPI_LU_CONTNAME: 1556290207Sjkim if (sizeof(TCHAR) != sizeof(char)) { 1557290207Sjkim WCHAR *contname, *provname; 1558290207Sjkim DWORD len; 1559290207Sjkim 1560290207Sjkim if ((len = MultiByteToWideChar(CP_ACP, 0, id, -1, NULL, 0)) && 1561290207Sjkim (contname = alloca(len * sizeof(WCHAR)), 1562290207Sjkim MultiByteToWideChar(CP_ACP, 0, id, -1, contname, len)) && 1563290207Sjkim (len = 1564290207Sjkim MultiByteToWideChar(CP_ACP, 0, ctx->cspname, -1, NULL, 0)) 1565290207Sjkim && (provname = 1566290207Sjkim alloca(len * sizeof(WCHAR)), MultiByteToWideChar(CP_ACP, 1567290207Sjkim 0, 1568290207Sjkim ctx->cspname, 1569290207Sjkim -1, 1570290207Sjkim provname, 1571290207Sjkim len))) 1572290207Sjkim key = 1573290207Sjkim capi_get_key(ctx, (TCHAR *)contname, (TCHAR *)provname, 1574290207Sjkim ctx->csptype, ctx->keytype); 1575290207Sjkim } else 1576290207Sjkim key = capi_get_key(ctx, (TCHAR *)id, 1577290207Sjkim (TCHAR *)ctx->cspname, 1578290207Sjkim ctx->csptype, ctx->keytype); 1579280297Sjkim break; 1580280297Sjkim } 1581183234Ssimon 1582280297Sjkim return key; 1583280297Sjkim} 1584183234Ssimon 1585280297Sjkimvoid capi_free_key(CAPI_KEY * key) 1586280297Sjkim{ 1587280297Sjkim if (!key) 1588280297Sjkim return; 1589280297Sjkim CryptDestroyKey(key->key); 1590280297Sjkim CryptReleaseContext(key->hprov, 0); 1591280297Sjkim if (key->pcert) 1592280297Sjkim CertFreeCertificateContext(key->pcert); 1593280297Sjkim OPENSSL_free(key); 1594280297Sjkim} 1595183234Ssimon 1596183234Ssimon/* Initialize a CAPI_CTX structure */ 1597183234Ssimon 1598183234Ssimonstatic CAPI_CTX *capi_ctx_new() 1599280297Sjkim{ 1600280297Sjkim CAPI_CTX *ctx; 1601280297Sjkim ctx = OPENSSL_malloc(sizeof(CAPI_CTX)); 1602280297Sjkim if (!ctx) { 1603280297Sjkim CAPIerr(CAPI_F_CAPI_CTX_NEW, ERR_R_MALLOC_FAILURE); 1604280297Sjkim return NULL; 1605280297Sjkim } 1606280297Sjkim ctx->cspname = NULL; 1607280297Sjkim ctx->csptype = PROV_RSA_FULL; 1608280297Sjkim ctx->dump_flags = CAPI_DMP_SUMMARY | CAPI_DMP_FNAME; 1609280297Sjkim ctx->keytype = AT_KEYEXCHANGE; 1610280297Sjkim ctx->storename = NULL; 1611280297Sjkim ctx->ssl_client_store = NULL; 1612280297Sjkim ctx->store_flags = CERT_STORE_OPEN_EXISTING_FLAG | 1613280297Sjkim CERT_STORE_READONLY_FLAG | CERT_SYSTEM_STORE_CURRENT_USER; 1614280297Sjkim ctx->lookup_method = CAPI_LU_SUBSTR; 1615280297Sjkim ctx->debug_level = 0; 1616280297Sjkim ctx->debug_file = NULL; 1617280297Sjkim ctx->client_cert_select = cert_select_simple; 1618280297Sjkim return ctx; 1619280297Sjkim} 1620183234Ssimon 1621280297Sjkimstatic void capi_ctx_free(CAPI_CTX * ctx) 1622280297Sjkim{ 1623280297Sjkim CAPI_trace(ctx, "Calling capi_ctx_free with %lx\n", ctx); 1624280297Sjkim if (!ctx) 1625280297Sjkim return; 1626280297Sjkim if (ctx->cspname) 1627280297Sjkim OPENSSL_free(ctx->cspname); 1628280297Sjkim if (ctx->debug_file) 1629280297Sjkim OPENSSL_free(ctx->debug_file); 1630280297Sjkim if (ctx->storename) 1631280297Sjkim OPENSSL_free(ctx->storename); 1632280297Sjkim if (ctx->ssl_client_store) 1633280297Sjkim OPENSSL_free(ctx->ssl_client_store); 1634280297Sjkim OPENSSL_free(ctx); 1635280297Sjkim} 1636183234Ssimon 1637280297Sjkimstatic int capi_ctx_set_provname(CAPI_CTX * ctx, LPSTR pname, DWORD type, 1638280297Sjkim int check) 1639280297Sjkim{ 1640280297Sjkim CAPI_trace(ctx, "capi_ctx_set_provname, name=%s, type=%d\n", pname, type); 1641280297Sjkim if (check) { 1642280297Sjkim HCRYPTPROV hprov; 1643290207Sjkim LPTSTR name = NULL; 1644290207Sjkim 1645290207Sjkim if (sizeof(TCHAR) != sizeof(char)) { 1646290207Sjkim DWORD len; 1647290207Sjkim if ((len = MultiByteToWideChar(CP_ACP, 0, pname, -1, NULL, 0))) { 1648290207Sjkim name = alloca(len * sizeof(WCHAR)); 1649290207Sjkim MultiByteToWideChar(CP_ACP, 0, pname, -1, (WCHAR *)name, len); 1650290207Sjkim } 1651290207Sjkim } else 1652290207Sjkim name = (TCHAR *)pname; 1653290207Sjkim 1654290207Sjkim if (!name || !CryptAcquireContext(&hprov, NULL, name, type, 1655290207Sjkim CRYPT_VERIFYCONTEXT)) { 1656280297Sjkim CAPIerr(CAPI_F_CAPI_CTX_SET_PROVNAME, 1657280297Sjkim CAPI_R_CRYPTACQUIRECONTEXT_ERROR); 1658280297Sjkim capi_addlasterror(); 1659280297Sjkim return 0; 1660280297Sjkim } 1661280297Sjkim CryptReleaseContext(hprov, 0); 1662280297Sjkim } 1663280297Sjkim if (ctx->cspname) 1664280297Sjkim OPENSSL_free(ctx->cspname); 1665280297Sjkim ctx->cspname = BUF_strdup(pname); 1666280297Sjkim ctx->csptype = type; 1667280297Sjkim return 1; 1668280297Sjkim} 1669183234Ssimon 1670280297Sjkimstatic int capi_ctx_set_provname_idx(CAPI_CTX * ctx, int idx) 1671280297Sjkim{ 1672280297Sjkim LPSTR pname; 1673280297Sjkim DWORD type; 1674280297Sjkim int res; 1675280297Sjkim if (capi_get_provname(ctx, &pname, &type, idx) != 1) 1676280297Sjkim return 0; 1677280297Sjkim res = capi_ctx_set_provname(ctx, pname, type, 0); 1678280297Sjkim OPENSSL_free(pname); 1679280297Sjkim return res; 1680280297Sjkim} 1681183234Ssimon 1682183234Ssimonstatic int cert_issuer_match(STACK_OF(X509_NAME) *ca_dn, X509 *x) 1683280297Sjkim{ 1684280297Sjkim int i; 1685280297Sjkim X509_NAME *nm; 1686280297Sjkim /* Special case: empty list: match anything */ 1687280297Sjkim if (sk_X509_NAME_num(ca_dn) <= 0) 1688280297Sjkim return 1; 1689280297Sjkim for (i = 0; i < sk_X509_NAME_num(ca_dn); i++) { 1690280297Sjkim nm = sk_X509_NAME_value(ca_dn, i); 1691280297Sjkim if (!X509_NAME_cmp(nm, X509_get_issuer_name(x))) 1692280297Sjkim return 1; 1693280297Sjkim } 1694280297Sjkim return 0; 1695280297Sjkim} 1696183234Ssimon 1697183234Ssimonstatic int capi_load_ssl_client_cert(ENGINE *e, SSL *ssl, 1698280297Sjkim STACK_OF(X509_NAME) *ca_dn, X509 **pcert, 1699280297Sjkim EVP_PKEY **pkey, STACK_OF(X509) **pother, 1700280297Sjkim UI_METHOD *ui_method, 1701280297Sjkim void *callback_data) 1702280297Sjkim{ 1703280297Sjkim STACK_OF(X509) *certs = NULL; 1704280297Sjkim X509 *x; 1705280297Sjkim char *storename; 1706280297Sjkim const char *p; 1707280297Sjkim int i, client_cert_idx; 1708280297Sjkim HCERTSTORE hstore; 1709280297Sjkim PCCERT_CONTEXT cert = NULL, excert = NULL; 1710280297Sjkim CAPI_CTX *ctx; 1711280297Sjkim CAPI_KEY *key; 1712280297Sjkim ctx = ENGINE_get_ex_data(e, capi_idx); 1713183234Ssimon 1714280297Sjkim *pcert = NULL; 1715280297Sjkim *pkey = NULL; 1716183234Ssimon 1717280297Sjkim storename = ctx->ssl_client_store; 1718280297Sjkim if (!storename) 1719280297Sjkim storename = "MY"; 1720183234Ssimon 1721280297Sjkim hstore = capi_open_store(ctx, storename); 1722280297Sjkim if (!hstore) 1723280297Sjkim return 0; 1724280297Sjkim /* Enumerate all certificates collect any matches */ 1725280297Sjkim for (i = 0;; i++) { 1726280297Sjkim cert = CertEnumCertificatesInStore(hstore, cert); 1727280297Sjkim if (!cert) 1728280297Sjkim break; 1729280297Sjkim p = cert->pbCertEncoded; 1730280297Sjkim x = d2i_X509(NULL, &p, cert->cbCertEncoded); 1731280297Sjkim if (!x) { 1732280297Sjkim CAPI_trace(ctx, "Can't Parse Certificate %d\n", i); 1733280297Sjkim continue; 1734280297Sjkim } 1735280297Sjkim if (cert_issuer_match(ca_dn, x) 1736280297Sjkim && X509_check_purpose(x, X509_PURPOSE_SSL_CLIENT, 0)) { 1737280297Sjkim key = capi_get_cert_key(ctx, cert); 1738280297Sjkim if (!key) { 1739280297Sjkim X509_free(x); 1740280297Sjkim continue; 1741280297Sjkim } 1742280297Sjkim /* 1743280297Sjkim * Match found: attach extra data to it so we can retrieve the 1744280297Sjkim * key later. 1745280297Sjkim */ 1746280297Sjkim excert = CertDuplicateCertificateContext(cert); 1747280297Sjkim key->pcert = excert; 1748280297Sjkim X509_set_ex_data(x, cert_capi_idx, key); 1749183234Ssimon 1750280297Sjkim if (!certs) 1751280297Sjkim certs = sk_X509_new_null(); 1752183234Ssimon 1753280297Sjkim sk_X509_push(certs, x); 1754280297Sjkim } else 1755280297Sjkim X509_free(x); 1756183234Ssimon 1757280297Sjkim } 1758183234Ssimon 1759280297Sjkim if (cert) 1760280297Sjkim CertFreeCertificateContext(cert); 1761280297Sjkim if (hstore) 1762280297Sjkim CertCloseStore(hstore, 0); 1763183234Ssimon 1764280297Sjkim if (!certs) 1765280297Sjkim return 0; 1766183234Ssimon 1767280297Sjkim /* Select the appropriate certificate */ 1768183234Ssimon 1769280297Sjkim client_cert_idx = ctx->client_cert_select(e, ssl, certs); 1770183234Ssimon 1771280297Sjkim /* Set the selected certificate and free the rest */ 1772183234Ssimon 1773280297Sjkim for (i = 0; i < sk_X509_num(certs); i++) { 1774280297Sjkim x = sk_X509_value(certs, i); 1775280297Sjkim if (i == client_cert_idx) 1776280297Sjkim *pcert = x; 1777280297Sjkim else { 1778280297Sjkim key = X509_get_ex_data(x, cert_capi_idx); 1779280297Sjkim capi_free_key(key); 1780280297Sjkim X509_free(x); 1781280297Sjkim } 1782280297Sjkim } 1783183234Ssimon 1784280297Sjkim sk_X509_free(certs); 1785183234Ssimon 1786280297Sjkim if (!*pcert) 1787280297Sjkim return 0; 1788183234Ssimon 1789280297Sjkim /* Setup key for selected certificate */ 1790183234Ssimon 1791280297Sjkim key = X509_get_ex_data(*pcert, cert_capi_idx); 1792280297Sjkim *pkey = capi_get_pkey(e, key); 1793280297Sjkim X509_set_ex_data(*pcert, cert_capi_idx, NULL); 1794183234Ssimon 1795280297Sjkim return 1; 1796183234Ssimon 1797280297Sjkim} 1798183234Ssimon 1799183234Ssimon/* Simple client cert selection function: always select first */ 1800183234Ssimon 1801183234Ssimonstatic int cert_select_simple(ENGINE *e, SSL *ssl, STACK_OF(X509) *certs) 1802280297Sjkim{ 1803280297Sjkim return 0; 1804280297Sjkim} 1805183234Ssimon 1806280297Sjkim# ifdef OPENSSL_CAPIENG_DIALOG 1807183234Ssimon 1808280297Sjkim/* 1809280297Sjkim * More complex cert selection function, using standard function 1810183234Ssimon * CryptUIDlgSelectCertificateFromStore() to produce a dialog box. 1811183234Ssimon */ 1812183234Ssimon 1813280297Sjkim/* 1814280297Sjkim * Definitions which are in cryptuiapi.h but this is not present in older 1815183234Ssimon * versions of headers. 1816183234Ssimon */ 1817183234Ssimon 1818280297Sjkim# ifndef CRYPTUI_SELECT_LOCATION_COLUMN 1819280297Sjkim# define CRYPTUI_SELECT_LOCATION_COLUMN 0x000000010 1820280297Sjkim# define CRYPTUI_SELECT_INTENDEDUSE_COLUMN 0x000000004 1821280297Sjkim# endif 1822183234Ssimon 1823280297Sjkim# define dlg_title L"OpenSSL Application SSL Client Certificate Selection" 1824280297Sjkim# define dlg_prompt L"Select a certificate to use for authentication" 1825280297Sjkim# define dlg_columns CRYPTUI_SELECT_LOCATION_COLUMN \ 1826280297Sjkim |CRYPTUI_SELECT_INTENDEDUSE_COLUMN 1827183234Ssimon 1828183234Ssimonstatic int cert_select_dialog(ENGINE *e, SSL *ssl, STACK_OF(X509) *certs) 1829280297Sjkim{ 1830280297Sjkim X509 *x; 1831280297Sjkim HCERTSTORE dstore; 1832280297Sjkim PCCERT_CONTEXT cert; 1833280297Sjkim CAPI_CTX *ctx; 1834280297Sjkim CAPI_KEY *key; 1835280297Sjkim HWND hwnd; 1836280297Sjkim int i, idx = -1; 1837280297Sjkim if (sk_X509_num(certs) == 1) 1838280297Sjkim return 0; 1839280297Sjkim ctx = ENGINE_get_ex_data(e, capi_idx); 1840280297Sjkim /* Create an in memory store of certificates */ 1841280297Sjkim dstore = CertOpenStore(CERT_STORE_PROV_MEMORY, 0, 0, 1842280297Sjkim CERT_STORE_CREATE_NEW_FLAG, NULL); 1843280297Sjkim if (!dstore) { 1844280297Sjkim CAPIerr(CAPI_F_CERT_SELECT_DIALOG, CAPI_R_ERROR_CREATING_STORE); 1845280297Sjkim capi_addlasterror(); 1846280297Sjkim goto err; 1847280297Sjkim } 1848280297Sjkim /* Add all certificates to store */ 1849280297Sjkim for (i = 0; i < sk_X509_num(certs); i++) { 1850280297Sjkim x = sk_X509_value(certs, i); 1851280297Sjkim key = X509_get_ex_data(x, cert_capi_idx); 1852183234Ssimon 1853280297Sjkim if (!CertAddCertificateContextToStore(dstore, key->pcert, 1854280297Sjkim CERT_STORE_ADD_NEW, NULL)) { 1855280297Sjkim CAPIerr(CAPI_F_CERT_SELECT_DIALOG, CAPI_R_ERROR_ADDING_CERT); 1856280297Sjkim capi_addlasterror(); 1857280297Sjkim goto err; 1858280297Sjkim } 1859183234Ssimon 1860280297Sjkim } 1861280297Sjkim hwnd = GetForegroundWindow(); 1862280297Sjkim if (!hwnd) 1863280297Sjkim hwnd = GetActiveWindow(); 1864280297Sjkim if (!hwnd && ctx->getconswindow) 1865280297Sjkim hwnd = ctx->getconswindow(); 1866280297Sjkim /* Call dialog to select one */ 1867280297Sjkim cert = ctx->certselectdlg(dstore, hwnd, dlg_title, dlg_prompt, 1868280297Sjkim dlg_columns, 0, NULL); 1869183234Ssimon 1870280297Sjkim /* Find matching cert from list */ 1871280297Sjkim if (cert) { 1872280297Sjkim for (i = 0; i < sk_X509_num(certs); i++) { 1873280297Sjkim x = sk_X509_value(certs, i); 1874280297Sjkim key = X509_get_ex_data(x, cert_capi_idx); 1875280297Sjkim if (CertCompareCertificate 1876280297Sjkim (X509_ASN_ENCODING | PKCS_7_ASN_ENCODING, cert->pCertInfo, 1877280297Sjkim key->pcert->pCertInfo)) { 1878280297Sjkim idx = i; 1879280297Sjkim break; 1880280297Sjkim } 1881280297Sjkim } 1882280297Sjkim } 1883183234Ssimon 1884280297Sjkim err: 1885280297Sjkim if (dstore) 1886280297Sjkim CertCloseStore(dstore, 0); 1887280297Sjkim return idx; 1888183234Ssimon 1889280297Sjkim} 1890280297Sjkim# endif 1891183234Ssimon 1892280297Sjkim#else /* !__COMPILE_CAPIENG */ 1893280297Sjkim# include <openssl/engine.h> 1894280297Sjkim# ifndef OPENSSL_NO_DYNAMIC_ENGINE 1895183234SsimonOPENSSL_EXPORT 1896280297Sjkim int bind_engine(ENGINE *e, const char *id, const dynamic_fns *fns); 1897238405SjkimOPENSSL_EXPORT 1898280297Sjkim int bind_engine(ENGINE *e, const char *id, const dynamic_fns *fns) 1899280297Sjkim{ 1900280297Sjkim return 0; 1901280297Sjkim} 1902280297Sjkim 1903183234SsimonIMPLEMENT_DYNAMIC_CHECK_FN() 1904280297Sjkim# else 1905280297Sjkimvoid ENGINE_load_capi(void) 1906280297Sjkim{ 1907280297Sjkim} 1908280297Sjkim# endif 1909183234Ssimon#endif 1910