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