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