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