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