1142425Snectar/*
2160814Ssimon * Copyright 2008-2021 The OpenSSL Project Authors. All Rights Reserved.
3142425Snectar *
4142425Snectar * Licensed under the Apache License 2.0 (the "License").  You may not use
5142425Snectar * this file except in compliance with the License.  You can obtain a copy
6142425Snectar * in the file LICENSE in the source distribution or at
7142425Snectar * https://www.openssl.org/source/license.html
8142425Snectar */
9142425Snectar
10142425Snectar/* We need to use some deprecated APIs */
11142425Snectar#define OPENSSL_SUPPRESS_DEPRECATED
12142425Snectar
13142425Snectar#ifdef _WIN32
14142425Snectar# ifndef _WIN32_WINNT
15142425Snectar#  define _WIN32_WINNT 0x0400
16142425Snectar# endif
17142425Snectar# include <windows.h>
18142425Snectar# include <wincrypt.h>
19142425Snectar
20142425Snectar# include <stdio.h>
21238405Sjkim# include <string.h>
22238405Sjkim# include <stdlib.h>
23142425Snectar# include <malloc.h>
24142425Snectar# ifndef alloca
25142425Snectar#  define alloca _alloca
26142425Snectar# endif
27238405Sjkim
28142425Snectar# include <openssl/crypto.h>
29142425Snectar
30142425Snectar# ifndef OPENSSL_NO_CAPIENG
31142425Snectar
32142425Snectar#  include <openssl/buffer.h>
33142425Snectar#  include <openssl/bn.h>
34238405Sjkim#  include <openssl/rsa.h>
35142425Snectar#  include <openssl/dsa.h>
36142425Snectar
37238405Sjkim/*
38142425Snectar * This module uses several "new" interfaces, among which is
39142425Snectar * CertGetCertificateContextProperty. CERT_KEY_PROV_INFO_PROP_ID is
40142425Snectar * one of possible values you can pass to function in question. By
41142425Snectar * checking if it's defined we can see if wincrypt.h and accompanying
42142425Snectar * crypt32.lib are in shape. The native MingW32 headers up to and
43142425Snectar * including __W32API_VERSION 3.14 lack of struct DSSPUBKEY and the
44142425Snectar * defines CERT_STORE_PROV_SYSTEM_A and CERT_STORE_READONLY_FLAG,
45142425Snectar * so we check for these too and avoid compiling.
46142425Snectar * Yes, it's rather "weak" test and if compilation fails,
47160814Ssimon * then re-configure with -DOPENSSL_NO_CAPIENG.
48142425Snectar */
49238405Sjkim#  if defined(CERT_KEY_PROV_INFO_PROP_ID) && \
50238405Sjkim    defined(CERT_STORE_PROV_SYSTEM_A) && \
51238405Sjkim    defined(CERT_STORE_READONLY_FLAG)
52238405Sjkim#   define __COMPILE_CAPIENG
53142425Snectar#  endif                        /* CERT_KEY_PROV_INFO_PROP_ID */
54142425Snectar# endif                         /* OPENSSL_NO_CAPIENG */
55142425Snectar#endif                          /* _WIN32 */
56142425Snectar
57142425Snectar#ifdef __COMPILE_CAPIENG
58142425Snectar
59142425Snectar# undef X509_EXTENSIONS
60142425Snectar
61142425Snectar/* Definitions which may be missing from earlier version of headers */
62160814Ssimon# ifndef CERT_STORE_OPEN_EXISTING_FLAG
63160814Ssimon#  define CERT_STORE_OPEN_EXISTING_FLAG                   0x00004000
64142425Snectar# endif
65142425Snectar
66142425Snectar# ifndef CERT_STORE_CREATE_NEW_FLAG
67142425Snectar#  define CERT_STORE_CREATE_NEW_FLAG                      0x00002000
68142425Snectar# endif
69142425Snectar
70142425Snectar# ifndef CERT_SYSTEM_STORE_CURRENT_USER
71142425Snectar#  define CERT_SYSTEM_STORE_CURRENT_USER                  0x00010000
72142425Snectar# endif
73142425Snectar
74142425Snectar# ifndef ALG_SID_SHA_256
75142425Snectar#  define ALG_SID_SHA_256   12
76142425Snectar# endif
77284285Sjkim# ifndef ALG_SID_SHA_384
78284285Sjkim#  define ALG_SID_SHA_384   13
79142425Snectar# endif
80160814Ssimon# ifndef ALG_SID_SHA_512
81142425Snectar#  define ALG_SID_SHA_512   14
82142425Snectar# endif
83142425Snectar
84142425Snectar# ifndef CALG_SHA_256
85142425Snectar#  define CALG_SHA_256      (ALG_CLASS_HASH | ALG_TYPE_ANY | ALG_SID_SHA_256)
86142425Snectar# endif
87142425Snectar# ifndef CALG_SHA_384
88142425Snectar#  define CALG_SHA_384      (ALG_CLASS_HASH | ALG_TYPE_ANY | ALG_SID_SHA_384)
89142425Snectar# endif
90142425Snectar# ifndef CALG_SHA_512
91142425Snectar#  define CALG_SHA_512      (ALG_CLASS_HASH | ALG_TYPE_ANY | ALG_SID_SHA_512)
92142425Snectar# endif
93160814Ssimon
94160814Ssimon# ifndef PROV_RSA_AES
95142425Snectar#  define PROV_RSA_AES 24
96142425Snectar# endif
97142425Snectar
98142425Snectar# include <openssl/engine.h>
99142425Snectar# include <openssl/pem.h>
100142425Snectar# include <openssl/x509v3.h>
101194206Ssimon
102194206Ssimon# include "e_capi_err.h"
103194206Ssimon# include "e_capi_err.c"
104194206Ssimon
105194206Ssimonstatic const char *engine_capi_id = "capi";
106194206Ssimonstatic const char *engine_capi_name = "CryptoAPI ENGINE";
107194206Ssimon
108194206Ssimontypedef struct CAPI_CTX_st CAPI_CTX;
109142425Snectartypedef struct CAPI_KEY_st CAPI_KEY;
110160814Ssimon
111160814Ssimonstatic void capi_addlasterror(void);
112160814Ssimonstatic void capi_adderror(DWORD err);
113160814Ssimon
114160814Ssimonstatic void CAPI_trace(CAPI_CTX *ctx, char *format, ...);
115160814Ssimon
116160814Ssimonstatic int capi_list_providers(CAPI_CTX *ctx, BIO *out);
117142425Snectarstatic int capi_list_containers(CAPI_CTX *ctx, BIO *out);
118160814Ssimonint capi_list_certs(CAPI_CTX *ctx, BIO *out, char *storename);
119160814Ssimonvoid capi_free_key(CAPI_KEY *key);
120160814Ssimon
121160814Ssimonstatic PCCERT_CONTEXT capi_find_cert(CAPI_CTX *ctx, const char *id,
122160814Ssimon                                     HCERTSTORE hstore);
123160814Ssimon
124160814SsimonCAPI_KEY *capi_find_key(CAPI_CTX *ctx, const char *id);
125160814Ssimon
126238405Sjkimstatic EVP_PKEY *capi_load_privkey(ENGINE *eng, const char *key_id,
127238405Sjkim                                   UI_METHOD *ui_method, void *callback_data);
128238405Sjkimstatic int capi_rsa_sign(int dtype, const unsigned char *m,
129238405Sjkim                         unsigned int m_len, unsigned char *sigret,
130238405Sjkim                         unsigned int *siglen, const RSA *rsa);
131238405Sjkimstatic int capi_rsa_priv_enc(int flen, const unsigned char *from,
132238405Sjkim                             unsigned char *to, RSA *rsa, int padding);
133static int capi_rsa_priv_dec(int flen, const unsigned char *from,
134                             unsigned char *to, RSA *rsa, int padding);
135static int capi_rsa_free(RSA *rsa);
136
137# ifndef OPENSSL_NO_DSA
138static DSA_SIG *capi_dsa_do_sign(const unsigned char *digest, int dlen,
139                                 DSA *dsa);
140static int capi_dsa_free(DSA *dsa);
141# endif
142
143static 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
149static int cert_select_simple(ENGINE *e, SSL *ssl, STACK_OF(X509) *certs);
150# ifdef OPENSSL_CAPIENG_DIALOG
151static int cert_select_dialog(ENGINE *e, SSL *ssl, STACK_OF(X509) *certs);
152# endif
153
154void engine_load_capi_int(void);
155
156typedef PCCERT_CONTEXT(WINAPI *CERTDLG)(HCERTSTORE, HWND, LPCWSTR,
157                                        LPCWSTR, DWORD, DWORD, void *);
158typedef 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
168struct 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
198static CAPI_CTX *capi_ctx_new(void);
199static void capi_ctx_free(CAPI_CTX *ctx);
200static int capi_ctx_set_provname(CAPI_CTX *ctx, LPSTR pname, DWORD type,
201                                 int check);
202static 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
219static 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
281static int capi_idx = -1;
282static int rsa_capi_idx = -1;
283static int dsa_capi_idx = -1;
284static int cert_capi_idx = -1;
285
286static 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            CAPIerr(CAPI_F_CAPI_CTRL, ERR_R_MALLOC_FAILURE);
327            ret = 0;
328        }
329        break;
330
331    case CAPI_CMD_STORE_FLAGS:
332        if (i & 1) {
333            ctx->store_flags |= CERT_SYSTEM_STORE_LOCAL_MACHINE;
334            ctx->store_flags &= ~CERT_SYSTEM_STORE_CURRENT_USER;
335        } else {
336            ctx->store_flags |= CERT_SYSTEM_STORE_CURRENT_USER;
337            ctx->store_flags &= ~CERT_SYSTEM_STORE_LOCAL_MACHINE;
338        }
339        CAPI_trace(ctx, "Setting flags to %d\n", i);
340        break;
341
342    case CAPI_CMD_DEBUG_LEVEL:
343        ctx->debug_level = (int)i;
344        CAPI_trace(ctx, "Setting debug level to %d\n", ctx->debug_level);
345        break;
346
347    case CAPI_CMD_DEBUG_FILE:
348        tmpstr = OPENSSL_strdup(p);
349        if (tmpstr != NULL) {
350            ctx->debug_file = tmpstr;
351            CAPI_trace(ctx, "Setting debug file to %s\n", ctx->debug_file);
352        } else {
353            CAPIerr(CAPI_F_CAPI_CTRL, ERR_R_MALLOC_FAILURE);
354            ret = 0;
355        }
356        break;
357
358    case CAPI_CMD_KEYTYPE:
359        ctx->keytype = i;
360        CAPI_trace(ctx, "Setting key type to %d\n", ctx->keytype);
361        break;
362
363    case CAPI_CMD_SET_CSP_IDX:
364        ret = capi_ctx_set_provname_idx(ctx, i);
365        break;
366
367    case CAPI_CMD_LIST_OPTIONS:
368        ctx->dump_flags = i;
369        break;
370
371    case CAPI_CMD_LOOKUP_METHOD:
372        if (i < 1 || i > 3) {
373            CAPIerr(CAPI_F_CAPI_CTRL, CAPI_R_INVALID_LOOKUP_METHOD);
374            BIO_free(out);
375            return 0;
376        }
377        ctx->lookup_method = i;
378        break;
379
380    case CAPI_CMD_SET_CSP_NAME:
381        ret = capi_ctx_set_provname(ctx, p, ctx->csptype, 1);
382        break;
383
384    case CAPI_CMD_SET_CSP_TYPE:
385        ctx->csptype = i;
386        break;
387
388    default:
389        CAPIerr(CAPI_F_CAPI_CTRL, CAPI_R_UNKNOWN_COMMAND);
390        ret = 0;
391    }
392
393    BIO_free(out);
394    return ret;
395
396}
397
398static RSA_METHOD *capi_rsa_method = NULL;
399# ifndef OPENSSL_NO_DSA
400static DSA_METHOD *capi_dsa_method = NULL;
401# endif
402
403static int use_aes_csp = 0;
404static const WCHAR rsa_aes_cspname[] =
405    L"Microsoft Enhanced RSA and AES Cryptographic Provider";
406static const WCHAR rsa_enh_cspname[] =
407    L"Microsoft Enhanced Cryptographic Provider v1.0";
408
409static int capi_init(ENGINE *e)
410{
411    CAPI_CTX *ctx;
412    const RSA_METHOD *ossl_rsa_meth;
413# ifndef OPENSSL_NO_DSA
414    const DSA_METHOD *ossl_dsa_meth;
415# endif
416    HCRYPTPROV hprov;
417
418    if (capi_idx < 0) {
419        capi_idx = ENGINE_get_ex_new_index(0, NULL, NULL, NULL, 0);
420        if (capi_idx < 0)
421            goto memerr;
422
423        cert_capi_idx = X509_get_ex_new_index(0, NULL, NULL, NULL, 0);
424
425        /* Setup RSA_METHOD */
426        rsa_capi_idx = RSA_get_ex_new_index(0, NULL, NULL, NULL, 0);
427        ossl_rsa_meth = RSA_PKCS1_OpenSSL();
428        if (   !RSA_meth_set_pub_enc(capi_rsa_method,
429                                     RSA_meth_get_pub_enc(ossl_rsa_meth))
430            || !RSA_meth_set_pub_dec(capi_rsa_method,
431                                     RSA_meth_get_pub_dec(ossl_rsa_meth))
432            || !RSA_meth_set_priv_enc(capi_rsa_method, capi_rsa_priv_enc)
433            || !RSA_meth_set_priv_dec(capi_rsa_method, capi_rsa_priv_dec)
434            || !RSA_meth_set_mod_exp(capi_rsa_method,
435                                     RSA_meth_get_mod_exp(ossl_rsa_meth))
436            || !RSA_meth_set_bn_mod_exp(capi_rsa_method,
437                                        RSA_meth_get_bn_mod_exp(ossl_rsa_meth))
438            || !RSA_meth_set_finish(capi_rsa_method, capi_rsa_free)
439            || !RSA_meth_set_sign(capi_rsa_method, capi_rsa_sign)) {
440            goto memerr;
441        }
442
443# ifndef OPENSSL_NO_DSA
444        /* Setup DSA Method */
445        dsa_capi_idx = DSA_get_ex_new_index(0, NULL, NULL, NULL, 0);
446        ossl_dsa_meth = DSA_OpenSSL();
447        if (   !DSA_meth_set_sign(capi_dsa_method, capi_dsa_do_sign)
448            || !DSA_meth_set_verify(capi_dsa_method,
449                                    DSA_meth_get_verify(ossl_dsa_meth))
450            || !DSA_meth_set_finish(capi_dsa_method, capi_dsa_free)
451            || !DSA_meth_set_mod_exp(capi_dsa_method,
452                                     DSA_meth_get_mod_exp(ossl_dsa_meth))
453            || !DSA_meth_set_bn_mod_exp(capi_dsa_method,
454                                    DSA_meth_get_bn_mod_exp(ossl_dsa_meth))) {
455            goto memerr;
456        }
457# endif
458    }
459
460    ctx = capi_ctx_new();
461    if (ctx == NULL)
462        goto memerr;
463
464    ENGINE_set_ex_data(e, capi_idx, ctx);
465
466# ifdef OPENSSL_CAPIENG_DIALOG
467    {
468        HMODULE cryptui = LoadLibrary(TEXT("CRYPTUI.DLL"));
469        HMODULE kernel = GetModuleHandle(TEXT("KERNEL32.DLL"));
470        if (cryptui)
471            ctx->certselectdlg =
472                (CERTDLG) GetProcAddress(cryptui,
473                                         "CryptUIDlgSelectCertificateFromStore");
474        if (kernel)
475            ctx->getconswindow =
476                (GETCONSWIN) GetProcAddress(kernel, "GetConsoleWindow");
477        if (cryptui && !OPENSSL_isservice())
478            ctx->client_cert_select = cert_select_dialog;
479    }
480# endif
481
482    /* See if there is RSA+AES CSP */
483    if (CryptAcquireContextW(&hprov, NULL, rsa_aes_cspname, PROV_RSA_AES,
484                             CRYPT_VERIFYCONTEXT)) {
485        use_aes_csp = 1;
486        CryptReleaseContext(hprov, 0);
487    }
488
489    return 1;
490
491 memerr:
492    CAPIerr(CAPI_F_CAPI_INIT, ERR_R_MALLOC_FAILURE);
493    return 0;
494
495    return 1;
496}
497
498static int capi_destroy(ENGINE *e)
499{
500    RSA_meth_free(capi_rsa_method);
501    capi_rsa_method = NULL;
502# ifndef OPENSSL_NO_DSA
503    DSA_meth_free(capi_dsa_method);
504    capi_dsa_method = NULL;
505# endif
506    ERR_unload_CAPI_strings();
507    return 1;
508}
509
510static int capi_finish(ENGINE *e)
511{
512    CAPI_CTX *ctx;
513    ctx = ENGINE_get_ex_data(e, capi_idx);
514    capi_ctx_free(ctx);
515    ENGINE_set_ex_data(e, capi_idx, NULL);
516    return 1;
517}
518
519/*
520 * CryptoAPI key application data. This contains a handle to the private key
521 * container (for sign operations) and a handle to the key (for decrypt
522 * operations).
523 */
524
525struct CAPI_KEY_st {
526    /* Associated certificate context (if any) */
527    PCCERT_CONTEXT pcert;
528    HCRYPTPROV hprov;
529    HCRYPTKEY key;
530    DWORD keyspec;
531};
532
533static int bind_capi(ENGINE *e)
534{
535    capi_rsa_method = RSA_meth_new("CryptoAPI RSA method", 0);
536    if (capi_rsa_method == NULL)
537        return 0;
538# ifndef OPENSSL_NO_DSA
539    capi_dsa_method = DSA_meth_new("CryptoAPI DSA method", 0);
540    if (capi_dsa_method == NULL)
541        goto memerr;
542# endif
543    if (!ENGINE_set_id(e, engine_capi_id)
544        || !ENGINE_set_name(e, engine_capi_name)
545        || !ENGINE_set_flags(e, ENGINE_FLAGS_NO_REGISTER_ALL)
546        || !ENGINE_set_init_function(e, capi_init)
547        || !ENGINE_set_finish_function(e, capi_finish)
548        || !ENGINE_set_destroy_function(e, capi_destroy)
549        || !ENGINE_set_RSA(e, capi_rsa_method)
550# ifndef OPENSSL_NO_DSA
551        || !ENGINE_set_DSA(e, capi_dsa_method)
552# endif
553        || !ENGINE_set_load_privkey_function(e, capi_load_privkey)
554        || !ENGINE_set_load_ssl_client_cert_function(e,
555                                                     capi_load_ssl_client_cert)
556        || !ENGINE_set_cmd_defns(e, capi_cmd_defns)
557        || !ENGINE_set_ctrl_function(e, capi_ctrl))
558        goto memerr;
559    ERR_load_CAPI_strings();
560
561    return 1;
562 memerr:
563    RSA_meth_free(capi_rsa_method);
564    capi_rsa_method = NULL;
565# ifndef OPENSSL_NO_DSA
566    DSA_meth_free(capi_dsa_method);
567    capi_dsa_method = NULL;
568# endif
569    return 0;
570}
571
572# ifndef OPENSSL_NO_DYNAMIC_ENGINE
573static int bind_helper(ENGINE *e, const char *id)
574{
575    if (id && (strcmp(id, engine_capi_id) != 0))
576        return 0;
577    if (!bind_capi(e))
578        return 0;
579    return 1;
580}
581
582IMPLEMENT_DYNAMIC_CHECK_FN()
583IMPLEMENT_DYNAMIC_BIND_FN(bind_helper)
584# else
585static ENGINE *engine_capi(void)
586{
587    ENGINE *ret = ENGINE_new();
588    if (ret == NULL)
589        return NULL;
590    if (!bind_capi(ret)) {
591        ENGINE_free(ret);
592        return NULL;
593    }
594    return ret;
595}
596
597void engine_load_capi_int(void)
598{
599    /* Copied from eng_[openssl|dyn].c */
600    ENGINE *toadd = engine_capi();
601    if (!toadd)
602        return;
603    ERR_set_mark();
604    ENGINE_add(toadd);
605    /*
606     * If the "add" worked, it gets a structural reference. So either way, we
607     * release our just-created reference.
608     */
609    ENGINE_free(toadd);
610    /*
611     * If the "add" didn't work, it was probably a conflict because it was
612     * already added (eg. someone calling ENGINE_load_blah then calling
613     * ENGINE_load_builtin_engines() perhaps).
614     */
615    ERR_pop_to_mark();
616}
617# endif
618
619static int lend_tobn(BIGNUM *bn, unsigned char *bin, int binlen)
620{
621    int i;
622    /*
623     * Reverse buffer in place: since this is a keyblob structure that will
624     * be freed up after conversion anyway it doesn't matter if we change
625     * it.
626     */
627    for (i = 0; i < binlen / 2; i++) {
628        unsigned char c;
629        c = bin[i];
630        bin[i] = bin[binlen - i - 1];
631        bin[binlen - i - 1] = c;
632    }
633
634    if (!BN_bin2bn(bin, binlen, bn))
635        return 0;
636    return 1;
637}
638
639/* Given a CAPI_KEY get an EVP_PKEY structure */
640
641static EVP_PKEY *capi_get_pkey(ENGINE *eng, CAPI_KEY *key)
642{
643    unsigned char *pubkey = NULL;
644    DWORD len;
645    BLOBHEADER *bh;
646    RSA *rkey = NULL;
647    DSA *dkey = NULL;
648    EVP_PKEY *ret = NULL;
649    if (!CryptExportKey(key->key, 0, PUBLICKEYBLOB, 0, NULL, &len)) {
650        CAPIerr(CAPI_F_CAPI_GET_PKEY, CAPI_R_PUBKEY_EXPORT_LENGTH_ERROR);
651        capi_addlasterror();
652        return NULL;
653    }
654
655    pubkey = OPENSSL_malloc(len);
656
657    if (pubkey == NULL)
658        goto memerr;
659
660    if (!CryptExportKey(key->key, 0, PUBLICKEYBLOB, 0, pubkey, &len)) {
661        CAPIerr(CAPI_F_CAPI_GET_PKEY, CAPI_R_PUBKEY_EXPORT_ERROR);
662        capi_addlasterror();
663        goto err;
664    }
665
666    bh = (BLOBHEADER *) pubkey;
667    if (bh->bType != PUBLICKEYBLOB) {
668        CAPIerr(CAPI_F_CAPI_GET_PKEY, CAPI_R_INVALID_PUBLIC_KEY_BLOB);
669        goto err;
670    }
671    if (bh->aiKeyAlg == CALG_RSA_SIGN || bh->aiKeyAlg == CALG_RSA_KEYX) {
672        RSAPUBKEY *rp;
673        DWORD rsa_modlen;
674        BIGNUM *e = NULL, *n = NULL;
675        unsigned char *rsa_modulus;
676        rp = (RSAPUBKEY *) (bh + 1);
677        if (rp->magic != 0x31415352) {
678            char magstr[10];
679            BIO_snprintf(magstr, 10, "%lx", rp->magic);
680            CAPIerr(CAPI_F_CAPI_GET_PKEY,
681                    CAPI_R_INVALID_RSA_PUBLIC_KEY_BLOB_MAGIC_NUMBER);
682            ERR_add_error_data(2, "magic=0x", magstr);
683            goto err;
684        }
685        rsa_modulus = (unsigned char *)(rp + 1);
686        rkey = RSA_new_method(eng);
687        if (!rkey)
688            goto memerr;
689
690        e = BN_new();
691        n = BN_new();
692
693        if (e == NULL || n == NULL) {
694            BN_free(e);
695            BN_free(n);
696            goto memerr;
697        }
698
699        RSA_set0_key(rkey, n, e, NULL);
700
701        if (!BN_set_word(e, rp->pubexp))
702            goto memerr;
703
704        rsa_modlen = rp->bitlen / 8;
705        if (!lend_tobn(n, rsa_modulus, rsa_modlen))
706            goto memerr;
707
708        RSA_set_ex_data(rkey, rsa_capi_idx, key);
709
710        if ((ret = EVP_PKEY_new()) == NULL)
711            goto memerr;
712
713        EVP_PKEY_assign_RSA(ret, rkey);
714        rkey = NULL;
715
716# ifndef OPENSSL_NO_DSA
717    } else if (bh->aiKeyAlg == CALG_DSS_SIGN) {
718        DSSPUBKEY *dp;
719        DWORD dsa_plen;
720        unsigned char *btmp;
721        BIGNUM *p, *q, *g, *pub_key;
722        dp = (DSSPUBKEY *) (bh + 1);
723        if (dp->magic != 0x31535344) {
724            char magstr[10];
725            BIO_snprintf(magstr, 10, "%lx", dp->magic);
726            CAPIerr(CAPI_F_CAPI_GET_PKEY,
727                    CAPI_R_INVALID_DSA_PUBLIC_KEY_BLOB_MAGIC_NUMBER);
728            ERR_add_error_data(2, "magic=0x", magstr);
729            goto err;
730        }
731        dsa_plen = dp->bitlen / 8;
732        btmp = (unsigned char *)(dp + 1);
733        dkey = DSA_new_method(eng);
734        if (!dkey)
735            goto memerr;
736        p = BN_new();
737        q = BN_new();
738        g = BN_new();
739        pub_key = BN_new();
740        if (p == NULL || q == NULL || g == NULL || pub_key == NULL) {
741            BN_free(p);
742            BN_free(q);
743            BN_free(g);
744            BN_free(pub_key);
745            goto memerr;
746        }
747        DSA_set0_pqg(dkey, p, q, g);
748        DSA_set0_key(dkey, pub_key, NULL);
749        if (!lend_tobn(p, btmp, dsa_plen))
750            goto memerr;
751        btmp += dsa_plen;
752        if (!lend_tobn(q, btmp, 20))
753            goto memerr;
754        btmp += 20;
755        if (!lend_tobn(g, btmp, dsa_plen))
756            goto memerr;
757        btmp += dsa_plen;
758        if (!lend_tobn(pub_key, btmp, dsa_plen))
759            goto memerr;
760        btmp += dsa_plen;
761
762        DSA_set_ex_data(dkey, dsa_capi_idx, key);
763
764        if ((ret = EVP_PKEY_new()) == NULL)
765            goto memerr;
766
767        EVP_PKEY_assign_DSA(ret, dkey);
768        dkey = NULL;
769# endif
770    } else {
771        char algstr[10];
772        BIO_snprintf(algstr, 10, "%ux", bh->aiKeyAlg);
773        CAPIerr(CAPI_F_CAPI_GET_PKEY,
774                CAPI_R_UNSUPPORTED_PUBLIC_KEY_ALGORITHM);
775        ERR_add_error_data(2, "aiKeyAlg=0x", algstr);
776        goto err;
777    }
778
779 err:
780    OPENSSL_free(pubkey);
781    if (!ret) {
782        RSA_free(rkey);
783# ifndef OPENSSL_NO_DSA
784        DSA_free(dkey);
785# endif
786    }
787
788    return ret;
789
790 memerr:
791    CAPIerr(CAPI_F_CAPI_GET_PKEY, ERR_R_MALLOC_FAILURE);
792    goto err;
793
794}
795
796static EVP_PKEY *capi_load_privkey(ENGINE *eng, const char *key_id,
797                                   UI_METHOD *ui_method, void *callback_data)
798{
799    CAPI_CTX *ctx;
800    CAPI_KEY *key;
801    EVP_PKEY *ret;
802    ctx = ENGINE_get_ex_data(eng, capi_idx);
803
804    if (!ctx) {
805        CAPIerr(CAPI_F_CAPI_LOAD_PRIVKEY, CAPI_R_CANT_FIND_CAPI_CONTEXT);
806        return NULL;
807    }
808
809    key = capi_find_key(ctx, key_id);
810
811    if (!key)
812        return NULL;
813
814    ret = capi_get_pkey(eng, key);
815
816    if (!ret)
817        capi_free_key(key);
818    return ret;
819
820}
821
822/* CryptoAPI RSA operations */
823
824int capi_rsa_priv_enc(int flen, const unsigned char *from,
825                      unsigned char *to, RSA *rsa, int padding)
826{
827    CAPIerr(CAPI_F_CAPI_RSA_PRIV_ENC, CAPI_R_FUNCTION_NOT_SUPPORTED);
828    return -1;
829}
830
831int capi_rsa_sign(int dtype, const unsigned char *m, unsigned int m_len,
832                  unsigned char *sigret, unsigned int *siglen, const RSA *rsa)
833{
834    ALG_ID alg;
835    HCRYPTHASH hash;
836    DWORD slen;
837    unsigned int i;
838    int ret = -1;
839    CAPI_KEY *capi_key;
840    CAPI_CTX *ctx;
841
842    ctx = ENGINE_get_ex_data(RSA_get0_engine(rsa), capi_idx);
843
844    CAPI_trace(ctx, "Called CAPI_rsa_sign()\n");
845
846    capi_key = RSA_get_ex_data(rsa, rsa_capi_idx);
847    if (!capi_key) {
848        CAPIerr(CAPI_F_CAPI_RSA_SIGN, CAPI_R_CANT_GET_KEY);
849        return -1;
850    }
851    /* Convert the signature type to a CryptoAPI algorithm ID */
852    switch (dtype) {
853    case NID_sha256:
854        alg = CALG_SHA_256;
855        break;
856
857    case NID_sha384:
858        alg = CALG_SHA_384;
859        break;
860
861    case NID_sha512:
862        alg = CALG_SHA_512;
863        break;
864
865    case NID_sha1:
866        alg = CALG_SHA1;
867        break;
868
869    case NID_md5:
870        alg = CALG_MD5;
871        break;
872
873    case NID_md5_sha1:
874        alg = CALG_SSL3_SHAMD5;
875        break;
876    default:
877        {
878            char algstr[10];
879            BIO_snprintf(algstr, 10, "%x", dtype);
880            CAPIerr(CAPI_F_CAPI_RSA_SIGN, CAPI_R_UNSUPPORTED_ALGORITHM_NID);
881            ERR_add_error_data(2, "NID=0x", algstr);
882            return -1;
883        }
884    }
885
886    /* Create the hash object */
887    if (!CryptCreateHash(capi_key->hprov, alg, 0, 0, &hash)) {
888        CAPIerr(CAPI_F_CAPI_RSA_SIGN, CAPI_R_CANT_CREATE_HASH_OBJECT);
889        capi_addlasterror();
890        return -1;
891    }
892    /* Set the hash value to the value passed */
893
894    if (!CryptSetHashParam(hash, HP_HASHVAL, (unsigned char *)m, 0)) {
895        CAPIerr(CAPI_F_CAPI_RSA_SIGN, CAPI_R_CANT_SET_HASH_VALUE);
896        capi_addlasterror();
897        goto err;
898    }
899
900    /* Finally sign it */
901    slen = RSA_size(rsa);
902    if (!CryptSignHash(hash, capi_key->keyspec, NULL, 0, sigret, &slen)) {
903        CAPIerr(CAPI_F_CAPI_RSA_SIGN, CAPI_R_ERROR_SIGNING_HASH);
904        capi_addlasterror();
905        goto err;
906    } else {
907        ret = 1;
908        /* Inplace byte reversal of signature */
909        for (i = 0; i < slen / 2; i++) {
910            unsigned char c;
911            c = sigret[i];
912            sigret[i] = sigret[slen - i - 1];
913            sigret[slen - i - 1] = c;
914        }
915        *siglen = slen;
916    }
917
918    /* Now cleanup */
919
920 err:
921    CryptDestroyHash(hash);
922
923    return ret;
924}
925
926int capi_rsa_priv_dec(int flen, const unsigned char *from,
927                      unsigned char *to, RSA *rsa, int padding)
928{
929    int i;
930    unsigned char *tmpbuf;
931    CAPI_KEY *capi_key;
932    CAPI_CTX *ctx;
933    DWORD flags = 0;
934    DWORD dlen;
935
936    if (flen <= 0)
937        return flen;
938
939    ctx = ENGINE_get_ex_data(RSA_get0_engine(rsa), capi_idx);
940
941    CAPI_trace(ctx, "Called capi_rsa_priv_dec()\n");
942
943    capi_key = RSA_get_ex_data(rsa, rsa_capi_idx);
944    if (!capi_key) {
945        CAPIerr(CAPI_F_CAPI_RSA_PRIV_DEC, CAPI_R_CANT_GET_KEY);
946        return -1;
947    }
948
949    switch (padding) {
950    case RSA_PKCS1_PADDING:
951        /* Nothing to do */
952        break;
953#ifdef CRYPT_DECRYPT_RSA_NO_PADDING_CHECK
954    case RSA_NO_PADDING:
955        flags = CRYPT_DECRYPT_RSA_NO_PADDING_CHECK;
956        break;
957#endif
958    default:
959        {
960            char errstr[10];
961            BIO_snprintf(errstr, 10, "%d", padding);
962            CAPIerr(CAPI_F_CAPI_RSA_PRIV_DEC, CAPI_R_UNSUPPORTED_PADDING);
963            ERR_add_error_data(2, "padding=", errstr);
964            return -1;
965        }
966    }
967
968    /* Create temp reverse order version of input */
969    if ((tmpbuf = OPENSSL_malloc(flen)) == NULL) {
970        CAPIerr(CAPI_F_CAPI_RSA_PRIV_DEC, ERR_R_MALLOC_FAILURE);
971        return -1;
972    }
973    for (i = 0; i < flen; i++)
974        tmpbuf[flen - i - 1] = from[i];
975
976    /* Finally decrypt it */
977    dlen = flen;
978    if (!CryptDecrypt(capi_key->key, 0, TRUE, flags, tmpbuf, &dlen)) {
979        CAPIerr(CAPI_F_CAPI_RSA_PRIV_DEC, CAPI_R_DECRYPT_ERROR);
980        capi_addlasterror();
981        OPENSSL_cleanse(tmpbuf, dlen);
982        OPENSSL_free(tmpbuf);
983        return -1;
984    } else {
985        memcpy(to, tmpbuf, (flen = (int)dlen));
986    }
987    OPENSSL_cleanse(tmpbuf, flen);
988    OPENSSL_free(tmpbuf);
989
990    return flen;
991}
992
993static int capi_rsa_free(RSA *rsa)
994{
995    CAPI_KEY *capi_key;
996    capi_key = RSA_get_ex_data(rsa, rsa_capi_idx);
997    capi_free_key(capi_key);
998    RSA_set_ex_data(rsa, rsa_capi_idx, 0);
999    return 1;
1000}
1001
1002# ifndef OPENSSL_NO_DSA
1003/* CryptoAPI DSA operations */
1004
1005static DSA_SIG *capi_dsa_do_sign(const unsigned char *digest, int dlen,
1006                                 DSA *dsa)
1007{
1008    HCRYPTHASH hash;
1009    DWORD slen;
1010    DSA_SIG *ret = NULL;
1011    CAPI_KEY *capi_key;
1012    CAPI_CTX *ctx;
1013    unsigned char csigbuf[40];
1014
1015    ctx = ENGINE_get_ex_data(DSA_get0_engine(dsa), capi_idx);
1016
1017    CAPI_trace(ctx, "Called CAPI_dsa_do_sign()\n");
1018
1019    capi_key = DSA_get_ex_data(dsa, dsa_capi_idx);
1020
1021    if (!capi_key) {
1022        CAPIerr(CAPI_F_CAPI_DSA_DO_SIGN, CAPI_R_CANT_GET_KEY);
1023        return NULL;
1024    }
1025
1026    if (dlen != 20) {
1027        CAPIerr(CAPI_F_CAPI_DSA_DO_SIGN, CAPI_R_INVALID_DIGEST_LENGTH);
1028        return NULL;
1029    }
1030
1031    /* Create the hash object */
1032    if (!CryptCreateHash(capi_key->hprov, CALG_SHA1, 0, 0, &hash)) {
1033        CAPIerr(CAPI_F_CAPI_DSA_DO_SIGN, CAPI_R_CANT_CREATE_HASH_OBJECT);
1034        capi_addlasterror();
1035        return NULL;
1036    }
1037
1038    /* Set the hash value to the value passed */
1039    if (!CryptSetHashParam(hash, HP_HASHVAL, (unsigned char *)digest, 0)) {
1040        CAPIerr(CAPI_F_CAPI_DSA_DO_SIGN, CAPI_R_CANT_SET_HASH_VALUE);
1041        capi_addlasterror();
1042        goto err;
1043    }
1044
1045    /* Finally sign it */
1046    slen = sizeof(csigbuf);
1047    if (!CryptSignHash(hash, capi_key->keyspec, NULL, 0, csigbuf, &slen)) {
1048        CAPIerr(CAPI_F_CAPI_DSA_DO_SIGN, CAPI_R_ERROR_SIGNING_HASH);
1049        capi_addlasterror();
1050        goto err;
1051    } else {
1052        BIGNUM *r = BN_new(), *s = BN_new();
1053
1054        if (r == NULL || s == NULL
1055            || !lend_tobn(r, csigbuf, 20)
1056            || !lend_tobn(s, csigbuf + 20, 20)
1057            || (ret = DSA_SIG_new()) == NULL) {
1058            BN_free(r); /* BN_free checks for BIGNUM * being NULL */
1059            BN_free(s);
1060            goto err;
1061        }
1062        DSA_SIG_set0(ret, r, s);
1063    }
1064
1065    /* Now cleanup */
1066
1067 err:
1068    OPENSSL_cleanse(csigbuf, 40);
1069    CryptDestroyHash(hash);
1070    return ret;
1071}
1072
1073static int capi_dsa_free(DSA *dsa)
1074{
1075    CAPI_KEY *capi_key;
1076    capi_key = DSA_get_ex_data(dsa, dsa_capi_idx);
1077    capi_free_key(capi_key);
1078    DSA_set_ex_data(dsa, dsa_capi_idx, 0);
1079    return 1;
1080}
1081# endif
1082
1083static void capi_vtrace(CAPI_CTX *ctx, int level, char *format,
1084                        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+");
1091    if (out == NULL) {
1092        CAPIerr(CAPI_F_CAPI_VTRACE, CAPI_R_FILE_OPEN_ERROR);
1093        return;
1094    }
1095    BIO_vprintf(out, format, argptr);
1096    BIO_free(out);
1097}
1098
1099static void CAPI_trace(CAPI_CTX *ctx, char *format, ...)
1100{
1101    va_list args;
1102    va_start(args, format);
1103    capi_vtrace(ctx, CAPI_DBG_TRACE, format, args);
1104    va_end(args);
1105}
1106
1107static void capi_addlasterror(void)
1108{
1109    capi_adderror(GetLastError());
1110}
1111
1112static void capi_adderror(DWORD err)
1113{
1114    char errstr[10];
1115    BIO_snprintf(errstr, 10, "%lX", err);
1116    ERR_add_error_data(2, "Error code= 0x", errstr);
1117}
1118
1119static char *wide_to_asc(LPCWSTR wstr)
1120{
1121    char *str;
1122    int len_0, sz;
1123    size_t len_1;
1124
1125    if (!wstr)
1126        return NULL;
1127
1128    len_1 = wcslen(wstr) + 1;
1129
1130    if (len_1 > INT_MAX) {
1131	    CAPIerr(CAPI_F_WIDE_TO_ASC, CAPI_R_FUNCTION_NOT_SUPPORTED);
1132	    return NULL;
1133    }
1134
1135    len_0 = (int)len_1; /* WideCharToMultiByte expects int */
1136    sz = WideCharToMultiByte(CP_ACP, 0, wstr, len_0, NULL, 0, NULL, NULL);
1137    if (!sz) {
1138        CAPIerr(CAPI_F_WIDE_TO_ASC, CAPI_R_WIN32_ERROR);
1139        return NULL;
1140    }
1141    str = OPENSSL_malloc(sz);
1142    if (str == NULL) {
1143        CAPIerr(CAPI_F_WIDE_TO_ASC, ERR_R_MALLOC_FAILURE);
1144        return NULL;
1145    }
1146    if (!WideCharToMultiByte(CP_ACP, 0, wstr, len_0, str, sz, NULL, NULL)) {
1147        OPENSSL_free(str);
1148        CAPIerr(CAPI_F_WIDE_TO_ASC, CAPI_R_WIN32_ERROR);
1149        return NULL;
1150    }
1151    return str;
1152}
1153
1154static int capi_get_provname(CAPI_CTX *ctx, LPSTR *pname, DWORD *ptype,
1155                             DWORD idx)
1156{
1157    DWORD len, err;
1158    LPTSTR name;
1159    CAPI_trace(ctx, "capi_get_provname, index=%d\n", idx);
1160    if (!CryptEnumProviders(idx, NULL, 0, ptype, NULL, &len)) {
1161        err = GetLastError();
1162        if (err == ERROR_NO_MORE_ITEMS)
1163            return 2;
1164        CAPIerr(CAPI_F_CAPI_GET_PROVNAME, CAPI_R_CRYPTENUMPROVIDERS_ERROR);
1165        capi_adderror(err);
1166        return 0;
1167    }
1168    name = OPENSSL_malloc(len);
1169    if (name == NULL) {
1170        CAPIerr(CAPI_F_CAPI_GET_PROVNAME, ERR_R_MALLOC_FAILURE);
1171        return 0;
1172    }
1173    if (!CryptEnumProviders(idx, NULL, 0, ptype, name, &len)) {
1174        err = GetLastError();
1175        OPENSSL_free(name);
1176        if (err == ERROR_NO_MORE_ITEMS)
1177            return 2;
1178        CAPIerr(CAPI_F_CAPI_GET_PROVNAME, CAPI_R_CRYPTENUMPROVIDERS_ERROR);
1179        capi_adderror(err);
1180        return 0;
1181    }
1182    if (sizeof(TCHAR) != sizeof(char)) {
1183        *pname = wide_to_asc((WCHAR *)name);
1184        OPENSSL_free(name);
1185        if (*pname == NULL)
1186            return 0;
1187    } else {
1188        *pname = (char *)name;
1189    }
1190    CAPI_trace(ctx, "capi_get_provname, returned name=%s, type=%d\n", *pname,
1191               *ptype);
1192
1193    return 1;
1194}
1195
1196static int capi_list_providers(CAPI_CTX *ctx, BIO *out)
1197{
1198    DWORD idx, ptype;
1199    int ret;
1200    LPSTR provname = NULL;
1201    CAPI_trace(ctx, "capi_list_providers\n");
1202    BIO_printf(out, "Available CSPs:\n");
1203    for (idx = 0;; idx++) {
1204        ret = capi_get_provname(ctx, &provname, &ptype, idx);
1205        if (ret == 2)
1206            break;
1207        if (ret == 0)
1208            break;
1209        BIO_printf(out, "%lu. %s, type %lu\n", idx, provname, ptype);
1210        OPENSSL_free(provname);
1211    }
1212    return 1;
1213}
1214
1215static int capi_list_containers(CAPI_CTX *ctx, BIO *out)
1216{
1217    int ret = 1;
1218    HCRYPTPROV hprov;
1219    DWORD err, idx, flags, buflen = 0, clen;
1220    LPSTR cname;
1221    LPWSTR cspname = NULL;
1222
1223    CAPI_trace(ctx, "Listing containers CSP=%s, type = %d\n", ctx->cspname,
1224               ctx->csptype);
1225    if (ctx->cspname != NULL) {
1226        if ((clen = MultiByteToWideChar(CP_ACP, 0, ctx->cspname, -1,
1227                                        NULL, 0))) {
1228            cspname = alloca(clen * sizeof(WCHAR));
1229            MultiByteToWideChar(CP_ACP, 0, ctx->cspname, -1, (WCHAR *)cspname,
1230                                clen);
1231        }
1232        if (cspname == NULL) {
1233            CAPIerr(CAPI_F_CAPI_LIST_CONTAINERS, ERR_R_MALLOC_FAILURE);
1234            capi_addlasterror();
1235            return 0;
1236        }
1237    }
1238    if (!CryptAcquireContextW(&hprov, NULL, cspname, ctx->csptype,
1239                              CRYPT_VERIFYCONTEXT)) {
1240        CAPIerr(CAPI_F_CAPI_LIST_CONTAINERS,
1241                CAPI_R_CRYPTACQUIRECONTEXT_ERROR);
1242        capi_addlasterror();
1243        return 0;
1244    }
1245    if (!CryptGetProvParam(hprov, PP_ENUMCONTAINERS, NULL, &buflen,
1246                           CRYPT_FIRST)) {
1247        CAPIerr(CAPI_F_CAPI_LIST_CONTAINERS, CAPI_R_ENUMCONTAINERS_ERROR);
1248        capi_addlasterror();
1249        CryptReleaseContext(hprov, 0);
1250        return 0;
1251    }
1252    CAPI_trace(ctx, "Got max container len %d\n", buflen);
1253    if (buflen == 0)
1254        buflen = 1024;
1255    cname = OPENSSL_malloc(buflen);
1256    if (cname == NULL) {
1257        CAPIerr(CAPI_F_CAPI_LIST_CONTAINERS, ERR_R_MALLOC_FAILURE);
1258        goto err;
1259    }
1260
1261    for (idx = 0;; idx++) {
1262        clen = buflen;
1263        cname[0] = 0;
1264
1265        if (idx == 0)
1266            flags = CRYPT_FIRST;
1267        else
1268            flags = 0;
1269        if (!CryptGetProvParam(hprov, PP_ENUMCONTAINERS, (BYTE *)cname,
1270                               &clen, flags)) {
1271            err = GetLastError();
1272            if (err == ERROR_NO_MORE_ITEMS)
1273                goto done;
1274            CAPIerr(CAPI_F_CAPI_LIST_CONTAINERS, CAPI_R_ENUMCONTAINERS_ERROR);
1275            capi_adderror(err);
1276            goto err;
1277        }
1278        CAPI_trace(ctx, "Container name %s, len=%d, index=%d, flags=%d\n",
1279                   cname, clen, idx, flags);
1280        if (!cname[0] && (clen == buflen)) {
1281            CAPI_trace(ctx, "Enumerate bug: using workaround\n");
1282            goto done;
1283        }
1284        BIO_printf(out, "%lu. %s\n", idx, cname);
1285    }
1286 err:
1287
1288    ret = 0;
1289
1290 done:
1291    OPENSSL_free(cname);
1292    CryptReleaseContext(hprov, 0);
1293
1294    return ret;
1295}
1296
1297static CRYPT_KEY_PROV_INFO *capi_get_prov_info(CAPI_CTX *ctx,
1298                                               PCCERT_CONTEXT cert)
1299{
1300    DWORD len;
1301    CRYPT_KEY_PROV_INFO *pinfo;
1302
1303    if (!CertGetCertificateContextProperty(cert, CERT_KEY_PROV_INFO_PROP_ID,
1304                                           NULL, &len))
1305        return NULL;
1306    pinfo = OPENSSL_malloc(len);
1307    if (pinfo == NULL) {
1308        CAPIerr(CAPI_F_CAPI_GET_PROV_INFO, ERR_R_MALLOC_FAILURE);
1309        return NULL;
1310    }
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
1322static 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
1346static 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
1371static 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
1413static 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
1432int 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
1470static 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
1501static 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 &&
1512        wcscmp(provname, rsa_enh_cspname) == 0) {
1513        provname = rsa_aes_cspname;
1514        ptype = PROV_RSA_AES;
1515    }
1516    if (ctx && ctx->debug_level >= CAPI_DBG_TRACE && ctx->debug_file) {
1517        /*
1518         * above 'if' is [complementary] copy from CAPI_trace and serves
1519         * as optimization to minimize [below] malloc-ations
1520         */
1521        char *_contname = wide_to_asc(contname);
1522        char *_provname = wide_to_asc(provname);
1523
1524        CAPI_trace(ctx, "capi_get_key, contname=%s, provname=%s, type=%d\n",
1525                   _contname, _provname, ptype);
1526        OPENSSL_free(_provname);
1527        OPENSSL_free(_contname);
1528    }
1529    if (ctx->store_flags & CERT_SYSTEM_STORE_LOCAL_MACHINE)
1530        dwFlags = CRYPT_MACHINE_KEYSET;
1531    if (!CryptAcquireContextW(&key->hprov, contname, provname, ptype,
1532                              dwFlags)) {
1533        CAPIerr(CAPI_F_CAPI_GET_KEY, CAPI_R_CRYPTACQUIRECONTEXT_ERROR);
1534        capi_addlasterror();
1535        goto err;
1536    }
1537    if (!CryptGetUserKey(key->hprov, keyspec, &key->key)) {
1538        CAPIerr(CAPI_F_CAPI_GET_KEY, CAPI_R_GETUSERKEY_ERROR);
1539        capi_addlasterror();
1540        CryptReleaseContext(key->hprov, 0);
1541        goto err;
1542    }
1543    key->keyspec = keyspec;
1544    key->pcert = NULL;
1545    return key;
1546
1547 err:
1548    OPENSSL_free(key);
1549    return NULL;
1550}
1551
1552static CAPI_KEY *capi_get_cert_key(CAPI_CTX *ctx, PCCERT_CONTEXT cert)
1553{
1554    CAPI_KEY *key = NULL;
1555    CRYPT_KEY_PROV_INFO *pinfo = NULL;
1556
1557    pinfo = capi_get_prov_info(ctx, cert);
1558
1559    if (pinfo != NULL)
1560        key = capi_get_key(ctx, pinfo->pwszContainerName, pinfo->pwszProvName,
1561                           pinfo->dwProvType, pinfo->dwKeySpec);
1562
1563    OPENSSL_free(pinfo);
1564    return key;
1565}
1566
1567CAPI_KEY *capi_find_key(CAPI_CTX *ctx, const char *id)
1568{
1569    PCCERT_CONTEXT cert;
1570    HCERTSTORE hstore;
1571    CAPI_KEY *key = NULL;
1572
1573    switch (ctx->lookup_method) {
1574    case CAPI_LU_SUBSTR:
1575    case CAPI_LU_FNAME:
1576        hstore = capi_open_store(ctx, NULL);
1577        if (!hstore)
1578            return NULL;
1579        cert = capi_find_cert(ctx, id, hstore);
1580        if (cert) {
1581            key = capi_get_cert_key(ctx, cert);
1582            CertFreeCertificateContext(cert);
1583        }
1584        CertCloseStore(hstore, 0);
1585        break;
1586
1587    case CAPI_LU_CONTNAME:
1588        {
1589            WCHAR *contname, *provname;
1590            DWORD len;
1591
1592            if ((len = MultiByteToWideChar(CP_ACP, 0, id, -1, NULL, 0)) &&
1593                (contname = alloca(len * sizeof(WCHAR)),
1594                 MultiByteToWideChar(CP_ACP, 0, id, -1, contname, len)) &&
1595                (len = MultiByteToWideChar(CP_ACP, 0, ctx->cspname, -1,
1596                                           NULL, 0)) &&
1597                (provname = alloca(len * sizeof(WCHAR)),
1598                 MultiByteToWideChar(CP_ACP, 0, ctx->cspname, -1,
1599                                     provname, len)))
1600                key = capi_get_key(ctx, contname, provname,
1601                                   ctx->csptype, ctx->keytype);
1602        }
1603        break;
1604    }
1605
1606    return key;
1607}
1608
1609void capi_free_key(CAPI_KEY *key)
1610{
1611    if (!key)
1612        return;
1613    CryptDestroyKey(key->key);
1614    CryptReleaseContext(key->hprov, 0);
1615    if (key->pcert)
1616        CertFreeCertificateContext(key->pcert);
1617    OPENSSL_free(key);
1618}
1619
1620/* Initialize a CAPI_CTX structure */
1621
1622static CAPI_CTX *capi_ctx_new(void)
1623{
1624    CAPI_CTX *ctx = OPENSSL_zalloc(sizeof(*ctx));
1625
1626    if (ctx == NULL) {
1627        CAPIerr(CAPI_F_CAPI_CTX_NEW, ERR_R_MALLOC_FAILURE);
1628        return NULL;
1629    }
1630    ctx->csptype = PROV_RSA_FULL;
1631    ctx->dump_flags = CAPI_DMP_SUMMARY | CAPI_DMP_FNAME;
1632    ctx->keytype = AT_KEYEXCHANGE;
1633    ctx->store_flags = CERT_STORE_OPEN_EXISTING_FLAG |
1634        CERT_STORE_READONLY_FLAG | CERT_SYSTEM_STORE_CURRENT_USER;
1635    ctx->lookup_method = CAPI_LU_SUBSTR;
1636    ctx->client_cert_select = cert_select_simple;
1637    return ctx;
1638}
1639
1640static void capi_ctx_free(CAPI_CTX *ctx)
1641{
1642    CAPI_trace(ctx, "Calling capi_ctx_free with %lx\n", ctx);
1643    if (!ctx)
1644        return;
1645    OPENSSL_free(ctx->cspname);
1646    OPENSSL_free(ctx->debug_file);
1647    OPENSSL_free(ctx->storename);
1648    OPENSSL_free(ctx->ssl_client_store);
1649    OPENSSL_free(ctx);
1650}
1651
1652static int capi_ctx_set_provname(CAPI_CTX *ctx, LPSTR pname, DWORD type,
1653                                 int check)
1654{
1655    LPSTR tmpcspname;
1656
1657    CAPI_trace(ctx, "capi_ctx_set_provname, name=%s, type=%d\n", pname, type);
1658    if (check) {
1659        HCRYPTPROV hprov;
1660        LPWSTR name = NULL;
1661        DWORD len;
1662
1663        if ((len = MultiByteToWideChar(CP_ACP, 0, pname, -1, NULL, 0))) {
1664            name = alloca(len * sizeof(WCHAR));
1665            MultiByteToWideChar(CP_ACP, 0, pname, -1, (WCHAR *)name, len);
1666        }
1667        if (name == NULL || !CryptAcquireContextW(&hprov, NULL, name, type,
1668                                                  CRYPT_VERIFYCONTEXT)) {
1669            CAPIerr(CAPI_F_CAPI_CTX_SET_PROVNAME,
1670                    CAPI_R_CRYPTACQUIRECONTEXT_ERROR);
1671            capi_addlasterror();
1672            return 0;
1673        }
1674        CryptReleaseContext(hprov, 0);
1675    }
1676    tmpcspname = OPENSSL_strdup(pname);
1677    if (tmpcspname == NULL) {
1678        CAPIerr(CAPI_F_CAPI_CTX_SET_PROVNAME, ERR_R_MALLOC_FAILURE);
1679        return 0;
1680    }
1681    OPENSSL_free(ctx->cspname);
1682    ctx->cspname = tmpcspname;
1683    ctx->csptype = type;
1684    return 1;
1685}
1686
1687static int capi_ctx_set_provname_idx(CAPI_CTX *ctx, int idx)
1688{
1689    LPSTR pname;
1690    DWORD type;
1691    int res;
1692    if (capi_get_provname(ctx, &pname, &type, idx) != 1)
1693        return 0;
1694    res = capi_ctx_set_provname(ctx, pname, type, 0);
1695    OPENSSL_free(pname);
1696    return res;
1697}
1698
1699static int cert_issuer_match(STACK_OF(X509_NAME) *ca_dn, X509 *x)
1700{
1701    int i;
1702    X509_NAME *nm;
1703    /* Special case: empty list: match anything */
1704    if (sk_X509_NAME_num(ca_dn) <= 0)
1705        return 1;
1706    for (i = 0; i < sk_X509_NAME_num(ca_dn); i++) {
1707        nm = sk_X509_NAME_value(ca_dn, i);
1708        if (!X509_NAME_cmp(nm, X509_get_issuer_name(x)))
1709            return 1;
1710    }
1711    return 0;
1712}
1713
1714static int capi_load_ssl_client_cert(ENGINE *e, SSL *ssl,
1715                                     STACK_OF(X509_NAME) *ca_dn, X509 **pcert,
1716                                     EVP_PKEY **pkey, STACK_OF(X509) **pother,
1717                                     UI_METHOD *ui_method,
1718                                     void *callback_data)
1719{
1720    STACK_OF(X509) *certs = NULL;
1721    X509 *x;
1722    char *storename;
1723    const unsigned char *p;
1724    int i, client_cert_idx;
1725    HCERTSTORE hstore;
1726    PCCERT_CONTEXT cert = NULL, excert = NULL;
1727    CAPI_CTX *ctx;
1728    CAPI_KEY *key;
1729    ctx = ENGINE_get_ex_data(e, capi_idx);
1730
1731    *pcert = NULL;
1732    *pkey = NULL;
1733
1734    storename = ctx->ssl_client_store;
1735    if (!storename)
1736        storename = "MY";
1737
1738    hstore = capi_open_store(ctx, storename);
1739    if (!hstore)
1740        return 0;
1741    /* Enumerate all certificates collect any matches */
1742    for (i = 0;; i++) {
1743        cert = CertEnumCertificatesInStore(hstore, cert);
1744        if (!cert)
1745            break;
1746        p = cert->pbCertEncoded;
1747        x = d2i_X509(NULL, &p, cert->cbCertEncoded);
1748        if (!x) {
1749            CAPI_trace(ctx, "Can't Parse Certificate %d\n", i);
1750            continue;
1751        }
1752        if (cert_issuer_match(ca_dn, x)
1753            && X509_check_purpose(x, X509_PURPOSE_SSL_CLIENT, 0)) {
1754            key = capi_get_cert_key(ctx, cert);
1755            if (!key) {
1756                X509_free(x);
1757                continue;
1758            }
1759            /*
1760             * Match found: attach extra data to it so we can retrieve the
1761             * key later.
1762             */
1763            excert = CertDuplicateCertificateContext(cert);
1764            key->pcert = excert;
1765            X509_set_ex_data(x, cert_capi_idx, key);
1766
1767            if (!certs)
1768                certs = sk_X509_new_null();
1769
1770            sk_X509_push(certs, x);
1771        } else {
1772            X509_free(x);
1773        }
1774    }
1775
1776    if (cert)
1777        CertFreeCertificateContext(cert);
1778    if (hstore)
1779        CertCloseStore(hstore, 0);
1780
1781    if (!certs)
1782        return 0;
1783
1784    /* Select the appropriate certificate */
1785
1786    client_cert_idx = ctx->client_cert_select(e, ssl, certs);
1787
1788    /* Set the selected certificate and free the rest */
1789
1790    for (i = 0; i < sk_X509_num(certs); i++) {
1791        x = sk_X509_value(certs, i);
1792        if (i == client_cert_idx)
1793            *pcert = x;
1794        else {
1795            key = X509_get_ex_data(x, cert_capi_idx);
1796            capi_free_key(key);
1797            X509_free(x);
1798        }
1799    }
1800
1801    sk_X509_free(certs);
1802
1803    if (*pcert == NULL)
1804        return 0;
1805
1806    /* Setup key for selected certificate */
1807
1808    key = X509_get_ex_data(*pcert, cert_capi_idx);
1809    *pkey = capi_get_pkey(e, key);
1810    X509_set_ex_data(*pcert, cert_capi_idx, NULL);
1811
1812    return 1;
1813
1814}
1815
1816/* Simple client cert selection function: always select first */
1817
1818static int cert_select_simple(ENGINE *e, SSL *ssl, STACK_OF(X509) *certs)
1819{
1820    return 0;
1821}
1822
1823# ifdef OPENSSL_CAPIENG_DIALOG
1824
1825/*
1826 * More complex cert selection function, using standard function
1827 * CryptUIDlgSelectCertificateFromStore() to produce a dialog box.
1828 */
1829
1830/*
1831 * Definitions which are in cryptuiapi.h but this is not present in older
1832 * versions of headers.
1833 */
1834
1835#  ifndef CRYPTUI_SELECT_LOCATION_COLUMN
1836#   define CRYPTUI_SELECT_LOCATION_COLUMN                   0x000000010
1837#   define CRYPTUI_SELECT_INTENDEDUSE_COLUMN                0x000000004
1838#  endif
1839
1840#  define dlg_title L"OpenSSL Application SSL Client Certificate Selection"
1841#  define dlg_prompt L"Select a certificate to use for authentication"
1842#  define dlg_columns      CRYPTUI_SELECT_LOCATION_COLUMN \
1843                        |CRYPTUI_SELECT_INTENDEDUSE_COLUMN
1844
1845static int cert_select_dialog(ENGINE *e, SSL *ssl, STACK_OF(X509) *certs)
1846{
1847    X509 *x;
1848    HCERTSTORE dstore;
1849    PCCERT_CONTEXT cert;
1850    CAPI_CTX *ctx;
1851    CAPI_KEY *key;
1852    HWND hwnd;
1853    int i, idx = -1;
1854    if (sk_X509_num(certs) == 1)
1855        return 0;
1856    ctx = ENGINE_get_ex_data(e, capi_idx);
1857    /* Create an in memory store of certificates */
1858    dstore = CertOpenStore(CERT_STORE_PROV_MEMORY, 0, 0,
1859                           CERT_STORE_CREATE_NEW_FLAG, NULL);
1860    if (!dstore) {
1861        CAPIerr(CAPI_F_CERT_SELECT_DIALOG, CAPI_R_ERROR_CREATING_STORE);
1862        capi_addlasterror();
1863        goto err;
1864    }
1865    /* Add all certificates to store */
1866    for (i = 0; i < sk_X509_num(certs); i++) {
1867        x = sk_X509_value(certs, i);
1868        key = X509_get_ex_data(x, cert_capi_idx);
1869
1870        if (!CertAddCertificateContextToStore(dstore, key->pcert,
1871                                              CERT_STORE_ADD_NEW, NULL)) {
1872            CAPIerr(CAPI_F_CERT_SELECT_DIALOG, CAPI_R_ERROR_ADDING_CERT);
1873            capi_addlasterror();
1874            goto err;
1875        }
1876
1877    }
1878    hwnd = GetForegroundWindow();
1879    if (!hwnd)
1880        hwnd = GetActiveWindow();
1881    if (!hwnd && ctx->getconswindow)
1882        hwnd = ctx->getconswindow();
1883    /* Call dialog to select one */
1884    cert = ctx->certselectdlg(dstore, hwnd, dlg_title, dlg_prompt,
1885                              dlg_columns, 0, NULL);
1886
1887    /* Find matching cert from list */
1888    if (cert) {
1889        for (i = 0; i < sk_X509_num(certs); i++) {
1890            x = sk_X509_value(certs, i);
1891            key = X509_get_ex_data(x, cert_capi_idx);
1892            if (CertCompareCertificate
1893                (X509_ASN_ENCODING | PKCS_7_ASN_ENCODING, cert->pCertInfo,
1894                 key->pcert->pCertInfo)) {
1895                idx = i;
1896                break;
1897            }
1898        }
1899    }
1900
1901 err:
1902    if (dstore)
1903        CertCloseStore(dstore, 0);
1904    return idx;
1905
1906}
1907# endif
1908
1909#else                           /* !__COMPILE_CAPIENG */
1910# include <openssl/engine.h>
1911# ifndef OPENSSL_NO_DYNAMIC_ENGINE
1912OPENSSL_EXPORT
1913    int bind_engine(ENGINE *e, const char *id, const dynamic_fns *fns);
1914OPENSSL_EXPORT
1915    int bind_engine(ENGINE *e, const char *id, const dynamic_fns *fns)
1916{
1917    return 0;
1918}
1919
1920IMPLEMENT_DYNAMIC_CHECK_FN()
1921# else
1922void engine_load_capi_int(void);
1923void engine_load_capi_int(void)
1924{
1925}
1926# endif
1927#endif
1928