1 /* 2 * Copyright 2008-2025 The OpenSSL Project Authors. All Rights Reserved. 3 * 4 * Licensed under the Apache License 2.0 (the "License"). You may not use 5 * this file except in compliance with the License. You can obtain a copy 6 * in the file LICENSE in the source distribution or at 7 * https://www.openssl.org/source/license.html 8 */ 9 10 /* We need to use some deprecated APIs */ 11 #define OPENSSL_SUPPRESS_DEPRECATED 12 13 #ifdef _WIN32 14 #ifndef _WIN32_WINNT 15 #define _WIN32_WINNT 0x0400 16 #endif 17 #include <windows.h> 18 #include <wincrypt.h> 19 20 #include <stdio.h> 21 #include <string.h> 22 #include <stdlib.h> 23 #include <malloc.h> 24 #ifndef alloca 25 #define alloca _alloca 26 #endif 27 28 #include <openssl/crypto.h> 29 30 #ifndef OPENSSL_NO_CAPIENG 31 32 #include <openssl/buffer.h> 33 #include <openssl/bn.h> 34 #include <openssl/rsa.h> 35 #include <openssl/dsa.h> 36 37 /* 38 * This module uses several "new" interfaces, among which is 39 * CertGetCertificateContextProperty. CERT_KEY_PROV_INFO_PROP_ID is 40 * one of possible values you can pass to function in question. By 41 * checking if it's defined we can see if wincrypt.h and accompanying 42 * crypt32.lib are in shape. The native MingW32 headers up to and 43 * including __W32API_VERSION 3.14 lack of struct DSSPUBKEY and the 44 * defines CERT_STORE_PROV_SYSTEM_A and CERT_STORE_READONLY_FLAG, 45 * so we check for these too and avoid compiling. 46 * Yes, it's rather "weak" test and if compilation fails, 47 * then re-configure with -DOPENSSL_NO_CAPIENG. 48 */ 49 #if defined(CERT_KEY_PROV_INFO_PROP_ID) && defined(CERT_STORE_PROV_SYSTEM_A) && defined(CERT_STORE_READONLY_FLAG) 50 #define __COMPILE_CAPIENG 51 #endif /* CERT_KEY_PROV_INFO_PROP_ID */ 52 #endif /* OPENSSL_NO_CAPIENG */ 53 #endif /* _WIN32 */ 54 55 #ifdef __COMPILE_CAPIENG 56 57 #undef X509_EXTENSIONS 58 59 /* Definitions which may be missing from earlier version of headers */ 60 #ifndef CERT_STORE_OPEN_EXISTING_FLAG 61 #define CERT_STORE_OPEN_EXISTING_FLAG 0x00004000 62 #endif 63 64 #ifndef CERT_STORE_CREATE_NEW_FLAG 65 #define CERT_STORE_CREATE_NEW_FLAG 0x00002000 66 #endif 67 68 #ifndef CERT_SYSTEM_STORE_CURRENT_USER 69 #define CERT_SYSTEM_STORE_CURRENT_USER 0x00010000 70 #endif 71 72 #ifndef ALG_SID_SHA_256 73 #define ALG_SID_SHA_256 12 74 #endif 75 #ifndef ALG_SID_SHA_384 76 #define ALG_SID_SHA_384 13 77 #endif 78 #ifndef ALG_SID_SHA_512 79 #define ALG_SID_SHA_512 14 80 #endif 81 82 #ifndef CALG_SHA_256 83 #define CALG_SHA_256 (ALG_CLASS_HASH | ALG_TYPE_ANY | ALG_SID_SHA_256) 84 #endif 85 #ifndef CALG_SHA_384 86 #define CALG_SHA_384 (ALG_CLASS_HASH | ALG_TYPE_ANY | ALG_SID_SHA_384) 87 #endif 88 #ifndef CALG_SHA_512 89 #define CALG_SHA_512 (ALG_CLASS_HASH | ALG_TYPE_ANY | ALG_SID_SHA_512) 90 #endif 91 92 #ifndef PROV_RSA_AES 93 #define PROV_RSA_AES 24 94 #endif 95 96 #include <openssl/engine.h> 97 #include <openssl/pem.h> 98 #include <openssl/x509v3.h> 99 100 /* clang-format off */ 101 # include "e_capi_err.h" 102 # include "e_capi_err.c" 103 /* clang-format on */ 104 105 static const char *engine_capi_id = "capi"; 106 static const char *engine_capi_name = "CryptoAPI ENGINE"; 107 108 typedef struct CAPI_CTX_st CAPI_CTX; 109 typedef struct CAPI_KEY_st CAPI_KEY; 110 111 static void capi_addlasterror(void); 112 static void capi_adderror(DWORD err); 113 114 static void CAPI_trace(CAPI_CTX *ctx, char *format, ...); 115 116 static int capi_list_providers(CAPI_CTX *ctx, BIO *out); 117 static int capi_list_containers(CAPI_CTX *ctx, BIO *out); 118 int capi_list_certs(CAPI_CTX *ctx, BIO *out, char *storename); 119 void capi_free_key(CAPI_KEY *key); 120 121 static PCCERT_CONTEXT capi_find_cert(CAPI_CTX *ctx, const char *id, 122 HCERTSTORE hstore); 123 124 CAPI_KEY *capi_find_key(CAPI_CTX *ctx, const char *id); 125 126 static EVP_PKEY *capi_load_privkey(ENGINE *eng, const char *key_id, 127 UI_METHOD *ui_method, void *callback_data); 128 static int capi_rsa_sign(int dtype, const unsigned char *m, 129 unsigned int m_len, unsigned char *sigret, 130 unsigned int *siglen, const RSA *rsa); 131 static int capi_rsa_priv_enc(int flen, const unsigned char *from, 132 unsigned char *to, RSA *rsa, int padding); 133 static int capi_rsa_priv_dec(int flen, const unsigned char *from, 134 unsigned char *to, RSA *rsa, int padding); 135 static int capi_rsa_free(RSA *rsa); 136 137 #ifndef OPENSSL_NO_DSA 138 static DSA_SIG *capi_dsa_do_sign(const unsigned char *digest, int dlen, 139 DSA *dsa); 140 static int capi_dsa_free(DSA *dsa); 141 #endif 142 143 static int capi_load_ssl_client_cert(ENGINE *e, SSL *ssl, 144 STACK_OF(X509_NAME) *ca_dn, X509 **pcert, 145 EVP_PKEY **pkey, STACK_OF(X509) **pother, 146 UI_METHOD *ui_method, 147 void *callback_data); 148 149 static int cert_select_simple(ENGINE *e, SSL *ssl, STACK_OF(X509) *certs); 150 #ifdef OPENSSL_CAPIENG_DIALOG 151 static int cert_select_dialog(ENGINE *e, SSL *ssl, STACK_OF(X509) *certs); 152 #endif 153 154 void engine_load_capi_int(void); 155 156 typedef PCCERT_CONTEXT(WINAPI *CERTDLG)(HCERTSTORE, HWND, LPCWSTR, 157 LPCWSTR, DWORD, DWORD, void *); 158 typedef HWND(WINAPI *GETCONSWIN)(void); 159 160 /* 161 * This structure contains CAPI ENGINE specific data: it contains various 162 * global options and affects how other functions behave. 163 */ 164 165 #define CAPI_DBG_TRACE 2 166 #define CAPI_DBG_ERROR 1 167 168 struct CAPI_CTX_st { 169 int debug_level; 170 char *debug_file; 171 /* Parameters to use for container lookup */ 172 DWORD keytype; 173 LPSTR cspname; 174 DWORD csptype; 175 /* Certificate store name to use */ 176 LPSTR storename; 177 LPSTR ssl_client_store; 178 /* System store flags */ 179 DWORD store_flags; 180 /* Lookup string meanings in load_private_key */ 181 #define CAPI_LU_SUBSTR 1 /* Substring of subject: uses "storename" */ 182 #define CAPI_LU_FNAME 2 /* Friendly name: uses storename */ 183 #define CAPI_LU_CONTNAME 3 /* Container name: uses cspname, keytype */ 184 int lookup_method; 185 /* Info to dump with dumpcerts option */ 186 #define CAPI_DMP_SUMMARY 0x1 /* Issuer and serial name strings */ 187 #define CAPI_DMP_FNAME 0x2 /* Friendly name */ 188 #define CAPI_DMP_FULL 0x4 /* Full X509_print dump */ 189 #define CAPI_DMP_PEM 0x8 /* Dump PEM format certificate */ 190 #define CAPI_DMP_PSKEY 0x10 /* Dump pseudo key (if possible) */ 191 #define CAPI_DMP_PKEYINFO 0x20 /* Dump key info (if possible) */ 192 DWORD dump_flags; 193 int (*client_cert_select)(ENGINE *e, SSL *ssl, STACK_OF(X509) *certs); 194 CERTDLG certselectdlg; 195 GETCONSWIN getconswindow; 196 }; 197 198 static CAPI_CTX *capi_ctx_new(void); 199 static void capi_ctx_free(CAPI_CTX *ctx); 200 static int capi_ctx_set_provname(CAPI_CTX *ctx, LPSTR pname, DWORD type, 201 int check); 202 static int capi_ctx_set_provname_idx(CAPI_CTX *ctx, int idx); 203 204 #define CAPI_CMD_LIST_CERTS ENGINE_CMD_BASE 205 #define CAPI_CMD_LOOKUP_CERT (ENGINE_CMD_BASE + 1) 206 #define CAPI_CMD_DEBUG_LEVEL (ENGINE_CMD_BASE + 2) 207 #define CAPI_CMD_DEBUG_FILE (ENGINE_CMD_BASE + 3) 208 #define CAPI_CMD_KEYTYPE (ENGINE_CMD_BASE + 4) 209 #define CAPI_CMD_LIST_CSPS (ENGINE_CMD_BASE + 5) 210 #define CAPI_CMD_SET_CSP_IDX (ENGINE_CMD_BASE + 6) 211 #define CAPI_CMD_SET_CSP_NAME (ENGINE_CMD_BASE + 7) 212 #define CAPI_CMD_SET_CSP_TYPE (ENGINE_CMD_BASE + 8) 213 #define CAPI_CMD_LIST_CONTAINERS (ENGINE_CMD_BASE + 9) 214 #define CAPI_CMD_LIST_OPTIONS (ENGINE_CMD_BASE + 10) 215 #define CAPI_CMD_LOOKUP_METHOD (ENGINE_CMD_BASE + 11) 216 #define CAPI_CMD_STORE_NAME (ENGINE_CMD_BASE + 12) 217 #define CAPI_CMD_STORE_FLAGS (ENGINE_CMD_BASE + 13) 218 219 static const ENGINE_CMD_DEFN capi_cmd_defns[] = { 220 { CAPI_CMD_LIST_CERTS, 221 "list_certs", 222 "List all certificates in store", 223 ENGINE_CMD_FLAG_NO_INPUT }, 224 { CAPI_CMD_LOOKUP_CERT, 225 "lookup_cert", 226 "Lookup and output certificates", 227 ENGINE_CMD_FLAG_STRING }, 228 { CAPI_CMD_DEBUG_LEVEL, 229 "debug_level", 230 "debug level (1=errors, 2=trace)", 231 ENGINE_CMD_FLAG_NUMERIC }, 232 { CAPI_CMD_DEBUG_FILE, 233 "debug_file", 234 "debugging filename)", 235 ENGINE_CMD_FLAG_STRING }, 236 { CAPI_CMD_KEYTYPE, 237 "key_type", 238 "Key type: 1=AT_KEYEXCHANGE (default), 2=AT_SIGNATURE", 239 ENGINE_CMD_FLAG_NUMERIC }, 240 { CAPI_CMD_LIST_CSPS, 241 "list_csps", 242 "List all CSPs", 243 ENGINE_CMD_FLAG_NO_INPUT }, 244 { CAPI_CMD_SET_CSP_IDX, 245 "csp_idx", 246 "Set CSP by index", 247 ENGINE_CMD_FLAG_NUMERIC }, 248 { CAPI_CMD_SET_CSP_NAME, 249 "csp_name", 250 "Set CSP name, (default CSP used if not specified)", 251 ENGINE_CMD_FLAG_STRING }, 252 { CAPI_CMD_SET_CSP_TYPE, 253 "csp_type", 254 "Set CSP type, (default RSA_PROV_FULL)", 255 ENGINE_CMD_FLAG_NUMERIC }, 256 { CAPI_CMD_LIST_CONTAINERS, 257 "list_containers", 258 "list container names", 259 ENGINE_CMD_FLAG_NO_INPUT }, 260 { CAPI_CMD_LIST_OPTIONS, 261 "list_options", 262 "Set list options (1=summary,2=friendly name, 4=full printout, 8=PEM output, 16=XXX, " 263 "32=private key info)", 264 ENGINE_CMD_FLAG_NUMERIC }, 265 { CAPI_CMD_LOOKUP_METHOD, 266 "lookup_method", 267 "Set key lookup method (1=substring, 2=friendlyname, 3=container name)", 268 ENGINE_CMD_FLAG_NUMERIC }, 269 { CAPI_CMD_STORE_NAME, 270 "store_name", 271 "certificate store name, default \"MY\"", 272 ENGINE_CMD_FLAG_STRING }, 273 { CAPI_CMD_STORE_FLAGS, 274 "store_flags", 275 "Certificate store flags: 1 = system store", 276 ENGINE_CMD_FLAG_NUMERIC }, 277 278 { 0, NULL, NULL, 0 } 279 }; 280 281 static int capi_idx = -1; 282 static int rsa_capi_idx = -1; 283 static int dsa_capi_idx = -1; 284 static int cert_capi_idx = -1; 285 286 static int capi_ctrl(ENGINE *e, int cmd, long i, void *p, void (*f)(void)) 287 { 288 int ret = 1; 289 CAPI_CTX *ctx; 290 BIO *out; 291 LPSTR tmpstr; 292 if (capi_idx == -1) { 293 CAPIerr(CAPI_F_CAPI_CTRL, CAPI_R_ENGINE_NOT_INITIALIZED); 294 return 0; 295 } 296 ctx = ENGINE_get_ex_data(e, capi_idx); 297 out = BIO_new_fp(stdout, BIO_NOCLOSE); 298 if (out == NULL) { 299 CAPIerr(CAPI_F_CAPI_CTRL, CAPI_R_FILE_OPEN_ERROR); 300 return 0; 301 } 302 switch (cmd) { 303 case CAPI_CMD_LIST_CSPS: 304 ret = capi_list_providers(ctx, out); 305 break; 306 307 case CAPI_CMD_LIST_CERTS: 308 ret = capi_list_certs(ctx, out, NULL); 309 break; 310 311 case CAPI_CMD_LOOKUP_CERT: 312 ret = capi_list_certs(ctx, out, p); 313 break; 314 315 case CAPI_CMD_LIST_CONTAINERS: 316 ret = capi_list_containers(ctx, out); 317 break; 318 319 case CAPI_CMD_STORE_NAME: 320 tmpstr = OPENSSL_strdup(p); 321 if (tmpstr != NULL) { 322 OPENSSL_free(ctx->storename); 323 ctx->storename = tmpstr; 324 CAPI_trace(ctx, "Setting store name to %s\n", p); 325 } else { 326 ret = 0; 327 } 328 break; 329 330 case CAPI_CMD_STORE_FLAGS: 331 if (i & 1) { 332 ctx->store_flags |= CERT_SYSTEM_STORE_LOCAL_MACHINE; 333 ctx->store_flags &= ~CERT_SYSTEM_STORE_CURRENT_USER; 334 } else { 335 ctx->store_flags |= CERT_SYSTEM_STORE_CURRENT_USER; 336 ctx->store_flags &= ~CERT_SYSTEM_STORE_LOCAL_MACHINE; 337 } 338 CAPI_trace(ctx, "Setting flags to %d\n", i); 339 break; 340 341 case CAPI_CMD_DEBUG_LEVEL: 342 ctx->debug_level = (int)i; 343 CAPI_trace(ctx, "Setting debug level to %d\n", ctx->debug_level); 344 break; 345 346 case CAPI_CMD_DEBUG_FILE: 347 tmpstr = OPENSSL_strdup(p); 348 if (tmpstr != NULL) { 349 ctx->debug_file = tmpstr; 350 CAPI_trace(ctx, "Setting debug file to %s\n", ctx->debug_file); 351 } else { 352 ret = 0; 353 } 354 break; 355 356 case CAPI_CMD_KEYTYPE: 357 ctx->keytype = i; 358 CAPI_trace(ctx, "Setting key type to %d\n", ctx->keytype); 359 break; 360 361 case CAPI_CMD_SET_CSP_IDX: 362 ret = capi_ctx_set_provname_idx(ctx, i); 363 break; 364 365 case CAPI_CMD_LIST_OPTIONS: 366 ctx->dump_flags = i; 367 break; 368 369 case CAPI_CMD_LOOKUP_METHOD: 370 if (i < 1 || i > 3) { 371 CAPIerr(CAPI_F_CAPI_CTRL, CAPI_R_INVALID_LOOKUP_METHOD); 372 BIO_free(out); 373 return 0; 374 } 375 ctx->lookup_method = i; 376 break; 377 378 case CAPI_CMD_SET_CSP_NAME: 379 ret = capi_ctx_set_provname(ctx, p, ctx->csptype, 1); 380 break; 381 382 case CAPI_CMD_SET_CSP_TYPE: 383 ctx->csptype = i; 384 break; 385 386 default: 387 CAPIerr(CAPI_F_CAPI_CTRL, CAPI_R_UNKNOWN_COMMAND); 388 ret = 0; 389 } 390 391 BIO_free(out); 392 return ret; 393 } 394 395 static RSA_METHOD *capi_rsa_method = NULL; 396 #ifndef OPENSSL_NO_DSA 397 static DSA_METHOD *capi_dsa_method = NULL; 398 #endif 399 400 static int use_aes_csp = 0; 401 static const WCHAR rsa_aes_cspname[] = L"Microsoft Enhanced RSA and AES Cryptographic Provider"; 402 static const WCHAR rsa_enh_cspname[] = L"Microsoft Enhanced Cryptographic Provider v1.0"; 403 404 static int capi_init(ENGINE *e) 405 { 406 CAPI_CTX *ctx; 407 const RSA_METHOD *ossl_rsa_meth; 408 #ifndef OPENSSL_NO_DSA 409 const DSA_METHOD *ossl_dsa_meth; 410 #endif 411 HCRYPTPROV hprov; 412 413 if (capi_idx < 0) { 414 capi_idx = ENGINE_get_ex_new_index(0, NULL, NULL, NULL, 0); 415 if (capi_idx < 0) { 416 CAPIerr(CAPI_F_CAPI_INIT, ERR_R_ENGINE_LIB); 417 goto err; 418 } 419 420 cert_capi_idx = X509_get_ex_new_index(0, NULL, NULL, NULL, 0); 421 422 /* Setup RSA_METHOD */ 423 rsa_capi_idx = RSA_get_ex_new_index(0, NULL, NULL, NULL, 0); 424 ossl_rsa_meth = RSA_PKCS1_OpenSSL(); 425 if (!RSA_meth_set_pub_enc(capi_rsa_method, 426 RSA_meth_get_pub_enc(ossl_rsa_meth)) 427 || !RSA_meth_set_pub_dec(capi_rsa_method, 428 RSA_meth_get_pub_dec(ossl_rsa_meth)) 429 || !RSA_meth_set_priv_enc(capi_rsa_method, capi_rsa_priv_enc) 430 || !RSA_meth_set_priv_dec(capi_rsa_method, capi_rsa_priv_dec) 431 || !RSA_meth_set_mod_exp(capi_rsa_method, 432 RSA_meth_get_mod_exp(ossl_rsa_meth)) 433 || !RSA_meth_set_bn_mod_exp(capi_rsa_method, 434 RSA_meth_get_bn_mod_exp(ossl_rsa_meth)) 435 || !RSA_meth_set_finish(capi_rsa_method, capi_rsa_free) 436 || !RSA_meth_set_sign(capi_rsa_method, capi_rsa_sign)) { 437 CAPIerr(CAPI_F_CAPI_INIT, ERR_R_RSA_LIB); 438 goto err; 439 } 440 441 #ifndef OPENSSL_NO_DSA 442 /* Setup DSA Method */ 443 dsa_capi_idx = DSA_get_ex_new_index(0, NULL, NULL, NULL, 0); 444 ossl_dsa_meth = DSA_OpenSSL(); 445 if (!DSA_meth_set_sign(capi_dsa_method, capi_dsa_do_sign) 446 || !DSA_meth_set_verify(capi_dsa_method, 447 DSA_meth_get_verify(ossl_dsa_meth)) 448 || !DSA_meth_set_finish(capi_dsa_method, capi_dsa_free) 449 || !DSA_meth_set_mod_exp(capi_dsa_method, 450 DSA_meth_get_mod_exp(ossl_dsa_meth)) 451 || !DSA_meth_set_bn_mod_exp(capi_dsa_method, 452 DSA_meth_get_bn_mod_exp(ossl_dsa_meth))) { 453 CAPIerr(CAPI_F_CAPI_INIT, ERR_R_DSA_LIB); 454 goto err; 455 } 456 #endif 457 } 458 459 ctx = capi_ctx_new(); 460 if (ctx == NULL) { 461 CAPIerr(CAPI_F_CAPI_INIT, ERR_R_CAPI_LIB); 462 goto err; 463 } 464 465 ENGINE_set_ex_data(e, capi_idx, ctx); 466 467 #ifdef OPENSSL_CAPIENG_DIALOG 468 { 469 HMODULE cryptui = LoadLibrary(TEXT("CRYPTUI.DLL")); 470 HMODULE kernel = GetModuleHandle(TEXT("KERNEL32.DLL")); 471 if (cryptui) 472 ctx->certselectdlg = (CERTDLG)GetProcAddress(cryptui, 473 "CryptUIDlgSelectCertificateFromStore"); 474 if (kernel) 475 ctx->getconswindow = (GETCONSWIN)GetProcAddress(kernel, "GetConsoleWindow"); 476 if (cryptui && !OPENSSL_isservice()) 477 ctx->client_cert_select = cert_select_dialog; 478 } 479 #endif 480 481 /* See if there is RSA+AES CSP */ 482 if (CryptAcquireContextW(&hprov, NULL, rsa_aes_cspname, PROV_RSA_AES, 483 CRYPT_VERIFYCONTEXT)) { 484 use_aes_csp = 1; 485 CryptReleaseContext(hprov, 0); 486 } 487 488 return 1; 489 490 err: 491 return 0; 492 } 493 494 static int capi_destroy(ENGINE *e) 495 { 496 RSA_meth_free(capi_rsa_method); 497 capi_rsa_method = NULL; 498 #ifndef OPENSSL_NO_DSA 499 DSA_meth_free(capi_dsa_method); 500 capi_dsa_method = NULL; 501 #endif 502 ERR_unload_CAPI_strings(); 503 return 1; 504 } 505 506 static int capi_finish(ENGINE *e) 507 { 508 CAPI_CTX *ctx; 509 ctx = ENGINE_get_ex_data(e, capi_idx); 510 capi_ctx_free(ctx); 511 ENGINE_set_ex_data(e, capi_idx, NULL); 512 return 1; 513 } 514 515 /* 516 * CryptoAPI key application data. This contains a handle to the private key 517 * container (for sign operations) and a handle to the key (for decrypt 518 * operations). 519 */ 520 521 struct CAPI_KEY_st { 522 /* Associated certificate context (if any) */ 523 PCCERT_CONTEXT pcert; 524 HCRYPTPROV hprov; 525 HCRYPTKEY key; 526 DWORD keyspec; 527 }; 528 529 static int bind_capi(ENGINE *e) 530 { 531 capi_rsa_method = RSA_meth_new("CryptoAPI RSA method", 0); 532 if (capi_rsa_method == NULL) 533 return 0; 534 #ifndef OPENSSL_NO_DSA 535 capi_dsa_method = DSA_meth_new("CryptoAPI DSA method", 0); 536 if (capi_dsa_method == NULL) 537 goto memerr; 538 #endif 539 if (!ENGINE_set_id(e, engine_capi_id) 540 || !ENGINE_set_name(e, engine_capi_name) 541 || !ENGINE_set_flags(e, ENGINE_FLAGS_NO_REGISTER_ALL) 542 || !ENGINE_set_init_function(e, capi_init) 543 || !ENGINE_set_finish_function(e, capi_finish) 544 || !ENGINE_set_destroy_function(e, capi_destroy) 545 || !ENGINE_set_RSA(e, capi_rsa_method) 546 #ifndef OPENSSL_NO_DSA 547 || !ENGINE_set_DSA(e, capi_dsa_method) 548 #endif 549 || !ENGINE_set_load_privkey_function(e, capi_load_privkey) 550 || !ENGINE_set_load_ssl_client_cert_function(e, 551 capi_load_ssl_client_cert) 552 || !ENGINE_set_cmd_defns(e, capi_cmd_defns) 553 || !ENGINE_set_ctrl_function(e, capi_ctrl)) 554 goto memerr; 555 ERR_load_CAPI_strings(); 556 557 return 1; 558 memerr: 559 RSA_meth_free(capi_rsa_method); 560 capi_rsa_method = NULL; 561 #ifndef OPENSSL_NO_DSA 562 DSA_meth_free(capi_dsa_method); 563 capi_dsa_method = NULL; 564 #endif 565 return 0; 566 } 567 568 #ifndef OPENSSL_NO_DYNAMIC_ENGINE 569 static int bind_helper(ENGINE *e, const char *id) 570 { 571 if (id && (strcmp(id, engine_capi_id) != 0)) 572 return 0; 573 if (!bind_capi(e)) 574 return 0; 575 return 1; 576 } 577 578 IMPLEMENT_DYNAMIC_CHECK_FN() 579 IMPLEMENT_DYNAMIC_BIND_FN(bind_helper) 580 #else 581 static ENGINE *engine_capi(void) 582 { 583 ENGINE *ret = ENGINE_new(); 584 if (ret == NULL) 585 return NULL; 586 if (!bind_capi(ret)) { 587 ENGINE_free(ret); 588 return NULL; 589 } 590 return ret; 591 } 592 593 void engine_load_capi_int(void) 594 { 595 /* Copied from eng_[openssl|dyn].c */ 596 ENGINE *toadd = engine_capi(); 597 if (!toadd) 598 return; 599 ERR_set_mark(); 600 ENGINE_add(toadd); 601 /* 602 * If the "add" worked, it gets a structural reference. So either way, we 603 * release our just-created reference. 604 */ 605 ENGINE_free(toadd); 606 /* 607 * If the "add" didn't work, it was probably a conflict because it was 608 * already added (eg. someone calling ENGINE_load_blah then calling 609 * ENGINE_load_builtin_engines() perhaps). 610 */ 611 ERR_pop_to_mark(); 612 } 613 #endif 614 615 static int lend_tobn(BIGNUM *bn, unsigned char *bin, int binlen) 616 { 617 int i; 618 /* 619 * Reverse buffer in place: since this is a keyblob structure that will 620 * be freed up after conversion anyway it doesn't matter if we change 621 * it. 622 */ 623 for (i = 0; i < binlen / 2; i++) { 624 unsigned char c; 625 c = bin[i]; 626 bin[i] = bin[binlen - i - 1]; 627 bin[binlen - i - 1] = c; 628 } 629 630 if (!BN_bin2bn(bin, binlen, bn)) 631 return 0; 632 return 1; 633 } 634 635 /* Given a CAPI_KEY get an EVP_PKEY structure */ 636 637 static EVP_PKEY *capi_get_pkey(ENGINE *eng, CAPI_KEY *key) 638 { 639 unsigned char *pubkey = NULL; 640 DWORD len; 641 BLOBHEADER *bh; 642 RSA *rkey = NULL; 643 DSA *dkey = NULL; 644 EVP_PKEY *ret = NULL; 645 if (!CryptExportKey(key->key, 0, PUBLICKEYBLOB, 0, NULL, &len)) { 646 CAPIerr(CAPI_F_CAPI_GET_PKEY, CAPI_R_PUBKEY_EXPORT_LENGTH_ERROR); 647 capi_addlasterror(); 648 return NULL; 649 } 650 651 pubkey = OPENSSL_malloc(len); 652 653 if (pubkey == NULL) 654 goto err; 655 656 if (!CryptExportKey(key->key, 0, PUBLICKEYBLOB, 0, pubkey, &len)) { 657 CAPIerr(CAPI_F_CAPI_GET_PKEY, CAPI_R_PUBKEY_EXPORT_ERROR); 658 capi_addlasterror(); 659 goto err; 660 } 661 662 bh = (BLOBHEADER *)pubkey; 663 if (bh->bType != PUBLICKEYBLOB) { 664 CAPIerr(CAPI_F_CAPI_GET_PKEY, CAPI_R_INVALID_PUBLIC_KEY_BLOB); 665 goto err; 666 } 667 if (bh->aiKeyAlg == CALG_RSA_SIGN || bh->aiKeyAlg == CALG_RSA_KEYX) { 668 RSAPUBKEY *rp; 669 DWORD rsa_modlen; 670 BIGNUM *e = NULL, *n = NULL; 671 unsigned char *rsa_modulus; 672 rp = (RSAPUBKEY *)(bh + 1); 673 if (rp->magic != 0x31415352) { 674 char magstr[10]; 675 BIO_snprintf(magstr, 10, "%lx", rp->magic); 676 CAPIerr(CAPI_F_CAPI_GET_PKEY, 677 CAPI_R_INVALID_RSA_PUBLIC_KEY_BLOB_MAGIC_NUMBER); 678 ERR_add_error_data(2, "magic=0x", magstr); 679 goto err; 680 } 681 rsa_modulus = (unsigned char *)(rp + 1); 682 rkey = RSA_new_method(eng); 683 if (!rkey) { 684 CAPIerr(CAPI_F_CAPI_GET_PKEY, ERR_R_RSA_LIB); 685 goto err; 686 } 687 688 e = BN_new(); 689 n = BN_new(); 690 691 if (e == NULL || n == NULL) { 692 BN_free(e); 693 BN_free(n); 694 CAPIerr(CAPI_F_CAPI_GET_PKEY, ERR_R_BN_LIB); 695 goto err; 696 } 697 698 RSA_set0_key(rkey, n, e, NULL); 699 700 if (!BN_set_word(e, rp->pubexp)) { 701 CAPIerr(CAPI_F_CAPI_GET_PKEY, ERR_R_BN_LIB); 702 goto err; 703 } 704 705 rsa_modlen = rp->bitlen / 8; 706 if (!lend_tobn(n, rsa_modulus, rsa_modlen)) { 707 CAPIerr(CAPI_F_CAPI_GET_PKEY, ERR_R_BN_LIB); 708 goto err; 709 } 710 711 RSA_set_ex_data(rkey, rsa_capi_idx, key); 712 713 if ((ret = EVP_PKEY_new()) == NULL) { 714 CAPIerr(CAPI_F_CAPI_GET_PKEY, ERR_R_EVP_LIB); 715 goto err; 716 } 717 718 EVP_PKEY_assign_RSA(ret, rkey); 719 rkey = NULL; 720 721 #ifndef OPENSSL_NO_DSA 722 } else if (bh->aiKeyAlg == CALG_DSS_SIGN) { 723 DSSPUBKEY *dp; 724 DWORD dsa_plen; 725 unsigned char *btmp; 726 BIGNUM *p, *q, *g, *pub_key; 727 dp = (DSSPUBKEY *)(bh + 1); 728 if (dp->magic != 0x31535344) { 729 char magstr[10]; 730 BIO_snprintf(magstr, 10, "%lx", dp->magic); 731 CAPIerr(CAPI_F_CAPI_GET_PKEY, 732 CAPI_R_INVALID_DSA_PUBLIC_KEY_BLOB_MAGIC_NUMBER); 733 ERR_add_error_data(2, "magic=0x", magstr); 734 goto err; 735 } 736 dsa_plen = dp->bitlen / 8; 737 btmp = (unsigned char *)(dp + 1); 738 dkey = DSA_new_method(eng); 739 if (!dkey) { 740 CAPIerr(CAPI_F_CAPI_GET_PKEY, ERR_R_DSA_LIB); 741 goto err; 742 } 743 p = BN_new(); 744 q = BN_new(); 745 g = BN_new(); 746 pub_key = BN_new(); 747 if (p == NULL || q == NULL || g == NULL || pub_key == NULL) { 748 BN_free(p); 749 BN_free(q); 750 BN_free(g); 751 BN_free(pub_key); 752 CAPIerr(CAPI_F_CAPI_GET_PKEY, ERR_R_BN_LIB); 753 goto err; 754 } 755 DSA_set0_pqg(dkey, p, q, g); 756 DSA_set0_key(dkey, pub_key, NULL); 757 if (!lend_tobn(p, btmp, dsa_plen)) { 758 CAPIerr(CAPI_F_CAPI_GET_PKEY, ERR_R_CAPI_LIB); 759 goto err; 760 } 761 btmp += dsa_plen; 762 if (!lend_tobn(q, btmp, 20)) { 763 CAPIerr(CAPI_F_CAPI_GET_PKEY, ERR_R_CAPI_LIB); 764 goto err; 765 } 766 btmp += 20; 767 if (!lend_tobn(g, btmp, dsa_plen)) { 768 CAPIerr(CAPI_F_CAPI_GET_PKEY, ERR_R_CAPI_LIB); 769 goto err; 770 } 771 btmp += dsa_plen; 772 if (!lend_tobn(pub_key, btmp, dsa_plen)) { 773 CAPIerr(CAPI_F_CAPI_GET_PKEY, ERR_R_CAPI_LIB); 774 goto err; 775 } 776 btmp += dsa_plen; 777 778 DSA_set_ex_data(dkey, dsa_capi_idx, key); 779 780 if ((ret = EVP_PKEY_new()) == NULL) { 781 CAPIerr(CAPI_F_CAPI_GET_PKEY, ERR_R_EVP_LIB); 782 goto err; 783 } 784 785 EVP_PKEY_assign_DSA(ret, dkey); 786 dkey = NULL; 787 #endif 788 } else { 789 char algstr[10]; 790 BIO_snprintf(algstr, 10, "%ux", bh->aiKeyAlg); 791 CAPIerr(CAPI_F_CAPI_GET_PKEY, 792 CAPI_R_UNSUPPORTED_PUBLIC_KEY_ALGORITHM); 793 ERR_add_error_data(2, "aiKeyAlg=0x", algstr); 794 goto err; 795 } 796 797 err: 798 OPENSSL_free(pubkey); 799 if (!ret) { 800 RSA_free(rkey); 801 #ifndef OPENSSL_NO_DSA 802 DSA_free(dkey); 803 #endif 804 } 805 806 return ret; 807 } 808 809 static EVP_PKEY *capi_load_privkey(ENGINE *eng, const char *key_id, 810 UI_METHOD *ui_method, void *callback_data) 811 { 812 CAPI_CTX *ctx; 813 CAPI_KEY *key; 814 EVP_PKEY *ret; 815 ctx = ENGINE_get_ex_data(eng, capi_idx); 816 817 if (!ctx) { 818 CAPIerr(CAPI_F_CAPI_LOAD_PRIVKEY, CAPI_R_CANT_FIND_CAPI_CONTEXT); 819 return NULL; 820 } 821 822 key = capi_find_key(ctx, key_id); 823 824 if (!key) 825 return NULL; 826 827 ret = capi_get_pkey(eng, key); 828 829 if (!ret) 830 capi_free_key(key); 831 return ret; 832 } 833 834 /* CryptoAPI RSA operations */ 835 836 int capi_rsa_priv_enc(int flen, const unsigned char *from, 837 unsigned char *to, RSA *rsa, int padding) 838 { 839 CAPIerr(CAPI_F_CAPI_RSA_PRIV_ENC, CAPI_R_FUNCTION_NOT_SUPPORTED); 840 return -1; 841 } 842 843 int capi_rsa_sign(int dtype, const unsigned char *m, unsigned int m_len, 844 unsigned char *sigret, unsigned int *siglen, const RSA *rsa) 845 { 846 ALG_ID alg; 847 HCRYPTHASH hash; 848 DWORD slen; 849 unsigned int i; 850 int ret = -1; 851 CAPI_KEY *capi_key; 852 CAPI_CTX *ctx; 853 854 ctx = ENGINE_get_ex_data(RSA_get0_engine(rsa), capi_idx); 855 856 CAPI_trace(ctx, "Called CAPI_rsa_sign()\n"); 857 858 capi_key = RSA_get_ex_data(rsa, rsa_capi_idx); 859 if (!capi_key) { 860 CAPIerr(CAPI_F_CAPI_RSA_SIGN, CAPI_R_CANT_GET_KEY); 861 return -1; 862 } 863 /* Convert the signature type to a CryptoAPI algorithm ID */ 864 switch (dtype) { 865 case NID_sha256: 866 alg = CALG_SHA_256; 867 break; 868 869 case NID_sha384: 870 alg = CALG_SHA_384; 871 break; 872 873 case NID_sha512: 874 alg = CALG_SHA_512; 875 break; 876 877 case NID_sha1: 878 alg = CALG_SHA1; 879 break; 880 881 case NID_md5: 882 alg = CALG_MD5; 883 break; 884 885 case NID_md5_sha1: 886 alg = CALG_SSL3_SHAMD5; 887 break; 888 default: { 889 char algstr[10]; 890 BIO_snprintf(algstr, 10, "%x", dtype); 891 CAPIerr(CAPI_F_CAPI_RSA_SIGN, CAPI_R_UNSUPPORTED_ALGORITHM_NID); 892 ERR_add_error_data(2, "NID=0x", algstr); 893 return -1; 894 } 895 } 896 897 /* Create the hash object */ 898 if (!CryptCreateHash(capi_key->hprov, alg, 0, 0, &hash)) { 899 CAPIerr(CAPI_F_CAPI_RSA_SIGN, CAPI_R_CANT_CREATE_HASH_OBJECT); 900 capi_addlasterror(); 901 return -1; 902 } 903 /* Set the hash value to the value passed */ 904 905 if (!CryptSetHashParam(hash, HP_HASHVAL, (unsigned char *)m, 0)) { 906 CAPIerr(CAPI_F_CAPI_RSA_SIGN, CAPI_R_CANT_SET_HASH_VALUE); 907 capi_addlasterror(); 908 goto err; 909 } 910 911 /* Finally sign it */ 912 slen = RSA_size(rsa); 913 if (!CryptSignHash(hash, capi_key->keyspec, NULL, 0, sigret, &slen)) { 914 CAPIerr(CAPI_F_CAPI_RSA_SIGN, CAPI_R_ERROR_SIGNING_HASH); 915 capi_addlasterror(); 916 goto err; 917 } else { 918 ret = 1; 919 /* Inplace byte reversal of signature */ 920 for (i = 0; i < slen / 2; i++) { 921 unsigned char c; 922 c = sigret[i]; 923 sigret[i] = sigret[slen - i - 1]; 924 sigret[slen - i - 1] = c; 925 } 926 *siglen = slen; 927 } 928 929 /* Now cleanup */ 930 931 err: 932 CryptDestroyHash(hash); 933 934 return ret; 935 } 936 937 int capi_rsa_priv_dec(int flen, const unsigned char *from, 938 unsigned char *to, RSA *rsa, int padding) 939 { 940 int i; 941 unsigned char *tmpbuf; 942 CAPI_KEY *capi_key; 943 CAPI_CTX *ctx; 944 DWORD flags = 0; 945 DWORD dlen; 946 947 if (flen <= 0) 948 return flen; 949 950 ctx = ENGINE_get_ex_data(RSA_get0_engine(rsa), capi_idx); 951 952 CAPI_trace(ctx, "Called capi_rsa_priv_dec()\n"); 953 954 capi_key = RSA_get_ex_data(rsa, rsa_capi_idx); 955 if (!capi_key) { 956 CAPIerr(CAPI_F_CAPI_RSA_PRIV_DEC, CAPI_R_CANT_GET_KEY); 957 return -1; 958 } 959 960 switch (padding) { 961 case RSA_PKCS1_PADDING: 962 /* Nothing to do */ 963 break; 964 #ifdef CRYPT_DECRYPT_RSA_NO_PADDING_CHECK 965 case RSA_NO_PADDING: 966 flags = CRYPT_DECRYPT_RSA_NO_PADDING_CHECK; 967 break; 968 #endif 969 default: { 970 char errstr[10]; 971 BIO_snprintf(errstr, 10, "%d", padding); 972 CAPIerr(CAPI_F_CAPI_RSA_PRIV_DEC, CAPI_R_UNSUPPORTED_PADDING); 973 ERR_add_error_data(2, "padding=", errstr); 974 return -1; 975 } 976 } 977 978 /* Create temp reverse order version of input */ 979 if ((tmpbuf = OPENSSL_malloc(flen)) == NULL) 980 return -1; 981 for (i = 0; i < flen; i++) 982 tmpbuf[flen - i - 1] = from[i]; 983 984 /* Finally decrypt it */ 985 dlen = flen; 986 if (!CryptDecrypt(capi_key->key, 0, TRUE, flags, tmpbuf, &dlen)) { 987 CAPIerr(CAPI_F_CAPI_RSA_PRIV_DEC, CAPI_R_DECRYPT_ERROR); 988 capi_addlasterror(); 989 OPENSSL_cleanse(tmpbuf, dlen); 990 OPENSSL_free(tmpbuf); 991 return -1; 992 } else { 993 memcpy(to, tmpbuf, (flen = (int)dlen)); 994 } 995 OPENSSL_cleanse(tmpbuf, flen); 996 OPENSSL_free(tmpbuf); 997 998 return flen; 999 } 1000 1001 static int capi_rsa_free(RSA *rsa) 1002 { 1003 CAPI_KEY *capi_key; 1004 capi_key = RSA_get_ex_data(rsa, rsa_capi_idx); 1005 capi_free_key(capi_key); 1006 RSA_set_ex_data(rsa, rsa_capi_idx, 0); 1007 return 1; 1008 } 1009 1010 #ifndef OPENSSL_NO_DSA 1011 /* CryptoAPI DSA operations */ 1012 1013 static DSA_SIG *capi_dsa_do_sign(const unsigned char *digest, int dlen, 1014 DSA *dsa) 1015 { 1016 HCRYPTHASH hash; 1017 DWORD slen; 1018 DSA_SIG *ret = NULL; 1019 CAPI_KEY *capi_key; 1020 CAPI_CTX *ctx; 1021 unsigned char csigbuf[40]; 1022 1023 ctx = ENGINE_get_ex_data(DSA_get0_engine(dsa), capi_idx); 1024 1025 CAPI_trace(ctx, "Called CAPI_dsa_do_sign()\n"); 1026 1027 capi_key = DSA_get_ex_data(dsa, dsa_capi_idx); 1028 1029 if (!capi_key) { 1030 CAPIerr(CAPI_F_CAPI_DSA_DO_SIGN, CAPI_R_CANT_GET_KEY); 1031 return NULL; 1032 } 1033 1034 if (dlen != 20) { 1035 CAPIerr(CAPI_F_CAPI_DSA_DO_SIGN, CAPI_R_INVALID_DIGEST_LENGTH); 1036 return NULL; 1037 } 1038 1039 /* Create the hash object */ 1040 if (!CryptCreateHash(capi_key->hprov, CALG_SHA1, 0, 0, &hash)) { 1041 CAPIerr(CAPI_F_CAPI_DSA_DO_SIGN, CAPI_R_CANT_CREATE_HASH_OBJECT); 1042 capi_addlasterror(); 1043 return NULL; 1044 } 1045 1046 /* Set the hash value to the value passed */ 1047 if (!CryptSetHashParam(hash, HP_HASHVAL, (unsigned char *)digest, 0)) { 1048 CAPIerr(CAPI_F_CAPI_DSA_DO_SIGN, CAPI_R_CANT_SET_HASH_VALUE); 1049 capi_addlasterror(); 1050 goto err; 1051 } 1052 1053 /* Finally sign it */ 1054 slen = sizeof(csigbuf); 1055 if (!CryptSignHash(hash, capi_key->keyspec, NULL, 0, csigbuf, &slen)) { 1056 CAPIerr(CAPI_F_CAPI_DSA_DO_SIGN, CAPI_R_ERROR_SIGNING_HASH); 1057 capi_addlasterror(); 1058 goto err; 1059 } else { 1060 BIGNUM *r = BN_new(), *s = BN_new(); 1061 1062 if (r == NULL || s == NULL 1063 || !lend_tobn(r, csigbuf, 20) 1064 || !lend_tobn(s, csigbuf + 20, 20) 1065 || (ret = DSA_SIG_new()) == NULL) { 1066 BN_free(r); /* BN_free checks for BIGNUM * being NULL */ 1067 BN_free(s); 1068 goto err; 1069 } 1070 DSA_SIG_set0(ret, r, s); 1071 } 1072 1073 /* Now cleanup */ 1074 1075 err: 1076 OPENSSL_cleanse(csigbuf, 40); 1077 CryptDestroyHash(hash); 1078 return ret; 1079 } 1080 1081 static int capi_dsa_free(DSA *dsa) 1082 { 1083 CAPI_KEY *capi_key; 1084 capi_key = DSA_get_ex_data(dsa, dsa_capi_idx); 1085 capi_free_key(capi_key); 1086 DSA_set_ex_data(dsa, dsa_capi_idx, 0); 1087 return 1; 1088 } 1089 #endif 1090 1091 static void capi_vtrace(CAPI_CTX *ctx, int level, char *format, 1092 va_list argptr) 1093 { 1094 BIO *out; 1095 1096 if (!ctx || (ctx->debug_level < level) || (!ctx->debug_file)) 1097 return; 1098 out = BIO_new_file(ctx->debug_file, "a+"); 1099 if (out == NULL) { 1100 CAPIerr(CAPI_F_CAPI_VTRACE, CAPI_R_FILE_OPEN_ERROR); 1101 return; 1102 } 1103 BIO_vprintf(out, format, argptr); 1104 BIO_free(out); 1105 } 1106 1107 static void CAPI_trace(CAPI_CTX *ctx, char *format, ...) 1108 { 1109 va_list args; 1110 va_start(args, format); 1111 capi_vtrace(ctx, CAPI_DBG_TRACE, format, args); 1112 va_end(args); 1113 } 1114 1115 static void capi_addlasterror(void) 1116 { 1117 capi_adderror(GetLastError()); 1118 } 1119 1120 static void capi_adderror(DWORD err) 1121 { 1122 char errstr[10]; 1123 BIO_snprintf(errstr, 10, "%lX", err); 1124 ERR_add_error_data(2, "Error code= 0x", errstr); 1125 } 1126 1127 static char *wide_to_asc(LPCWSTR wstr) 1128 { 1129 char *str; 1130 int len_0, sz; 1131 size_t len_1; 1132 1133 if (!wstr) 1134 return NULL; 1135 1136 len_1 = wcslen(wstr) + 1; 1137 1138 if (len_1 > INT_MAX) { 1139 CAPIerr(CAPI_F_WIDE_TO_ASC, CAPI_R_FUNCTION_NOT_SUPPORTED); 1140 return NULL; 1141 } 1142 1143 len_0 = (int)len_1; /* WideCharToMultiByte expects int */ 1144 sz = WideCharToMultiByte(CP_ACP, 0, wstr, len_0, NULL, 0, NULL, NULL); 1145 if (!sz) { 1146 CAPIerr(CAPI_F_WIDE_TO_ASC, CAPI_R_WIN32_ERROR); 1147 return NULL; 1148 } 1149 str = OPENSSL_malloc(sz); 1150 if (str == NULL) 1151 return NULL; 1152 if (!WideCharToMultiByte(CP_ACP, 0, wstr, len_0, str, sz, NULL, NULL)) { 1153 OPENSSL_free(str); 1154 CAPIerr(CAPI_F_WIDE_TO_ASC, CAPI_R_WIN32_ERROR); 1155 return NULL; 1156 } 1157 return str; 1158 } 1159 1160 static int capi_get_provname(CAPI_CTX *ctx, LPSTR *pname, DWORD *ptype, 1161 DWORD idx) 1162 { 1163 DWORD len, err; 1164 LPTSTR name; 1165 CAPI_trace(ctx, "capi_get_provname, index=%d\n", idx); 1166 if (!CryptEnumProviders(idx, NULL, 0, ptype, NULL, &len)) { 1167 err = GetLastError(); 1168 if (err == ERROR_NO_MORE_ITEMS) 1169 return 2; 1170 CAPIerr(CAPI_F_CAPI_GET_PROVNAME, CAPI_R_CRYPTENUMPROVIDERS_ERROR); 1171 capi_adderror(err); 1172 return 0; 1173 } 1174 name = OPENSSL_malloc(len); 1175 if (name == NULL) 1176 return 0; 1177 if (!CryptEnumProviders(idx, NULL, 0, ptype, name, &len)) { 1178 err = GetLastError(); 1179 OPENSSL_free(name); 1180 if (err == ERROR_NO_MORE_ITEMS) 1181 return 2; 1182 CAPIerr(CAPI_F_CAPI_GET_PROVNAME, CAPI_R_CRYPTENUMPROVIDERS_ERROR); 1183 capi_adderror(err); 1184 return 0; 1185 } 1186 if (sizeof(TCHAR) != sizeof(char)) { 1187 *pname = wide_to_asc((WCHAR *)name); 1188 OPENSSL_free(name); 1189 if (*pname == NULL) 1190 return 0; 1191 } else { 1192 *pname = (char *)name; 1193 } 1194 CAPI_trace(ctx, "capi_get_provname, returned name=%s, type=%d\n", *pname, 1195 *ptype); 1196 1197 return 1; 1198 } 1199 1200 static int capi_list_providers(CAPI_CTX *ctx, BIO *out) 1201 { 1202 DWORD idx, ptype; 1203 int ret; 1204 LPSTR provname = NULL; 1205 CAPI_trace(ctx, "capi_list_providers\n"); 1206 BIO_printf(out, "Available CSPs:\n"); 1207 for (idx = 0;; idx++) { 1208 ret = capi_get_provname(ctx, &provname, &ptype, idx); 1209 if (ret == 2) 1210 break; 1211 if (ret == 0) 1212 break; 1213 BIO_printf(out, "%lu. %s, type %lu\n", idx, provname, ptype); 1214 OPENSSL_free(provname); 1215 } 1216 return 1; 1217 } 1218 1219 static int capi_list_containers(CAPI_CTX *ctx, BIO *out) 1220 { 1221 int ret = 1; 1222 HCRYPTPROV hprov; 1223 DWORD err, idx, flags, buflen = 0, clen; 1224 LPSTR cname; 1225 LPWSTR cspname = NULL; 1226 1227 CAPI_trace(ctx, "Listing containers CSP=%s, type = %d\n", ctx->cspname, 1228 ctx->csptype); 1229 if (ctx->cspname != NULL) { 1230 if ((clen = MultiByteToWideChar(CP_ACP, 0, ctx->cspname, -1, 1231 NULL, 0))) { 1232 cspname = alloca(clen * sizeof(WCHAR)); 1233 MultiByteToWideChar(CP_ACP, 0, ctx->cspname, -1, (WCHAR *)cspname, 1234 clen); 1235 } 1236 if (cspname == NULL) { 1237 CAPIerr(CAPI_F_CAPI_LIST_CONTAINERS, ERR_R_MALLOC_FAILURE); 1238 capi_addlasterror(); 1239 return 0; 1240 } 1241 } 1242 if (!CryptAcquireContextW(&hprov, NULL, cspname, ctx->csptype, 1243 CRYPT_VERIFYCONTEXT)) { 1244 CAPIerr(CAPI_F_CAPI_LIST_CONTAINERS, 1245 CAPI_R_CRYPTACQUIRECONTEXT_ERROR); 1246 capi_addlasterror(); 1247 return 0; 1248 } 1249 if (!CryptGetProvParam(hprov, PP_ENUMCONTAINERS, NULL, &buflen, 1250 CRYPT_FIRST)) { 1251 CAPIerr(CAPI_F_CAPI_LIST_CONTAINERS, CAPI_R_ENUMCONTAINERS_ERROR); 1252 capi_addlasterror(); 1253 CryptReleaseContext(hprov, 0); 1254 return 0; 1255 } 1256 CAPI_trace(ctx, "Got max container len %d\n", buflen); 1257 if (buflen == 0) 1258 buflen = 1024; 1259 cname = OPENSSL_malloc(buflen); 1260 if (cname == NULL) 1261 goto err; 1262 1263 for (idx = 0;; idx++) { 1264 clen = buflen; 1265 cname[0] = 0; 1266 1267 if (idx == 0) 1268 flags = CRYPT_FIRST; 1269 else 1270 flags = 0; 1271 if (!CryptGetProvParam(hprov, PP_ENUMCONTAINERS, (BYTE *)cname, 1272 &clen, flags)) { 1273 err = GetLastError(); 1274 if (err == ERROR_NO_MORE_ITEMS) 1275 goto done; 1276 CAPIerr(CAPI_F_CAPI_LIST_CONTAINERS, CAPI_R_ENUMCONTAINERS_ERROR); 1277 capi_adderror(err); 1278 goto err; 1279 } 1280 CAPI_trace(ctx, "Container name %s, len=%d, index=%d, flags=%d\n", 1281 cname, clen, idx, flags); 1282 if (!cname[0] && (clen == buflen)) { 1283 CAPI_trace(ctx, "Enumerate bug: using workaround\n"); 1284 goto done; 1285 } 1286 BIO_printf(out, "%lu. %s\n", idx, cname); 1287 } 1288 err: 1289 1290 ret = 0; 1291 1292 done: 1293 OPENSSL_free(cname); 1294 CryptReleaseContext(hprov, 0); 1295 1296 return ret; 1297 } 1298 1299 static CRYPT_KEY_PROV_INFO *capi_get_prov_info(CAPI_CTX *ctx, 1300 PCCERT_CONTEXT cert) 1301 { 1302 DWORD len; 1303 CRYPT_KEY_PROV_INFO *pinfo; 1304 1305 if (!CertGetCertificateContextProperty(cert, CERT_KEY_PROV_INFO_PROP_ID, 1306 NULL, &len)) 1307 return NULL; 1308 pinfo = OPENSSL_malloc(len); 1309 if (pinfo == NULL) 1310 return NULL; 1311 if (!CertGetCertificateContextProperty(cert, CERT_KEY_PROV_INFO_PROP_ID, 1312 pinfo, &len)) { 1313 CAPIerr(CAPI_F_CAPI_GET_PROV_INFO, 1314 CAPI_R_ERROR_GETTING_KEY_PROVIDER_INFO); 1315 capi_addlasterror(); 1316 OPENSSL_free(pinfo); 1317 return NULL; 1318 } 1319 return pinfo; 1320 } 1321 1322 static void capi_dump_prov_info(CAPI_CTX *ctx, BIO *out, 1323 CRYPT_KEY_PROV_INFO *pinfo) 1324 { 1325 char *provname = NULL, *contname = NULL; 1326 1327 if (pinfo == NULL) { 1328 BIO_printf(out, " No Private Key\n"); 1329 return; 1330 } 1331 provname = wide_to_asc(pinfo->pwszProvName); 1332 contname = wide_to_asc(pinfo->pwszContainerName); 1333 if (provname == NULL || contname == NULL) 1334 goto err; 1335 1336 BIO_printf(out, " Private Key Info:\n"); 1337 BIO_printf(out, " Provider Name: %s, Provider Type %lu\n", provname, 1338 pinfo->dwProvType); 1339 BIO_printf(out, " Container Name: %s, Key Type %lu\n", contname, 1340 pinfo->dwKeySpec); 1341 err: 1342 OPENSSL_free(provname); 1343 OPENSSL_free(contname); 1344 } 1345 1346 static char *capi_cert_get_fname(CAPI_CTX *ctx, PCCERT_CONTEXT cert) 1347 { 1348 LPWSTR wfname; 1349 DWORD dlen; 1350 1351 CAPI_trace(ctx, "capi_cert_get_fname\n"); 1352 if (!CertGetCertificateContextProperty(cert, CERT_FRIENDLY_NAME_PROP_ID, 1353 NULL, &dlen)) 1354 return NULL; 1355 wfname = OPENSSL_malloc(dlen); 1356 if (wfname == NULL) 1357 return NULL; 1358 if (CertGetCertificateContextProperty(cert, CERT_FRIENDLY_NAME_PROP_ID, 1359 wfname, &dlen)) { 1360 char *fname = wide_to_asc(wfname); 1361 OPENSSL_free(wfname); 1362 return fname; 1363 } 1364 CAPIerr(CAPI_F_CAPI_CERT_GET_FNAME, CAPI_R_ERROR_GETTING_FRIENDLY_NAME); 1365 capi_addlasterror(); 1366 1367 OPENSSL_free(wfname); 1368 return NULL; 1369 } 1370 1371 static void capi_dump_cert(CAPI_CTX *ctx, BIO *out, PCCERT_CONTEXT cert) 1372 { 1373 X509 *x; 1374 const unsigned char *p; 1375 unsigned long flags = ctx->dump_flags; 1376 if (flags & CAPI_DMP_FNAME) { 1377 char *fname; 1378 fname = capi_cert_get_fname(ctx, cert); 1379 if (fname) { 1380 BIO_printf(out, " Friendly Name \"%s\"\n", fname); 1381 OPENSSL_free(fname); 1382 } else { 1383 BIO_printf(out, " <No Friendly Name>\n"); 1384 } 1385 } 1386 1387 p = cert->pbCertEncoded; 1388 x = d2i_X509(NULL, &p, cert->cbCertEncoded); 1389 if (!x) 1390 BIO_printf(out, " <Can't parse certificate>\n"); 1391 if (flags & CAPI_DMP_SUMMARY) { 1392 BIO_printf(out, " Subject: "); 1393 X509_NAME_print_ex(out, X509_get_subject_name(x), 0, XN_FLAG_ONELINE); 1394 BIO_printf(out, "\n Issuer: "); 1395 X509_NAME_print_ex(out, X509_get_issuer_name(x), 0, XN_FLAG_ONELINE); 1396 BIO_printf(out, "\n"); 1397 } 1398 if (flags & CAPI_DMP_FULL) 1399 X509_print_ex(out, x, XN_FLAG_ONELINE, 0); 1400 1401 if (flags & CAPI_DMP_PKEYINFO) { 1402 CRYPT_KEY_PROV_INFO *pinfo; 1403 pinfo = capi_get_prov_info(ctx, cert); 1404 capi_dump_prov_info(ctx, out, pinfo); 1405 OPENSSL_free(pinfo); 1406 } 1407 1408 if (flags & CAPI_DMP_PEM) 1409 PEM_write_bio_X509(out, x); 1410 X509_free(x); 1411 } 1412 1413 static HCERTSTORE capi_open_store(CAPI_CTX *ctx, char *storename) 1414 { 1415 HCERTSTORE hstore; 1416 1417 if (!storename) 1418 storename = ctx->storename; 1419 if (!storename) 1420 storename = "MY"; 1421 CAPI_trace(ctx, "Opening certificate store %s\n", storename); 1422 1423 hstore = CertOpenStore(CERT_STORE_PROV_SYSTEM_A, 0, 0, 1424 ctx->store_flags, storename); 1425 if (!hstore) { 1426 CAPIerr(CAPI_F_CAPI_OPEN_STORE, CAPI_R_ERROR_OPENING_STORE); 1427 capi_addlasterror(); 1428 } 1429 return hstore; 1430 } 1431 1432 int capi_list_certs(CAPI_CTX *ctx, BIO *out, char *id) 1433 { 1434 char *storename; 1435 int idx; 1436 int ret = 1; 1437 HCERTSTORE hstore; 1438 PCCERT_CONTEXT cert = NULL; 1439 1440 storename = ctx->storename; 1441 if (!storename) 1442 storename = "MY"; 1443 CAPI_trace(ctx, "Listing certs for store %s\n", storename); 1444 1445 hstore = capi_open_store(ctx, storename); 1446 if (!hstore) 1447 return 0; 1448 if (id) { 1449 cert = capi_find_cert(ctx, id, hstore); 1450 if (!cert) { 1451 ret = 0; 1452 goto err; 1453 } 1454 capi_dump_cert(ctx, out, cert); 1455 CertFreeCertificateContext(cert); 1456 } else { 1457 for (idx = 0;; idx++) { 1458 cert = CertEnumCertificatesInStore(hstore, cert); 1459 if (!cert) 1460 break; 1461 BIO_printf(out, "Certificate %d\n", idx); 1462 capi_dump_cert(ctx, out, cert); 1463 } 1464 } 1465 err: 1466 CertCloseStore(hstore, 0); 1467 return ret; 1468 } 1469 1470 static PCCERT_CONTEXT capi_find_cert(CAPI_CTX *ctx, const char *id, 1471 HCERTSTORE hstore) 1472 { 1473 PCCERT_CONTEXT cert = NULL; 1474 char *fname = NULL; 1475 int match; 1476 switch (ctx->lookup_method) { 1477 case CAPI_LU_SUBSTR: 1478 return CertFindCertificateInStore(hstore, X509_ASN_ENCODING, 0, 1479 CERT_FIND_SUBJECT_STR_A, id, NULL); 1480 case CAPI_LU_FNAME: 1481 for (;;) { 1482 cert = CertEnumCertificatesInStore(hstore, cert); 1483 if (!cert) 1484 return NULL; 1485 fname = capi_cert_get_fname(ctx, cert); 1486 if (fname) { 1487 if (strcmp(fname, id)) 1488 match = 0; 1489 else 1490 match = 1; 1491 OPENSSL_free(fname); 1492 if (match) 1493 return cert; 1494 } 1495 } 1496 default: 1497 return NULL; 1498 } 1499 } 1500 1501 static CAPI_KEY *capi_get_key(CAPI_CTX *ctx, const WCHAR *contname, 1502 const WCHAR *provname, DWORD ptype, 1503 DWORD keyspec) 1504 { 1505 DWORD dwFlags = 0; 1506 CAPI_KEY *key = OPENSSL_malloc(sizeof(*key)); 1507 1508 if (key == NULL) 1509 return NULL; 1510 /* If PROV_RSA_AES supported use it instead */ 1511 if (ptype == PROV_RSA_FULL && use_aes_csp && wcscmp(provname, rsa_enh_cspname) == 0) { 1512 provname = rsa_aes_cspname; 1513 ptype = PROV_RSA_AES; 1514 } 1515 if (ctx && ctx->debug_level >= CAPI_DBG_TRACE && ctx->debug_file) { 1516 /* 1517 * above 'if' is [complementary] copy from CAPI_trace and serves 1518 * as optimization to minimize [below] malloc-ations 1519 */ 1520 char *_contname = wide_to_asc(contname); 1521 char *_provname = wide_to_asc(provname); 1522 1523 CAPI_trace(ctx, "capi_get_key, contname=%s, provname=%s, type=%d\n", 1524 _contname, _provname, ptype); 1525 OPENSSL_free(_provname); 1526 OPENSSL_free(_contname); 1527 } 1528 if (ctx->store_flags & CERT_SYSTEM_STORE_LOCAL_MACHINE) 1529 dwFlags = CRYPT_MACHINE_KEYSET; 1530 if (!CryptAcquireContextW(&key->hprov, contname, provname, ptype, 1531 dwFlags)) { 1532 CAPIerr(CAPI_F_CAPI_GET_KEY, CAPI_R_CRYPTACQUIRECONTEXT_ERROR); 1533 capi_addlasterror(); 1534 goto err; 1535 } 1536 if (!CryptGetUserKey(key->hprov, keyspec, &key->key)) { 1537 CAPIerr(CAPI_F_CAPI_GET_KEY, CAPI_R_GETUSERKEY_ERROR); 1538 capi_addlasterror(); 1539 CryptReleaseContext(key->hprov, 0); 1540 goto err; 1541 } 1542 key->keyspec = keyspec; 1543 key->pcert = NULL; 1544 return key; 1545 1546 err: 1547 OPENSSL_free(key); 1548 return NULL; 1549 } 1550 1551 static CAPI_KEY *capi_get_cert_key(CAPI_CTX *ctx, PCCERT_CONTEXT cert) 1552 { 1553 CAPI_KEY *key = NULL; 1554 CRYPT_KEY_PROV_INFO *pinfo = NULL; 1555 1556 pinfo = capi_get_prov_info(ctx, cert); 1557 1558 if (pinfo != NULL) 1559 key = capi_get_key(ctx, pinfo->pwszContainerName, pinfo->pwszProvName, 1560 pinfo->dwProvType, pinfo->dwKeySpec); 1561 1562 OPENSSL_free(pinfo); 1563 return key; 1564 } 1565 1566 CAPI_KEY *capi_find_key(CAPI_CTX *ctx, const char *id) 1567 { 1568 PCCERT_CONTEXT cert; 1569 HCERTSTORE hstore; 1570 CAPI_KEY *key = NULL; 1571 1572 switch (ctx->lookup_method) { 1573 case CAPI_LU_SUBSTR: 1574 case CAPI_LU_FNAME: 1575 hstore = capi_open_store(ctx, NULL); 1576 if (!hstore) 1577 return NULL; 1578 cert = capi_find_cert(ctx, id, hstore); 1579 if (cert) { 1580 key = capi_get_cert_key(ctx, cert); 1581 CertFreeCertificateContext(cert); 1582 } 1583 CertCloseStore(hstore, 0); 1584 break; 1585 1586 case CAPI_LU_CONTNAME: { 1587 WCHAR *contname, *provname; 1588 DWORD len; 1589 1590 if ((len = MultiByteToWideChar(CP_ACP, 0, id, -1, NULL, 0)) && (contname = alloca(len * sizeof(WCHAR)), MultiByteToWideChar(CP_ACP, 0, id, -1, contname, len)) && (len = MultiByteToWideChar(CP_ACP, 0, ctx->cspname, -1, NULL, 0)) && (provname = alloca(len * sizeof(WCHAR)), MultiByteToWideChar(CP_ACP, 0, ctx->cspname, -1, provname, len))) 1591 key = capi_get_key(ctx, contname, provname, 1592 ctx->csptype, ctx->keytype); 1593 } break; 1594 } 1595 1596 return key; 1597 } 1598 1599 void capi_free_key(CAPI_KEY *key) 1600 { 1601 if (!key) 1602 return; 1603 CryptDestroyKey(key->key); 1604 CryptReleaseContext(key->hprov, 0); 1605 if (key->pcert) 1606 CertFreeCertificateContext(key->pcert); 1607 OPENSSL_free(key); 1608 } 1609 1610 /* Initialize a CAPI_CTX structure */ 1611 1612 static CAPI_CTX *capi_ctx_new(void) 1613 { 1614 CAPI_CTX *ctx = OPENSSL_zalloc(sizeof(*ctx)); 1615 1616 if (ctx == NULL) 1617 return NULL; 1618 ctx->csptype = PROV_RSA_FULL; 1619 ctx->dump_flags = CAPI_DMP_SUMMARY | CAPI_DMP_FNAME; 1620 ctx->keytype = AT_KEYEXCHANGE; 1621 ctx->store_flags = CERT_STORE_OPEN_EXISTING_FLAG | CERT_STORE_READONLY_FLAG | CERT_SYSTEM_STORE_CURRENT_USER; 1622 ctx->lookup_method = CAPI_LU_SUBSTR; 1623 ctx->client_cert_select = cert_select_simple; 1624 return ctx; 1625 } 1626 1627 static void capi_ctx_free(CAPI_CTX *ctx) 1628 { 1629 CAPI_trace(ctx, "Calling capi_ctx_free with %lx\n", ctx); 1630 if (!ctx) 1631 return; 1632 OPENSSL_free(ctx->cspname); 1633 OPENSSL_free(ctx->debug_file); 1634 OPENSSL_free(ctx->storename); 1635 OPENSSL_free(ctx->ssl_client_store); 1636 OPENSSL_free(ctx); 1637 } 1638 1639 static int capi_ctx_set_provname(CAPI_CTX *ctx, LPSTR pname, DWORD type, 1640 int check) 1641 { 1642 LPSTR tmpcspname; 1643 1644 CAPI_trace(ctx, "capi_ctx_set_provname, name=%s, type=%d\n", pname, type); 1645 if (check) { 1646 HCRYPTPROV hprov; 1647 LPWSTR name = NULL; 1648 DWORD len; 1649 1650 if ((len = MultiByteToWideChar(CP_ACP, 0, pname, -1, NULL, 0))) { 1651 name = alloca(len * sizeof(WCHAR)); 1652 MultiByteToWideChar(CP_ACP, 0, pname, -1, (WCHAR *)name, len); 1653 } 1654 if (name == NULL || !CryptAcquireContextW(&hprov, NULL, name, type, CRYPT_VERIFYCONTEXT)) { 1655 CAPIerr(CAPI_F_CAPI_CTX_SET_PROVNAME, 1656 CAPI_R_CRYPTACQUIRECONTEXT_ERROR); 1657 capi_addlasterror(); 1658 return 0; 1659 } 1660 CryptReleaseContext(hprov, 0); 1661 } 1662 tmpcspname = OPENSSL_strdup(pname); 1663 if (tmpcspname == NULL) 1664 return 0; 1665 OPENSSL_free(ctx->cspname); 1666 ctx->cspname = tmpcspname; 1667 ctx->csptype = type; 1668 return 1; 1669 } 1670 1671 static int capi_ctx_set_provname_idx(CAPI_CTX *ctx, int idx) 1672 { 1673 LPSTR pname; 1674 DWORD type; 1675 int res; 1676 if (capi_get_provname(ctx, &pname, &type, idx) != 1) 1677 return 0; 1678 res = capi_ctx_set_provname(ctx, pname, type, 0); 1679 OPENSSL_free(pname); 1680 return res; 1681 } 1682 1683 static int cert_issuer_match(STACK_OF(X509_NAME) *ca_dn, X509 *x) 1684 { 1685 int i; 1686 X509_NAME *nm; 1687 /* Special case: empty list: match anything */ 1688 if (sk_X509_NAME_num(ca_dn) <= 0) 1689 return 1; 1690 for (i = 0; i < sk_X509_NAME_num(ca_dn); i++) { 1691 nm = sk_X509_NAME_value(ca_dn, i); 1692 if (!X509_NAME_cmp(nm, X509_get_issuer_name(x))) 1693 return 1; 1694 } 1695 return 0; 1696 } 1697 1698 static int capi_load_ssl_client_cert(ENGINE *e, SSL *ssl, 1699 STACK_OF(X509_NAME) *ca_dn, X509 **pcert, 1700 EVP_PKEY **pkey, STACK_OF(X509) **pother, 1701 UI_METHOD *ui_method, 1702 void *callback_data) 1703 { 1704 STACK_OF(X509) *certs = NULL; 1705 X509 *x; 1706 char *storename; 1707 const unsigned char *p; 1708 int i, client_cert_idx; 1709 HCERTSTORE hstore; 1710 PCCERT_CONTEXT cert = NULL, excert = NULL; 1711 CAPI_CTX *ctx; 1712 CAPI_KEY *key; 1713 ctx = ENGINE_get_ex_data(e, capi_idx); 1714 1715 *pcert = NULL; 1716 *pkey = NULL; 1717 1718 storename = ctx->ssl_client_store; 1719 if (!storename) 1720 storename = "MY"; 1721 1722 hstore = capi_open_store(ctx, storename); 1723 if (!hstore) 1724 return 0; 1725 /* Enumerate all certificates collect any matches */ 1726 for (i = 0;; i++) { 1727 cert = CertEnumCertificatesInStore(hstore, cert); 1728 if (!cert) 1729 break; 1730 p = cert->pbCertEncoded; 1731 x = d2i_X509(NULL, &p, cert->cbCertEncoded); 1732 if (!x) { 1733 CAPI_trace(ctx, "Can't Parse Certificate %d\n", i); 1734 continue; 1735 } 1736 if (cert_issuer_match(ca_dn, x) 1737 && X509_check_purpose(x, X509_PURPOSE_SSL_CLIENT, 0)) { 1738 key = capi_get_cert_key(ctx, cert); 1739 if (!key) { 1740 X509_free(x); 1741 continue; 1742 } 1743 /* 1744 * Match found: attach extra data to it so we can retrieve the 1745 * key later. 1746 */ 1747 excert = CertDuplicateCertificateContext(cert); 1748 key->pcert = excert; 1749 X509_set_ex_data(x, cert_capi_idx, key); 1750 1751 if (!certs) 1752 certs = sk_X509_new_null(); 1753 1754 if (!sk_X509_push(certs, x)) { 1755 X509_free(x); 1756 continue; 1757 } 1758 } else { 1759 X509_free(x); 1760 } 1761 } 1762 1763 if (cert) 1764 CertFreeCertificateContext(cert); 1765 if (hstore) 1766 CertCloseStore(hstore, 0); 1767 1768 if (!certs) 1769 return 0; 1770 1771 /* Select the appropriate certificate */ 1772 1773 client_cert_idx = ctx->client_cert_select(e, ssl, certs); 1774 1775 /* Set the selected certificate and free the rest */ 1776 1777 for (i = 0; i < sk_X509_num(certs); i++) { 1778 x = sk_X509_value(certs, i); 1779 if (i == client_cert_idx) 1780 *pcert = x; 1781 else { 1782 key = X509_get_ex_data(x, cert_capi_idx); 1783 capi_free_key(key); 1784 X509_free(x); 1785 } 1786 } 1787 1788 sk_X509_free(certs); 1789 1790 if (*pcert == NULL) 1791 return 0; 1792 1793 /* Setup key for selected certificate */ 1794 1795 key = X509_get_ex_data(*pcert, cert_capi_idx); 1796 *pkey = capi_get_pkey(e, key); 1797 X509_set_ex_data(*pcert, cert_capi_idx, NULL); 1798 1799 return 1; 1800 } 1801 1802 /* Simple client cert selection function: always select first */ 1803 1804 static int cert_select_simple(ENGINE *e, SSL *ssl, STACK_OF(X509) *certs) 1805 { 1806 return 0; 1807 } 1808 1809 #ifdef OPENSSL_CAPIENG_DIALOG 1810 1811 /* 1812 * More complex cert selection function, using standard function 1813 * CryptUIDlgSelectCertificateFromStore() to produce a dialog box. 1814 */ 1815 1816 /* 1817 * Definitions which are in cryptuiapi.h but this is not present in older 1818 * versions of headers. 1819 */ 1820 1821 #ifndef CRYPTUI_SELECT_LOCATION_COLUMN 1822 #define CRYPTUI_SELECT_LOCATION_COLUMN 0x000000010 1823 #define CRYPTUI_SELECT_INTENDEDUSE_COLUMN 0x000000004 1824 #endif 1825 1826 #define dlg_title L"OpenSSL Application SSL Client Certificate Selection" 1827 #define dlg_prompt L"Select a certificate to use for authentication" 1828 #define dlg_columns \ 1829 CRYPTUI_SELECT_LOCATION_COLUMN \ 1830 | CRYPTUI_SELECT_INTENDEDUSE_COLUMN 1831 1832 static int cert_select_dialog(ENGINE *e, SSL *ssl, STACK_OF(X509) *certs) 1833 { 1834 X509 *x; 1835 HCERTSTORE dstore; 1836 PCCERT_CONTEXT cert; 1837 CAPI_CTX *ctx; 1838 CAPI_KEY *key; 1839 HWND hwnd; 1840 int i, idx = -1; 1841 if (sk_X509_num(certs) == 1) 1842 return 0; 1843 ctx = ENGINE_get_ex_data(e, capi_idx); 1844 /* Create an in memory store of certificates */ 1845 dstore = CertOpenStore(CERT_STORE_PROV_MEMORY, 0, 0, 1846 CERT_STORE_CREATE_NEW_FLAG, NULL); 1847 if (!dstore) { 1848 CAPIerr(CAPI_F_CERT_SELECT_DIALOG, CAPI_R_ERROR_CREATING_STORE); 1849 capi_addlasterror(); 1850 goto err; 1851 } 1852 /* Add all certificates to store */ 1853 for (i = 0; i < sk_X509_num(certs); i++) { 1854 x = sk_X509_value(certs, i); 1855 key = X509_get_ex_data(x, cert_capi_idx); 1856 1857 if (!CertAddCertificateContextToStore(dstore, key->pcert, 1858 CERT_STORE_ADD_NEW, NULL)) { 1859 CAPIerr(CAPI_F_CERT_SELECT_DIALOG, CAPI_R_ERROR_ADDING_CERT); 1860 capi_addlasterror(); 1861 goto err; 1862 } 1863 } 1864 hwnd = GetForegroundWindow(); 1865 if (!hwnd) 1866 hwnd = GetActiveWindow(); 1867 if (!hwnd && ctx->getconswindow) 1868 hwnd = ctx->getconswindow(); 1869 /* Call dialog to select one */ 1870 cert = ctx->certselectdlg(dstore, hwnd, dlg_title, dlg_prompt, 1871 dlg_columns, 0, NULL); 1872 1873 /* Find matching cert from list */ 1874 if (cert) { 1875 for (i = 0; i < sk_X509_num(certs); i++) { 1876 x = sk_X509_value(certs, i); 1877 key = X509_get_ex_data(x, cert_capi_idx); 1878 if (CertCompareCertificate(X509_ASN_ENCODING | PKCS_7_ASN_ENCODING, cert->pCertInfo, 1879 key->pcert->pCertInfo)) { 1880 idx = i; 1881 break; 1882 } 1883 } 1884 } 1885 1886 err: 1887 if (dstore) 1888 CertCloseStore(dstore, 0); 1889 return idx; 1890 } 1891 #endif 1892 1893 #else /* !__COMPILE_CAPIENG */ 1894 #include <openssl/engine.h> 1895 #ifndef OPENSSL_NO_DYNAMIC_ENGINE 1896 OPENSSL_EXPORT 1897 int bind_engine(ENGINE *e, const char *id, const dynamic_fns *fns); 1898 OPENSSL_EXPORT 1899 int bind_engine(ENGINE *e, const char *id, const dynamic_fns *fns) 1900 { 1901 return 0; 1902 } 1903 1904 IMPLEMENT_DYNAMIC_CHECK_FN() 1905 #else 1906 void engine_load_capi_int(void); 1907 void engine_load_capi_int(void) 1908 { 1909 } 1910 #endif 1911 #endif 1912