1183234Ssimon/* engines/e_capi.c */
2280304Sjkim/*
3280304Sjkim * Written by Dr Stephen N Henson (steve@openssl.org) for the OpenSSL
4183234Ssimon * project.
5183234Ssimon */
6183234Ssimon/* ====================================================================
7183234Ssimon * Copyright (c) 2008 The OpenSSL Project.  All rights reserved.
8183234Ssimon *
9183234Ssimon * Redistribution and use in source and binary forms, with or without
10183234Ssimon * modification, are permitted provided that the following conditions
11183234Ssimon * are met:
12183234Ssimon *
13183234Ssimon * 1. Redistributions of source code must retain the above copyright
14280304Sjkim *    notice, this list of conditions and the following disclaimer.
15183234Ssimon *
16183234Ssimon * 2. Redistributions in binary form must reproduce the above copyright
17183234Ssimon *    notice, this list of conditions and the following disclaimer in
18183234Ssimon *    the documentation and/or other materials provided with the
19183234Ssimon *    distribution.
20183234Ssimon *
21183234Ssimon * 3. All advertising materials mentioning features or use of this
22183234Ssimon *    software must display the following acknowledgment:
23183234Ssimon *    "This product includes software developed by the OpenSSL Project
24183234Ssimon *    for use in the OpenSSL Toolkit. (http://www.OpenSSL.org/)"
25183234Ssimon *
26183234Ssimon * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to
27183234Ssimon *    endorse or promote products derived from this software without
28183234Ssimon *    prior written permission. For written permission, please contact
29183234Ssimon *    licensing@OpenSSL.org.
30183234Ssimon *
31183234Ssimon * 5. Products derived from this software may not be called "OpenSSL"
32183234Ssimon *    nor may "OpenSSL" appear in their names without prior written
33183234Ssimon *    permission of the OpenSSL Project.
34183234Ssimon *
35183234Ssimon * 6. Redistributions of any form whatsoever must retain the following
36183234Ssimon *    acknowledgment:
37183234Ssimon *    "This product includes software developed by the OpenSSL Project
38183234Ssimon *    for use in the OpenSSL Toolkit (http://www.OpenSSL.org/)"
39183234Ssimon *
40183234Ssimon * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY
41183234Ssimon * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
42183234Ssimon * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
43183234Ssimon * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE OpenSSL PROJECT OR
44183234Ssimon * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
45183234Ssimon * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
46183234Ssimon * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
47183234Ssimon * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
48183234Ssimon * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
49183234Ssimon * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
50183234Ssimon * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
51183234Ssimon * OF THE POSSIBILITY OF SUCH DAMAGE.
52183234Ssimon * ====================================================================
53183234Ssimon */
54183234Ssimon
55183234Ssimon#include <stdio.h>
56183234Ssimon#include <string.h>
57183234Ssimon#include <openssl/crypto.h>
58183234Ssimon#include <openssl/buffer.h>
59183234Ssimon#include <openssl/bn.h>
60183234Ssimon
61183234Ssimon#ifdef OPENSSL_SYS_WIN32
62280304Sjkim# ifndef OPENSSL_NO_CAPIENG
63183234Ssimon
64280304Sjkim#  include <openssl/rsa.h>
65183234Ssimon
66280304Sjkim#  include <windows.h>
67183234Ssimon
68280304Sjkim#  ifndef _WIN32_WINNT
69280304Sjkim#   define _WIN32_WINNT 0x0400
70280304Sjkim#  endif
71183234Ssimon
72280304Sjkim#  include <wincrypt.h>
73183234Ssimon
74238405Sjkim/*
75238405Sjkim * This module uses several "new" interfaces, among which is
76238405Sjkim * CertGetCertificateContextProperty. CERT_KEY_PROV_INFO_PROP_ID is
77238405Sjkim * one of possible values you can pass to function in question. By
78238405Sjkim * checking if it's defined we can see if wincrypt.h and accompanying
79238405Sjkim * crypt32.lib are in shape. The native MingW32 headers up to and
80238405Sjkim * including __W32API_VERSION 3.14 lack of struct DSSPUBKEY and the
81238405Sjkim * defines CERT_STORE_PROV_SYSTEM_A and CERT_STORE_READONLY_FLAG,
82238405Sjkim * so we check for these too and avoid compiling.
83238405Sjkim * Yes, it's rather "weak" test and if compilation fails,
84238405Sjkim * then re-configure with -DOPENSSL_NO_CAPIENG.
85238405Sjkim */
86280304Sjkim#  if defined(CERT_KEY_PROV_INFO_PROP_ID) && \
87238405Sjkim    defined(CERT_STORE_PROV_SYSTEM_A) && \
88238405Sjkim    defined(CERT_STORE_READONLY_FLAG)
89280304Sjkim#   define __COMPILE_CAPIENG
90280304Sjkim#  endif                        /* CERT_KEY_PROV_INFO_PROP_ID */
91280304Sjkim# endif                         /* OPENSSL_NO_CAPIENG */
92280304Sjkim#endif                          /* OPENSSL_SYS_WIN32 */
93238405Sjkim
94238405Sjkim#ifdef __COMPILE_CAPIENG
95238405Sjkim
96280304Sjkim# undef X509_EXTENSIONS
97280304Sjkim# undef X509_CERT_PAIR
98183234Ssimon
99183234Ssimon/* Definitions which may be missing from earlier version of headers */
100280304Sjkim# ifndef CERT_STORE_OPEN_EXISTING_FLAG
101280304Sjkim#  define CERT_STORE_OPEN_EXISTING_FLAG                   0x00004000
102280304Sjkim# endif
103183234Ssimon
104280304Sjkim# ifndef CERT_STORE_CREATE_NEW_FLAG
105280304Sjkim#  define CERT_STORE_CREATE_NEW_FLAG                      0x00002000
106280304Sjkim# endif
107183234Ssimon
108280304Sjkim# ifndef CERT_SYSTEM_STORE_CURRENT_USER
109280304Sjkim#  define CERT_SYSTEM_STORE_CURRENT_USER                  0x00010000
110280304Sjkim# endif
111206046Ssimon
112280304Sjkim# include <openssl/engine.h>
113280304Sjkim# include <openssl/pem.h>
114280304Sjkim# include <openssl/x509v3.h>
115183234Ssimon
116280304Sjkim# include "e_capi_err.h"
117280304Sjkim# include "e_capi_err.c"
118183234Ssimon
119183234Ssimonstatic const char *engine_capi_id = "capi";
120183234Ssimonstatic const char *engine_capi_name = "CryptoAPI ENGINE";
121183234Ssimon
122183234Ssimontypedef struct CAPI_CTX_st CAPI_CTX;
123183234Ssimontypedef struct CAPI_KEY_st CAPI_KEY;
124183234Ssimon
125183234Ssimonstatic void capi_addlasterror(void);
126183234Ssimonstatic void capi_adderror(DWORD err);
127183234Ssimon
128280304Sjkimstatic void CAPI_trace(CAPI_CTX * ctx, char *format, ...);
129183234Ssimon
130280304Sjkimstatic int capi_list_providers(CAPI_CTX * ctx, BIO *out);
131280304Sjkimstatic int capi_list_containers(CAPI_CTX * ctx, BIO *out);
132280304Sjkimint capi_list_certs(CAPI_CTX * ctx, BIO *out, char *storename);
133280304Sjkimvoid capi_free_key(CAPI_KEY * key);
134183234Ssimon
135280304Sjkimstatic PCCERT_CONTEXT capi_find_cert(CAPI_CTX * ctx, const char *id,
136280304Sjkim                                     HCERTSTORE hstore);
137183234Ssimon
138280304SjkimCAPI_KEY *capi_find_key(CAPI_CTX * ctx, const char *id);
139183234Ssimon
140183234Ssimonstatic EVP_PKEY *capi_load_privkey(ENGINE *eng, const char *key_id,
141280304Sjkim                                   UI_METHOD *ui_method, void *callback_data);
142280304Sjkimstatic int capi_rsa_sign(int dtype, const unsigned char *m,
143280304Sjkim                         unsigned int m_len, unsigned char *sigret,
144280304Sjkim                         unsigned int *siglen, const RSA *rsa);
145183234Ssimonstatic int capi_rsa_priv_enc(int flen, const unsigned char *from,
146280304Sjkim                             unsigned char *to, RSA *rsa, int padding);
147183234Ssimonstatic int capi_rsa_priv_dec(int flen, const unsigned char *from,
148280304Sjkim                             unsigned char *to, RSA *rsa, int padding);
149183234Ssimonstatic int capi_rsa_free(RSA *rsa);
150183234Ssimon
151183234Ssimonstatic DSA_SIG *capi_dsa_do_sign(const unsigned char *digest, int dlen,
152280304Sjkim                                 DSA *dsa);
153183234Ssimonstatic int capi_dsa_free(DSA *dsa);
154183234Ssimon
155183234Ssimonstatic int capi_load_ssl_client_cert(ENGINE *e, SSL *ssl,
156280304Sjkim                                     STACK_OF(X509_NAME) *ca_dn, X509 **pcert,
157280304Sjkim                                     EVP_PKEY **pkey, STACK_OF(X509) **pother,
158280304Sjkim                                     UI_METHOD *ui_method,
159280304Sjkim                                     void *callback_data);
160183234Ssimon
161183234Ssimonstatic int cert_select_simple(ENGINE *e, SSL *ssl, STACK_OF(X509) *certs);
162280304Sjkim# ifdef OPENSSL_CAPIENG_DIALOG
163183234Ssimonstatic int cert_select_dialog(ENGINE *e, SSL *ssl, STACK_OF(X509) *certs);
164280304Sjkim# endif
165183234Ssimon
166280304Sjkimtypedef PCCERT_CONTEXT(WINAPI *CERTDLG) (HCERTSTORE, HWND, LPCWSTR,
167280304Sjkim                                         LPCWSTR, DWORD, DWORD, void *);
168280304Sjkimtypedef HWND(WINAPI *GETCONSWIN) (void);
169183234Ssimon
170280304Sjkim/*
171280304Sjkim * This structure contains CAPI ENGINE specific data: it contains various
172280304Sjkim * global options and affects how other functions behave.
173183234Ssimon */
174183234Ssimon
175280304Sjkim# define CAPI_DBG_TRACE  2
176280304Sjkim# define CAPI_DBG_ERROR  1
177183234Ssimon
178183234Ssimonstruct CAPI_CTX_st {
179280304Sjkim    int debug_level;
180280304Sjkim    char *debug_file;
181280304Sjkim    /* Parameters to use for container lookup */
182280304Sjkim    DWORD keytype;
183280304Sjkim    LPSTR cspname;
184280304Sjkim    DWORD csptype;
185280304Sjkim    /* Certificate store name to use */
186280304Sjkim    LPSTR storename;
187280304Sjkim    LPSTR ssl_client_store;
188280304Sjkim    /* System store flags */
189280304Sjkim    DWORD store_flags;
190183234Ssimon/* Lookup string meanings in load_private_key */
191183234Ssimon/* Substring of subject: uses "storename" */
192280304Sjkim# define CAPI_LU_SUBSTR          1
193183234Ssimon/* Friendly name: uses storename */
194280304Sjkim# define CAPI_LU_FNAME           2
195183234Ssimon/* Container name: uses cspname, keytype */
196280304Sjkim# define CAPI_LU_CONTNAME        3
197280304Sjkim    int lookup_method;
198183234Ssimon/* Info to dump with dumpcerts option */
199183234Ssimon/* Issuer and serial name strings */
200280304Sjkim# define CAPI_DMP_SUMMARY        0x1
201183234Ssimon/* Friendly name */
202280304Sjkim# define CAPI_DMP_FNAME          0x2
203183234Ssimon/* Full X509_print dump */
204280304Sjkim# define CAPI_DMP_FULL           0x4
205183234Ssimon/* Dump PEM format certificate */
206280304Sjkim# define CAPI_DMP_PEM            0x8
207183234Ssimon/* Dump pseudo key (if possible) */
208280304Sjkim# define CAPI_DMP_PSKEY          0x10
209183234Ssimon/* Dump key info (if possible) */
210280304Sjkim# define CAPI_DMP_PKEYINFO       0x20
211280304Sjkim    DWORD dump_flags;
212280304Sjkim    int (*client_cert_select) (ENGINE *e, SSL *ssl, STACK_OF(X509) *certs);
213280304Sjkim    CERTDLG certselectdlg;
214280304Sjkim    GETCONSWIN getconswindow;
215183234Ssimon};
216183234Ssimon
217183234Ssimonstatic CAPI_CTX *capi_ctx_new();
218280304Sjkimstatic void capi_ctx_free(CAPI_CTX * ctx);
219280304Sjkimstatic int capi_ctx_set_provname(CAPI_CTX * ctx, LPSTR pname, DWORD type,
220280304Sjkim                                 int check);
221280304Sjkimstatic int capi_ctx_set_provname_idx(CAPI_CTX * ctx, int idx);
222183234Ssimon
223280304Sjkim# define CAPI_CMD_LIST_CERTS             ENGINE_CMD_BASE
224280304Sjkim# define CAPI_CMD_LOOKUP_CERT            (ENGINE_CMD_BASE + 1)
225280304Sjkim# define CAPI_CMD_DEBUG_LEVEL            (ENGINE_CMD_BASE + 2)
226280304Sjkim# define CAPI_CMD_DEBUG_FILE             (ENGINE_CMD_BASE + 3)
227280304Sjkim# define CAPI_CMD_KEYTYPE                (ENGINE_CMD_BASE + 4)
228280304Sjkim# define CAPI_CMD_LIST_CSPS              (ENGINE_CMD_BASE + 5)
229280304Sjkim# define CAPI_CMD_SET_CSP_IDX            (ENGINE_CMD_BASE + 6)
230280304Sjkim# define CAPI_CMD_SET_CSP_NAME           (ENGINE_CMD_BASE + 7)
231280304Sjkim# define CAPI_CMD_SET_CSP_TYPE           (ENGINE_CMD_BASE + 8)
232280304Sjkim# define CAPI_CMD_LIST_CONTAINERS        (ENGINE_CMD_BASE + 9)
233280304Sjkim# define CAPI_CMD_LIST_OPTIONS           (ENGINE_CMD_BASE + 10)
234280304Sjkim# define CAPI_CMD_LOOKUP_METHOD          (ENGINE_CMD_BASE + 11)
235280304Sjkim# define CAPI_CMD_STORE_NAME             (ENGINE_CMD_BASE + 12)
236280304Sjkim# define CAPI_CMD_STORE_FLAGS            (ENGINE_CMD_BASE + 13)
237183234Ssimon
238183234Ssimonstatic const ENGINE_CMD_DEFN capi_cmd_defns[] = {
239280304Sjkim    {CAPI_CMD_LIST_CERTS,
240280304Sjkim     "list_certs",
241280304Sjkim     "List all certificates in store",
242280304Sjkim     ENGINE_CMD_FLAG_NO_INPUT},
243280304Sjkim    {CAPI_CMD_LOOKUP_CERT,
244280304Sjkim     "lookup_cert",
245280304Sjkim     "Lookup and output certificates",
246280304Sjkim     ENGINE_CMD_FLAG_STRING},
247280304Sjkim    {CAPI_CMD_DEBUG_LEVEL,
248280304Sjkim     "debug_level",
249280304Sjkim     "debug level (1=errors, 2=trace)",
250280304Sjkim     ENGINE_CMD_FLAG_NUMERIC},
251280304Sjkim    {CAPI_CMD_DEBUG_FILE,
252280304Sjkim     "debug_file",
253280304Sjkim     "debugging filename)",
254280304Sjkim     ENGINE_CMD_FLAG_STRING},
255280304Sjkim    {CAPI_CMD_KEYTYPE,
256280304Sjkim     "key_type",
257280304Sjkim     "Key type: 1=AT_KEYEXCHANGE (default), 2=AT_SIGNATURE",
258280304Sjkim     ENGINE_CMD_FLAG_NUMERIC},
259280304Sjkim    {CAPI_CMD_LIST_CSPS,
260280304Sjkim     "list_csps",
261280304Sjkim     "List all CSPs",
262280304Sjkim     ENGINE_CMD_FLAG_NO_INPUT},
263280304Sjkim    {CAPI_CMD_SET_CSP_IDX,
264280304Sjkim     "csp_idx",
265280304Sjkim     "Set CSP by index",
266280304Sjkim     ENGINE_CMD_FLAG_NUMERIC},
267280304Sjkim    {CAPI_CMD_SET_CSP_NAME,
268280304Sjkim     "csp_name",
269280304Sjkim     "Set CSP name, (default CSP used if not specified)",
270280304Sjkim     ENGINE_CMD_FLAG_STRING},
271280304Sjkim    {CAPI_CMD_SET_CSP_TYPE,
272280304Sjkim     "csp_type",
273280304Sjkim     "Set CSP type, (default RSA_PROV_FULL)",
274280304Sjkim     ENGINE_CMD_FLAG_NUMERIC},
275280304Sjkim    {CAPI_CMD_LIST_CONTAINERS,
276280304Sjkim     "list_containers",
277280304Sjkim     "list container names",
278280304Sjkim     ENGINE_CMD_FLAG_NO_INPUT},
279280304Sjkim    {CAPI_CMD_LIST_OPTIONS,
280280304Sjkim     "list_options",
281280304Sjkim     "Set list options (1=summary,2=friendly name, 4=full printout, 8=PEM output, 16=XXX, "
282280304Sjkim     "32=private key info)",
283280304Sjkim     ENGINE_CMD_FLAG_NUMERIC},
284280304Sjkim    {CAPI_CMD_LOOKUP_METHOD,
285280304Sjkim     "lookup_method",
286280304Sjkim     "Set key lookup method (1=substring, 2=friendlyname, 3=container name)",
287280304Sjkim     ENGINE_CMD_FLAG_NUMERIC},
288280304Sjkim    {CAPI_CMD_STORE_NAME,
289280304Sjkim     "store_name",
290280304Sjkim     "certificate store name, default \"MY\"",
291280304Sjkim     ENGINE_CMD_FLAG_STRING},
292280304Sjkim    {CAPI_CMD_STORE_FLAGS,
293280304Sjkim     "store_flags",
294280304Sjkim     "Certificate store flags: 1 = system store",
295280304Sjkim     ENGINE_CMD_FLAG_NUMERIC},
296183234Ssimon
297280304Sjkim    {0, NULL, NULL, 0}
298280304Sjkim};
299183234Ssimon
300183234Ssimonstatic int capi_idx = -1;
301183234Ssimonstatic int rsa_capi_idx = -1;
302183234Ssimonstatic int dsa_capi_idx = -1;
303183234Ssimonstatic int cert_capi_idx = -1;
304183234Ssimon
305280304Sjkimstatic int capi_ctrl(ENGINE *e, int cmd, long i, void *p, void (*f) (void))
306280304Sjkim{
307280304Sjkim    int ret = 1;
308280304Sjkim    CAPI_CTX *ctx;
309280304Sjkim    BIO *out;
310280304Sjkim    if (capi_idx == -1) {
311280304Sjkim        CAPIerr(CAPI_F_CAPI_CTRL, CAPI_R_ENGINE_NOT_INITIALIZED);
312280304Sjkim        return 0;
313280304Sjkim    }
314280304Sjkim    ctx = ENGINE_get_ex_data(e, capi_idx);
315280304Sjkim    out = BIO_new_fp(stdout, BIO_NOCLOSE);
316280304Sjkim    switch (cmd) {
317280304Sjkim    case CAPI_CMD_LIST_CSPS:
318280304Sjkim        ret = capi_list_providers(ctx, out);
319280304Sjkim        break;
320183234Ssimon
321280304Sjkim    case CAPI_CMD_LIST_CERTS:
322280304Sjkim        ret = capi_list_certs(ctx, out, NULL);
323280304Sjkim        break;
324183234Ssimon
325280304Sjkim    case CAPI_CMD_LOOKUP_CERT:
326280304Sjkim        ret = capi_list_certs(ctx, out, p);
327280304Sjkim        break;
328183234Ssimon
329280304Sjkim    case CAPI_CMD_LIST_CONTAINERS:
330280304Sjkim        ret = capi_list_containers(ctx, out);
331280304Sjkim        break;
332183234Ssimon
333280304Sjkim    case CAPI_CMD_STORE_NAME:
334280304Sjkim        if (ctx->storename)
335280304Sjkim            OPENSSL_free(ctx->storename);
336280304Sjkim        ctx->storename = BUF_strdup(p);
337280304Sjkim        CAPI_trace(ctx, "Setting store name to %s\n", p);
338280304Sjkim        break;
339183234Ssimon
340280304Sjkim    case CAPI_CMD_STORE_FLAGS:
341280304Sjkim        if (i & 1) {
342280304Sjkim            ctx->store_flags |= CERT_SYSTEM_STORE_LOCAL_MACHINE;
343280304Sjkim            ctx->store_flags &= ~CERT_SYSTEM_STORE_CURRENT_USER;
344280304Sjkim        } else {
345280304Sjkim            ctx->store_flags |= CERT_SYSTEM_STORE_CURRENT_USER;
346280304Sjkim            ctx->store_flags &= ~CERT_SYSTEM_STORE_LOCAL_MACHINE;
347280304Sjkim        }
348280304Sjkim        CAPI_trace(ctx, "Setting flags to %d\n", i);
349280304Sjkim        break;
350183234Ssimon
351280304Sjkim    case CAPI_CMD_DEBUG_LEVEL:
352280304Sjkim        ctx->debug_level = (int)i;
353280304Sjkim        CAPI_trace(ctx, "Setting debug level to %d\n", ctx->debug_level);
354280304Sjkim        break;
355183234Ssimon
356280304Sjkim    case CAPI_CMD_DEBUG_FILE:
357280304Sjkim        ctx->debug_file = BUF_strdup(p);
358280304Sjkim        CAPI_trace(ctx, "Setting debug file to %s\n", ctx->debug_file);
359280304Sjkim        break;
360183234Ssimon
361280304Sjkim    case CAPI_CMD_KEYTYPE:
362280304Sjkim        ctx->keytype = i;
363280304Sjkim        CAPI_trace(ctx, "Setting key type to %d\n", ctx->keytype);
364280304Sjkim        break;
365183234Ssimon
366280304Sjkim    case CAPI_CMD_SET_CSP_IDX:
367280304Sjkim        ret = capi_ctx_set_provname_idx(ctx, i);
368280304Sjkim        break;
369183234Ssimon
370280304Sjkim    case CAPI_CMD_LIST_OPTIONS:
371280304Sjkim        ctx->dump_flags = i;
372280304Sjkim        break;
373183234Ssimon
374280304Sjkim    case CAPI_CMD_LOOKUP_METHOD:
375280304Sjkim        if (i < 1 || i > 3) {
376280304Sjkim            CAPIerr(CAPI_F_CAPI_CTRL, CAPI_R_INVALID_LOOKUP_METHOD);
377280304Sjkim            return 0;
378280304Sjkim        }
379280304Sjkim        ctx->lookup_method = i;
380280304Sjkim        break;
381183234Ssimon
382280304Sjkim    case CAPI_CMD_SET_CSP_NAME:
383280304Sjkim        ret = capi_ctx_set_provname(ctx, p, ctx->csptype, 1);
384280304Sjkim        break;
385183234Ssimon
386280304Sjkim    case CAPI_CMD_SET_CSP_TYPE:
387280304Sjkim        ctx->csptype = i;
388280304Sjkim        break;
389183234Ssimon
390280304Sjkim    default:
391280304Sjkim        CAPIerr(CAPI_F_CAPI_CTRL, CAPI_R_UNKNOWN_COMMAND);
392280304Sjkim        ret = 0;
393280304Sjkim    }
394183234Ssimon
395280304Sjkim    BIO_free(out);
396280304Sjkim    return ret;
397183234Ssimon
398280304Sjkim}
399183234Ssimon
400280304Sjkimstatic RSA_METHOD capi_rsa_method = {
401280304Sjkim    "CryptoAPI RSA method",
402280304Sjkim    0,                          /* pub_enc */
403280304Sjkim    0,                          /* pub_dec */
404280304Sjkim    capi_rsa_priv_enc,          /* priv_enc */
405280304Sjkim    capi_rsa_priv_dec,          /* priv_dec */
406280304Sjkim    0,                          /* rsa_mod_exp */
407280304Sjkim    0,                          /* bn_mod_exp */
408280304Sjkim    0,                          /* init */
409280304Sjkim    capi_rsa_free,              /* finish */
410280304Sjkim    RSA_FLAG_SIGN_VER,          /* flags */
411280304Sjkim    NULL,                       /* app_data */
412280304Sjkim    capi_rsa_sign,              /* rsa_sign */
413280304Sjkim    0                           /* rsa_verify */
414280304Sjkim};
415183234Ssimon
416280304Sjkimstatic DSA_METHOD capi_dsa_method = {
417280304Sjkim    "CryptoAPI DSA method",
418280304Sjkim    capi_dsa_do_sign,           /* dsa_do_sign */
419280304Sjkim    0,                          /* dsa_sign_setup */
420280304Sjkim    0,                          /* dsa_do_verify */
421280304Sjkim    0,                          /* dsa_mod_exp */
422280304Sjkim    0,                          /* bn_mod_exp */
423280304Sjkim    0,                          /* init */
424280304Sjkim    capi_dsa_free,              /* finish */
425280304Sjkim    0,                          /* flags */
426280304Sjkim    NULL,                       /* app_data */
427280304Sjkim    0,                          /* dsa_paramgen */
428280304Sjkim    0                           /* dsa_keygen */
429280304Sjkim};
430183234Ssimon
431183234Ssimonstatic int capi_init(ENGINE *e)
432280304Sjkim{
433280304Sjkim    CAPI_CTX *ctx;
434280304Sjkim    const RSA_METHOD *ossl_rsa_meth;
435280304Sjkim    const DSA_METHOD *ossl_dsa_meth;
436183234Ssimon
437280304Sjkim    if (capi_idx < 0) {
438280304Sjkim        capi_idx = ENGINE_get_ex_new_index(0, NULL, NULL, NULL, 0);
439280304Sjkim        if (capi_idx < 0)
440280304Sjkim            goto memerr;
441237657Sjkim
442280304Sjkim        cert_capi_idx = X509_get_ex_new_index(0, NULL, NULL, NULL, 0);
443237657Sjkim
444280304Sjkim        /* Setup RSA_METHOD */
445280304Sjkim        rsa_capi_idx = RSA_get_ex_new_index(0, NULL, NULL, NULL, 0);
446280304Sjkim        ossl_rsa_meth = RSA_PKCS1_SSLeay();
447280304Sjkim        capi_rsa_method.rsa_pub_enc = ossl_rsa_meth->rsa_pub_enc;
448280304Sjkim        capi_rsa_method.rsa_pub_dec = ossl_rsa_meth->rsa_pub_dec;
449280304Sjkim        capi_rsa_method.rsa_mod_exp = ossl_rsa_meth->rsa_mod_exp;
450280304Sjkim        capi_rsa_method.bn_mod_exp = ossl_rsa_meth->bn_mod_exp;
451237657Sjkim
452280304Sjkim        /* Setup DSA Method */
453280304Sjkim        dsa_capi_idx = DSA_get_ex_new_index(0, NULL, NULL, NULL, 0);
454280304Sjkim        ossl_dsa_meth = DSA_OpenSSL();
455280304Sjkim        capi_dsa_method.dsa_do_verify = ossl_dsa_meth->dsa_do_verify;
456280304Sjkim        capi_dsa_method.dsa_mod_exp = ossl_dsa_meth->dsa_mod_exp;
457280304Sjkim        capi_dsa_method.bn_mod_exp = ossl_dsa_meth->bn_mod_exp;
458280304Sjkim    }
459237657Sjkim
460280304Sjkim    ctx = capi_ctx_new();
461280304Sjkim    if (!ctx)
462280304Sjkim        goto memerr;
463183234Ssimon
464280304Sjkim    ENGINE_set_ex_data(e, capi_idx, ctx);
465183234Ssimon
466280304Sjkim# ifdef OPENSSL_CAPIENG_DIALOG
467280304Sjkim    {
468280304Sjkim        HMODULE cryptui = LoadLibrary(TEXT("CRYPTUI.DLL"));
469280304Sjkim        HMODULE kernel = GetModuleHandle(TEXT("KERNEL32.DLL"));
470280304Sjkim        if (cryptui)
471280304Sjkim            ctx->certselectdlg =
472280304Sjkim                (CERTDLG) GetProcAddress(cryptui,
473280304Sjkim                                         "CryptUIDlgSelectCertificateFromStore");
474280304Sjkim        if (kernel)
475280304Sjkim            ctx->getconswindow =
476280304Sjkim                (GETCONSWIN) GetProcAddress(kernel, "GetConsoleWindow");
477280304Sjkim        if (cryptui && !OPENSSL_isservice())
478280304Sjkim            ctx->client_cert_select = cert_select_dialog;
479280304Sjkim    }
480280304Sjkim# endif
481183234Ssimon
482280304Sjkim    return 1;
483183234Ssimon
484280304Sjkim memerr:
485280304Sjkim    CAPIerr(CAPI_F_CAPI_INIT, ERR_R_MALLOC_FAILURE);
486280304Sjkim    return 0;
487183234Ssimon
488280304Sjkim    return 1;
489280304Sjkim}
490183234Ssimon
491183234Ssimonstatic int capi_destroy(ENGINE *e)
492280304Sjkim{
493280304Sjkim    ERR_unload_CAPI_strings();
494280304Sjkim    return 1;
495280304Sjkim}
496183234Ssimon
497183234Ssimonstatic int capi_finish(ENGINE *e)
498280304Sjkim{
499280304Sjkim    CAPI_CTX *ctx;
500280304Sjkim    ctx = ENGINE_get_ex_data(e, capi_idx);
501280304Sjkim    capi_ctx_free(ctx);
502280304Sjkim    ENGINE_set_ex_data(e, capi_idx, NULL);
503280304Sjkim    return 1;
504280304Sjkim}
505183234Ssimon
506280304Sjkim/*
507280304Sjkim * CryptoAPI key application data. This contains a handle to the private key
508280304Sjkim * container (for sign operations) and a handle to the key (for decrypt
509280304Sjkim * operations).
510183234Ssimon */
511183234Ssimon
512280304Sjkimstruct CAPI_KEY_st {
513280304Sjkim    /* Associated certificate context (if any) */
514280304Sjkim    PCCERT_CONTEXT pcert;
515280304Sjkim    HCRYPTPROV hprov;
516280304Sjkim    HCRYPTKEY key;
517280304Sjkim    DWORD keyspec;
518280304Sjkim};
519183234Ssimon
520183234Ssimonstatic int bind_capi(ENGINE *e)
521280304Sjkim{
522280304Sjkim    if (!ENGINE_set_id(e, engine_capi_id)
523280304Sjkim        || !ENGINE_set_name(e, engine_capi_name)
524280304Sjkim        || !ENGINE_set_flags(e, ENGINE_FLAGS_NO_REGISTER_ALL)
525280304Sjkim        || !ENGINE_set_init_function(e, capi_init)
526280304Sjkim        || !ENGINE_set_finish_function(e, capi_finish)
527280304Sjkim        || !ENGINE_set_destroy_function(e, capi_destroy)
528280304Sjkim        || !ENGINE_set_RSA(e, &capi_rsa_method)
529280304Sjkim        || !ENGINE_set_DSA(e, &capi_dsa_method)
530280304Sjkim        || !ENGINE_set_load_privkey_function(e, capi_load_privkey)
531280304Sjkim        || !ENGINE_set_load_ssl_client_cert_function(e,
532280304Sjkim                                                     capi_load_ssl_client_cert)
533280304Sjkim        || !ENGINE_set_cmd_defns(e, capi_cmd_defns)
534280304Sjkim        || !ENGINE_set_ctrl_function(e, capi_ctrl))
535280304Sjkim        return 0;
536280304Sjkim    ERR_load_CAPI_strings();
537183234Ssimon
538280304Sjkim    return 1;
539183234Ssimon
540280304Sjkim}
541183234Ssimon
542280304Sjkim# ifndef OPENSSL_NO_DYNAMIC_ENGINE
543183234Ssimonstatic int bind_helper(ENGINE *e, const char *id)
544280304Sjkim{
545280304Sjkim    if (id && (strcmp(id, engine_capi_id) != 0))
546280304Sjkim        return 0;
547280304Sjkim    if (!bind_capi(e))
548280304Sjkim        return 0;
549280304Sjkim    return 1;
550280304Sjkim}
551280304Sjkim
552183234SsimonIMPLEMENT_DYNAMIC_CHECK_FN()
553280304Sjkim    IMPLEMENT_DYNAMIC_BIND_FN(bind_helper)
554280304Sjkim# else
555183234Ssimonstatic ENGINE *engine_capi(void)
556280304Sjkim{
557280304Sjkim    ENGINE *ret = ENGINE_new();
558280304Sjkim    if (!ret)
559280304Sjkim        return NULL;
560280304Sjkim    if (!bind_capi(ret)) {
561280304Sjkim        ENGINE_free(ret);
562280304Sjkim        return NULL;
563280304Sjkim    }
564280304Sjkim    return ret;
565280304Sjkim}
566183234Ssimon
567183234Ssimonvoid ENGINE_load_capi(void)
568280304Sjkim{
569280304Sjkim    /* Copied from eng_[openssl|dyn].c */
570280304Sjkim    ENGINE *toadd = engine_capi();
571280304Sjkim    if (!toadd)
572280304Sjkim        return;
573280304Sjkim    ENGINE_add(toadd);
574280304Sjkim    ENGINE_free(toadd);
575280304Sjkim    ERR_clear_error();
576280304Sjkim}
577280304Sjkim# endif
578183234Ssimon
579183234Ssimonstatic int lend_tobn(BIGNUM *bn, unsigned char *bin, int binlen)
580280304Sjkim{
581280304Sjkim    int i;
582280304Sjkim    /*
583280304Sjkim     * Reverse buffer in place: since this is a keyblob structure that will
584280304Sjkim     * be freed up after conversion anyway it doesn't matter if we change
585280304Sjkim     * it.
586280304Sjkim     */
587280304Sjkim    for (i = 0; i < binlen / 2; i++) {
588280304Sjkim        unsigned char c;
589280304Sjkim        c = bin[i];
590280304Sjkim        bin[i] = bin[binlen - i - 1];
591280304Sjkim        bin[binlen - i - 1] = c;
592280304Sjkim    }
593183234Ssimon
594280304Sjkim    if (!BN_bin2bn(bin, binlen, bn))
595280304Sjkim        return 0;
596280304Sjkim    return 1;
597280304Sjkim}
598183234Ssimon
599183234Ssimon/* Given a CAPI_KEY get an EVP_PKEY structure */
600183234Ssimon
601280304Sjkimstatic EVP_PKEY *capi_get_pkey(ENGINE *eng, CAPI_KEY * key)
602280304Sjkim{
603280304Sjkim    unsigned char *pubkey = NULL;
604280304Sjkim    DWORD len;
605280304Sjkim    BLOBHEADER *bh;
606280304Sjkim    RSA *rkey = NULL;
607280304Sjkim    DSA *dkey = NULL;
608280304Sjkim    EVP_PKEY *ret = NULL;
609280304Sjkim    if (!CryptExportKey(key->key, 0, PUBLICKEYBLOB, 0, NULL, &len)) {
610280304Sjkim        CAPIerr(CAPI_F_CAPI_GET_PKEY, CAPI_R_PUBKEY_EXPORT_LENGTH_ERROR);
611280304Sjkim        capi_addlasterror();
612280304Sjkim        return NULL;
613280304Sjkim    }
614183234Ssimon
615280304Sjkim    pubkey = OPENSSL_malloc(len);
616183234Ssimon
617280304Sjkim    if (!pubkey)
618280304Sjkim        goto memerr;
619183234Ssimon
620280304Sjkim    if (!CryptExportKey(key->key, 0, PUBLICKEYBLOB, 0, pubkey, &len)) {
621280304Sjkim        CAPIerr(CAPI_F_CAPI_GET_PKEY, CAPI_R_PUBKEY_EXPORT_ERROR);
622280304Sjkim        capi_addlasterror();
623280304Sjkim        goto err;
624280304Sjkim    }
625183234Ssimon
626280304Sjkim    bh = (BLOBHEADER *) pubkey;
627280304Sjkim    if (bh->bType != PUBLICKEYBLOB) {
628280304Sjkim        CAPIerr(CAPI_F_CAPI_GET_PKEY, CAPI_R_INVALID_PUBLIC_KEY_BLOB);
629280304Sjkim        goto err;
630280304Sjkim    }
631280304Sjkim    if (bh->aiKeyAlg == CALG_RSA_SIGN || bh->aiKeyAlg == CALG_RSA_KEYX) {
632280304Sjkim        RSAPUBKEY *rp;
633280304Sjkim        DWORD rsa_modlen;
634280304Sjkim        unsigned char *rsa_modulus;
635280304Sjkim        rp = (RSAPUBKEY *) (bh + 1);
636280304Sjkim        if (rp->magic != 0x31415352) {
637280304Sjkim            char magstr[10];
638280304Sjkim            BIO_snprintf(magstr, 10, "%lx", rp->magic);
639280304Sjkim            CAPIerr(CAPI_F_CAPI_GET_PKEY,
640280304Sjkim                    CAPI_R_INVALID_RSA_PUBLIC_KEY_BLOB_MAGIC_NUMBER);
641280304Sjkim            ERR_add_error_data(2, "magic=0x", magstr);
642280304Sjkim            goto err;
643280304Sjkim        }
644280304Sjkim        rsa_modulus = (unsigned char *)(rp + 1);
645280304Sjkim        rkey = RSA_new_method(eng);
646280304Sjkim        if (!rkey)
647280304Sjkim            goto memerr;
648183234Ssimon
649280304Sjkim        rkey->e = BN_new();
650280304Sjkim        rkey->n = BN_new();
651183234Ssimon
652280304Sjkim        if (!rkey->e || !rkey->n)
653280304Sjkim            goto memerr;
654183234Ssimon
655280304Sjkim        if (!BN_set_word(rkey->e, rp->pubexp))
656280304Sjkim            goto memerr;
657183234Ssimon
658280304Sjkim        rsa_modlen = rp->bitlen / 8;
659280304Sjkim        if (!lend_tobn(rkey->n, rsa_modulus, rsa_modlen))
660280304Sjkim            goto memerr;
661183234Ssimon
662280304Sjkim        RSA_set_ex_data(rkey, rsa_capi_idx, key);
663183234Ssimon
664280304Sjkim        if (!(ret = EVP_PKEY_new()))
665280304Sjkim            goto memerr;
666183234Ssimon
667280304Sjkim        EVP_PKEY_assign_RSA(ret, rkey);
668280304Sjkim        rkey = NULL;
669183234Ssimon
670280304Sjkim    } else if (bh->aiKeyAlg == CALG_DSS_SIGN) {
671280304Sjkim        DSSPUBKEY *dp;
672280304Sjkim        DWORD dsa_plen;
673280304Sjkim        unsigned char *btmp;
674280304Sjkim        dp = (DSSPUBKEY *) (bh + 1);
675280304Sjkim        if (dp->magic != 0x31535344) {
676280304Sjkim            char magstr[10];
677280304Sjkim            BIO_snprintf(magstr, 10, "%lx", dp->magic);
678280304Sjkim            CAPIerr(CAPI_F_CAPI_GET_PKEY,
679280304Sjkim                    CAPI_R_INVALID_DSA_PUBLIC_KEY_BLOB_MAGIC_NUMBER);
680280304Sjkim            ERR_add_error_data(2, "magic=0x", magstr);
681280304Sjkim            goto err;
682280304Sjkim        }
683280304Sjkim        dsa_plen = dp->bitlen / 8;
684280304Sjkim        btmp = (unsigned char *)(dp + 1);
685280304Sjkim        dkey = DSA_new_method(eng);
686280304Sjkim        if (!dkey)
687280304Sjkim            goto memerr;
688280304Sjkim        dkey->p = BN_new();
689280304Sjkim        dkey->q = BN_new();
690280304Sjkim        dkey->g = BN_new();
691280304Sjkim        dkey->pub_key = BN_new();
692280304Sjkim        if (!dkey->p || !dkey->q || !dkey->g || !dkey->pub_key)
693280304Sjkim            goto memerr;
694280304Sjkim        if (!lend_tobn(dkey->p, btmp, dsa_plen))
695280304Sjkim            goto memerr;
696280304Sjkim        btmp += dsa_plen;
697280304Sjkim        if (!lend_tobn(dkey->q, btmp, 20))
698280304Sjkim            goto memerr;
699280304Sjkim        btmp += 20;
700280304Sjkim        if (!lend_tobn(dkey->g, btmp, dsa_plen))
701280304Sjkim            goto memerr;
702280304Sjkim        btmp += dsa_plen;
703280304Sjkim        if (!lend_tobn(dkey->pub_key, btmp, dsa_plen))
704280304Sjkim            goto memerr;
705280304Sjkim        btmp += dsa_plen;
706183234Ssimon
707280304Sjkim        DSA_set_ex_data(dkey, dsa_capi_idx, key);
708183234Ssimon
709280304Sjkim        if (!(ret = EVP_PKEY_new()))
710280304Sjkim            goto memerr;
711183234Ssimon
712280304Sjkim        EVP_PKEY_assign_DSA(ret, dkey);
713280304Sjkim        dkey = NULL;
714280304Sjkim    } else {
715280304Sjkim        char algstr[10];
716280304Sjkim        BIO_snprintf(algstr, 10, "%lx", bh->aiKeyAlg);
717280304Sjkim        CAPIerr(CAPI_F_CAPI_GET_PKEY,
718280304Sjkim                CAPI_R_UNSUPPORTED_PUBLIC_KEY_ALGORITHM);
719280304Sjkim        ERR_add_error_data(2, "aiKeyAlg=0x", algstr);
720280304Sjkim        goto err;
721280304Sjkim    }
722183234Ssimon
723280304Sjkim err:
724280304Sjkim    if (pubkey)
725280304Sjkim        OPENSSL_free(pubkey);
726280304Sjkim    if (!ret) {
727280304Sjkim        if (rkey)
728280304Sjkim            RSA_free(rkey);
729280304Sjkim        if (dkey)
730280304Sjkim            DSA_free(dkey);
731280304Sjkim    }
732183234Ssimon
733280304Sjkim    return ret;
734183234Ssimon
735280304Sjkim memerr:
736280304Sjkim    CAPIerr(CAPI_F_CAPI_GET_PKEY, ERR_R_MALLOC_FAILURE);
737280304Sjkim    goto err;
738183234Ssimon
739280304Sjkim}
740183234Ssimon
741183234Ssimonstatic EVP_PKEY *capi_load_privkey(ENGINE *eng, const char *key_id,
742280304Sjkim                                   UI_METHOD *ui_method, void *callback_data)
743280304Sjkim{
744280304Sjkim    CAPI_CTX *ctx;
745280304Sjkim    CAPI_KEY *key;
746280304Sjkim    EVP_PKEY *ret;
747280304Sjkim    ctx = ENGINE_get_ex_data(eng, capi_idx);
748183234Ssimon
749280304Sjkim    if (!ctx) {
750280304Sjkim        CAPIerr(CAPI_F_CAPI_LOAD_PRIVKEY, CAPI_R_CANT_FIND_CAPI_CONTEXT);
751280304Sjkim        return NULL;
752280304Sjkim    }
753183234Ssimon
754280304Sjkim    key = capi_find_key(ctx, key_id);
755183234Ssimon
756280304Sjkim    if (!key)
757280304Sjkim        return NULL;
758183234Ssimon
759280304Sjkim    ret = capi_get_pkey(eng, key);
760183234Ssimon
761280304Sjkim    if (!ret)
762280304Sjkim        capi_free_key(key);
763280304Sjkim    return ret;
764183234Ssimon
765280304Sjkim}
766183234Ssimon
767183234Ssimon/* CryptoAPI RSA operations */
768183234Ssimon
769183234Ssimonint capi_rsa_priv_enc(int flen, const unsigned char *from,
770280304Sjkim                      unsigned char *to, RSA *rsa, int padding)
771280304Sjkim{
772280304Sjkim    CAPIerr(CAPI_F_CAPI_RSA_PRIV_ENC, CAPI_R_FUNCTION_NOT_SUPPORTED);
773280304Sjkim    return -1;
774280304Sjkim}
775183234Ssimon
776183234Ssimonint capi_rsa_sign(int dtype, const unsigned char *m, unsigned int m_len,
777280304Sjkim                  unsigned char *sigret, unsigned int *siglen, const RSA *rsa)
778280304Sjkim{
779280304Sjkim    ALG_ID alg;
780280304Sjkim    HCRYPTHASH hash;
781280304Sjkim    DWORD slen;
782280304Sjkim    unsigned int i;
783280304Sjkim    int ret = -1;
784280304Sjkim    CAPI_KEY *capi_key;
785280304Sjkim    CAPI_CTX *ctx;
786183234Ssimon
787280304Sjkim    ctx = ENGINE_get_ex_data(rsa->engine, capi_idx);
788183234Ssimon
789280304Sjkim    CAPI_trace(ctx, "Called CAPI_rsa_sign()\n");
790183234Ssimon
791280304Sjkim    capi_key = RSA_get_ex_data(rsa, rsa_capi_idx);
792280304Sjkim    if (!capi_key) {
793280304Sjkim        CAPIerr(CAPI_F_CAPI_RSA_SIGN, CAPI_R_CANT_GET_KEY);
794280304Sjkim        return -1;
795280304Sjkim    }
796183234Ssimon/* Convert the signature type to a CryptoAPI algorithm ID */
797280304Sjkim    switch (dtype) {
798280304Sjkim    case NID_sha1:
799280304Sjkim        alg = CALG_SHA1;
800280304Sjkim        break;
801183234Ssimon
802280304Sjkim    case NID_md5:
803280304Sjkim        alg = CALG_MD5;
804280304Sjkim        break;
805183234Ssimon
806280304Sjkim    case NID_md5_sha1:
807280304Sjkim        alg = CALG_SSL3_SHAMD5;
808280304Sjkim        break;
809280304Sjkim    default:
810280304Sjkim        {
811280304Sjkim            char algstr[10];
812280304Sjkim            BIO_snprintf(algstr, 10, "%lx", dtype);
813280304Sjkim            CAPIerr(CAPI_F_CAPI_RSA_SIGN, CAPI_R_UNSUPPORTED_ALGORITHM_NID);
814280304Sjkim            ERR_add_error_data(2, "NID=0x", algstr);
815280304Sjkim            return -1;
816280304Sjkim        }
817280304Sjkim    }
818183234Ssimon
819183234Ssimon/* Create the hash object */
820280304Sjkim    if (!CryptCreateHash(capi_key->hprov, alg, 0, 0, &hash)) {
821280304Sjkim        CAPIerr(CAPI_F_CAPI_RSA_SIGN, CAPI_R_CANT_CREATE_HASH_OBJECT);
822280304Sjkim        capi_addlasterror();
823280304Sjkim        return -1;
824280304Sjkim    }
825183234Ssimon/* Set the hash value to the value passed */
826183234Ssimon
827280304Sjkim    if (!CryptSetHashParam(hash, HP_HASHVAL, (unsigned char *)m, 0)) {
828280304Sjkim        CAPIerr(CAPI_F_CAPI_RSA_SIGN, CAPI_R_CANT_SET_HASH_VALUE);
829280304Sjkim        capi_addlasterror();
830280304Sjkim        goto err;
831280304Sjkim    }
832183234Ssimon
833183234Ssimon/* Finally sign it */
834280304Sjkim    slen = RSA_size(rsa);
835280304Sjkim    if (!CryptSignHashA(hash, capi_key->keyspec, NULL, 0, sigret, &slen)) {
836280304Sjkim        CAPIerr(CAPI_F_CAPI_RSA_SIGN, CAPI_R_ERROR_SIGNING_HASH);
837280304Sjkim        capi_addlasterror();
838280304Sjkim        goto err;
839280304Sjkim    } else {
840280304Sjkim        ret = 1;
841280304Sjkim        /* Inplace byte reversal of signature */
842280304Sjkim        for (i = 0; i < slen / 2; i++) {
843280304Sjkim            unsigned char c;
844280304Sjkim            c = sigret[i];
845280304Sjkim            sigret[i] = sigret[slen - i - 1];
846280304Sjkim            sigret[slen - i - 1] = c;
847280304Sjkim        }
848280304Sjkim        *siglen = slen;
849280304Sjkim    }
850183234Ssimon
851280304Sjkim    /* Now cleanup */
852183234Ssimon
853280304Sjkim err:
854280304Sjkim    CryptDestroyHash(hash);
855183234Ssimon
856280304Sjkim    return ret;
857280304Sjkim}
858183234Ssimon
859183234Ssimonint capi_rsa_priv_dec(int flen, const unsigned char *from,
860280304Sjkim                      unsigned char *to, RSA *rsa, int padding)
861280304Sjkim{
862280304Sjkim    int i;
863280304Sjkim    unsigned char *tmpbuf;
864280304Sjkim    CAPI_KEY *capi_key;
865280304Sjkim    CAPI_CTX *ctx;
866280304Sjkim    ctx = ENGINE_get_ex_data(rsa->engine, capi_idx);
867183234Ssimon
868280304Sjkim    CAPI_trace(ctx, "Called capi_rsa_priv_dec()\n");
869183234Ssimon
870280304Sjkim    capi_key = RSA_get_ex_data(rsa, rsa_capi_idx);
871280304Sjkim    if (!capi_key) {
872280304Sjkim        CAPIerr(CAPI_F_CAPI_RSA_PRIV_DEC, CAPI_R_CANT_GET_KEY);
873280304Sjkim        return -1;
874280304Sjkim    }
875183234Ssimon
876280304Sjkim    if (padding != RSA_PKCS1_PADDING) {
877280304Sjkim        char errstr[10];
878280304Sjkim        BIO_snprintf(errstr, 10, "%d", padding);
879280304Sjkim        CAPIerr(CAPI_F_CAPI_RSA_PRIV_DEC, CAPI_R_UNSUPPORTED_PADDING);
880280304Sjkim        ERR_add_error_data(2, "padding=", errstr);
881280304Sjkim        return -1;
882280304Sjkim    }
883183234Ssimon
884280304Sjkim    /* Create temp reverse order version of input */
885280304Sjkim    if (!(tmpbuf = OPENSSL_malloc(flen))) {
886280304Sjkim        CAPIerr(CAPI_F_CAPI_RSA_PRIV_DEC, ERR_R_MALLOC_FAILURE);
887280304Sjkim        return -1;
888280304Sjkim    }
889280304Sjkim    for (i = 0; i < flen; i++)
890280304Sjkim        tmpbuf[flen - i - 1] = from[i];
891183234Ssimon
892280304Sjkim    /* Finally decrypt it */
893280304Sjkim    if (!CryptDecrypt(capi_key->key, 0, TRUE, 0, tmpbuf, &flen)) {
894280304Sjkim        CAPIerr(CAPI_F_CAPI_RSA_PRIV_DEC, CAPI_R_DECRYPT_ERROR);
895280304Sjkim        capi_addlasterror();
896280304Sjkim        OPENSSL_free(tmpbuf);
897280304Sjkim        return -1;
898280304Sjkim    } else
899280304Sjkim        memcpy(to, tmpbuf, flen);
900183234Ssimon
901280304Sjkim    OPENSSL_free(tmpbuf);
902183234Ssimon
903280304Sjkim    return flen;
904280304Sjkim}
905183234Ssimon
906183234Ssimonstatic int capi_rsa_free(RSA *rsa)
907280304Sjkim{
908280304Sjkim    CAPI_KEY *capi_key;
909280304Sjkim    capi_key = RSA_get_ex_data(rsa, rsa_capi_idx);
910280304Sjkim    capi_free_key(capi_key);
911280304Sjkim    RSA_set_ex_data(rsa, rsa_capi_idx, 0);
912280304Sjkim    return 1;
913280304Sjkim}
914183234Ssimon
915183234Ssimon/* CryptoAPI DSA operations */
916183234Ssimon
917183234Ssimonstatic DSA_SIG *capi_dsa_do_sign(const unsigned char *digest, int dlen,
918280304Sjkim                                 DSA *dsa)
919280304Sjkim{
920280304Sjkim    HCRYPTHASH hash;
921280304Sjkim    DWORD slen;
922280304Sjkim    DSA_SIG *ret = NULL;
923280304Sjkim    CAPI_KEY *capi_key;
924280304Sjkim    CAPI_CTX *ctx;
925280304Sjkim    unsigned char csigbuf[40];
926183234Ssimon
927280304Sjkim    ctx = ENGINE_get_ex_data(dsa->engine, capi_idx);
928183234Ssimon
929280304Sjkim    CAPI_trace(ctx, "Called CAPI_dsa_do_sign()\n");
930183234Ssimon
931280304Sjkim    capi_key = DSA_get_ex_data(dsa, dsa_capi_idx);
932183234Ssimon
933280304Sjkim    if (!capi_key) {
934280304Sjkim        CAPIerr(CAPI_F_CAPI_DSA_DO_SIGN, CAPI_R_CANT_GET_KEY);
935280304Sjkim        return NULL;
936280304Sjkim    }
937183234Ssimon
938280304Sjkim    if (dlen != 20) {
939280304Sjkim        CAPIerr(CAPI_F_CAPI_DSA_DO_SIGN, CAPI_R_INVALID_DIGEST_LENGTH);
940280304Sjkim        return NULL;
941280304Sjkim    }
942183234Ssimon
943280304Sjkim    /* Create the hash object */
944280304Sjkim    if (!CryptCreateHash(capi_key->hprov, CALG_SHA1, 0, 0, &hash)) {
945280304Sjkim        CAPIerr(CAPI_F_CAPI_DSA_DO_SIGN, CAPI_R_CANT_CREATE_HASH_OBJECT);
946280304Sjkim        capi_addlasterror();
947280304Sjkim        return NULL;
948280304Sjkim    }
949183234Ssimon
950280304Sjkim    /* Set the hash value to the value passed */
951280304Sjkim    if (!CryptSetHashParam(hash, HP_HASHVAL, (unsigned char *)digest, 0)) {
952280304Sjkim        CAPIerr(CAPI_F_CAPI_DSA_DO_SIGN, CAPI_R_CANT_SET_HASH_VALUE);
953280304Sjkim        capi_addlasterror();
954280304Sjkim        goto err;
955280304Sjkim    }
956183234Ssimon
957280304Sjkim    /* Finally sign it */
958280304Sjkim    slen = sizeof(csigbuf);
959280304Sjkim    if (!CryptSignHashA(hash, capi_key->keyspec, NULL, 0, csigbuf, &slen)) {
960280304Sjkim        CAPIerr(CAPI_F_CAPI_DSA_DO_SIGN, CAPI_R_ERROR_SIGNING_HASH);
961280304Sjkim        capi_addlasterror();
962280304Sjkim        goto err;
963280304Sjkim    } else {
964280304Sjkim        ret = DSA_SIG_new();
965280304Sjkim        if (!ret)
966280304Sjkim            goto err;
967280304Sjkim        ret->r = BN_new();
968280304Sjkim        ret->s = BN_new();
969280304Sjkim        if (!ret->r || !ret->s)
970280304Sjkim            goto err;
971280304Sjkim        if (!lend_tobn(ret->r, csigbuf, 20)
972280304Sjkim            || !lend_tobn(ret->s, csigbuf + 20, 20)) {
973280304Sjkim            DSA_SIG_free(ret);
974280304Sjkim            ret = NULL;
975280304Sjkim            goto err;
976280304Sjkim        }
977280304Sjkim    }
978183234Ssimon
979280304Sjkim    /* Now cleanup */
980183234Ssimon
981280304Sjkim err:
982280304Sjkim    OPENSSL_cleanse(csigbuf, 40);
983280304Sjkim    CryptDestroyHash(hash);
984280304Sjkim    return ret;
985280304Sjkim}
986183234Ssimon
987183234Ssimonstatic int capi_dsa_free(DSA *dsa)
988280304Sjkim{
989280304Sjkim    CAPI_KEY *capi_key;
990280304Sjkim    capi_key = DSA_get_ex_data(dsa, dsa_capi_idx);
991280304Sjkim    capi_free_key(capi_key);
992280304Sjkim    DSA_set_ex_data(dsa, dsa_capi_idx, 0);
993280304Sjkim    return 1;
994280304Sjkim}
995183234Ssimon
996280304Sjkimstatic void capi_vtrace(CAPI_CTX * ctx, int level, char *format,
997280304Sjkim                        va_list argptr)
998280304Sjkim{
999280304Sjkim    BIO *out;
1000183234Ssimon
1001280304Sjkim    if (!ctx || (ctx->debug_level < level) || (!ctx->debug_file))
1002280304Sjkim        return;
1003280304Sjkim    out = BIO_new_file(ctx->debug_file, "a+");
1004280304Sjkim    BIO_vprintf(out, format, argptr);
1005280304Sjkim    BIO_free(out);
1006280304Sjkim}
1007183234Ssimon
1008280304Sjkimstatic void CAPI_trace(CAPI_CTX * ctx, char *format, ...)
1009280304Sjkim{
1010280304Sjkim    va_list args;
1011280304Sjkim    va_start(args, format);
1012280304Sjkim    capi_vtrace(ctx, CAPI_DBG_TRACE, format, args);
1013280304Sjkim    va_end(args);
1014280304Sjkim}
1015183234Ssimon
1016183234Ssimonstatic void capi_addlasterror(void)
1017280304Sjkim{
1018280304Sjkim    capi_adderror(GetLastError());
1019280304Sjkim}
1020183234Ssimon
1021183234Ssimonstatic void capi_adderror(DWORD err)
1022280304Sjkim{
1023280304Sjkim    char errstr[10];
1024280304Sjkim    BIO_snprintf(errstr, 10, "%lX", err);
1025280304Sjkim    ERR_add_error_data(2, "Error code= 0x", errstr);
1026280304Sjkim}
1027183234Ssimon
1028183234Ssimonstatic char *wide_to_asc(LPWSTR wstr)
1029280304Sjkim{
1030280304Sjkim    char *str;
1031280304Sjkim    int len_0, sz;
1032205128Ssimon
1033280304Sjkim    if (!wstr)
1034280304Sjkim        return NULL;
1035280304Sjkim    len_0 = (int)wcslen(wstr) + 1; /* WideCharToMultiByte expects int */
1036280304Sjkim    sz = WideCharToMultiByte(CP_ACP, 0, wstr, len_0, NULL, 0, NULL, NULL);
1037280304Sjkim    if (!sz) {
1038280304Sjkim        CAPIerr(CAPI_F_WIDE_TO_ASC, CAPI_R_WIN32_ERROR);
1039280304Sjkim        return NULL;
1040280304Sjkim    }
1041280304Sjkim    str = OPENSSL_malloc(sz);
1042280304Sjkim    if (!str) {
1043280304Sjkim        CAPIerr(CAPI_F_WIDE_TO_ASC, ERR_R_MALLOC_FAILURE);
1044280304Sjkim        return NULL;
1045280304Sjkim    }
1046280304Sjkim    if (!WideCharToMultiByte(CP_ACP, 0, wstr, len_0, str, sz, NULL, NULL)) {
1047280304Sjkim        OPENSSL_free(str);
1048280304Sjkim        CAPIerr(CAPI_F_WIDE_TO_ASC, CAPI_R_WIN32_ERROR);
1049280304Sjkim        return NULL;
1050280304Sjkim    }
1051280304Sjkim    return str;
1052280304Sjkim}
1053183234Ssimon
1054280304Sjkimstatic int capi_get_provname(CAPI_CTX * ctx, LPSTR * pname, DWORD * ptype,
1055280304Sjkim                             DWORD idx)
1056280304Sjkim{
1057280304Sjkim    LPSTR name;
1058280304Sjkim    DWORD len, err;
1059280304Sjkim    CAPI_trace(ctx, "capi_get_provname, index=%d\n", idx);
1060280304Sjkim    if (!CryptEnumProvidersA(idx, NULL, 0, ptype, NULL, &len)) {
1061280304Sjkim        err = GetLastError();
1062280304Sjkim        if (err == ERROR_NO_MORE_ITEMS)
1063280304Sjkim            return 2;
1064280304Sjkim        CAPIerr(CAPI_F_CAPI_GET_PROVNAME, CAPI_R_CRYPTENUMPROVIDERS_ERROR);
1065280304Sjkim        capi_adderror(err);
1066280304Sjkim        return 0;
1067280304Sjkim    }
1068280304Sjkim    name = OPENSSL_malloc(len);
1069280304Sjkim    if (!CryptEnumProvidersA(idx, NULL, 0, ptype, name, &len)) {
1070280304Sjkim        err = GetLastError();
1071280304Sjkim        if (err == ERROR_NO_MORE_ITEMS)
1072280304Sjkim            return 2;
1073280304Sjkim        CAPIerr(CAPI_F_CAPI_GET_PROVNAME, CAPI_R_CRYPTENUMPROVIDERS_ERROR);
1074280304Sjkim        capi_adderror(err);
1075280304Sjkim        return 0;
1076280304Sjkim    }
1077280304Sjkim    *pname = name;
1078280304Sjkim    CAPI_trace(ctx, "capi_get_provname, returned name=%s, type=%d\n", name,
1079280304Sjkim               *ptype);
1080183234Ssimon
1081280304Sjkim    return 1;
1082280304Sjkim}
1083183234Ssimon
1084280304Sjkimstatic int capi_list_providers(CAPI_CTX * ctx, BIO *out)
1085280304Sjkim{
1086280304Sjkim    DWORD idx, ptype;
1087280304Sjkim    int ret;
1088280304Sjkim    LPSTR provname = NULL;
1089280304Sjkim    CAPI_trace(ctx, "capi_list_providers\n");
1090280304Sjkim    BIO_printf(out, "Available CSPs:\n");
1091280304Sjkim    for (idx = 0;; idx++) {
1092280304Sjkim        ret = capi_get_provname(ctx, &provname, &ptype, idx);
1093280304Sjkim        if (ret == 2)
1094280304Sjkim            break;
1095280304Sjkim        if (ret == 0)
1096280304Sjkim            break;
1097280304Sjkim        BIO_printf(out, "%d. %s, type %d\n", idx, provname, ptype);
1098280304Sjkim        OPENSSL_free(provname);
1099280304Sjkim    }
1100280304Sjkim    return 1;
1101280304Sjkim}
1102183234Ssimon
1103280304Sjkimstatic int capi_list_containers(CAPI_CTX * ctx, BIO *out)
1104280304Sjkim{
1105280304Sjkim    int ret = 1;
1106280304Sjkim    HCRYPTPROV hprov;
1107280304Sjkim    DWORD err, idx, flags, buflen = 0, clen;
1108280304Sjkim    LPSTR cname;
1109280304Sjkim    CAPI_trace(ctx, "Listing containers CSP=%s, type = %d\n", ctx->cspname,
1110280304Sjkim               ctx->csptype);
1111280304Sjkim    if (!CryptAcquireContextA
1112280304Sjkim        (&hprov, NULL, ctx->cspname, ctx->csptype, CRYPT_VERIFYCONTEXT)) {
1113280304Sjkim        CAPIerr(CAPI_F_CAPI_LIST_CONTAINERS,
1114280304Sjkim                CAPI_R_CRYPTACQUIRECONTEXT_ERROR);
1115280304Sjkim        capi_addlasterror();
1116280304Sjkim        return 0;
1117280304Sjkim    }
1118280304Sjkim    if (!CryptGetProvParam
1119280304Sjkim        (hprov, PP_ENUMCONTAINERS, NULL, &buflen, CRYPT_FIRST)) {
1120280304Sjkim        CAPIerr(CAPI_F_CAPI_LIST_CONTAINERS, CAPI_R_ENUMCONTAINERS_ERROR);
1121280304Sjkim        capi_addlasterror();
1122280304Sjkim        CryptReleaseContext(hprov, 0);
1123280304Sjkim        return 0;
1124280304Sjkim    }
1125280304Sjkim    CAPI_trace(ctx, "Got max container len %d\n", buflen);
1126280304Sjkim    if (buflen == 0)
1127280304Sjkim        buflen = 1024;
1128280304Sjkim    cname = OPENSSL_malloc(buflen);
1129280304Sjkim    if (!cname) {
1130280304Sjkim        CAPIerr(CAPI_F_CAPI_LIST_CONTAINERS, ERR_R_MALLOC_FAILURE);
1131280304Sjkim        goto err;
1132280304Sjkim    }
1133183234Ssimon
1134280304Sjkim    for (idx = 0;; idx++) {
1135280304Sjkim        clen = buflen;
1136280304Sjkim        cname[0] = 0;
1137183234Ssimon
1138280304Sjkim        if (idx == 0)
1139280304Sjkim            flags = CRYPT_FIRST;
1140280304Sjkim        else
1141280304Sjkim            flags = 0;
1142280304Sjkim        if (!CryptGetProvParam(hprov, PP_ENUMCONTAINERS, cname, &clen, flags)) {
1143280304Sjkim            err = GetLastError();
1144280304Sjkim            if (err == ERROR_NO_MORE_ITEMS)
1145280304Sjkim                goto done;
1146280304Sjkim            CAPIerr(CAPI_F_CAPI_LIST_CONTAINERS, CAPI_R_ENUMCONTAINERS_ERROR);
1147280304Sjkim            capi_adderror(err);
1148280304Sjkim            goto err;
1149280304Sjkim        }
1150280304Sjkim        CAPI_trace(ctx, "Container name %s, len=%d, index=%d, flags=%d\n",
1151280304Sjkim                   cname, clen, idx, flags);
1152280304Sjkim        if (!cname[0] && (clen == buflen)) {
1153280304Sjkim            CAPI_trace(ctx, "Enumerate bug: using workaround\n");
1154280304Sjkim            goto done;
1155280304Sjkim        }
1156280304Sjkim        BIO_printf(out, "%d. %s\n", idx, cname);
1157280304Sjkim    }
1158280304Sjkim err:
1159183234Ssimon
1160280304Sjkim    ret = 0;
1161183234Ssimon
1162280304Sjkim done:
1163280304Sjkim    if (cname)
1164280304Sjkim        OPENSSL_free(cname);
1165280304Sjkim    CryptReleaseContext(hprov, 0);
1166183234Ssimon
1167280304Sjkim    return ret;
1168280304Sjkim}
1169183234Ssimon
1170280304SjkimCRYPT_KEY_PROV_INFO *capi_get_prov_info(CAPI_CTX * ctx, PCCERT_CONTEXT cert)
1171280304Sjkim{
1172280304Sjkim    DWORD len;
1173280304Sjkim    CRYPT_KEY_PROV_INFO *pinfo;
1174183234Ssimon
1175280304Sjkim    if (!CertGetCertificateContextProperty
1176280304Sjkim        (cert, CERT_KEY_PROV_INFO_PROP_ID, NULL, &len))
1177280304Sjkim        return NULL;
1178280304Sjkim    pinfo = OPENSSL_malloc(len);
1179280304Sjkim    if (!pinfo) {
1180280304Sjkim        CAPIerr(CAPI_F_CAPI_GET_PROV_INFO, ERR_R_MALLOC_FAILURE);
1181280304Sjkim        return NULL;
1182280304Sjkim    }
1183280304Sjkim    if (!CertGetCertificateContextProperty
1184280304Sjkim        (cert, CERT_KEY_PROV_INFO_PROP_ID, pinfo, &len)) {
1185280304Sjkim        CAPIerr(CAPI_F_CAPI_GET_PROV_INFO,
1186280304Sjkim                CAPI_R_ERROR_GETTING_KEY_PROVIDER_INFO);
1187280304Sjkim        capi_addlasterror();
1188280304Sjkim        OPENSSL_free(pinfo);
1189280304Sjkim        return NULL;
1190280304Sjkim    }
1191280304Sjkim    return pinfo;
1192280304Sjkim}
1193183234Ssimon
1194280304Sjkimstatic void capi_dump_prov_info(CAPI_CTX * ctx, BIO *out,
1195280304Sjkim                                CRYPT_KEY_PROV_INFO * pinfo)
1196280304Sjkim{
1197280304Sjkim    char *provname = NULL, *contname = NULL;
1198280304Sjkim    if (!pinfo) {
1199280304Sjkim        BIO_printf(out, "  No Private Key\n");
1200280304Sjkim        return;
1201280304Sjkim    }
1202280304Sjkim    provname = wide_to_asc(pinfo->pwszProvName);
1203280304Sjkim    contname = wide_to_asc(pinfo->pwszContainerName);
1204280304Sjkim    if (!provname || !contname)
1205280304Sjkim        goto err;
1206183234Ssimon
1207280304Sjkim    BIO_printf(out, "  Private Key Info:\n");
1208280304Sjkim    BIO_printf(out, "    Provider Name:  %s, Provider Type %d\n", provname,
1209280304Sjkim               pinfo->dwProvType);
1210280304Sjkim    BIO_printf(out, "    Container Name: %s, Key Type %d\n", contname,
1211280304Sjkim               pinfo->dwKeySpec);
1212280304Sjkim err:
1213280304Sjkim    if (provname)
1214280304Sjkim        OPENSSL_free(provname);
1215280304Sjkim    if (contname)
1216280304Sjkim        OPENSSL_free(contname);
1217280304Sjkim}
1218183234Ssimon
1219280304Sjkimchar *capi_cert_get_fname(CAPI_CTX * ctx, PCCERT_CONTEXT cert)
1220280304Sjkim{
1221280304Sjkim    LPWSTR wfname;
1222280304Sjkim    DWORD dlen;
1223183234Ssimon
1224280304Sjkim    CAPI_trace(ctx, "capi_cert_get_fname\n");
1225280304Sjkim    if (!CertGetCertificateContextProperty
1226280304Sjkim        (cert, CERT_FRIENDLY_NAME_PROP_ID, NULL, &dlen))
1227280304Sjkim        return NULL;
1228280304Sjkim    wfname = OPENSSL_malloc(dlen);
1229280304Sjkim    if (CertGetCertificateContextProperty
1230280304Sjkim        (cert, CERT_FRIENDLY_NAME_PROP_ID, wfname, &dlen)) {
1231280304Sjkim        char *fname = wide_to_asc(wfname);
1232280304Sjkim        OPENSSL_free(wfname);
1233280304Sjkim        return fname;
1234280304Sjkim    }
1235280304Sjkim    CAPIerr(CAPI_F_CAPI_CERT_GET_FNAME, CAPI_R_ERROR_GETTING_FRIENDLY_NAME);
1236280304Sjkim    capi_addlasterror();
1237183234Ssimon
1238280304Sjkim    OPENSSL_free(wfname);
1239280304Sjkim    return NULL;
1240280304Sjkim}
1241183234Ssimon
1242280304Sjkimvoid capi_dump_cert(CAPI_CTX * ctx, BIO *out, PCCERT_CONTEXT cert)
1243280304Sjkim{
1244280304Sjkim    X509 *x;
1245280304Sjkim    unsigned char *p;
1246280304Sjkim    unsigned long flags = ctx->dump_flags;
1247280304Sjkim    if (flags & CAPI_DMP_FNAME) {
1248280304Sjkim        char *fname;
1249280304Sjkim        fname = capi_cert_get_fname(ctx, cert);
1250280304Sjkim        if (fname) {
1251280304Sjkim            BIO_printf(out, "  Friendly Name \"%s\"\n", fname);
1252280304Sjkim            OPENSSL_free(fname);
1253280304Sjkim        } else
1254280304Sjkim            BIO_printf(out, "  <No Friendly Name>\n");
1255280304Sjkim    }
1256183234Ssimon
1257280304Sjkim    p = cert->pbCertEncoded;
1258280304Sjkim    x = d2i_X509(NULL, &p, cert->cbCertEncoded);
1259280304Sjkim    if (!x)
1260280304Sjkim        BIO_printf(out, "  <Can't parse certificate>\n");
1261280304Sjkim    if (flags & CAPI_DMP_SUMMARY) {
1262280304Sjkim        BIO_printf(out, "  Subject: ");
1263280304Sjkim        X509_NAME_print_ex(out, X509_get_subject_name(x), 0, XN_FLAG_ONELINE);
1264280304Sjkim        BIO_printf(out, "\n  Issuer: ");
1265280304Sjkim        X509_NAME_print_ex(out, X509_get_issuer_name(x), 0, XN_FLAG_ONELINE);
1266280304Sjkim        BIO_printf(out, "\n");
1267280304Sjkim    }
1268280304Sjkim    if (flags & CAPI_DMP_FULL)
1269280304Sjkim        X509_print_ex(out, x, XN_FLAG_ONELINE, 0);
1270183234Ssimon
1271280304Sjkim    if (flags & CAPI_DMP_PKEYINFO) {
1272280304Sjkim        CRYPT_KEY_PROV_INFO *pinfo;
1273280304Sjkim        pinfo = capi_get_prov_info(ctx, cert);
1274280304Sjkim        capi_dump_prov_info(ctx, out, pinfo);
1275280304Sjkim        if (pinfo)
1276280304Sjkim            OPENSSL_free(pinfo);
1277280304Sjkim    }
1278183234Ssimon
1279280304Sjkim    if (flags & CAPI_DMP_PEM)
1280280304Sjkim        PEM_write_bio_X509(out, x);
1281280304Sjkim    X509_free(x);
1282280304Sjkim}
1283183234Ssimon
1284280304SjkimHCERTSTORE capi_open_store(CAPI_CTX * ctx, char *storename)
1285280304Sjkim{
1286280304Sjkim    HCERTSTORE hstore;
1287183234Ssimon
1288280304Sjkim    if (!storename)
1289280304Sjkim        storename = ctx->storename;
1290280304Sjkim    if (!storename)
1291280304Sjkim        storename = "MY";
1292280304Sjkim    CAPI_trace(ctx, "Opening certificate store %s\n", storename);
1293183234Ssimon
1294280304Sjkim    hstore = CertOpenStore(CERT_STORE_PROV_SYSTEM_A, 0, 0,
1295280304Sjkim                           ctx->store_flags, storename);
1296280304Sjkim    if (!hstore) {
1297280304Sjkim        CAPIerr(CAPI_F_CAPI_OPEN_STORE, CAPI_R_ERROR_OPENING_STORE);
1298280304Sjkim        capi_addlasterror();
1299280304Sjkim    }
1300280304Sjkim    return hstore;
1301280304Sjkim}
1302183234Ssimon
1303280304Sjkimint capi_list_certs(CAPI_CTX * ctx, BIO *out, char *id)
1304280304Sjkim{
1305280304Sjkim    char *storename;
1306280304Sjkim    int idx;
1307280304Sjkim    int ret = 1;
1308280304Sjkim    HCERTSTORE hstore;
1309280304Sjkim    PCCERT_CONTEXT cert = NULL;
1310183234Ssimon
1311280304Sjkim    storename = ctx->storename;
1312280304Sjkim    if (!storename)
1313280304Sjkim        storename = "MY";
1314280304Sjkim    CAPI_trace(ctx, "Listing certs for store %s\n", storename);
1315183234Ssimon
1316280304Sjkim    hstore = capi_open_store(ctx, storename);
1317280304Sjkim    if (!hstore)
1318280304Sjkim        return 0;
1319280304Sjkim    if (id) {
1320280304Sjkim        cert = capi_find_cert(ctx, id, hstore);
1321280304Sjkim        if (!cert) {
1322280304Sjkim            ret = 0;
1323280304Sjkim            goto err;
1324280304Sjkim        }
1325280304Sjkim        capi_dump_cert(ctx, out, cert);
1326280304Sjkim        CertFreeCertificateContext(cert);
1327280304Sjkim    } else {
1328280304Sjkim        for (idx = 0;; idx++) {
1329280304Sjkim            LPWSTR fname = NULL;
1330280304Sjkim            cert = CertEnumCertificatesInStore(hstore, cert);
1331280304Sjkim            if (!cert)
1332280304Sjkim                break;
1333280304Sjkim            BIO_printf(out, "Certificate %d\n", idx);
1334280304Sjkim            capi_dump_cert(ctx, out, cert);
1335280304Sjkim        }
1336280304Sjkim    }
1337280304Sjkim err:
1338280304Sjkim    CertCloseStore(hstore, 0);
1339280304Sjkim    return ret;
1340280304Sjkim}
1341183234Ssimon
1342280304Sjkimstatic PCCERT_CONTEXT capi_find_cert(CAPI_CTX * ctx, const char *id,
1343280304Sjkim                                     HCERTSTORE hstore)
1344280304Sjkim{
1345280304Sjkim    PCCERT_CONTEXT cert = NULL;
1346280304Sjkim    char *fname = NULL;
1347280304Sjkim    int match;
1348280304Sjkim    switch (ctx->lookup_method) {
1349280304Sjkim    case CAPI_LU_SUBSTR:
1350280304Sjkim        return CertFindCertificateInStore(hstore,
1351280304Sjkim                                          X509_ASN_ENCODING, 0,
1352280304Sjkim                                          CERT_FIND_SUBJECT_STR_A, id, NULL);
1353280304Sjkim    case CAPI_LU_FNAME:
1354280304Sjkim        for (;;) {
1355280304Sjkim            cert = CertEnumCertificatesInStore(hstore, cert);
1356280304Sjkim            if (!cert)
1357280304Sjkim                return NULL;
1358280304Sjkim            fname = capi_cert_get_fname(ctx, cert);
1359280304Sjkim            if (fname) {
1360280304Sjkim                if (strcmp(fname, id))
1361280304Sjkim                    match = 0;
1362280304Sjkim                else
1363280304Sjkim                    match = 1;
1364280304Sjkim                OPENSSL_free(fname);
1365280304Sjkim                if (match)
1366280304Sjkim                    return cert;
1367280304Sjkim            }
1368280304Sjkim        }
1369280304Sjkim    default:
1370280304Sjkim        return NULL;
1371280304Sjkim    }
1372280304Sjkim}
1373183234Ssimon
1374280304Sjkimstatic CAPI_KEY *capi_get_key(CAPI_CTX * ctx, const char *contname,
1375280304Sjkim                              char *provname, DWORD ptype, DWORD keyspec)
1376280304Sjkim{
1377280304Sjkim    CAPI_KEY *key;
1378280304Sjkim    DWORD dwFlags = 0;
1379280304Sjkim    key = OPENSSL_malloc(sizeof(CAPI_KEY));
1380280304Sjkim    CAPI_trace(ctx, "capi_get_key, contname=%s, provname=%s, type=%d\n",
1381280304Sjkim               contname, provname, ptype);
1382280304Sjkim    if (ctx->store_flags & CERT_SYSTEM_STORE_LOCAL_MACHINE)
1383246772Sjkim        dwFlags = CRYPT_MACHINE_KEYSET;
1384280304Sjkim    if (!CryptAcquireContextA
1385280304Sjkim        (&key->hprov, contname, provname, ptype, dwFlags)) {
1386280304Sjkim        CAPIerr(CAPI_F_CAPI_GET_KEY, CAPI_R_CRYPTACQUIRECONTEXT_ERROR);
1387280304Sjkim        capi_addlasterror();
1388280304Sjkim        goto err;
1389280304Sjkim    }
1390280304Sjkim    if (!CryptGetUserKey(key->hprov, keyspec, &key->key)) {
1391280304Sjkim        CAPIerr(CAPI_F_CAPI_GET_KEY, CAPI_R_GETUSERKEY_ERROR);
1392280304Sjkim        capi_addlasterror();
1393280304Sjkim        CryptReleaseContext(key->hprov, 0);
1394280304Sjkim        goto err;
1395280304Sjkim    }
1396280304Sjkim    key->keyspec = keyspec;
1397280304Sjkim    key->pcert = NULL;
1398280304Sjkim    return key;
1399183234Ssimon
1400280304Sjkim err:
1401280304Sjkim    OPENSSL_free(key);
1402280304Sjkim    return NULL;
1403280304Sjkim}
1404183234Ssimon
1405280304Sjkimstatic CAPI_KEY *capi_get_cert_key(CAPI_CTX * ctx, PCCERT_CONTEXT cert)
1406280304Sjkim{
1407280304Sjkim    CAPI_KEY *key = NULL;
1408280304Sjkim    CRYPT_KEY_PROV_INFO *pinfo = NULL;
1409280304Sjkim    char *provname = NULL, *contname = NULL;
1410280304Sjkim    pinfo = capi_get_prov_info(ctx, cert);
1411280304Sjkim    if (!pinfo)
1412280304Sjkim        goto err;
1413280304Sjkim    provname = wide_to_asc(pinfo->pwszProvName);
1414280304Sjkim    contname = wide_to_asc(pinfo->pwszContainerName);
1415280304Sjkim    if (!provname || !contname)
1416280304Sjkim        goto err;
1417280304Sjkim    key = capi_get_key(ctx, contname, provname,
1418280304Sjkim                       pinfo->dwProvType, pinfo->dwKeySpec);
1419183234Ssimon
1420280304Sjkim err:
1421280304Sjkim    if (pinfo)
1422280304Sjkim        OPENSSL_free(pinfo);
1423280304Sjkim    if (provname)
1424280304Sjkim        OPENSSL_free(provname);
1425280304Sjkim    if (contname)
1426280304Sjkim        OPENSSL_free(contname);
1427280304Sjkim    return key;
1428280304Sjkim}
1429183234Ssimon
1430280304SjkimCAPI_KEY *capi_find_key(CAPI_CTX * ctx, const char *id)
1431280304Sjkim{
1432280304Sjkim    PCCERT_CONTEXT cert;
1433280304Sjkim    HCERTSTORE hstore;
1434280304Sjkim    CAPI_KEY *key = NULL;
1435280304Sjkim    switch (ctx->lookup_method) {
1436280304Sjkim    case CAPI_LU_SUBSTR:
1437280304Sjkim    case CAPI_LU_FNAME:
1438280304Sjkim        hstore = capi_open_store(ctx, NULL);
1439280304Sjkim        if (!hstore)
1440280304Sjkim            return NULL;
1441280304Sjkim        cert = capi_find_cert(ctx, id, hstore);
1442280304Sjkim        if (cert) {
1443280304Sjkim            key = capi_get_cert_key(ctx, cert);
1444280304Sjkim            CertFreeCertificateContext(cert);
1445280304Sjkim        }
1446280304Sjkim        CertCloseStore(hstore, 0);
1447280304Sjkim        break;
1448183234Ssimon
1449280304Sjkim    case CAPI_LU_CONTNAME:
1450280304Sjkim        key = capi_get_key(ctx, id, ctx->cspname, ctx->csptype, ctx->keytype);
1451280304Sjkim        break;
1452280304Sjkim    }
1453183234Ssimon
1454280304Sjkim    return key;
1455280304Sjkim}
1456183234Ssimon
1457280304Sjkimvoid capi_free_key(CAPI_KEY * key)
1458280304Sjkim{
1459280304Sjkim    if (!key)
1460280304Sjkim        return;
1461280304Sjkim    CryptDestroyKey(key->key);
1462280304Sjkim    CryptReleaseContext(key->hprov, 0);
1463280304Sjkim    if (key->pcert)
1464280304Sjkim        CertFreeCertificateContext(key->pcert);
1465280304Sjkim    OPENSSL_free(key);
1466280304Sjkim}
1467183234Ssimon
1468183234Ssimon/* Initialize a CAPI_CTX structure */
1469183234Ssimon
1470183234Ssimonstatic CAPI_CTX *capi_ctx_new()
1471280304Sjkim{
1472280304Sjkim    CAPI_CTX *ctx;
1473280304Sjkim    ctx = OPENSSL_malloc(sizeof(CAPI_CTX));
1474280304Sjkim    if (!ctx) {
1475280304Sjkim        CAPIerr(CAPI_F_CAPI_CTX_NEW, ERR_R_MALLOC_FAILURE);
1476280304Sjkim        return NULL;
1477280304Sjkim    }
1478280304Sjkim    ctx->cspname = NULL;
1479280304Sjkim    ctx->csptype = PROV_RSA_FULL;
1480280304Sjkim    ctx->dump_flags = CAPI_DMP_SUMMARY | CAPI_DMP_FNAME;
1481280304Sjkim    ctx->keytype = AT_KEYEXCHANGE;
1482280304Sjkim    ctx->storename = NULL;
1483280304Sjkim    ctx->ssl_client_store = NULL;
1484280304Sjkim    ctx->store_flags = CERT_STORE_OPEN_EXISTING_FLAG |
1485280304Sjkim        CERT_STORE_READONLY_FLAG | CERT_SYSTEM_STORE_CURRENT_USER;
1486280304Sjkim    ctx->lookup_method = CAPI_LU_SUBSTR;
1487280304Sjkim    ctx->debug_level = 0;
1488280304Sjkim    ctx->debug_file = NULL;
1489280304Sjkim    ctx->client_cert_select = cert_select_simple;
1490280304Sjkim    return ctx;
1491280304Sjkim}
1492183234Ssimon
1493280304Sjkimstatic void capi_ctx_free(CAPI_CTX * ctx)
1494280304Sjkim{
1495280304Sjkim    CAPI_trace(ctx, "Calling capi_ctx_free with %lx\n", ctx);
1496280304Sjkim    if (!ctx)
1497280304Sjkim        return;
1498280304Sjkim    if (ctx->cspname)
1499280304Sjkim        OPENSSL_free(ctx->cspname);
1500280304Sjkim    if (ctx->debug_file)
1501280304Sjkim        OPENSSL_free(ctx->debug_file);
1502280304Sjkim    if (ctx->storename)
1503280304Sjkim        OPENSSL_free(ctx->storename);
1504280304Sjkim    if (ctx->ssl_client_store)
1505280304Sjkim        OPENSSL_free(ctx->ssl_client_store);
1506280304Sjkim    OPENSSL_free(ctx);
1507280304Sjkim}
1508183234Ssimon
1509280304Sjkimstatic int capi_ctx_set_provname(CAPI_CTX * ctx, LPSTR pname, DWORD type,
1510280304Sjkim                                 int check)
1511280304Sjkim{
1512280304Sjkim    CAPI_trace(ctx, "capi_ctx_set_provname, name=%s, type=%d\n", pname, type);
1513280304Sjkim    if (check) {
1514280304Sjkim        HCRYPTPROV hprov;
1515280304Sjkim        if (!CryptAcquireContextA(&hprov, NULL, pname, type,
1516280304Sjkim                                  CRYPT_VERIFYCONTEXT)) {
1517280304Sjkim            CAPIerr(CAPI_F_CAPI_CTX_SET_PROVNAME,
1518280304Sjkim                    CAPI_R_CRYPTACQUIRECONTEXT_ERROR);
1519280304Sjkim            capi_addlasterror();
1520280304Sjkim            return 0;
1521280304Sjkim        }
1522280304Sjkim        CryptReleaseContext(hprov, 0);
1523280304Sjkim    }
1524280304Sjkim    if (ctx->cspname)
1525280304Sjkim        OPENSSL_free(ctx->cspname);
1526280304Sjkim    ctx->cspname = BUF_strdup(pname);
1527280304Sjkim    ctx->csptype = type;
1528280304Sjkim    return 1;
1529280304Sjkim}
1530183234Ssimon
1531280304Sjkimstatic int capi_ctx_set_provname_idx(CAPI_CTX * ctx, int idx)
1532280304Sjkim{
1533280304Sjkim    LPSTR pname;
1534280304Sjkim    DWORD type;
1535280304Sjkim    int res;
1536280304Sjkim    if (capi_get_provname(ctx, &pname, &type, idx) != 1)
1537280304Sjkim        return 0;
1538280304Sjkim    res = capi_ctx_set_provname(ctx, pname, type, 0);
1539280304Sjkim    OPENSSL_free(pname);
1540280304Sjkim    return res;
1541280304Sjkim}
1542183234Ssimon
1543183234Ssimonstatic int cert_issuer_match(STACK_OF(X509_NAME) *ca_dn, X509 *x)
1544280304Sjkim{
1545280304Sjkim    int i;
1546280304Sjkim    X509_NAME *nm;
1547280304Sjkim    /* Special case: empty list: match anything */
1548280304Sjkim    if (sk_X509_NAME_num(ca_dn) <= 0)
1549280304Sjkim        return 1;
1550280304Sjkim    for (i = 0; i < sk_X509_NAME_num(ca_dn); i++) {
1551280304Sjkim        nm = sk_X509_NAME_value(ca_dn, i);
1552280304Sjkim        if (!X509_NAME_cmp(nm, X509_get_issuer_name(x)))
1553280304Sjkim            return 1;
1554280304Sjkim    }
1555280304Sjkim    return 0;
1556280304Sjkim}
1557183234Ssimon
1558183234Ssimonstatic int capi_load_ssl_client_cert(ENGINE *e, SSL *ssl,
1559280304Sjkim                                     STACK_OF(X509_NAME) *ca_dn, X509 **pcert,
1560280304Sjkim                                     EVP_PKEY **pkey, STACK_OF(X509) **pother,
1561280304Sjkim                                     UI_METHOD *ui_method,
1562280304Sjkim                                     void *callback_data)
1563280304Sjkim{
1564280304Sjkim    STACK_OF(X509) *certs = NULL;
1565280304Sjkim    X509 *x;
1566280304Sjkim    char *storename;
1567280304Sjkim    const char *p;
1568280304Sjkim    int i, client_cert_idx;
1569280304Sjkim    HCERTSTORE hstore;
1570280304Sjkim    PCCERT_CONTEXT cert = NULL, excert = NULL;
1571280304Sjkim    CAPI_CTX *ctx;
1572280304Sjkim    CAPI_KEY *key;
1573280304Sjkim    ctx = ENGINE_get_ex_data(e, capi_idx);
1574183234Ssimon
1575280304Sjkim    *pcert = NULL;
1576280304Sjkim    *pkey = NULL;
1577183234Ssimon
1578280304Sjkim    storename = ctx->ssl_client_store;
1579280304Sjkim    if (!storename)
1580280304Sjkim        storename = "MY";
1581183234Ssimon
1582280304Sjkim    hstore = capi_open_store(ctx, storename);
1583280304Sjkim    if (!hstore)
1584280304Sjkim        return 0;
1585280304Sjkim    /* Enumerate all certificates collect any matches */
1586280304Sjkim    for (i = 0;; i++) {
1587280304Sjkim        cert = CertEnumCertificatesInStore(hstore, cert);
1588280304Sjkim        if (!cert)
1589280304Sjkim            break;
1590280304Sjkim        p = cert->pbCertEncoded;
1591280304Sjkim        x = d2i_X509(NULL, &p, cert->cbCertEncoded);
1592280304Sjkim        if (!x) {
1593280304Sjkim            CAPI_trace(ctx, "Can't Parse Certificate %d\n", i);
1594280304Sjkim            continue;
1595280304Sjkim        }
1596280304Sjkim        if (cert_issuer_match(ca_dn, x)
1597280304Sjkim            && X509_check_purpose(x, X509_PURPOSE_SSL_CLIENT, 0)) {
1598280304Sjkim            key = capi_get_cert_key(ctx, cert);
1599280304Sjkim            if (!key) {
1600280304Sjkim                X509_free(x);
1601280304Sjkim                continue;
1602280304Sjkim            }
1603280304Sjkim            /*
1604280304Sjkim             * Match found: attach extra data to it so we can retrieve the
1605280304Sjkim             * key later.
1606280304Sjkim             */
1607280304Sjkim            excert = CertDuplicateCertificateContext(cert);
1608280304Sjkim            key->pcert = excert;
1609280304Sjkim            X509_set_ex_data(x, cert_capi_idx, key);
1610183234Ssimon
1611280304Sjkim            if (!certs)
1612280304Sjkim                certs = sk_X509_new_null();
1613183234Ssimon
1614280304Sjkim            sk_X509_push(certs, x);
1615280304Sjkim        } else
1616280304Sjkim            X509_free(x);
1617183234Ssimon
1618280304Sjkim    }
1619183234Ssimon
1620280304Sjkim    if (cert)
1621280304Sjkim        CertFreeCertificateContext(cert);
1622280304Sjkim    if (hstore)
1623280304Sjkim        CertCloseStore(hstore, 0);
1624183234Ssimon
1625280304Sjkim    if (!certs)
1626280304Sjkim        return 0;
1627183234Ssimon
1628280304Sjkim    /* Select the appropriate certificate */
1629183234Ssimon
1630280304Sjkim    client_cert_idx = ctx->client_cert_select(e, ssl, certs);
1631183234Ssimon
1632280304Sjkim    /* Set the selected certificate and free the rest */
1633183234Ssimon
1634280304Sjkim    for (i = 0; i < sk_X509_num(certs); i++) {
1635280304Sjkim        x = sk_X509_value(certs, i);
1636280304Sjkim        if (i == client_cert_idx)
1637280304Sjkim            *pcert = x;
1638280304Sjkim        else {
1639280304Sjkim            key = X509_get_ex_data(x, cert_capi_idx);
1640280304Sjkim            capi_free_key(key);
1641280304Sjkim            X509_free(x);
1642280304Sjkim        }
1643280304Sjkim    }
1644183234Ssimon
1645280304Sjkim    sk_X509_free(certs);
1646183234Ssimon
1647280304Sjkim    if (!*pcert)
1648280304Sjkim        return 0;
1649183234Ssimon
1650280304Sjkim    /* Setup key for selected certificate */
1651183234Ssimon
1652280304Sjkim    key = X509_get_ex_data(*pcert, cert_capi_idx);
1653280304Sjkim    *pkey = capi_get_pkey(e, key);
1654280304Sjkim    X509_set_ex_data(*pcert, cert_capi_idx, NULL);
1655183234Ssimon
1656280304Sjkim    return 1;
1657183234Ssimon
1658280304Sjkim}
1659183234Ssimon
1660183234Ssimon/* Simple client cert selection function: always select first */
1661183234Ssimon
1662183234Ssimonstatic int cert_select_simple(ENGINE *e, SSL *ssl, STACK_OF(X509) *certs)
1663280304Sjkim{
1664280304Sjkim    return 0;
1665280304Sjkim}
1666183234Ssimon
1667280304Sjkim# ifdef OPENSSL_CAPIENG_DIALOG
1668183234Ssimon
1669280304Sjkim/*
1670280304Sjkim * More complex cert selection function, using standard function
1671183234Ssimon * CryptUIDlgSelectCertificateFromStore() to produce a dialog box.
1672183234Ssimon */
1673183234Ssimon
1674280304Sjkim/*
1675280304Sjkim * Definitions which are in cryptuiapi.h but this is not present in older
1676183234Ssimon * versions of headers.
1677183234Ssimon */
1678183234Ssimon
1679280304Sjkim#  ifndef CRYPTUI_SELECT_LOCATION_COLUMN
1680280304Sjkim#   define CRYPTUI_SELECT_LOCATION_COLUMN                   0x000000010
1681280304Sjkim#   define CRYPTUI_SELECT_INTENDEDUSE_COLUMN                0x000000004
1682280304Sjkim#  endif
1683183234Ssimon
1684280304Sjkim#  define dlg_title L"OpenSSL Application SSL Client Certificate Selection"
1685280304Sjkim#  define dlg_prompt L"Select a certificate to use for authentication"
1686280304Sjkim#  define dlg_columns      CRYPTUI_SELECT_LOCATION_COLUMN \
1687280304Sjkim                        |CRYPTUI_SELECT_INTENDEDUSE_COLUMN
1688183234Ssimon
1689183234Ssimonstatic int cert_select_dialog(ENGINE *e, SSL *ssl, STACK_OF(X509) *certs)
1690280304Sjkim{
1691280304Sjkim    X509 *x;
1692280304Sjkim    HCERTSTORE dstore;
1693280304Sjkim    PCCERT_CONTEXT cert;
1694280304Sjkim    CAPI_CTX *ctx;
1695280304Sjkim    CAPI_KEY *key;
1696280304Sjkim    HWND hwnd;
1697280304Sjkim    int i, idx = -1;
1698280304Sjkim    if (sk_X509_num(certs) == 1)
1699280304Sjkim        return 0;
1700280304Sjkim    ctx = ENGINE_get_ex_data(e, capi_idx);
1701280304Sjkim    /* Create an in memory store of certificates */
1702280304Sjkim    dstore = CertOpenStore(CERT_STORE_PROV_MEMORY, 0, 0,
1703280304Sjkim                           CERT_STORE_CREATE_NEW_FLAG, NULL);
1704280304Sjkim    if (!dstore) {
1705280304Sjkim        CAPIerr(CAPI_F_CERT_SELECT_DIALOG, CAPI_R_ERROR_CREATING_STORE);
1706280304Sjkim        capi_addlasterror();
1707280304Sjkim        goto err;
1708280304Sjkim    }
1709280304Sjkim    /* Add all certificates to store */
1710280304Sjkim    for (i = 0; i < sk_X509_num(certs); i++) {
1711280304Sjkim        x = sk_X509_value(certs, i);
1712280304Sjkim        key = X509_get_ex_data(x, cert_capi_idx);
1713183234Ssimon
1714280304Sjkim        if (!CertAddCertificateContextToStore(dstore, key->pcert,
1715280304Sjkim                                              CERT_STORE_ADD_NEW, NULL)) {
1716280304Sjkim            CAPIerr(CAPI_F_CERT_SELECT_DIALOG, CAPI_R_ERROR_ADDING_CERT);
1717280304Sjkim            capi_addlasterror();
1718280304Sjkim            goto err;
1719280304Sjkim        }
1720183234Ssimon
1721280304Sjkim    }
1722280304Sjkim    hwnd = GetForegroundWindow();
1723280304Sjkim    if (!hwnd)
1724280304Sjkim        hwnd = GetActiveWindow();
1725280304Sjkim    if (!hwnd && ctx->getconswindow)
1726280304Sjkim        hwnd = ctx->getconswindow();
1727280304Sjkim    /* Call dialog to select one */
1728280304Sjkim    cert = ctx->certselectdlg(dstore, hwnd, dlg_title, dlg_prompt,
1729280304Sjkim                              dlg_columns, 0, NULL);
1730183234Ssimon
1731280304Sjkim    /* Find matching cert from list */
1732280304Sjkim    if (cert) {
1733280304Sjkim        for (i = 0; i < sk_X509_num(certs); i++) {
1734280304Sjkim            x = sk_X509_value(certs, i);
1735280304Sjkim            key = X509_get_ex_data(x, cert_capi_idx);
1736280304Sjkim            if (CertCompareCertificate
1737280304Sjkim                (X509_ASN_ENCODING | PKCS_7_ASN_ENCODING, cert->pCertInfo,
1738280304Sjkim                 key->pcert->pCertInfo)) {
1739280304Sjkim                idx = i;
1740280304Sjkim                break;
1741280304Sjkim            }
1742280304Sjkim        }
1743280304Sjkim    }
1744183234Ssimon
1745280304Sjkim err:
1746280304Sjkim    if (dstore)
1747280304Sjkim        CertCloseStore(dstore, 0);
1748280304Sjkim    return idx;
1749183234Ssimon
1750280304Sjkim}
1751280304Sjkim# endif
1752183234Ssimon
1753280304Sjkim#else                           /* !__COMPILE_CAPIENG */
1754280304Sjkim# include <openssl/engine.h>
1755280304Sjkim# ifndef OPENSSL_NO_DYNAMIC_ENGINE
1756183234SsimonOPENSSL_EXPORT
1757280304Sjkim    int bind_engine(ENGINE *e, const char *id, const dynamic_fns *fns);
1758238405SjkimOPENSSL_EXPORT
1759280304Sjkim    int bind_engine(ENGINE *e, const char *id, const dynamic_fns *fns)
1760280304Sjkim{
1761280304Sjkim    return 0;
1762280304Sjkim}
1763280304Sjkim
1764183234SsimonIMPLEMENT_DYNAMIC_CHECK_FN()
1765280304Sjkim# else
1766280304Sjkimvoid ENGINE_load_capi(void)
1767280304Sjkim{
1768280304Sjkim}
1769280304Sjkim# endif
1770183234Ssimon#endif
1771