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