1183234Ssimon/* engines/e_capi.c */ 2280304Sjkim/* 3280304Sjkim * Written by Dr Stephen N Henson (steve@openssl.org) for the OpenSSL 4183234Ssimon * project. 5183234Ssimon */ 6183234Ssimon/* ==================================================================== 7183234Ssimon * Copyright (c) 2008 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 14280304Sjkim * 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> 57183234Ssimon#include <openssl/crypto.h> 58183234Ssimon#include <openssl/buffer.h> 59183234Ssimon#include <openssl/bn.h> 60183234Ssimon 61183234Ssimon#ifdef OPENSSL_SYS_WIN32 62280304Sjkim# ifndef OPENSSL_NO_CAPIENG 63183234Ssimon 64280304Sjkim# include <openssl/rsa.h> 65183234Ssimon 66280304Sjkim# include <windows.h> 67183234Ssimon 68280304Sjkim# ifndef _WIN32_WINNT 69280304Sjkim# define _WIN32_WINNT 0x0400 70280304Sjkim# endif 71183234Ssimon 72280304Sjkim# 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 */ 86280304Sjkim# if defined(CERT_KEY_PROV_INFO_PROP_ID) && \ 87238405Sjkim defined(CERT_STORE_PROV_SYSTEM_A) && \ 88238405Sjkim defined(CERT_STORE_READONLY_FLAG) 89280304Sjkim# define __COMPILE_CAPIENG 90280304Sjkim# endif /* CERT_KEY_PROV_INFO_PROP_ID */ 91280304Sjkim# endif /* OPENSSL_NO_CAPIENG */ 92280304Sjkim#endif /* OPENSSL_SYS_WIN32 */ 93238405Sjkim 94238405Sjkim#ifdef __COMPILE_CAPIENG 95238405Sjkim 96280304Sjkim# undef X509_EXTENSIONS 97280304Sjkim# undef X509_CERT_PAIR 98183234Ssimon 99183234Ssimon/* Definitions which may be missing from earlier version of headers */ 100280304Sjkim# ifndef CERT_STORE_OPEN_EXISTING_FLAG 101280304Sjkim# define CERT_STORE_OPEN_EXISTING_FLAG 0x00004000 102280304Sjkim# endif 103183234Ssimon 104280304Sjkim# ifndef CERT_STORE_CREATE_NEW_FLAG 105280304Sjkim# define CERT_STORE_CREATE_NEW_FLAG 0x00002000 106280304Sjkim# endif 107183234Ssimon 108280304Sjkim# ifndef CERT_SYSTEM_STORE_CURRENT_USER 109280304Sjkim# define CERT_SYSTEM_STORE_CURRENT_USER 0x00010000 110280304Sjkim# endif 111206046Ssimon 112280304Sjkim# include <openssl/engine.h> 113280304Sjkim# include <openssl/pem.h> 114280304Sjkim# include <openssl/x509v3.h> 115183234Ssimon 116280304Sjkim# include "e_capi_err.h" 117280304Sjkim# include "e_capi_err.c" 118183234Ssimon 119183234Ssimonstatic const char *engine_capi_id = "capi"; 120183234Ssimonstatic const char *engine_capi_name = "CryptoAPI ENGINE"; 121183234Ssimon 122183234Ssimontypedef struct CAPI_CTX_st CAPI_CTX; 123183234Ssimontypedef struct CAPI_KEY_st CAPI_KEY; 124183234Ssimon 125183234Ssimonstatic void capi_addlasterror(void); 126183234Ssimonstatic void capi_adderror(DWORD err); 127183234Ssimon 128280304Sjkimstatic void CAPI_trace(CAPI_CTX * ctx, char *format, ...); 129183234Ssimon 130280304Sjkimstatic int capi_list_providers(CAPI_CTX * ctx, BIO *out); 131280304Sjkimstatic int capi_list_containers(CAPI_CTX * ctx, BIO *out); 132280304Sjkimint capi_list_certs(CAPI_CTX * ctx, BIO *out, char *storename); 133280304Sjkimvoid capi_free_key(CAPI_KEY * key); 134183234Ssimon 135280304Sjkimstatic PCCERT_CONTEXT capi_find_cert(CAPI_CTX * ctx, const char *id, 136280304Sjkim HCERTSTORE hstore); 137183234Ssimon 138280304SjkimCAPI_KEY *capi_find_key(CAPI_CTX * ctx, const char *id); 139183234Ssimon 140183234Ssimonstatic EVP_PKEY *capi_load_privkey(ENGINE *eng, const char *key_id, 141280304Sjkim UI_METHOD *ui_method, void *callback_data); 142280304Sjkimstatic int capi_rsa_sign(int dtype, const unsigned char *m, 143280304Sjkim unsigned int m_len, unsigned char *sigret, 144280304Sjkim unsigned int *siglen, const RSA *rsa); 145183234Ssimonstatic int capi_rsa_priv_enc(int flen, const unsigned char *from, 146280304Sjkim unsigned char *to, RSA *rsa, int padding); 147183234Ssimonstatic int capi_rsa_priv_dec(int flen, const unsigned char *from, 148280304Sjkim unsigned char *to, RSA *rsa, int padding); 149183234Ssimonstatic int capi_rsa_free(RSA *rsa); 150183234Ssimon 151183234Ssimonstatic DSA_SIG *capi_dsa_do_sign(const unsigned char *digest, int dlen, 152280304Sjkim DSA *dsa); 153183234Ssimonstatic int capi_dsa_free(DSA *dsa); 154183234Ssimon 155183234Ssimonstatic int capi_load_ssl_client_cert(ENGINE *e, SSL *ssl, 156280304Sjkim STACK_OF(X509_NAME) *ca_dn, X509 **pcert, 157280304Sjkim EVP_PKEY **pkey, STACK_OF(X509) **pother, 158280304Sjkim UI_METHOD *ui_method, 159280304Sjkim void *callback_data); 160183234Ssimon 161183234Ssimonstatic int cert_select_simple(ENGINE *e, SSL *ssl, STACK_OF(X509) *certs); 162280304Sjkim# ifdef OPENSSL_CAPIENG_DIALOG 163183234Ssimonstatic int cert_select_dialog(ENGINE *e, SSL *ssl, STACK_OF(X509) *certs); 164280304Sjkim# endif 165183234Ssimon 166280304Sjkimtypedef PCCERT_CONTEXT(WINAPI *CERTDLG) (HCERTSTORE, HWND, LPCWSTR, 167280304Sjkim LPCWSTR, DWORD, DWORD, void *); 168280304Sjkimtypedef HWND(WINAPI *GETCONSWIN) (void); 169183234Ssimon 170280304Sjkim/* 171280304Sjkim * This structure contains CAPI ENGINE specific data: it contains various 172280304Sjkim * global options and affects how other functions behave. 173183234Ssimon */ 174183234Ssimon 175280304Sjkim# define CAPI_DBG_TRACE 2 176280304Sjkim# define CAPI_DBG_ERROR 1 177183234Ssimon 178183234Ssimonstruct CAPI_CTX_st { 179280304Sjkim int debug_level; 180280304Sjkim char *debug_file; 181280304Sjkim /* Parameters to use for container lookup */ 182280304Sjkim DWORD keytype; 183280304Sjkim LPSTR cspname; 184280304Sjkim DWORD csptype; 185280304Sjkim /* Certificate store name to use */ 186280304Sjkim LPSTR storename; 187280304Sjkim LPSTR ssl_client_store; 188280304Sjkim /* System store flags */ 189280304Sjkim DWORD store_flags; 190183234Ssimon/* Lookup string meanings in load_private_key */ 191183234Ssimon/* Substring of subject: uses "storename" */ 192280304Sjkim# define CAPI_LU_SUBSTR 1 193183234Ssimon/* Friendly name: uses storename */ 194280304Sjkim# define CAPI_LU_FNAME 2 195183234Ssimon/* Container name: uses cspname, keytype */ 196280304Sjkim# define CAPI_LU_CONTNAME 3 197280304Sjkim int lookup_method; 198183234Ssimon/* Info to dump with dumpcerts option */ 199183234Ssimon/* Issuer and serial name strings */ 200280304Sjkim# define CAPI_DMP_SUMMARY 0x1 201183234Ssimon/* Friendly name */ 202280304Sjkim# define CAPI_DMP_FNAME 0x2 203183234Ssimon/* Full X509_print dump */ 204280304Sjkim# define CAPI_DMP_FULL 0x4 205183234Ssimon/* Dump PEM format certificate */ 206280304Sjkim# define CAPI_DMP_PEM 0x8 207183234Ssimon/* Dump pseudo key (if possible) */ 208280304Sjkim# define CAPI_DMP_PSKEY 0x10 209183234Ssimon/* Dump key info (if possible) */ 210280304Sjkim# define CAPI_DMP_PKEYINFO 0x20 211280304Sjkim DWORD dump_flags; 212280304Sjkim int (*client_cert_select) (ENGINE *e, SSL *ssl, STACK_OF(X509) *certs); 213280304Sjkim CERTDLG certselectdlg; 214280304Sjkim GETCONSWIN getconswindow; 215183234Ssimon}; 216183234Ssimon 217183234Ssimonstatic CAPI_CTX *capi_ctx_new(); 218280304Sjkimstatic void capi_ctx_free(CAPI_CTX * ctx); 219280304Sjkimstatic int capi_ctx_set_provname(CAPI_CTX * ctx, LPSTR pname, DWORD type, 220280304Sjkim int check); 221280304Sjkimstatic int capi_ctx_set_provname_idx(CAPI_CTX * ctx, int idx); 222183234Ssimon 223280304Sjkim# define CAPI_CMD_LIST_CERTS ENGINE_CMD_BASE 224280304Sjkim# define CAPI_CMD_LOOKUP_CERT (ENGINE_CMD_BASE + 1) 225280304Sjkim# define CAPI_CMD_DEBUG_LEVEL (ENGINE_CMD_BASE + 2) 226280304Sjkim# define CAPI_CMD_DEBUG_FILE (ENGINE_CMD_BASE + 3) 227280304Sjkim# define CAPI_CMD_KEYTYPE (ENGINE_CMD_BASE + 4) 228280304Sjkim# define CAPI_CMD_LIST_CSPS (ENGINE_CMD_BASE + 5) 229280304Sjkim# define CAPI_CMD_SET_CSP_IDX (ENGINE_CMD_BASE + 6) 230280304Sjkim# define CAPI_CMD_SET_CSP_NAME (ENGINE_CMD_BASE + 7) 231280304Sjkim# define CAPI_CMD_SET_CSP_TYPE (ENGINE_CMD_BASE + 8) 232280304Sjkim# define CAPI_CMD_LIST_CONTAINERS (ENGINE_CMD_BASE + 9) 233280304Sjkim# define CAPI_CMD_LIST_OPTIONS (ENGINE_CMD_BASE + 10) 234280304Sjkim# define CAPI_CMD_LOOKUP_METHOD (ENGINE_CMD_BASE + 11) 235280304Sjkim# define CAPI_CMD_STORE_NAME (ENGINE_CMD_BASE + 12) 236280304Sjkim# define CAPI_CMD_STORE_FLAGS (ENGINE_CMD_BASE + 13) 237183234Ssimon 238183234Ssimonstatic const ENGINE_CMD_DEFN capi_cmd_defns[] = { 239280304Sjkim {CAPI_CMD_LIST_CERTS, 240280304Sjkim "list_certs", 241280304Sjkim "List all certificates in store", 242280304Sjkim ENGINE_CMD_FLAG_NO_INPUT}, 243280304Sjkim {CAPI_CMD_LOOKUP_CERT, 244280304Sjkim "lookup_cert", 245280304Sjkim "Lookup and output certificates", 246280304Sjkim ENGINE_CMD_FLAG_STRING}, 247280304Sjkim {CAPI_CMD_DEBUG_LEVEL, 248280304Sjkim "debug_level", 249280304Sjkim "debug level (1=errors, 2=trace)", 250280304Sjkim ENGINE_CMD_FLAG_NUMERIC}, 251280304Sjkim {CAPI_CMD_DEBUG_FILE, 252280304Sjkim "debug_file", 253280304Sjkim "debugging filename)", 254280304Sjkim ENGINE_CMD_FLAG_STRING}, 255280304Sjkim {CAPI_CMD_KEYTYPE, 256280304Sjkim "key_type", 257280304Sjkim "Key type: 1=AT_KEYEXCHANGE (default), 2=AT_SIGNATURE", 258280304Sjkim ENGINE_CMD_FLAG_NUMERIC}, 259280304Sjkim {CAPI_CMD_LIST_CSPS, 260280304Sjkim "list_csps", 261280304Sjkim "List all CSPs", 262280304Sjkim ENGINE_CMD_FLAG_NO_INPUT}, 263280304Sjkim {CAPI_CMD_SET_CSP_IDX, 264280304Sjkim "csp_idx", 265280304Sjkim "Set CSP by index", 266280304Sjkim ENGINE_CMD_FLAG_NUMERIC}, 267280304Sjkim {CAPI_CMD_SET_CSP_NAME, 268280304Sjkim "csp_name", 269280304Sjkim "Set CSP name, (default CSP used if not specified)", 270280304Sjkim ENGINE_CMD_FLAG_STRING}, 271280304Sjkim {CAPI_CMD_SET_CSP_TYPE, 272280304Sjkim "csp_type", 273280304Sjkim "Set CSP type, (default RSA_PROV_FULL)", 274280304Sjkim ENGINE_CMD_FLAG_NUMERIC}, 275280304Sjkim {CAPI_CMD_LIST_CONTAINERS, 276280304Sjkim "list_containers", 277280304Sjkim "list container names", 278280304Sjkim ENGINE_CMD_FLAG_NO_INPUT}, 279280304Sjkim {CAPI_CMD_LIST_OPTIONS, 280280304Sjkim "list_options", 281280304Sjkim "Set list options (1=summary,2=friendly name, 4=full printout, 8=PEM output, 16=XXX, " 282280304Sjkim "32=private key info)", 283280304Sjkim ENGINE_CMD_FLAG_NUMERIC}, 284280304Sjkim {CAPI_CMD_LOOKUP_METHOD, 285280304Sjkim "lookup_method", 286280304Sjkim "Set key lookup method (1=substring, 2=friendlyname, 3=container name)", 287280304Sjkim ENGINE_CMD_FLAG_NUMERIC}, 288280304Sjkim {CAPI_CMD_STORE_NAME, 289280304Sjkim "store_name", 290280304Sjkim "certificate store name, default \"MY\"", 291280304Sjkim ENGINE_CMD_FLAG_STRING}, 292280304Sjkim {CAPI_CMD_STORE_FLAGS, 293280304Sjkim "store_flags", 294280304Sjkim "Certificate store flags: 1 = system store", 295280304Sjkim ENGINE_CMD_FLAG_NUMERIC}, 296183234Ssimon 297280304Sjkim {0, NULL, NULL, 0} 298280304Sjkim}; 299183234Ssimon 300183234Ssimonstatic int capi_idx = -1; 301183234Ssimonstatic int rsa_capi_idx = -1; 302183234Ssimonstatic int dsa_capi_idx = -1; 303183234Ssimonstatic int cert_capi_idx = -1; 304183234Ssimon 305280304Sjkimstatic int capi_ctrl(ENGINE *e, int cmd, long i, void *p, void (*f) (void)) 306280304Sjkim{ 307280304Sjkim int ret = 1; 308280304Sjkim CAPI_CTX *ctx; 309280304Sjkim BIO *out; 310280304Sjkim if (capi_idx == -1) { 311280304Sjkim CAPIerr(CAPI_F_CAPI_CTRL, CAPI_R_ENGINE_NOT_INITIALIZED); 312280304Sjkim return 0; 313280304Sjkim } 314280304Sjkim ctx = ENGINE_get_ex_data(e, capi_idx); 315280304Sjkim out = BIO_new_fp(stdout, BIO_NOCLOSE); 316280304Sjkim switch (cmd) { 317280304Sjkim case CAPI_CMD_LIST_CSPS: 318280304Sjkim ret = capi_list_providers(ctx, out); 319280304Sjkim break; 320183234Ssimon 321280304Sjkim case CAPI_CMD_LIST_CERTS: 322280304Sjkim ret = capi_list_certs(ctx, out, NULL); 323280304Sjkim break; 324183234Ssimon 325280304Sjkim case CAPI_CMD_LOOKUP_CERT: 326280304Sjkim ret = capi_list_certs(ctx, out, p); 327280304Sjkim break; 328183234Ssimon 329280304Sjkim case CAPI_CMD_LIST_CONTAINERS: 330280304Sjkim ret = capi_list_containers(ctx, out); 331280304Sjkim break; 332183234Ssimon 333280304Sjkim case CAPI_CMD_STORE_NAME: 334280304Sjkim if (ctx->storename) 335280304Sjkim OPENSSL_free(ctx->storename); 336280304Sjkim ctx->storename = BUF_strdup(p); 337280304Sjkim CAPI_trace(ctx, "Setting store name to %s\n", p); 338280304Sjkim break; 339183234Ssimon 340280304Sjkim case CAPI_CMD_STORE_FLAGS: 341280304Sjkim if (i & 1) { 342280304Sjkim ctx->store_flags |= CERT_SYSTEM_STORE_LOCAL_MACHINE; 343280304Sjkim ctx->store_flags &= ~CERT_SYSTEM_STORE_CURRENT_USER; 344280304Sjkim } else { 345280304Sjkim ctx->store_flags |= CERT_SYSTEM_STORE_CURRENT_USER; 346280304Sjkim ctx->store_flags &= ~CERT_SYSTEM_STORE_LOCAL_MACHINE; 347280304Sjkim } 348280304Sjkim CAPI_trace(ctx, "Setting flags to %d\n", i); 349280304Sjkim break; 350183234Ssimon 351280304Sjkim case CAPI_CMD_DEBUG_LEVEL: 352280304Sjkim ctx->debug_level = (int)i; 353280304Sjkim CAPI_trace(ctx, "Setting debug level to %d\n", ctx->debug_level); 354280304Sjkim break; 355183234Ssimon 356280304Sjkim case CAPI_CMD_DEBUG_FILE: 357280304Sjkim ctx->debug_file = BUF_strdup(p); 358280304Sjkim CAPI_trace(ctx, "Setting debug file to %s\n", ctx->debug_file); 359280304Sjkim break; 360183234Ssimon 361280304Sjkim case CAPI_CMD_KEYTYPE: 362280304Sjkim ctx->keytype = i; 363280304Sjkim CAPI_trace(ctx, "Setting key type to %d\n", ctx->keytype); 364280304Sjkim break; 365183234Ssimon 366280304Sjkim case CAPI_CMD_SET_CSP_IDX: 367280304Sjkim ret = capi_ctx_set_provname_idx(ctx, i); 368280304Sjkim break; 369183234Ssimon 370280304Sjkim case CAPI_CMD_LIST_OPTIONS: 371280304Sjkim ctx->dump_flags = i; 372280304Sjkim break; 373183234Ssimon 374280304Sjkim case CAPI_CMD_LOOKUP_METHOD: 375280304Sjkim if (i < 1 || i > 3) { 376280304Sjkim CAPIerr(CAPI_F_CAPI_CTRL, CAPI_R_INVALID_LOOKUP_METHOD); 377280304Sjkim return 0; 378280304Sjkim } 379280304Sjkim ctx->lookup_method = i; 380280304Sjkim break; 381183234Ssimon 382280304Sjkim case CAPI_CMD_SET_CSP_NAME: 383280304Sjkim ret = capi_ctx_set_provname(ctx, p, ctx->csptype, 1); 384280304Sjkim break; 385183234Ssimon 386280304Sjkim case CAPI_CMD_SET_CSP_TYPE: 387280304Sjkim ctx->csptype = i; 388280304Sjkim break; 389183234Ssimon 390280304Sjkim default: 391280304Sjkim CAPIerr(CAPI_F_CAPI_CTRL, CAPI_R_UNKNOWN_COMMAND); 392280304Sjkim ret = 0; 393280304Sjkim } 394183234Ssimon 395280304Sjkim BIO_free(out); 396280304Sjkim return ret; 397183234Ssimon 398280304Sjkim} 399183234Ssimon 400280304Sjkimstatic RSA_METHOD capi_rsa_method = { 401280304Sjkim "CryptoAPI RSA method", 402280304Sjkim 0, /* pub_enc */ 403280304Sjkim 0, /* pub_dec */ 404280304Sjkim capi_rsa_priv_enc, /* priv_enc */ 405280304Sjkim capi_rsa_priv_dec, /* priv_dec */ 406280304Sjkim 0, /* rsa_mod_exp */ 407280304Sjkim 0, /* bn_mod_exp */ 408280304Sjkim 0, /* init */ 409280304Sjkim capi_rsa_free, /* finish */ 410280304Sjkim RSA_FLAG_SIGN_VER, /* flags */ 411280304Sjkim NULL, /* app_data */ 412280304Sjkim capi_rsa_sign, /* rsa_sign */ 413280304Sjkim 0 /* rsa_verify */ 414280304Sjkim}; 415183234Ssimon 416280304Sjkimstatic DSA_METHOD capi_dsa_method = { 417280304Sjkim "CryptoAPI DSA method", 418280304Sjkim capi_dsa_do_sign, /* dsa_do_sign */ 419280304Sjkim 0, /* dsa_sign_setup */ 420280304Sjkim 0, /* dsa_do_verify */ 421280304Sjkim 0, /* dsa_mod_exp */ 422280304Sjkim 0, /* bn_mod_exp */ 423280304Sjkim 0, /* init */ 424280304Sjkim capi_dsa_free, /* finish */ 425280304Sjkim 0, /* flags */ 426280304Sjkim NULL, /* app_data */ 427280304Sjkim 0, /* dsa_paramgen */ 428280304Sjkim 0 /* dsa_keygen */ 429280304Sjkim}; 430183234Ssimon 431183234Ssimonstatic int capi_init(ENGINE *e) 432280304Sjkim{ 433280304Sjkim CAPI_CTX *ctx; 434280304Sjkim const RSA_METHOD *ossl_rsa_meth; 435280304Sjkim const DSA_METHOD *ossl_dsa_meth; 436183234Ssimon 437280304Sjkim if (capi_idx < 0) { 438280304Sjkim capi_idx = ENGINE_get_ex_new_index(0, NULL, NULL, NULL, 0); 439280304Sjkim if (capi_idx < 0) 440280304Sjkim goto memerr; 441237657Sjkim 442280304Sjkim cert_capi_idx = X509_get_ex_new_index(0, NULL, NULL, NULL, 0); 443237657Sjkim 444280304Sjkim /* Setup RSA_METHOD */ 445280304Sjkim rsa_capi_idx = RSA_get_ex_new_index(0, NULL, NULL, NULL, 0); 446280304Sjkim ossl_rsa_meth = RSA_PKCS1_SSLeay(); 447280304Sjkim capi_rsa_method.rsa_pub_enc = ossl_rsa_meth->rsa_pub_enc; 448280304Sjkim capi_rsa_method.rsa_pub_dec = ossl_rsa_meth->rsa_pub_dec; 449280304Sjkim capi_rsa_method.rsa_mod_exp = ossl_rsa_meth->rsa_mod_exp; 450280304Sjkim capi_rsa_method.bn_mod_exp = ossl_rsa_meth->bn_mod_exp; 451237657Sjkim 452280304Sjkim /* Setup DSA Method */ 453280304Sjkim dsa_capi_idx = DSA_get_ex_new_index(0, NULL, NULL, NULL, 0); 454280304Sjkim ossl_dsa_meth = DSA_OpenSSL(); 455280304Sjkim capi_dsa_method.dsa_do_verify = ossl_dsa_meth->dsa_do_verify; 456280304Sjkim capi_dsa_method.dsa_mod_exp = ossl_dsa_meth->dsa_mod_exp; 457280304Sjkim capi_dsa_method.bn_mod_exp = ossl_dsa_meth->bn_mod_exp; 458280304Sjkim } 459237657Sjkim 460280304Sjkim ctx = capi_ctx_new(); 461280304Sjkim if (!ctx) 462280304Sjkim goto memerr; 463183234Ssimon 464280304Sjkim ENGINE_set_ex_data(e, capi_idx, ctx); 465183234Ssimon 466280304Sjkim# ifdef OPENSSL_CAPIENG_DIALOG 467280304Sjkim { 468280304Sjkim HMODULE cryptui = LoadLibrary(TEXT("CRYPTUI.DLL")); 469280304Sjkim HMODULE kernel = GetModuleHandle(TEXT("KERNEL32.DLL")); 470280304Sjkim if (cryptui) 471280304Sjkim ctx->certselectdlg = 472280304Sjkim (CERTDLG) GetProcAddress(cryptui, 473280304Sjkim "CryptUIDlgSelectCertificateFromStore"); 474280304Sjkim if (kernel) 475280304Sjkim ctx->getconswindow = 476280304Sjkim (GETCONSWIN) GetProcAddress(kernel, "GetConsoleWindow"); 477280304Sjkim if (cryptui && !OPENSSL_isservice()) 478280304Sjkim ctx->client_cert_select = cert_select_dialog; 479280304Sjkim } 480280304Sjkim# endif 481183234Ssimon 482280304Sjkim return 1; 483183234Ssimon 484280304Sjkim memerr: 485280304Sjkim CAPIerr(CAPI_F_CAPI_INIT, ERR_R_MALLOC_FAILURE); 486280304Sjkim return 0; 487183234Ssimon 488280304Sjkim return 1; 489280304Sjkim} 490183234Ssimon 491183234Ssimonstatic int capi_destroy(ENGINE *e) 492280304Sjkim{ 493280304Sjkim ERR_unload_CAPI_strings(); 494280304Sjkim return 1; 495280304Sjkim} 496183234Ssimon 497183234Ssimonstatic int capi_finish(ENGINE *e) 498280304Sjkim{ 499280304Sjkim CAPI_CTX *ctx; 500280304Sjkim ctx = ENGINE_get_ex_data(e, capi_idx); 501280304Sjkim capi_ctx_free(ctx); 502280304Sjkim ENGINE_set_ex_data(e, capi_idx, NULL); 503280304Sjkim return 1; 504280304Sjkim} 505183234Ssimon 506280304Sjkim/* 507280304Sjkim * CryptoAPI key application data. This contains a handle to the private key 508280304Sjkim * container (for sign operations) and a handle to the key (for decrypt 509280304Sjkim * operations). 510183234Ssimon */ 511183234Ssimon 512280304Sjkimstruct CAPI_KEY_st { 513280304Sjkim /* Associated certificate context (if any) */ 514280304Sjkim PCCERT_CONTEXT pcert; 515280304Sjkim HCRYPTPROV hprov; 516280304Sjkim HCRYPTKEY key; 517280304Sjkim DWORD keyspec; 518280304Sjkim}; 519183234Ssimon 520183234Ssimonstatic int bind_capi(ENGINE *e) 521280304Sjkim{ 522280304Sjkim if (!ENGINE_set_id(e, engine_capi_id) 523280304Sjkim || !ENGINE_set_name(e, engine_capi_name) 524280304Sjkim || !ENGINE_set_flags(e, ENGINE_FLAGS_NO_REGISTER_ALL) 525280304Sjkim || !ENGINE_set_init_function(e, capi_init) 526280304Sjkim || !ENGINE_set_finish_function(e, capi_finish) 527280304Sjkim || !ENGINE_set_destroy_function(e, capi_destroy) 528280304Sjkim || !ENGINE_set_RSA(e, &capi_rsa_method) 529280304Sjkim || !ENGINE_set_DSA(e, &capi_dsa_method) 530280304Sjkim || !ENGINE_set_load_privkey_function(e, capi_load_privkey) 531280304Sjkim || !ENGINE_set_load_ssl_client_cert_function(e, 532280304Sjkim capi_load_ssl_client_cert) 533280304Sjkim || !ENGINE_set_cmd_defns(e, capi_cmd_defns) 534280304Sjkim || !ENGINE_set_ctrl_function(e, capi_ctrl)) 535280304Sjkim return 0; 536280304Sjkim ERR_load_CAPI_strings(); 537183234Ssimon 538280304Sjkim return 1; 539183234Ssimon 540280304Sjkim} 541183234Ssimon 542280304Sjkim# ifndef OPENSSL_NO_DYNAMIC_ENGINE 543183234Ssimonstatic int bind_helper(ENGINE *e, const char *id) 544280304Sjkim{ 545280304Sjkim if (id && (strcmp(id, engine_capi_id) != 0)) 546280304Sjkim return 0; 547280304Sjkim if (!bind_capi(e)) 548280304Sjkim return 0; 549280304Sjkim return 1; 550280304Sjkim} 551280304Sjkim 552183234SsimonIMPLEMENT_DYNAMIC_CHECK_FN() 553280304Sjkim IMPLEMENT_DYNAMIC_BIND_FN(bind_helper) 554280304Sjkim# else 555183234Ssimonstatic ENGINE *engine_capi(void) 556280304Sjkim{ 557280304Sjkim ENGINE *ret = ENGINE_new(); 558280304Sjkim if (!ret) 559280304Sjkim return NULL; 560280304Sjkim if (!bind_capi(ret)) { 561280304Sjkim ENGINE_free(ret); 562280304Sjkim return NULL; 563280304Sjkim } 564280304Sjkim return ret; 565280304Sjkim} 566183234Ssimon 567183234Ssimonvoid ENGINE_load_capi(void) 568280304Sjkim{ 569280304Sjkim /* Copied from eng_[openssl|dyn].c */ 570280304Sjkim ENGINE *toadd = engine_capi(); 571280304Sjkim if (!toadd) 572280304Sjkim return; 573280304Sjkim ENGINE_add(toadd); 574280304Sjkim ENGINE_free(toadd); 575280304Sjkim ERR_clear_error(); 576280304Sjkim} 577280304Sjkim# endif 578183234Ssimon 579183234Ssimonstatic int lend_tobn(BIGNUM *bn, unsigned char *bin, int binlen) 580280304Sjkim{ 581280304Sjkim int i; 582280304Sjkim /* 583280304Sjkim * Reverse buffer in place: since this is a keyblob structure that will 584280304Sjkim * be freed up after conversion anyway it doesn't matter if we change 585280304Sjkim * it. 586280304Sjkim */ 587280304Sjkim for (i = 0; i < binlen / 2; i++) { 588280304Sjkim unsigned char c; 589280304Sjkim c = bin[i]; 590280304Sjkim bin[i] = bin[binlen - i - 1]; 591280304Sjkim bin[binlen - i - 1] = c; 592280304Sjkim } 593183234Ssimon 594280304Sjkim if (!BN_bin2bn(bin, binlen, bn)) 595280304Sjkim return 0; 596280304Sjkim return 1; 597280304Sjkim} 598183234Ssimon 599183234Ssimon/* Given a CAPI_KEY get an EVP_PKEY structure */ 600183234Ssimon 601280304Sjkimstatic EVP_PKEY *capi_get_pkey(ENGINE *eng, CAPI_KEY * key) 602280304Sjkim{ 603280304Sjkim unsigned char *pubkey = NULL; 604280304Sjkim DWORD len; 605280304Sjkim BLOBHEADER *bh; 606280304Sjkim RSA *rkey = NULL; 607280304Sjkim DSA *dkey = NULL; 608280304Sjkim EVP_PKEY *ret = NULL; 609280304Sjkim if (!CryptExportKey(key->key, 0, PUBLICKEYBLOB, 0, NULL, &len)) { 610280304Sjkim CAPIerr(CAPI_F_CAPI_GET_PKEY, CAPI_R_PUBKEY_EXPORT_LENGTH_ERROR); 611280304Sjkim capi_addlasterror(); 612280304Sjkim return NULL; 613280304Sjkim } 614183234Ssimon 615280304Sjkim pubkey = OPENSSL_malloc(len); 616183234Ssimon 617280304Sjkim if (!pubkey) 618280304Sjkim goto memerr; 619183234Ssimon 620280304Sjkim if (!CryptExportKey(key->key, 0, PUBLICKEYBLOB, 0, pubkey, &len)) { 621280304Sjkim CAPIerr(CAPI_F_CAPI_GET_PKEY, CAPI_R_PUBKEY_EXPORT_ERROR); 622280304Sjkim capi_addlasterror(); 623280304Sjkim goto err; 624280304Sjkim } 625183234Ssimon 626280304Sjkim bh = (BLOBHEADER *) pubkey; 627280304Sjkim if (bh->bType != PUBLICKEYBLOB) { 628280304Sjkim CAPIerr(CAPI_F_CAPI_GET_PKEY, CAPI_R_INVALID_PUBLIC_KEY_BLOB); 629280304Sjkim goto err; 630280304Sjkim } 631280304Sjkim if (bh->aiKeyAlg == CALG_RSA_SIGN || bh->aiKeyAlg == CALG_RSA_KEYX) { 632280304Sjkim RSAPUBKEY *rp; 633280304Sjkim DWORD rsa_modlen; 634280304Sjkim unsigned char *rsa_modulus; 635280304Sjkim rp = (RSAPUBKEY *) (bh + 1); 636280304Sjkim if (rp->magic != 0x31415352) { 637280304Sjkim char magstr[10]; 638280304Sjkim BIO_snprintf(magstr, 10, "%lx", rp->magic); 639280304Sjkim CAPIerr(CAPI_F_CAPI_GET_PKEY, 640280304Sjkim CAPI_R_INVALID_RSA_PUBLIC_KEY_BLOB_MAGIC_NUMBER); 641280304Sjkim ERR_add_error_data(2, "magic=0x", magstr); 642280304Sjkim goto err; 643280304Sjkim } 644280304Sjkim rsa_modulus = (unsigned char *)(rp + 1); 645280304Sjkim rkey = RSA_new_method(eng); 646280304Sjkim if (!rkey) 647280304Sjkim goto memerr; 648183234Ssimon 649280304Sjkim rkey->e = BN_new(); 650280304Sjkim rkey->n = BN_new(); 651183234Ssimon 652280304Sjkim if (!rkey->e || !rkey->n) 653280304Sjkim goto memerr; 654183234Ssimon 655280304Sjkim if (!BN_set_word(rkey->e, rp->pubexp)) 656280304Sjkim goto memerr; 657183234Ssimon 658280304Sjkim rsa_modlen = rp->bitlen / 8; 659280304Sjkim if (!lend_tobn(rkey->n, rsa_modulus, rsa_modlen)) 660280304Sjkim goto memerr; 661183234Ssimon 662280304Sjkim RSA_set_ex_data(rkey, rsa_capi_idx, key); 663183234Ssimon 664280304Sjkim if (!(ret = EVP_PKEY_new())) 665280304Sjkim goto memerr; 666183234Ssimon 667280304Sjkim EVP_PKEY_assign_RSA(ret, rkey); 668280304Sjkim rkey = NULL; 669183234Ssimon 670280304Sjkim } else if (bh->aiKeyAlg == CALG_DSS_SIGN) { 671280304Sjkim DSSPUBKEY *dp; 672280304Sjkim DWORD dsa_plen; 673280304Sjkim unsigned char *btmp; 674280304Sjkim dp = (DSSPUBKEY *) (bh + 1); 675280304Sjkim if (dp->magic != 0x31535344) { 676280304Sjkim char magstr[10]; 677280304Sjkim BIO_snprintf(magstr, 10, "%lx", dp->magic); 678280304Sjkim CAPIerr(CAPI_F_CAPI_GET_PKEY, 679280304Sjkim CAPI_R_INVALID_DSA_PUBLIC_KEY_BLOB_MAGIC_NUMBER); 680280304Sjkim ERR_add_error_data(2, "magic=0x", magstr); 681280304Sjkim goto err; 682280304Sjkim } 683280304Sjkim dsa_plen = dp->bitlen / 8; 684280304Sjkim btmp = (unsigned char *)(dp + 1); 685280304Sjkim dkey = DSA_new_method(eng); 686280304Sjkim if (!dkey) 687280304Sjkim goto memerr; 688280304Sjkim dkey->p = BN_new(); 689280304Sjkim dkey->q = BN_new(); 690280304Sjkim dkey->g = BN_new(); 691280304Sjkim dkey->pub_key = BN_new(); 692280304Sjkim if (!dkey->p || !dkey->q || !dkey->g || !dkey->pub_key) 693280304Sjkim goto memerr; 694280304Sjkim if (!lend_tobn(dkey->p, btmp, dsa_plen)) 695280304Sjkim goto memerr; 696280304Sjkim btmp += dsa_plen; 697280304Sjkim if (!lend_tobn(dkey->q, btmp, 20)) 698280304Sjkim goto memerr; 699280304Sjkim btmp += 20; 700280304Sjkim if (!lend_tobn(dkey->g, btmp, dsa_plen)) 701280304Sjkim goto memerr; 702280304Sjkim btmp += dsa_plen; 703280304Sjkim if (!lend_tobn(dkey->pub_key, btmp, dsa_plen)) 704280304Sjkim goto memerr; 705280304Sjkim btmp += dsa_plen; 706183234Ssimon 707280304Sjkim DSA_set_ex_data(dkey, dsa_capi_idx, key); 708183234Ssimon 709280304Sjkim if (!(ret = EVP_PKEY_new())) 710280304Sjkim goto memerr; 711183234Ssimon 712280304Sjkim EVP_PKEY_assign_DSA(ret, dkey); 713280304Sjkim dkey = NULL; 714280304Sjkim } else { 715280304Sjkim char algstr[10]; 716280304Sjkim BIO_snprintf(algstr, 10, "%lx", bh->aiKeyAlg); 717280304Sjkim CAPIerr(CAPI_F_CAPI_GET_PKEY, 718280304Sjkim CAPI_R_UNSUPPORTED_PUBLIC_KEY_ALGORITHM); 719280304Sjkim ERR_add_error_data(2, "aiKeyAlg=0x", algstr); 720280304Sjkim goto err; 721280304Sjkim } 722183234Ssimon 723280304Sjkim err: 724280304Sjkim if (pubkey) 725280304Sjkim OPENSSL_free(pubkey); 726280304Sjkim if (!ret) { 727280304Sjkim if (rkey) 728280304Sjkim RSA_free(rkey); 729280304Sjkim if (dkey) 730280304Sjkim DSA_free(dkey); 731280304Sjkim } 732183234Ssimon 733280304Sjkim return ret; 734183234Ssimon 735280304Sjkim memerr: 736280304Sjkim CAPIerr(CAPI_F_CAPI_GET_PKEY, ERR_R_MALLOC_FAILURE); 737280304Sjkim goto err; 738183234Ssimon 739280304Sjkim} 740183234Ssimon 741183234Ssimonstatic EVP_PKEY *capi_load_privkey(ENGINE *eng, const char *key_id, 742280304Sjkim UI_METHOD *ui_method, void *callback_data) 743280304Sjkim{ 744280304Sjkim CAPI_CTX *ctx; 745280304Sjkim CAPI_KEY *key; 746280304Sjkim EVP_PKEY *ret; 747280304Sjkim ctx = ENGINE_get_ex_data(eng, capi_idx); 748183234Ssimon 749280304Sjkim if (!ctx) { 750280304Sjkim CAPIerr(CAPI_F_CAPI_LOAD_PRIVKEY, CAPI_R_CANT_FIND_CAPI_CONTEXT); 751280304Sjkim return NULL; 752280304Sjkim } 753183234Ssimon 754280304Sjkim key = capi_find_key(ctx, key_id); 755183234Ssimon 756280304Sjkim if (!key) 757280304Sjkim return NULL; 758183234Ssimon 759280304Sjkim ret = capi_get_pkey(eng, key); 760183234Ssimon 761280304Sjkim if (!ret) 762280304Sjkim capi_free_key(key); 763280304Sjkim return ret; 764183234Ssimon 765280304Sjkim} 766183234Ssimon 767183234Ssimon/* CryptoAPI RSA operations */ 768183234Ssimon 769183234Ssimonint capi_rsa_priv_enc(int flen, const unsigned char *from, 770280304Sjkim unsigned char *to, RSA *rsa, int padding) 771280304Sjkim{ 772280304Sjkim CAPIerr(CAPI_F_CAPI_RSA_PRIV_ENC, CAPI_R_FUNCTION_NOT_SUPPORTED); 773280304Sjkim return -1; 774280304Sjkim} 775183234Ssimon 776183234Ssimonint capi_rsa_sign(int dtype, const unsigned char *m, unsigned int m_len, 777280304Sjkim unsigned char *sigret, unsigned int *siglen, const RSA *rsa) 778280304Sjkim{ 779280304Sjkim ALG_ID alg; 780280304Sjkim HCRYPTHASH hash; 781280304Sjkim DWORD slen; 782280304Sjkim unsigned int i; 783280304Sjkim int ret = -1; 784280304Sjkim CAPI_KEY *capi_key; 785280304Sjkim CAPI_CTX *ctx; 786183234Ssimon 787280304Sjkim ctx = ENGINE_get_ex_data(rsa->engine, capi_idx); 788183234Ssimon 789280304Sjkim CAPI_trace(ctx, "Called CAPI_rsa_sign()\n"); 790183234Ssimon 791280304Sjkim capi_key = RSA_get_ex_data(rsa, rsa_capi_idx); 792280304Sjkim if (!capi_key) { 793280304Sjkim CAPIerr(CAPI_F_CAPI_RSA_SIGN, CAPI_R_CANT_GET_KEY); 794280304Sjkim return -1; 795280304Sjkim } 796183234Ssimon/* Convert the signature type to a CryptoAPI algorithm ID */ 797280304Sjkim switch (dtype) { 798280304Sjkim case NID_sha1: 799280304Sjkim alg = CALG_SHA1; 800280304Sjkim break; 801183234Ssimon 802280304Sjkim case NID_md5: 803280304Sjkim alg = CALG_MD5; 804280304Sjkim break; 805183234Ssimon 806280304Sjkim case NID_md5_sha1: 807280304Sjkim alg = CALG_SSL3_SHAMD5; 808280304Sjkim break; 809280304Sjkim default: 810280304Sjkim { 811280304Sjkim char algstr[10]; 812280304Sjkim BIO_snprintf(algstr, 10, "%lx", dtype); 813280304Sjkim CAPIerr(CAPI_F_CAPI_RSA_SIGN, CAPI_R_UNSUPPORTED_ALGORITHM_NID); 814280304Sjkim ERR_add_error_data(2, "NID=0x", algstr); 815280304Sjkim return -1; 816280304Sjkim } 817280304Sjkim } 818183234Ssimon 819183234Ssimon/* Create the hash object */ 820280304Sjkim if (!CryptCreateHash(capi_key->hprov, alg, 0, 0, &hash)) { 821280304Sjkim CAPIerr(CAPI_F_CAPI_RSA_SIGN, CAPI_R_CANT_CREATE_HASH_OBJECT); 822280304Sjkim capi_addlasterror(); 823280304Sjkim return -1; 824280304Sjkim } 825183234Ssimon/* Set the hash value to the value passed */ 826183234Ssimon 827280304Sjkim if (!CryptSetHashParam(hash, HP_HASHVAL, (unsigned char *)m, 0)) { 828280304Sjkim CAPIerr(CAPI_F_CAPI_RSA_SIGN, CAPI_R_CANT_SET_HASH_VALUE); 829280304Sjkim capi_addlasterror(); 830280304Sjkim goto err; 831280304Sjkim } 832183234Ssimon 833183234Ssimon/* Finally sign it */ 834280304Sjkim slen = RSA_size(rsa); 835280304Sjkim if (!CryptSignHashA(hash, capi_key->keyspec, NULL, 0, sigret, &slen)) { 836280304Sjkim CAPIerr(CAPI_F_CAPI_RSA_SIGN, CAPI_R_ERROR_SIGNING_HASH); 837280304Sjkim capi_addlasterror(); 838280304Sjkim goto err; 839280304Sjkim } else { 840280304Sjkim ret = 1; 841280304Sjkim /* Inplace byte reversal of signature */ 842280304Sjkim for (i = 0; i < slen / 2; i++) { 843280304Sjkim unsigned char c; 844280304Sjkim c = sigret[i]; 845280304Sjkim sigret[i] = sigret[slen - i - 1]; 846280304Sjkim sigret[slen - i - 1] = c; 847280304Sjkim } 848280304Sjkim *siglen = slen; 849280304Sjkim } 850183234Ssimon 851280304Sjkim /* Now cleanup */ 852183234Ssimon 853280304Sjkim err: 854280304Sjkim CryptDestroyHash(hash); 855183234Ssimon 856280304Sjkim return ret; 857280304Sjkim} 858183234Ssimon 859183234Ssimonint capi_rsa_priv_dec(int flen, const unsigned char *from, 860280304Sjkim unsigned char *to, RSA *rsa, int padding) 861280304Sjkim{ 862280304Sjkim int i; 863280304Sjkim unsigned char *tmpbuf; 864280304Sjkim CAPI_KEY *capi_key; 865280304Sjkim CAPI_CTX *ctx; 866280304Sjkim ctx = ENGINE_get_ex_data(rsa->engine, capi_idx); 867183234Ssimon 868280304Sjkim CAPI_trace(ctx, "Called capi_rsa_priv_dec()\n"); 869183234Ssimon 870280304Sjkim capi_key = RSA_get_ex_data(rsa, rsa_capi_idx); 871280304Sjkim if (!capi_key) { 872280304Sjkim CAPIerr(CAPI_F_CAPI_RSA_PRIV_DEC, CAPI_R_CANT_GET_KEY); 873280304Sjkim return -1; 874280304Sjkim } 875183234Ssimon 876280304Sjkim if (padding != RSA_PKCS1_PADDING) { 877280304Sjkim char errstr[10]; 878280304Sjkim BIO_snprintf(errstr, 10, "%d", padding); 879280304Sjkim CAPIerr(CAPI_F_CAPI_RSA_PRIV_DEC, CAPI_R_UNSUPPORTED_PADDING); 880280304Sjkim ERR_add_error_data(2, "padding=", errstr); 881280304Sjkim return -1; 882280304Sjkim } 883183234Ssimon 884280304Sjkim /* Create temp reverse order version of input */ 885280304Sjkim if (!(tmpbuf = OPENSSL_malloc(flen))) { 886280304Sjkim CAPIerr(CAPI_F_CAPI_RSA_PRIV_DEC, ERR_R_MALLOC_FAILURE); 887280304Sjkim return -1; 888280304Sjkim } 889280304Sjkim for (i = 0; i < flen; i++) 890280304Sjkim tmpbuf[flen - i - 1] = from[i]; 891183234Ssimon 892280304Sjkim /* Finally decrypt it */ 893280304Sjkim if (!CryptDecrypt(capi_key->key, 0, TRUE, 0, tmpbuf, &flen)) { 894280304Sjkim CAPIerr(CAPI_F_CAPI_RSA_PRIV_DEC, CAPI_R_DECRYPT_ERROR); 895280304Sjkim capi_addlasterror(); 896280304Sjkim OPENSSL_free(tmpbuf); 897280304Sjkim return -1; 898280304Sjkim } else 899280304Sjkim memcpy(to, tmpbuf, flen); 900183234Ssimon 901280304Sjkim OPENSSL_free(tmpbuf); 902183234Ssimon 903280304Sjkim return flen; 904280304Sjkim} 905183234Ssimon 906183234Ssimonstatic int capi_rsa_free(RSA *rsa) 907280304Sjkim{ 908280304Sjkim CAPI_KEY *capi_key; 909280304Sjkim capi_key = RSA_get_ex_data(rsa, rsa_capi_idx); 910280304Sjkim capi_free_key(capi_key); 911280304Sjkim RSA_set_ex_data(rsa, rsa_capi_idx, 0); 912280304Sjkim return 1; 913280304Sjkim} 914183234Ssimon 915183234Ssimon/* CryptoAPI DSA operations */ 916183234Ssimon 917183234Ssimonstatic DSA_SIG *capi_dsa_do_sign(const unsigned char *digest, int dlen, 918280304Sjkim DSA *dsa) 919280304Sjkim{ 920280304Sjkim HCRYPTHASH hash; 921280304Sjkim DWORD slen; 922280304Sjkim DSA_SIG *ret = NULL; 923280304Sjkim CAPI_KEY *capi_key; 924280304Sjkim CAPI_CTX *ctx; 925280304Sjkim unsigned char csigbuf[40]; 926183234Ssimon 927280304Sjkim ctx = ENGINE_get_ex_data(dsa->engine, capi_idx); 928183234Ssimon 929280304Sjkim CAPI_trace(ctx, "Called CAPI_dsa_do_sign()\n"); 930183234Ssimon 931280304Sjkim capi_key = DSA_get_ex_data(dsa, dsa_capi_idx); 932183234Ssimon 933280304Sjkim if (!capi_key) { 934280304Sjkim CAPIerr(CAPI_F_CAPI_DSA_DO_SIGN, CAPI_R_CANT_GET_KEY); 935280304Sjkim return NULL; 936280304Sjkim } 937183234Ssimon 938280304Sjkim if (dlen != 20) { 939280304Sjkim CAPIerr(CAPI_F_CAPI_DSA_DO_SIGN, CAPI_R_INVALID_DIGEST_LENGTH); 940280304Sjkim return NULL; 941280304Sjkim } 942183234Ssimon 943280304Sjkim /* Create the hash object */ 944280304Sjkim if (!CryptCreateHash(capi_key->hprov, CALG_SHA1, 0, 0, &hash)) { 945280304Sjkim CAPIerr(CAPI_F_CAPI_DSA_DO_SIGN, CAPI_R_CANT_CREATE_HASH_OBJECT); 946280304Sjkim capi_addlasterror(); 947280304Sjkim return NULL; 948280304Sjkim } 949183234Ssimon 950280304Sjkim /* Set the hash value to the value passed */ 951280304Sjkim if (!CryptSetHashParam(hash, HP_HASHVAL, (unsigned char *)digest, 0)) { 952280304Sjkim CAPIerr(CAPI_F_CAPI_DSA_DO_SIGN, CAPI_R_CANT_SET_HASH_VALUE); 953280304Sjkim capi_addlasterror(); 954280304Sjkim goto err; 955280304Sjkim } 956183234Ssimon 957280304Sjkim /* Finally sign it */ 958280304Sjkim slen = sizeof(csigbuf); 959280304Sjkim if (!CryptSignHashA(hash, capi_key->keyspec, NULL, 0, csigbuf, &slen)) { 960280304Sjkim CAPIerr(CAPI_F_CAPI_DSA_DO_SIGN, CAPI_R_ERROR_SIGNING_HASH); 961280304Sjkim capi_addlasterror(); 962280304Sjkim goto err; 963280304Sjkim } else { 964280304Sjkim ret = DSA_SIG_new(); 965280304Sjkim if (!ret) 966280304Sjkim goto err; 967280304Sjkim ret->r = BN_new(); 968280304Sjkim ret->s = BN_new(); 969280304Sjkim if (!ret->r || !ret->s) 970280304Sjkim goto err; 971280304Sjkim if (!lend_tobn(ret->r, csigbuf, 20) 972280304Sjkim || !lend_tobn(ret->s, csigbuf + 20, 20)) { 973280304Sjkim DSA_SIG_free(ret); 974280304Sjkim ret = NULL; 975280304Sjkim goto err; 976280304Sjkim } 977280304Sjkim } 978183234Ssimon 979280304Sjkim /* Now cleanup */ 980183234Ssimon 981280304Sjkim err: 982280304Sjkim OPENSSL_cleanse(csigbuf, 40); 983280304Sjkim CryptDestroyHash(hash); 984280304Sjkim return ret; 985280304Sjkim} 986183234Ssimon 987183234Ssimonstatic int capi_dsa_free(DSA *dsa) 988280304Sjkim{ 989280304Sjkim CAPI_KEY *capi_key; 990280304Sjkim capi_key = DSA_get_ex_data(dsa, dsa_capi_idx); 991280304Sjkim capi_free_key(capi_key); 992280304Sjkim DSA_set_ex_data(dsa, dsa_capi_idx, 0); 993280304Sjkim return 1; 994280304Sjkim} 995183234Ssimon 996280304Sjkimstatic void capi_vtrace(CAPI_CTX * ctx, int level, char *format, 997280304Sjkim va_list argptr) 998280304Sjkim{ 999280304Sjkim BIO *out; 1000183234Ssimon 1001280304Sjkim if (!ctx || (ctx->debug_level < level) || (!ctx->debug_file)) 1002280304Sjkim return; 1003280304Sjkim out = BIO_new_file(ctx->debug_file, "a+"); 1004280304Sjkim BIO_vprintf(out, format, argptr); 1005280304Sjkim BIO_free(out); 1006280304Sjkim} 1007183234Ssimon 1008280304Sjkimstatic void CAPI_trace(CAPI_CTX * ctx, char *format, ...) 1009280304Sjkim{ 1010280304Sjkim va_list args; 1011280304Sjkim va_start(args, format); 1012280304Sjkim capi_vtrace(ctx, CAPI_DBG_TRACE, format, args); 1013280304Sjkim va_end(args); 1014280304Sjkim} 1015183234Ssimon 1016183234Ssimonstatic void capi_addlasterror(void) 1017280304Sjkim{ 1018280304Sjkim capi_adderror(GetLastError()); 1019280304Sjkim} 1020183234Ssimon 1021183234Ssimonstatic void capi_adderror(DWORD err) 1022280304Sjkim{ 1023280304Sjkim char errstr[10]; 1024280304Sjkim BIO_snprintf(errstr, 10, "%lX", err); 1025280304Sjkim ERR_add_error_data(2, "Error code= 0x", errstr); 1026280304Sjkim} 1027183234Ssimon 1028183234Ssimonstatic char *wide_to_asc(LPWSTR wstr) 1029280304Sjkim{ 1030280304Sjkim char *str; 1031280304Sjkim int len_0, sz; 1032205128Ssimon 1033280304Sjkim if (!wstr) 1034280304Sjkim return NULL; 1035280304Sjkim len_0 = (int)wcslen(wstr) + 1; /* WideCharToMultiByte expects int */ 1036280304Sjkim sz = WideCharToMultiByte(CP_ACP, 0, wstr, len_0, NULL, 0, NULL, NULL); 1037280304Sjkim if (!sz) { 1038280304Sjkim CAPIerr(CAPI_F_WIDE_TO_ASC, CAPI_R_WIN32_ERROR); 1039280304Sjkim return NULL; 1040280304Sjkim } 1041280304Sjkim str = OPENSSL_malloc(sz); 1042280304Sjkim if (!str) { 1043280304Sjkim CAPIerr(CAPI_F_WIDE_TO_ASC, ERR_R_MALLOC_FAILURE); 1044280304Sjkim return NULL; 1045280304Sjkim } 1046280304Sjkim if (!WideCharToMultiByte(CP_ACP, 0, wstr, len_0, str, sz, NULL, NULL)) { 1047280304Sjkim OPENSSL_free(str); 1048280304Sjkim CAPIerr(CAPI_F_WIDE_TO_ASC, CAPI_R_WIN32_ERROR); 1049280304Sjkim return NULL; 1050280304Sjkim } 1051280304Sjkim return str; 1052280304Sjkim} 1053183234Ssimon 1054280304Sjkimstatic int capi_get_provname(CAPI_CTX * ctx, LPSTR * pname, DWORD * ptype, 1055280304Sjkim DWORD idx) 1056280304Sjkim{ 1057280304Sjkim LPSTR name; 1058280304Sjkim DWORD len, err; 1059280304Sjkim CAPI_trace(ctx, "capi_get_provname, index=%d\n", idx); 1060280304Sjkim if (!CryptEnumProvidersA(idx, NULL, 0, ptype, NULL, &len)) { 1061280304Sjkim err = GetLastError(); 1062280304Sjkim if (err == ERROR_NO_MORE_ITEMS) 1063280304Sjkim return 2; 1064280304Sjkim CAPIerr(CAPI_F_CAPI_GET_PROVNAME, CAPI_R_CRYPTENUMPROVIDERS_ERROR); 1065280304Sjkim capi_adderror(err); 1066280304Sjkim return 0; 1067280304Sjkim } 1068280304Sjkim name = OPENSSL_malloc(len); 1069280304Sjkim if (!CryptEnumProvidersA(idx, NULL, 0, ptype, name, &len)) { 1070280304Sjkim err = GetLastError(); 1071280304Sjkim if (err == ERROR_NO_MORE_ITEMS) 1072280304Sjkim return 2; 1073280304Sjkim CAPIerr(CAPI_F_CAPI_GET_PROVNAME, CAPI_R_CRYPTENUMPROVIDERS_ERROR); 1074280304Sjkim capi_adderror(err); 1075280304Sjkim return 0; 1076280304Sjkim } 1077280304Sjkim *pname = name; 1078280304Sjkim CAPI_trace(ctx, "capi_get_provname, returned name=%s, type=%d\n", name, 1079280304Sjkim *ptype); 1080183234Ssimon 1081280304Sjkim return 1; 1082280304Sjkim} 1083183234Ssimon 1084280304Sjkimstatic int capi_list_providers(CAPI_CTX * ctx, BIO *out) 1085280304Sjkim{ 1086280304Sjkim DWORD idx, ptype; 1087280304Sjkim int ret; 1088280304Sjkim LPSTR provname = NULL; 1089280304Sjkim CAPI_trace(ctx, "capi_list_providers\n"); 1090280304Sjkim BIO_printf(out, "Available CSPs:\n"); 1091280304Sjkim for (idx = 0;; idx++) { 1092280304Sjkim ret = capi_get_provname(ctx, &provname, &ptype, idx); 1093280304Sjkim if (ret == 2) 1094280304Sjkim break; 1095280304Sjkim if (ret == 0) 1096280304Sjkim break; 1097280304Sjkim BIO_printf(out, "%d. %s, type %d\n", idx, provname, ptype); 1098280304Sjkim OPENSSL_free(provname); 1099280304Sjkim } 1100280304Sjkim return 1; 1101280304Sjkim} 1102183234Ssimon 1103280304Sjkimstatic int capi_list_containers(CAPI_CTX * ctx, BIO *out) 1104280304Sjkim{ 1105280304Sjkim int ret = 1; 1106280304Sjkim HCRYPTPROV hprov; 1107280304Sjkim DWORD err, idx, flags, buflen = 0, clen; 1108280304Sjkim LPSTR cname; 1109280304Sjkim CAPI_trace(ctx, "Listing containers CSP=%s, type = %d\n", ctx->cspname, 1110280304Sjkim ctx->csptype); 1111280304Sjkim if (!CryptAcquireContextA 1112280304Sjkim (&hprov, NULL, ctx->cspname, ctx->csptype, CRYPT_VERIFYCONTEXT)) { 1113280304Sjkim CAPIerr(CAPI_F_CAPI_LIST_CONTAINERS, 1114280304Sjkim CAPI_R_CRYPTACQUIRECONTEXT_ERROR); 1115280304Sjkim capi_addlasterror(); 1116280304Sjkim return 0; 1117280304Sjkim } 1118280304Sjkim if (!CryptGetProvParam 1119280304Sjkim (hprov, PP_ENUMCONTAINERS, NULL, &buflen, CRYPT_FIRST)) { 1120280304Sjkim CAPIerr(CAPI_F_CAPI_LIST_CONTAINERS, CAPI_R_ENUMCONTAINERS_ERROR); 1121280304Sjkim capi_addlasterror(); 1122280304Sjkim CryptReleaseContext(hprov, 0); 1123280304Sjkim return 0; 1124280304Sjkim } 1125280304Sjkim CAPI_trace(ctx, "Got max container len %d\n", buflen); 1126280304Sjkim if (buflen == 0) 1127280304Sjkim buflen = 1024; 1128280304Sjkim cname = OPENSSL_malloc(buflen); 1129280304Sjkim if (!cname) { 1130280304Sjkim CAPIerr(CAPI_F_CAPI_LIST_CONTAINERS, ERR_R_MALLOC_FAILURE); 1131280304Sjkim goto err; 1132280304Sjkim } 1133183234Ssimon 1134280304Sjkim for (idx = 0;; idx++) { 1135280304Sjkim clen = buflen; 1136280304Sjkim cname[0] = 0; 1137183234Ssimon 1138280304Sjkim if (idx == 0) 1139280304Sjkim flags = CRYPT_FIRST; 1140280304Sjkim else 1141280304Sjkim flags = 0; 1142280304Sjkim if (!CryptGetProvParam(hprov, PP_ENUMCONTAINERS, cname, &clen, flags)) { 1143280304Sjkim err = GetLastError(); 1144280304Sjkim if (err == ERROR_NO_MORE_ITEMS) 1145280304Sjkim goto done; 1146280304Sjkim CAPIerr(CAPI_F_CAPI_LIST_CONTAINERS, CAPI_R_ENUMCONTAINERS_ERROR); 1147280304Sjkim capi_adderror(err); 1148280304Sjkim goto err; 1149280304Sjkim } 1150280304Sjkim CAPI_trace(ctx, "Container name %s, len=%d, index=%d, flags=%d\n", 1151280304Sjkim cname, clen, idx, flags); 1152280304Sjkim if (!cname[0] && (clen == buflen)) { 1153280304Sjkim CAPI_trace(ctx, "Enumerate bug: using workaround\n"); 1154280304Sjkim goto done; 1155280304Sjkim } 1156280304Sjkim BIO_printf(out, "%d. %s\n", idx, cname); 1157280304Sjkim } 1158280304Sjkim err: 1159183234Ssimon 1160280304Sjkim ret = 0; 1161183234Ssimon 1162280304Sjkim done: 1163280304Sjkim if (cname) 1164280304Sjkim OPENSSL_free(cname); 1165280304Sjkim CryptReleaseContext(hprov, 0); 1166183234Ssimon 1167280304Sjkim return ret; 1168280304Sjkim} 1169183234Ssimon 1170280304SjkimCRYPT_KEY_PROV_INFO *capi_get_prov_info(CAPI_CTX * ctx, PCCERT_CONTEXT cert) 1171280304Sjkim{ 1172280304Sjkim DWORD len; 1173280304Sjkim CRYPT_KEY_PROV_INFO *pinfo; 1174183234Ssimon 1175280304Sjkim if (!CertGetCertificateContextProperty 1176280304Sjkim (cert, CERT_KEY_PROV_INFO_PROP_ID, NULL, &len)) 1177280304Sjkim return NULL; 1178280304Sjkim pinfo = OPENSSL_malloc(len); 1179280304Sjkim if (!pinfo) { 1180280304Sjkim CAPIerr(CAPI_F_CAPI_GET_PROV_INFO, ERR_R_MALLOC_FAILURE); 1181280304Sjkim return NULL; 1182280304Sjkim } 1183280304Sjkim if (!CertGetCertificateContextProperty 1184280304Sjkim (cert, CERT_KEY_PROV_INFO_PROP_ID, pinfo, &len)) { 1185280304Sjkim CAPIerr(CAPI_F_CAPI_GET_PROV_INFO, 1186280304Sjkim CAPI_R_ERROR_GETTING_KEY_PROVIDER_INFO); 1187280304Sjkim capi_addlasterror(); 1188280304Sjkim OPENSSL_free(pinfo); 1189280304Sjkim return NULL; 1190280304Sjkim } 1191280304Sjkim return pinfo; 1192280304Sjkim} 1193183234Ssimon 1194280304Sjkimstatic void capi_dump_prov_info(CAPI_CTX * ctx, BIO *out, 1195280304Sjkim CRYPT_KEY_PROV_INFO * pinfo) 1196280304Sjkim{ 1197280304Sjkim char *provname = NULL, *contname = NULL; 1198280304Sjkim if (!pinfo) { 1199280304Sjkim BIO_printf(out, " No Private Key\n"); 1200280304Sjkim return; 1201280304Sjkim } 1202280304Sjkim provname = wide_to_asc(pinfo->pwszProvName); 1203280304Sjkim contname = wide_to_asc(pinfo->pwszContainerName); 1204280304Sjkim if (!provname || !contname) 1205280304Sjkim goto err; 1206183234Ssimon 1207280304Sjkim BIO_printf(out, " Private Key Info:\n"); 1208280304Sjkim BIO_printf(out, " Provider Name: %s, Provider Type %d\n", provname, 1209280304Sjkim pinfo->dwProvType); 1210280304Sjkim BIO_printf(out, " Container Name: %s, Key Type %d\n", contname, 1211280304Sjkim pinfo->dwKeySpec); 1212280304Sjkim err: 1213280304Sjkim if (provname) 1214280304Sjkim OPENSSL_free(provname); 1215280304Sjkim if (contname) 1216280304Sjkim OPENSSL_free(contname); 1217280304Sjkim} 1218183234Ssimon 1219280304Sjkimchar *capi_cert_get_fname(CAPI_CTX * ctx, PCCERT_CONTEXT cert) 1220280304Sjkim{ 1221280304Sjkim LPWSTR wfname; 1222280304Sjkim DWORD dlen; 1223183234Ssimon 1224280304Sjkim CAPI_trace(ctx, "capi_cert_get_fname\n"); 1225280304Sjkim if (!CertGetCertificateContextProperty 1226280304Sjkim (cert, CERT_FRIENDLY_NAME_PROP_ID, NULL, &dlen)) 1227280304Sjkim return NULL; 1228280304Sjkim wfname = OPENSSL_malloc(dlen); 1229280304Sjkim if (CertGetCertificateContextProperty 1230280304Sjkim (cert, CERT_FRIENDLY_NAME_PROP_ID, wfname, &dlen)) { 1231280304Sjkim char *fname = wide_to_asc(wfname); 1232280304Sjkim OPENSSL_free(wfname); 1233280304Sjkim return fname; 1234280304Sjkim } 1235280304Sjkim CAPIerr(CAPI_F_CAPI_CERT_GET_FNAME, CAPI_R_ERROR_GETTING_FRIENDLY_NAME); 1236280304Sjkim capi_addlasterror(); 1237183234Ssimon 1238280304Sjkim OPENSSL_free(wfname); 1239280304Sjkim return NULL; 1240280304Sjkim} 1241183234Ssimon 1242280304Sjkimvoid capi_dump_cert(CAPI_CTX * ctx, BIO *out, PCCERT_CONTEXT cert) 1243280304Sjkim{ 1244280304Sjkim X509 *x; 1245280304Sjkim unsigned char *p; 1246280304Sjkim unsigned long flags = ctx->dump_flags; 1247280304Sjkim if (flags & CAPI_DMP_FNAME) { 1248280304Sjkim char *fname; 1249280304Sjkim fname = capi_cert_get_fname(ctx, cert); 1250280304Sjkim if (fname) { 1251280304Sjkim BIO_printf(out, " Friendly Name \"%s\"\n", fname); 1252280304Sjkim OPENSSL_free(fname); 1253280304Sjkim } else 1254280304Sjkim BIO_printf(out, " <No Friendly Name>\n"); 1255280304Sjkim } 1256183234Ssimon 1257280304Sjkim p = cert->pbCertEncoded; 1258280304Sjkim x = d2i_X509(NULL, &p, cert->cbCertEncoded); 1259280304Sjkim if (!x) 1260280304Sjkim BIO_printf(out, " <Can't parse certificate>\n"); 1261280304Sjkim if (flags & CAPI_DMP_SUMMARY) { 1262280304Sjkim BIO_printf(out, " Subject: "); 1263280304Sjkim X509_NAME_print_ex(out, X509_get_subject_name(x), 0, XN_FLAG_ONELINE); 1264280304Sjkim BIO_printf(out, "\n Issuer: "); 1265280304Sjkim X509_NAME_print_ex(out, X509_get_issuer_name(x), 0, XN_FLAG_ONELINE); 1266280304Sjkim BIO_printf(out, "\n"); 1267280304Sjkim } 1268280304Sjkim if (flags & CAPI_DMP_FULL) 1269280304Sjkim X509_print_ex(out, x, XN_FLAG_ONELINE, 0); 1270183234Ssimon 1271280304Sjkim if (flags & CAPI_DMP_PKEYINFO) { 1272280304Sjkim CRYPT_KEY_PROV_INFO *pinfo; 1273280304Sjkim pinfo = capi_get_prov_info(ctx, cert); 1274280304Sjkim capi_dump_prov_info(ctx, out, pinfo); 1275280304Sjkim if (pinfo) 1276280304Sjkim OPENSSL_free(pinfo); 1277280304Sjkim } 1278183234Ssimon 1279280304Sjkim if (flags & CAPI_DMP_PEM) 1280280304Sjkim PEM_write_bio_X509(out, x); 1281280304Sjkim X509_free(x); 1282280304Sjkim} 1283183234Ssimon 1284280304SjkimHCERTSTORE capi_open_store(CAPI_CTX * ctx, char *storename) 1285280304Sjkim{ 1286280304Sjkim HCERTSTORE hstore; 1287183234Ssimon 1288280304Sjkim if (!storename) 1289280304Sjkim storename = ctx->storename; 1290280304Sjkim if (!storename) 1291280304Sjkim storename = "MY"; 1292280304Sjkim CAPI_trace(ctx, "Opening certificate store %s\n", storename); 1293183234Ssimon 1294280304Sjkim hstore = CertOpenStore(CERT_STORE_PROV_SYSTEM_A, 0, 0, 1295280304Sjkim ctx->store_flags, storename); 1296280304Sjkim if (!hstore) { 1297280304Sjkim CAPIerr(CAPI_F_CAPI_OPEN_STORE, CAPI_R_ERROR_OPENING_STORE); 1298280304Sjkim capi_addlasterror(); 1299280304Sjkim } 1300280304Sjkim return hstore; 1301280304Sjkim} 1302183234Ssimon 1303280304Sjkimint capi_list_certs(CAPI_CTX * ctx, BIO *out, char *id) 1304280304Sjkim{ 1305280304Sjkim char *storename; 1306280304Sjkim int idx; 1307280304Sjkim int ret = 1; 1308280304Sjkim HCERTSTORE hstore; 1309280304Sjkim PCCERT_CONTEXT cert = NULL; 1310183234Ssimon 1311280304Sjkim storename = ctx->storename; 1312280304Sjkim if (!storename) 1313280304Sjkim storename = "MY"; 1314280304Sjkim CAPI_trace(ctx, "Listing certs for store %s\n", storename); 1315183234Ssimon 1316280304Sjkim hstore = capi_open_store(ctx, storename); 1317280304Sjkim if (!hstore) 1318280304Sjkim return 0; 1319280304Sjkim if (id) { 1320280304Sjkim cert = capi_find_cert(ctx, id, hstore); 1321280304Sjkim if (!cert) { 1322280304Sjkim ret = 0; 1323280304Sjkim goto err; 1324280304Sjkim } 1325280304Sjkim capi_dump_cert(ctx, out, cert); 1326280304Sjkim CertFreeCertificateContext(cert); 1327280304Sjkim } else { 1328280304Sjkim for (idx = 0;; idx++) { 1329280304Sjkim LPWSTR fname = NULL; 1330280304Sjkim cert = CertEnumCertificatesInStore(hstore, cert); 1331280304Sjkim if (!cert) 1332280304Sjkim break; 1333280304Sjkim BIO_printf(out, "Certificate %d\n", idx); 1334280304Sjkim capi_dump_cert(ctx, out, cert); 1335280304Sjkim } 1336280304Sjkim } 1337280304Sjkim err: 1338280304Sjkim CertCloseStore(hstore, 0); 1339280304Sjkim return ret; 1340280304Sjkim} 1341183234Ssimon 1342280304Sjkimstatic PCCERT_CONTEXT capi_find_cert(CAPI_CTX * ctx, const char *id, 1343280304Sjkim HCERTSTORE hstore) 1344280304Sjkim{ 1345280304Sjkim PCCERT_CONTEXT cert = NULL; 1346280304Sjkim char *fname = NULL; 1347280304Sjkim int match; 1348280304Sjkim switch (ctx->lookup_method) { 1349280304Sjkim case CAPI_LU_SUBSTR: 1350280304Sjkim return CertFindCertificateInStore(hstore, 1351280304Sjkim X509_ASN_ENCODING, 0, 1352280304Sjkim CERT_FIND_SUBJECT_STR_A, id, NULL); 1353280304Sjkim case CAPI_LU_FNAME: 1354280304Sjkim for (;;) { 1355280304Sjkim cert = CertEnumCertificatesInStore(hstore, cert); 1356280304Sjkim if (!cert) 1357280304Sjkim return NULL; 1358280304Sjkim fname = capi_cert_get_fname(ctx, cert); 1359280304Sjkim if (fname) { 1360280304Sjkim if (strcmp(fname, id)) 1361280304Sjkim match = 0; 1362280304Sjkim else 1363280304Sjkim match = 1; 1364280304Sjkim OPENSSL_free(fname); 1365280304Sjkim if (match) 1366280304Sjkim return cert; 1367280304Sjkim } 1368280304Sjkim } 1369280304Sjkim default: 1370280304Sjkim return NULL; 1371280304Sjkim } 1372280304Sjkim} 1373183234Ssimon 1374280304Sjkimstatic CAPI_KEY *capi_get_key(CAPI_CTX * ctx, const char *contname, 1375280304Sjkim char *provname, DWORD ptype, DWORD keyspec) 1376280304Sjkim{ 1377280304Sjkim CAPI_KEY *key; 1378280304Sjkim DWORD dwFlags = 0; 1379280304Sjkim key = OPENSSL_malloc(sizeof(CAPI_KEY)); 1380280304Sjkim CAPI_trace(ctx, "capi_get_key, contname=%s, provname=%s, type=%d\n", 1381280304Sjkim contname, provname, ptype); 1382280304Sjkim if (ctx->store_flags & CERT_SYSTEM_STORE_LOCAL_MACHINE) 1383246772Sjkim dwFlags = CRYPT_MACHINE_KEYSET; 1384280304Sjkim if (!CryptAcquireContextA 1385280304Sjkim (&key->hprov, contname, provname, ptype, dwFlags)) { 1386280304Sjkim CAPIerr(CAPI_F_CAPI_GET_KEY, CAPI_R_CRYPTACQUIRECONTEXT_ERROR); 1387280304Sjkim capi_addlasterror(); 1388280304Sjkim goto err; 1389280304Sjkim } 1390280304Sjkim if (!CryptGetUserKey(key->hprov, keyspec, &key->key)) { 1391280304Sjkim CAPIerr(CAPI_F_CAPI_GET_KEY, CAPI_R_GETUSERKEY_ERROR); 1392280304Sjkim capi_addlasterror(); 1393280304Sjkim CryptReleaseContext(key->hprov, 0); 1394280304Sjkim goto err; 1395280304Sjkim } 1396280304Sjkim key->keyspec = keyspec; 1397280304Sjkim key->pcert = NULL; 1398280304Sjkim return key; 1399183234Ssimon 1400280304Sjkim err: 1401280304Sjkim OPENSSL_free(key); 1402280304Sjkim return NULL; 1403280304Sjkim} 1404183234Ssimon 1405280304Sjkimstatic CAPI_KEY *capi_get_cert_key(CAPI_CTX * ctx, PCCERT_CONTEXT cert) 1406280304Sjkim{ 1407280304Sjkim CAPI_KEY *key = NULL; 1408280304Sjkim CRYPT_KEY_PROV_INFO *pinfo = NULL; 1409280304Sjkim char *provname = NULL, *contname = NULL; 1410280304Sjkim pinfo = capi_get_prov_info(ctx, cert); 1411280304Sjkim if (!pinfo) 1412280304Sjkim goto err; 1413280304Sjkim provname = wide_to_asc(pinfo->pwszProvName); 1414280304Sjkim contname = wide_to_asc(pinfo->pwszContainerName); 1415280304Sjkim if (!provname || !contname) 1416280304Sjkim goto err; 1417280304Sjkim key = capi_get_key(ctx, contname, provname, 1418280304Sjkim pinfo->dwProvType, pinfo->dwKeySpec); 1419183234Ssimon 1420280304Sjkim err: 1421280304Sjkim if (pinfo) 1422280304Sjkim OPENSSL_free(pinfo); 1423280304Sjkim if (provname) 1424280304Sjkim OPENSSL_free(provname); 1425280304Sjkim if (contname) 1426280304Sjkim OPENSSL_free(contname); 1427280304Sjkim return key; 1428280304Sjkim} 1429183234Ssimon 1430280304SjkimCAPI_KEY *capi_find_key(CAPI_CTX * ctx, const char *id) 1431280304Sjkim{ 1432280304Sjkim PCCERT_CONTEXT cert; 1433280304Sjkim HCERTSTORE hstore; 1434280304Sjkim CAPI_KEY *key = NULL; 1435280304Sjkim switch (ctx->lookup_method) { 1436280304Sjkim case CAPI_LU_SUBSTR: 1437280304Sjkim case CAPI_LU_FNAME: 1438280304Sjkim hstore = capi_open_store(ctx, NULL); 1439280304Sjkim if (!hstore) 1440280304Sjkim return NULL; 1441280304Sjkim cert = capi_find_cert(ctx, id, hstore); 1442280304Sjkim if (cert) { 1443280304Sjkim key = capi_get_cert_key(ctx, cert); 1444280304Sjkim CertFreeCertificateContext(cert); 1445280304Sjkim } 1446280304Sjkim CertCloseStore(hstore, 0); 1447280304Sjkim break; 1448183234Ssimon 1449280304Sjkim case CAPI_LU_CONTNAME: 1450280304Sjkim key = capi_get_key(ctx, id, ctx->cspname, ctx->csptype, ctx->keytype); 1451280304Sjkim break; 1452280304Sjkim } 1453183234Ssimon 1454280304Sjkim return key; 1455280304Sjkim} 1456183234Ssimon 1457280304Sjkimvoid capi_free_key(CAPI_KEY * key) 1458280304Sjkim{ 1459280304Sjkim if (!key) 1460280304Sjkim return; 1461280304Sjkim CryptDestroyKey(key->key); 1462280304Sjkim CryptReleaseContext(key->hprov, 0); 1463280304Sjkim if (key->pcert) 1464280304Sjkim CertFreeCertificateContext(key->pcert); 1465280304Sjkim OPENSSL_free(key); 1466280304Sjkim} 1467183234Ssimon 1468183234Ssimon/* Initialize a CAPI_CTX structure */ 1469183234Ssimon 1470183234Ssimonstatic CAPI_CTX *capi_ctx_new() 1471280304Sjkim{ 1472280304Sjkim CAPI_CTX *ctx; 1473280304Sjkim ctx = OPENSSL_malloc(sizeof(CAPI_CTX)); 1474280304Sjkim if (!ctx) { 1475280304Sjkim CAPIerr(CAPI_F_CAPI_CTX_NEW, ERR_R_MALLOC_FAILURE); 1476280304Sjkim return NULL; 1477280304Sjkim } 1478280304Sjkim ctx->cspname = NULL; 1479280304Sjkim ctx->csptype = PROV_RSA_FULL; 1480280304Sjkim ctx->dump_flags = CAPI_DMP_SUMMARY | CAPI_DMP_FNAME; 1481280304Sjkim ctx->keytype = AT_KEYEXCHANGE; 1482280304Sjkim ctx->storename = NULL; 1483280304Sjkim ctx->ssl_client_store = NULL; 1484280304Sjkim ctx->store_flags = CERT_STORE_OPEN_EXISTING_FLAG | 1485280304Sjkim CERT_STORE_READONLY_FLAG | CERT_SYSTEM_STORE_CURRENT_USER; 1486280304Sjkim ctx->lookup_method = CAPI_LU_SUBSTR; 1487280304Sjkim ctx->debug_level = 0; 1488280304Sjkim ctx->debug_file = NULL; 1489280304Sjkim ctx->client_cert_select = cert_select_simple; 1490280304Sjkim return ctx; 1491280304Sjkim} 1492183234Ssimon 1493280304Sjkimstatic void capi_ctx_free(CAPI_CTX * ctx) 1494280304Sjkim{ 1495280304Sjkim CAPI_trace(ctx, "Calling capi_ctx_free with %lx\n", ctx); 1496280304Sjkim if (!ctx) 1497280304Sjkim return; 1498280304Sjkim if (ctx->cspname) 1499280304Sjkim OPENSSL_free(ctx->cspname); 1500280304Sjkim if (ctx->debug_file) 1501280304Sjkim OPENSSL_free(ctx->debug_file); 1502280304Sjkim if (ctx->storename) 1503280304Sjkim OPENSSL_free(ctx->storename); 1504280304Sjkim if (ctx->ssl_client_store) 1505280304Sjkim OPENSSL_free(ctx->ssl_client_store); 1506280304Sjkim OPENSSL_free(ctx); 1507280304Sjkim} 1508183234Ssimon 1509280304Sjkimstatic int capi_ctx_set_provname(CAPI_CTX * ctx, LPSTR pname, DWORD type, 1510280304Sjkim int check) 1511280304Sjkim{ 1512280304Sjkim CAPI_trace(ctx, "capi_ctx_set_provname, name=%s, type=%d\n", pname, type); 1513280304Sjkim if (check) { 1514280304Sjkim HCRYPTPROV hprov; 1515280304Sjkim if (!CryptAcquireContextA(&hprov, NULL, pname, type, 1516280304Sjkim CRYPT_VERIFYCONTEXT)) { 1517280304Sjkim CAPIerr(CAPI_F_CAPI_CTX_SET_PROVNAME, 1518280304Sjkim CAPI_R_CRYPTACQUIRECONTEXT_ERROR); 1519280304Sjkim capi_addlasterror(); 1520280304Sjkim return 0; 1521280304Sjkim } 1522280304Sjkim CryptReleaseContext(hprov, 0); 1523280304Sjkim } 1524280304Sjkim if (ctx->cspname) 1525280304Sjkim OPENSSL_free(ctx->cspname); 1526280304Sjkim ctx->cspname = BUF_strdup(pname); 1527280304Sjkim ctx->csptype = type; 1528280304Sjkim return 1; 1529280304Sjkim} 1530183234Ssimon 1531280304Sjkimstatic int capi_ctx_set_provname_idx(CAPI_CTX * ctx, int idx) 1532280304Sjkim{ 1533280304Sjkim LPSTR pname; 1534280304Sjkim DWORD type; 1535280304Sjkim int res; 1536280304Sjkim if (capi_get_provname(ctx, &pname, &type, idx) != 1) 1537280304Sjkim return 0; 1538280304Sjkim res = capi_ctx_set_provname(ctx, pname, type, 0); 1539280304Sjkim OPENSSL_free(pname); 1540280304Sjkim return res; 1541280304Sjkim} 1542183234Ssimon 1543183234Ssimonstatic int cert_issuer_match(STACK_OF(X509_NAME) *ca_dn, X509 *x) 1544280304Sjkim{ 1545280304Sjkim int i; 1546280304Sjkim X509_NAME *nm; 1547280304Sjkim /* Special case: empty list: match anything */ 1548280304Sjkim if (sk_X509_NAME_num(ca_dn) <= 0) 1549280304Sjkim return 1; 1550280304Sjkim for (i = 0; i < sk_X509_NAME_num(ca_dn); i++) { 1551280304Sjkim nm = sk_X509_NAME_value(ca_dn, i); 1552280304Sjkim if (!X509_NAME_cmp(nm, X509_get_issuer_name(x))) 1553280304Sjkim return 1; 1554280304Sjkim } 1555280304Sjkim return 0; 1556280304Sjkim} 1557183234Ssimon 1558183234Ssimonstatic int capi_load_ssl_client_cert(ENGINE *e, SSL *ssl, 1559280304Sjkim STACK_OF(X509_NAME) *ca_dn, X509 **pcert, 1560280304Sjkim EVP_PKEY **pkey, STACK_OF(X509) **pother, 1561280304Sjkim UI_METHOD *ui_method, 1562280304Sjkim void *callback_data) 1563280304Sjkim{ 1564280304Sjkim STACK_OF(X509) *certs = NULL; 1565280304Sjkim X509 *x; 1566280304Sjkim char *storename; 1567280304Sjkim const char *p; 1568280304Sjkim int i, client_cert_idx; 1569280304Sjkim HCERTSTORE hstore; 1570280304Sjkim PCCERT_CONTEXT cert = NULL, excert = NULL; 1571280304Sjkim CAPI_CTX *ctx; 1572280304Sjkim CAPI_KEY *key; 1573280304Sjkim ctx = ENGINE_get_ex_data(e, capi_idx); 1574183234Ssimon 1575280304Sjkim *pcert = NULL; 1576280304Sjkim *pkey = NULL; 1577183234Ssimon 1578280304Sjkim storename = ctx->ssl_client_store; 1579280304Sjkim if (!storename) 1580280304Sjkim storename = "MY"; 1581183234Ssimon 1582280304Sjkim hstore = capi_open_store(ctx, storename); 1583280304Sjkim if (!hstore) 1584280304Sjkim return 0; 1585280304Sjkim /* Enumerate all certificates collect any matches */ 1586280304Sjkim for (i = 0;; i++) { 1587280304Sjkim cert = CertEnumCertificatesInStore(hstore, cert); 1588280304Sjkim if (!cert) 1589280304Sjkim break; 1590280304Sjkim p = cert->pbCertEncoded; 1591280304Sjkim x = d2i_X509(NULL, &p, cert->cbCertEncoded); 1592280304Sjkim if (!x) { 1593280304Sjkim CAPI_trace(ctx, "Can't Parse Certificate %d\n", i); 1594280304Sjkim continue; 1595280304Sjkim } 1596280304Sjkim if (cert_issuer_match(ca_dn, x) 1597280304Sjkim && X509_check_purpose(x, X509_PURPOSE_SSL_CLIENT, 0)) { 1598280304Sjkim key = capi_get_cert_key(ctx, cert); 1599280304Sjkim if (!key) { 1600280304Sjkim X509_free(x); 1601280304Sjkim continue; 1602280304Sjkim } 1603280304Sjkim /* 1604280304Sjkim * Match found: attach extra data to it so we can retrieve the 1605280304Sjkim * key later. 1606280304Sjkim */ 1607280304Sjkim excert = CertDuplicateCertificateContext(cert); 1608280304Sjkim key->pcert = excert; 1609280304Sjkim X509_set_ex_data(x, cert_capi_idx, key); 1610183234Ssimon 1611280304Sjkim if (!certs) 1612280304Sjkim certs = sk_X509_new_null(); 1613183234Ssimon 1614280304Sjkim sk_X509_push(certs, x); 1615280304Sjkim } else 1616280304Sjkim X509_free(x); 1617183234Ssimon 1618280304Sjkim } 1619183234Ssimon 1620280304Sjkim if (cert) 1621280304Sjkim CertFreeCertificateContext(cert); 1622280304Sjkim if (hstore) 1623280304Sjkim CertCloseStore(hstore, 0); 1624183234Ssimon 1625280304Sjkim if (!certs) 1626280304Sjkim return 0; 1627183234Ssimon 1628280304Sjkim /* Select the appropriate certificate */ 1629183234Ssimon 1630280304Sjkim client_cert_idx = ctx->client_cert_select(e, ssl, certs); 1631183234Ssimon 1632280304Sjkim /* Set the selected certificate and free the rest */ 1633183234Ssimon 1634280304Sjkim for (i = 0; i < sk_X509_num(certs); i++) { 1635280304Sjkim x = sk_X509_value(certs, i); 1636280304Sjkim if (i == client_cert_idx) 1637280304Sjkim *pcert = x; 1638280304Sjkim else { 1639280304Sjkim key = X509_get_ex_data(x, cert_capi_idx); 1640280304Sjkim capi_free_key(key); 1641280304Sjkim X509_free(x); 1642280304Sjkim } 1643280304Sjkim } 1644183234Ssimon 1645280304Sjkim sk_X509_free(certs); 1646183234Ssimon 1647280304Sjkim if (!*pcert) 1648280304Sjkim return 0; 1649183234Ssimon 1650280304Sjkim /* Setup key for selected certificate */ 1651183234Ssimon 1652280304Sjkim key = X509_get_ex_data(*pcert, cert_capi_idx); 1653280304Sjkim *pkey = capi_get_pkey(e, key); 1654280304Sjkim X509_set_ex_data(*pcert, cert_capi_idx, NULL); 1655183234Ssimon 1656280304Sjkim return 1; 1657183234Ssimon 1658280304Sjkim} 1659183234Ssimon 1660183234Ssimon/* Simple client cert selection function: always select first */ 1661183234Ssimon 1662183234Ssimonstatic int cert_select_simple(ENGINE *e, SSL *ssl, STACK_OF(X509) *certs) 1663280304Sjkim{ 1664280304Sjkim return 0; 1665280304Sjkim} 1666183234Ssimon 1667280304Sjkim# ifdef OPENSSL_CAPIENG_DIALOG 1668183234Ssimon 1669280304Sjkim/* 1670280304Sjkim * More complex cert selection function, using standard function 1671183234Ssimon * CryptUIDlgSelectCertificateFromStore() to produce a dialog box. 1672183234Ssimon */ 1673183234Ssimon 1674280304Sjkim/* 1675280304Sjkim * Definitions which are in cryptuiapi.h but this is not present in older 1676183234Ssimon * versions of headers. 1677183234Ssimon */ 1678183234Ssimon 1679280304Sjkim# ifndef CRYPTUI_SELECT_LOCATION_COLUMN 1680280304Sjkim# define CRYPTUI_SELECT_LOCATION_COLUMN 0x000000010 1681280304Sjkim# define CRYPTUI_SELECT_INTENDEDUSE_COLUMN 0x000000004 1682280304Sjkim# endif 1683183234Ssimon 1684280304Sjkim# define dlg_title L"OpenSSL Application SSL Client Certificate Selection" 1685280304Sjkim# define dlg_prompt L"Select a certificate to use for authentication" 1686280304Sjkim# define dlg_columns CRYPTUI_SELECT_LOCATION_COLUMN \ 1687280304Sjkim |CRYPTUI_SELECT_INTENDEDUSE_COLUMN 1688183234Ssimon 1689183234Ssimonstatic int cert_select_dialog(ENGINE *e, SSL *ssl, STACK_OF(X509) *certs) 1690280304Sjkim{ 1691280304Sjkim X509 *x; 1692280304Sjkim HCERTSTORE dstore; 1693280304Sjkim PCCERT_CONTEXT cert; 1694280304Sjkim CAPI_CTX *ctx; 1695280304Sjkim CAPI_KEY *key; 1696280304Sjkim HWND hwnd; 1697280304Sjkim int i, idx = -1; 1698280304Sjkim if (sk_X509_num(certs) == 1) 1699280304Sjkim return 0; 1700280304Sjkim ctx = ENGINE_get_ex_data(e, capi_idx); 1701280304Sjkim /* Create an in memory store of certificates */ 1702280304Sjkim dstore = CertOpenStore(CERT_STORE_PROV_MEMORY, 0, 0, 1703280304Sjkim CERT_STORE_CREATE_NEW_FLAG, NULL); 1704280304Sjkim if (!dstore) { 1705280304Sjkim CAPIerr(CAPI_F_CERT_SELECT_DIALOG, CAPI_R_ERROR_CREATING_STORE); 1706280304Sjkim capi_addlasterror(); 1707280304Sjkim goto err; 1708280304Sjkim } 1709280304Sjkim /* Add all certificates to store */ 1710280304Sjkim for (i = 0; i < sk_X509_num(certs); i++) { 1711280304Sjkim x = sk_X509_value(certs, i); 1712280304Sjkim key = X509_get_ex_data(x, cert_capi_idx); 1713183234Ssimon 1714280304Sjkim if (!CertAddCertificateContextToStore(dstore, key->pcert, 1715280304Sjkim CERT_STORE_ADD_NEW, NULL)) { 1716280304Sjkim CAPIerr(CAPI_F_CERT_SELECT_DIALOG, CAPI_R_ERROR_ADDING_CERT); 1717280304Sjkim capi_addlasterror(); 1718280304Sjkim goto err; 1719280304Sjkim } 1720183234Ssimon 1721280304Sjkim } 1722280304Sjkim hwnd = GetForegroundWindow(); 1723280304Sjkim if (!hwnd) 1724280304Sjkim hwnd = GetActiveWindow(); 1725280304Sjkim if (!hwnd && ctx->getconswindow) 1726280304Sjkim hwnd = ctx->getconswindow(); 1727280304Sjkim /* Call dialog to select one */ 1728280304Sjkim cert = ctx->certselectdlg(dstore, hwnd, dlg_title, dlg_prompt, 1729280304Sjkim dlg_columns, 0, NULL); 1730183234Ssimon 1731280304Sjkim /* Find matching cert from list */ 1732280304Sjkim if (cert) { 1733280304Sjkim for (i = 0; i < sk_X509_num(certs); i++) { 1734280304Sjkim x = sk_X509_value(certs, i); 1735280304Sjkim key = X509_get_ex_data(x, cert_capi_idx); 1736280304Sjkim if (CertCompareCertificate 1737280304Sjkim (X509_ASN_ENCODING | PKCS_7_ASN_ENCODING, cert->pCertInfo, 1738280304Sjkim key->pcert->pCertInfo)) { 1739280304Sjkim idx = i; 1740280304Sjkim break; 1741280304Sjkim } 1742280304Sjkim } 1743280304Sjkim } 1744183234Ssimon 1745280304Sjkim err: 1746280304Sjkim if (dstore) 1747280304Sjkim CertCloseStore(dstore, 0); 1748280304Sjkim return idx; 1749183234Ssimon 1750280304Sjkim} 1751280304Sjkim# endif 1752183234Ssimon 1753280304Sjkim#else /* !__COMPILE_CAPIENG */ 1754280304Sjkim# include <openssl/engine.h> 1755280304Sjkim# ifndef OPENSSL_NO_DYNAMIC_ENGINE 1756183234SsimonOPENSSL_EXPORT 1757280304Sjkim int bind_engine(ENGINE *e, const char *id, const dynamic_fns *fns); 1758238405SjkimOPENSSL_EXPORT 1759280304Sjkim int bind_engine(ENGINE *e, const char *id, const dynamic_fns *fns) 1760280304Sjkim{ 1761280304Sjkim return 0; 1762280304Sjkim} 1763280304Sjkim 1764183234SsimonIMPLEMENT_DYNAMIC_CHECK_FN() 1765280304Sjkim# else 1766280304Sjkimvoid ENGINE_load_capi(void) 1767280304Sjkim{ 1768280304Sjkim} 1769280304Sjkim# endif 1770183234Ssimon#endif 1771