1183234Ssimon/* engines/e_capi.c */
2280297Sjkim/*
3280297Sjkim * Written by Dr Stephen N Henson (steve@openssl.org) for the OpenSSL
4183234Ssimon * project.
5183234Ssimon */
6183234Ssimon/* ====================================================================
7340704Sjkim * Copyright (c) 2008-2018 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
14280297Sjkim *    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>
57290207Sjkim#include <stdlib.h>
58290207Sjkim
59183234Ssimon#include <openssl/crypto.h>
60183234Ssimon
61183234Ssimon#ifdef OPENSSL_SYS_WIN32
62280297Sjkim# ifndef OPENSSL_NO_CAPIENG
63183234Ssimon
64290207Sjkim#  include <openssl/buffer.h>
65290207Sjkim#  include <openssl/bn.h>
66280297Sjkim#  include <openssl/rsa.h>
67183234Ssimon
68280297Sjkim#  ifndef _WIN32_WINNT
69280297Sjkim#   define _WIN32_WINNT 0x0400
70280297Sjkim#  endif
71183234Ssimon
72290207Sjkim#  include <windows.h>
73280297Sjkim#  include <wincrypt.h>
74290207Sjkim#  include <malloc.h>
75290207Sjkim#  ifndef alloca
76290207Sjkim#   define alloca _alloca
77290207Sjkim#  endif
78183234Ssimon
79238405Sjkim/*
80238405Sjkim * This module uses several "new" interfaces, among which is
81238405Sjkim * CertGetCertificateContextProperty. CERT_KEY_PROV_INFO_PROP_ID is
82238405Sjkim * one of possible values you can pass to function in question. By
83238405Sjkim * checking if it's defined we can see if wincrypt.h and accompanying
84238405Sjkim * crypt32.lib are in shape. The native MingW32 headers up to and
85238405Sjkim * including __W32API_VERSION 3.14 lack of struct DSSPUBKEY and the
86238405Sjkim * defines CERT_STORE_PROV_SYSTEM_A and CERT_STORE_READONLY_FLAG,
87238405Sjkim * so we check for these too and avoid compiling.
88238405Sjkim * Yes, it's rather "weak" test and if compilation fails,
89238405Sjkim * then re-configure with -DOPENSSL_NO_CAPIENG.
90238405Sjkim */
91280297Sjkim#  if defined(CERT_KEY_PROV_INFO_PROP_ID) && \
92238405Sjkim    defined(CERT_STORE_PROV_SYSTEM_A) && \
93238405Sjkim    defined(CERT_STORE_READONLY_FLAG)
94280297Sjkim#   define __COMPILE_CAPIENG
95280297Sjkim#  endif                        /* CERT_KEY_PROV_INFO_PROP_ID */
96280297Sjkim# endif                         /* OPENSSL_NO_CAPIENG */
97280297Sjkim#endif                          /* OPENSSL_SYS_WIN32 */
98238405Sjkim
99238405Sjkim#ifdef __COMPILE_CAPIENG
100238405Sjkim
101280297Sjkim# undef X509_EXTENSIONS
102280297Sjkim# undef X509_CERT_PAIR
103183234Ssimon
104183234Ssimon/* Definitions which may be missing from earlier version of headers */
105280297Sjkim# ifndef CERT_STORE_OPEN_EXISTING_FLAG
106280297Sjkim#  define CERT_STORE_OPEN_EXISTING_FLAG                   0x00004000
107280297Sjkim# endif
108183234Ssimon
109280297Sjkim# ifndef CERT_STORE_CREATE_NEW_FLAG
110280297Sjkim#  define CERT_STORE_CREATE_NEW_FLAG                      0x00002000
111280297Sjkim# endif
112183234Ssimon
113280297Sjkim# ifndef CERT_SYSTEM_STORE_CURRENT_USER
114280297Sjkim#  define CERT_SYSTEM_STORE_CURRENT_USER                  0x00010000
115280297Sjkim# endif
116206046Ssimon
117296279Sjkim# ifndef ALG_SID_SHA_256
118296279Sjkim#  define ALG_SID_SHA_256                 12
119296279Sjkim# endif
120296279Sjkim# ifndef ALG_SID_SHA_384
121296279Sjkim#  define ALG_SID_SHA_384                 13
122296279Sjkim# endif
123296279Sjkim# ifndef ALG_SID_SHA_512
124296279Sjkim#  define ALG_SID_SHA_512                 14
125296279Sjkim# endif
126296279Sjkim
127296279Sjkim# ifndef CALG_SHA_256
128296279Sjkim#  define CALG_SHA_256            (ALG_CLASS_HASH | ALG_TYPE_ANY | ALG_SID_SHA_256)
129296279Sjkim# endif
130296279Sjkim# ifndef CALG_SHA_384
131296279Sjkim#  define CALG_SHA_384            (ALG_CLASS_HASH | ALG_TYPE_ANY | ALG_SID_SHA_384)
132296279Sjkim# endif
133296279Sjkim# ifndef CALG_SHA_512
134296279Sjkim#  define CALG_SHA_512            (ALG_CLASS_HASH | ALG_TYPE_ANY | ALG_SID_SHA_512)
135296279Sjkim# endif
136296279Sjkim
137280297Sjkim# include <openssl/engine.h>
138280297Sjkim# include <openssl/pem.h>
139280297Sjkim# include <openssl/x509v3.h>
140183234Ssimon
141280297Sjkim# include "e_capi_err.h"
142280297Sjkim# include "e_capi_err.c"
143183234Ssimon
144183234Ssimonstatic const char *engine_capi_id = "capi";
145183234Ssimonstatic const char *engine_capi_name = "CryptoAPI ENGINE";
146183234Ssimon
147183234Ssimontypedef struct CAPI_CTX_st CAPI_CTX;
148183234Ssimontypedef struct CAPI_KEY_st CAPI_KEY;
149183234Ssimon
150183234Ssimonstatic void capi_addlasterror(void);
151183234Ssimonstatic void capi_adderror(DWORD err);
152183234Ssimon
153280297Sjkimstatic void CAPI_trace(CAPI_CTX * ctx, char *format, ...);
154183234Ssimon
155280297Sjkimstatic int capi_list_providers(CAPI_CTX * ctx, BIO *out);
156280297Sjkimstatic int capi_list_containers(CAPI_CTX * ctx, BIO *out);
157280297Sjkimint capi_list_certs(CAPI_CTX * ctx, BIO *out, char *storename);
158280297Sjkimvoid capi_free_key(CAPI_KEY * key);
159183234Ssimon
160280297Sjkimstatic PCCERT_CONTEXT capi_find_cert(CAPI_CTX * ctx, const char *id,
161280297Sjkim                                     HCERTSTORE hstore);
162183234Ssimon
163280297SjkimCAPI_KEY *capi_find_key(CAPI_CTX * ctx, const char *id);
164183234Ssimon
165183234Ssimonstatic EVP_PKEY *capi_load_privkey(ENGINE *eng, const char *key_id,
166280297Sjkim                                   UI_METHOD *ui_method, void *callback_data);
167280297Sjkimstatic int capi_rsa_sign(int dtype, const unsigned char *m,
168280297Sjkim                         unsigned int m_len, unsigned char *sigret,
169280297Sjkim                         unsigned int *siglen, const RSA *rsa);
170183234Ssimonstatic int capi_rsa_priv_enc(int flen, const unsigned char *from,
171280297Sjkim                             unsigned char *to, RSA *rsa, int padding);
172183234Ssimonstatic int capi_rsa_priv_dec(int flen, const unsigned char *from,
173280297Sjkim                             unsigned char *to, RSA *rsa, int padding);
174183234Ssimonstatic int capi_rsa_free(RSA *rsa);
175183234Ssimon
176183234Ssimonstatic DSA_SIG *capi_dsa_do_sign(const unsigned char *digest, int dlen,
177280297Sjkim                                 DSA *dsa);
178183234Ssimonstatic int capi_dsa_free(DSA *dsa);
179183234Ssimon
180183234Ssimonstatic int capi_load_ssl_client_cert(ENGINE *e, SSL *ssl,
181280297Sjkim                                     STACK_OF(X509_NAME) *ca_dn, X509 **pcert,
182280297Sjkim                                     EVP_PKEY **pkey, STACK_OF(X509) **pother,
183280297Sjkim                                     UI_METHOD *ui_method,
184280297Sjkim                                     void *callback_data);
185183234Ssimon
186183234Ssimonstatic int cert_select_simple(ENGINE *e, SSL *ssl, STACK_OF(X509) *certs);
187280297Sjkim# ifdef OPENSSL_CAPIENG_DIALOG
188183234Ssimonstatic int cert_select_dialog(ENGINE *e, SSL *ssl, STACK_OF(X509) *certs);
189280297Sjkim# endif
190183234Ssimon
191280297Sjkimtypedef PCCERT_CONTEXT(WINAPI *CERTDLG) (HCERTSTORE, HWND, LPCWSTR,
192280297Sjkim                                         LPCWSTR, DWORD, DWORD, void *);
193280297Sjkimtypedef HWND(WINAPI *GETCONSWIN) (void);
194183234Ssimon
195280297Sjkim/*
196280297Sjkim * This structure contains CAPI ENGINE specific data: it contains various
197280297Sjkim * global options and affects how other functions behave.
198183234Ssimon */
199183234Ssimon
200280297Sjkim# define CAPI_DBG_TRACE  2
201280297Sjkim# define CAPI_DBG_ERROR  1
202183234Ssimon
203183234Ssimonstruct CAPI_CTX_st {
204280297Sjkim    int debug_level;
205280297Sjkim    char *debug_file;
206280297Sjkim    /* Parameters to use for container lookup */
207280297Sjkim    DWORD keytype;
208280297Sjkim    LPSTR cspname;
209280297Sjkim    DWORD csptype;
210280297Sjkim    /* Certificate store name to use */
211280297Sjkim    LPSTR storename;
212280297Sjkim    LPSTR ssl_client_store;
213280297Sjkim    /* System store flags */
214280297Sjkim    DWORD store_flags;
215183234Ssimon/* Lookup string meanings in load_private_key */
216183234Ssimon/* Substring of subject: uses "storename" */
217280297Sjkim# define CAPI_LU_SUBSTR          1
218183234Ssimon/* Friendly name: uses storename */
219280297Sjkim# define CAPI_LU_FNAME           2
220183234Ssimon/* Container name: uses cspname, keytype */
221280297Sjkim# define CAPI_LU_CONTNAME        3
222280297Sjkim    int lookup_method;
223183234Ssimon/* Info to dump with dumpcerts option */
224183234Ssimon/* Issuer and serial name strings */
225280297Sjkim# define CAPI_DMP_SUMMARY        0x1
226183234Ssimon/* Friendly name */
227280297Sjkim# define CAPI_DMP_FNAME          0x2
228183234Ssimon/* Full X509_print dump */
229280297Sjkim# define CAPI_DMP_FULL           0x4
230183234Ssimon/* Dump PEM format certificate */
231280297Sjkim# define CAPI_DMP_PEM            0x8
232183234Ssimon/* Dump pseudo key (if possible) */
233280297Sjkim# define CAPI_DMP_PSKEY          0x10
234183234Ssimon/* Dump key info (if possible) */
235280297Sjkim# define CAPI_DMP_PKEYINFO       0x20
236280297Sjkim    DWORD dump_flags;
237280297Sjkim    int (*client_cert_select) (ENGINE *e, SSL *ssl, STACK_OF(X509) *certs);
238280297Sjkim    CERTDLG certselectdlg;
239280297Sjkim    GETCONSWIN getconswindow;
240183234Ssimon};
241183234Ssimon
242183234Ssimonstatic CAPI_CTX *capi_ctx_new();
243280297Sjkimstatic void capi_ctx_free(CAPI_CTX * ctx);
244280297Sjkimstatic int capi_ctx_set_provname(CAPI_CTX * ctx, LPSTR pname, DWORD type,
245280297Sjkim                                 int check);
246280297Sjkimstatic int capi_ctx_set_provname_idx(CAPI_CTX * ctx, int idx);
247183234Ssimon
248280297Sjkim# define CAPI_CMD_LIST_CERTS             ENGINE_CMD_BASE
249280297Sjkim# define CAPI_CMD_LOOKUP_CERT            (ENGINE_CMD_BASE + 1)
250280297Sjkim# define CAPI_CMD_DEBUG_LEVEL            (ENGINE_CMD_BASE + 2)
251280297Sjkim# define CAPI_CMD_DEBUG_FILE             (ENGINE_CMD_BASE + 3)
252280297Sjkim# define CAPI_CMD_KEYTYPE                (ENGINE_CMD_BASE + 4)
253280297Sjkim# define CAPI_CMD_LIST_CSPS              (ENGINE_CMD_BASE + 5)
254280297Sjkim# define CAPI_CMD_SET_CSP_IDX            (ENGINE_CMD_BASE + 6)
255280297Sjkim# define CAPI_CMD_SET_CSP_NAME           (ENGINE_CMD_BASE + 7)
256280297Sjkim# define CAPI_CMD_SET_CSP_TYPE           (ENGINE_CMD_BASE + 8)
257280297Sjkim# define CAPI_CMD_LIST_CONTAINERS        (ENGINE_CMD_BASE + 9)
258280297Sjkim# define CAPI_CMD_LIST_OPTIONS           (ENGINE_CMD_BASE + 10)
259280297Sjkim# define CAPI_CMD_LOOKUP_METHOD          (ENGINE_CMD_BASE + 11)
260280297Sjkim# define CAPI_CMD_STORE_NAME             (ENGINE_CMD_BASE + 12)
261280297Sjkim# define CAPI_CMD_STORE_FLAGS            (ENGINE_CMD_BASE + 13)
262183234Ssimon
263183234Ssimonstatic const ENGINE_CMD_DEFN capi_cmd_defns[] = {
264280297Sjkim    {CAPI_CMD_LIST_CERTS,
265280297Sjkim     "list_certs",
266280297Sjkim     "List all certificates in store",
267280297Sjkim     ENGINE_CMD_FLAG_NO_INPUT},
268280297Sjkim    {CAPI_CMD_LOOKUP_CERT,
269280297Sjkim     "lookup_cert",
270280297Sjkim     "Lookup and output certificates",
271280297Sjkim     ENGINE_CMD_FLAG_STRING},
272280297Sjkim    {CAPI_CMD_DEBUG_LEVEL,
273280297Sjkim     "debug_level",
274280297Sjkim     "debug level (1=errors, 2=trace)",
275280297Sjkim     ENGINE_CMD_FLAG_NUMERIC},
276280297Sjkim    {CAPI_CMD_DEBUG_FILE,
277280297Sjkim     "debug_file",
278280297Sjkim     "debugging filename)",
279280297Sjkim     ENGINE_CMD_FLAG_STRING},
280280297Sjkim    {CAPI_CMD_KEYTYPE,
281280297Sjkim     "key_type",
282280297Sjkim     "Key type: 1=AT_KEYEXCHANGE (default), 2=AT_SIGNATURE",
283280297Sjkim     ENGINE_CMD_FLAG_NUMERIC},
284280297Sjkim    {CAPI_CMD_LIST_CSPS,
285280297Sjkim     "list_csps",
286280297Sjkim     "List all CSPs",
287280297Sjkim     ENGINE_CMD_FLAG_NO_INPUT},
288280297Sjkim    {CAPI_CMD_SET_CSP_IDX,
289280297Sjkim     "csp_idx",
290280297Sjkim     "Set CSP by index",
291280297Sjkim     ENGINE_CMD_FLAG_NUMERIC},
292280297Sjkim    {CAPI_CMD_SET_CSP_NAME,
293280297Sjkim     "csp_name",
294280297Sjkim     "Set CSP name, (default CSP used if not specified)",
295280297Sjkim     ENGINE_CMD_FLAG_STRING},
296280297Sjkim    {CAPI_CMD_SET_CSP_TYPE,
297280297Sjkim     "csp_type",
298280297Sjkim     "Set CSP type, (default RSA_PROV_FULL)",
299280297Sjkim     ENGINE_CMD_FLAG_NUMERIC},
300280297Sjkim    {CAPI_CMD_LIST_CONTAINERS,
301280297Sjkim     "list_containers",
302280297Sjkim     "list container names",
303280297Sjkim     ENGINE_CMD_FLAG_NO_INPUT},
304280297Sjkim    {CAPI_CMD_LIST_OPTIONS,
305280297Sjkim     "list_options",
306280297Sjkim     "Set list options (1=summary,2=friendly name, 4=full printout, 8=PEM output, 16=XXX, "
307280297Sjkim     "32=private key info)",
308280297Sjkim     ENGINE_CMD_FLAG_NUMERIC},
309280297Sjkim    {CAPI_CMD_LOOKUP_METHOD,
310280297Sjkim     "lookup_method",
311280297Sjkim     "Set key lookup method (1=substring, 2=friendlyname, 3=container name)",
312280297Sjkim     ENGINE_CMD_FLAG_NUMERIC},
313280297Sjkim    {CAPI_CMD_STORE_NAME,
314280297Sjkim     "store_name",
315280297Sjkim     "certificate store name, default \"MY\"",
316280297Sjkim     ENGINE_CMD_FLAG_STRING},
317280297Sjkim    {CAPI_CMD_STORE_FLAGS,
318280297Sjkim     "store_flags",
319280297Sjkim     "Certificate store flags: 1 = system store",
320280297Sjkim     ENGINE_CMD_FLAG_NUMERIC},
321183234Ssimon
322280297Sjkim    {0, NULL, NULL, 0}
323280297Sjkim};
324183234Ssimon
325183234Ssimonstatic int capi_idx = -1;
326183234Ssimonstatic int rsa_capi_idx = -1;
327183234Ssimonstatic int dsa_capi_idx = -1;
328183234Ssimonstatic int cert_capi_idx = -1;
329183234Ssimon
330280297Sjkimstatic int capi_ctrl(ENGINE *e, int cmd, long i, void *p, void (*f) (void))
331280297Sjkim{
332280297Sjkim    int ret = 1;
333280297Sjkim    CAPI_CTX *ctx;
334280297Sjkim    BIO *out;
335280297Sjkim    if (capi_idx == -1) {
336280297Sjkim        CAPIerr(CAPI_F_CAPI_CTRL, CAPI_R_ENGINE_NOT_INITIALIZED);
337280297Sjkim        return 0;
338280297Sjkim    }
339280297Sjkim    ctx = ENGINE_get_ex_data(e, capi_idx);
340280297Sjkim    out = BIO_new_fp(stdout, BIO_NOCLOSE);
341280297Sjkim    switch (cmd) {
342280297Sjkim    case CAPI_CMD_LIST_CSPS:
343280297Sjkim        ret = capi_list_providers(ctx, out);
344280297Sjkim        break;
345183234Ssimon
346280297Sjkim    case CAPI_CMD_LIST_CERTS:
347280297Sjkim        ret = capi_list_certs(ctx, out, NULL);
348280297Sjkim        break;
349183234Ssimon
350280297Sjkim    case CAPI_CMD_LOOKUP_CERT:
351280297Sjkim        ret = capi_list_certs(ctx, out, p);
352280297Sjkim        break;
353183234Ssimon
354280297Sjkim    case CAPI_CMD_LIST_CONTAINERS:
355280297Sjkim        ret = capi_list_containers(ctx, out);
356280297Sjkim        break;
357183234Ssimon
358280297Sjkim    case CAPI_CMD_STORE_NAME:
359280297Sjkim        if (ctx->storename)
360280297Sjkim            OPENSSL_free(ctx->storename);
361280297Sjkim        ctx->storename = BUF_strdup(p);
362280297Sjkim        CAPI_trace(ctx, "Setting store name to %s\n", p);
363280297Sjkim        break;
364183234Ssimon
365280297Sjkim    case CAPI_CMD_STORE_FLAGS:
366280297Sjkim        if (i & 1) {
367280297Sjkim            ctx->store_flags |= CERT_SYSTEM_STORE_LOCAL_MACHINE;
368280297Sjkim            ctx->store_flags &= ~CERT_SYSTEM_STORE_CURRENT_USER;
369280297Sjkim        } else {
370280297Sjkim            ctx->store_flags |= CERT_SYSTEM_STORE_CURRENT_USER;
371280297Sjkim            ctx->store_flags &= ~CERT_SYSTEM_STORE_LOCAL_MACHINE;
372280297Sjkim        }
373280297Sjkim        CAPI_trace(ctx, "Setting flags to %d\n", i);
374280297Sjkim        break;
375183234Ssimon
376280297Sjkim    case CAPI_CMD_DEBUG_LEVEL:
377280297Sjkim        ctx->debug_level = (int)i;
378280297Sjkim        CAPI_trace(ctx, "Setting debug level to %d\n", ctx->debug_level);
379280297Sjkim        break;
380183234Ssimon
381280297Sjkim    case CAPI_CMD_DEBUG_FILE:
382280297Sjkim        ctx->debug_file = BUF_strdup(p);
383280297Sjkim        CAPI_trace(ctx, "Setting debug file to %s\n", ctx->debug_file);
384280297Sjkim        break;
385183234Ssimon
386280297Sjkim    case CAPI_CMD_KEYTYPE:
387280297Sjkim        ctx->keytype = i;
388280297Sjkim        CAPI_trace(ctx, "Setting key type to %d\n", ctx->keytype);
389280297Sjkim        break;
390183234Ssimon
391280297Sjkim    case CAPI_CMD_SET_CSP_IDX:
392280297Sjkim        ret = capi_ctx_set_provname_idx(ctx, i);
393280297Sjkim        break;
394183234Ssimon
395280297Sjkim    case CAPI_CMD_LIST_OPTIONS:
396280297Sjkim        ctx->dump_flags = i;
397280297Sjkim        break;
398183234Ssimon
399280297Sjkim    case CAPI_CMD_LOOKUP_METHOD:
400280297Sjkim        if (i < 1 || i > 3) {
401280297Sjkim            CAPIerr(CAPI_F_CAPI_CTRL, CAPI_R_INVALID_LOOKUP_METHOD);
402280297Sjkim            return 0;
403280297Sjkim        }
404280297Sjkim        ctx->lookup_method = i;
405280297Sjkim        break;
406183234Ssimon
407280297Sjkim    case CAPI_CMD_SET_CSP_NAME:
408280297Sjkim        ret = capi_ctx_set_provname(ctx, p, ctx->csptype, 1);
409280297Sjkim        break;
410183234Ssimon
411280297Sjkim    case CAPI_CMD_SET_CSP_TYPE:
412280297Sjkim        ctx->csptype = i;
413280297Sjkim        break;
414183234Ssimon
415280297Sjkim    default:
416280297Sjkim        CAPIerr(CAPI_F_CAPI_CTRL, CAPI_R_UNKNOWN_COMMAND);
417280297Sjkim        ret = 0;
418280297Sjkim    }
419183234Ssimon
420280297Sjkim    BIO_free(out);
421280297Sjkim    return ret;
422183234Ssimon
423280297Sjkim}
424183234Ssimon
425280297Sjkimstatic RSA_METHOD capi_rsa_method = {
426280297Sjkim    "CryptoAPI RSA method",
427280297Sjkim    0,                          /* pub_enc */
428280297Sjkim    0,                          /* pub_dec */
429280297Sjkim    capi_rsa_priv_enc,          /* priv_enc */
430280297Sjkim    capi_rsa_priv_dec,          /* priv_dec */
431280297Sjkim    0,                          /* rsa_mod_exp */
432280297Sjkim    0,                          /* bn_mod_exp */
433280297Sjkim    0,                          /* init */
434280297Sjkim    capi_rsa_free,              /* finish */
435280297Sjkim    RSA_FLAG_SIGN_VER,          /* flags */
436280297Sjkim    NULL,                       /* app_data */
437280297Sjkim    capi_rsa_sign,              /* rsa_sign */
438280297Sjkim    0                           /* rsa_verify */
439280297Sjkim};
440183234Ssimon
441280297Sjkimstatic DSA_METHOD capi_dsa_method = {
442280297Sjkim    "CryptoAPI DSA method",
443280297Sjkim    capi_dsa_do_sign,           /* dsa_do_sign */
444280297Sjkim    0,                          /* dsa_sign_setup */
445280297Sjkim    0,                          /* dsa_do_verify */
446280297Sjkim    0,                          /* dsa_mod_exp */
447280297Sjkim    0,                          /* bn_mod_exp */
448280297Sjkim    0,                          /* init */
449280297Sjkim    capi_dsa_free,              /* finish */
450280297Sjkim    0,                          /* flags */
451280297Sjkim    NULL,                       /* app_data */
452280297Sjkim    0,                          /* dsa_paramgen */
453280297Sjkim    0                           /* dsa_keygen */
454280297Sjkim};
455183234Ssimon
456183234Ssimonstatic int capi_init(ENGINE *e)
457280297Sjkim{
458280297Sjkim    CAPI_CTX *ctx;
459280297Sjkim    const RSA_METHOD *ossl_rsa_meth;
460280297Sjkim    const DSA_METHOD *ossl_dsa_meth;
461183234Ssimon
462280297Sjkim    if (capi_idx < 0) {
463280297Sjkim        capi_idx = ENGINE_get_ex_new_index(0, NULL, NULL, NULL, 0);
464280297Sjkim        if (capi_idx < 0)
465280297Sjkim            goto memerr;
466237657Sjkim
467280297Sjkim        cert_capi_idx = X509_get_ex_new_index(0, NULL, NULL, NULL, 0);
468237657Sjkim
469280297Sjkim        /* Setup RSA_METHOD */
470280297Sjkim        rsa_capi_idx = RSA_get_ex_new_index(0, NULL, NULL, NULL, 0);
471280297Sjkim        ossl_rsa_meth = RSA_PKCS1_SSLeay();
472280297Sjkim        capi_rsa_method.rsa_pub_enc = ossl_rsa_meth->rsa_pub_enc;
473280297Sjkim        capi_rsa_method.rsa_pub_dec = ossl_rsa_meth->rsa_pub_dec;
474280297Sjkim        capi_rsa_method.rsa_mod_exp = ossl_rsa_meth->rsa_mod_exp;
475280297Sjkim        capi_rsa_method.bn_mod_exp = ossl_rsa_meth->bn_mod_exp;
476237657Sjkim
477280297Sjkim        /* Setup DSA Method */
478280297Sjkim        dsa_capi_idx = DSA_get_ex_new_index(0, NULL, NULL, NULL, 0);
479280297Sjkim        ossl_dsa_meth = DSA_OpenSSL();
480280297Sjkim        capi_dsa_method.dsa_do_verify = ossl_dsa_meth->dsa_do_verify;
481280297Sjkim        capi_dsa_method.dsa_mod_exp = ossl_dsa_meth->dsa_mod_exp;
482280297Sjkim        capi_dsa_method.bn_mod_exp = ossl_dsa_meth->bn_mod_exp;
483280297Sjkim    }
484237657Sjkim
485280297Sjkim    ctx = capi_ctx_new();
486280297Sjkim    if (!ctx)
487280297Sjkim        goto memerr;
488183234Ssimon
489280297Sjkim    ENGINE_set_ex_data(e, capi_idx, ctx);
490183234Ssimon
491280297Sjkim# ifdef OPENSSL_CAPIENG_DIALOG
492280297Sjkim    {
493280297Sjkim        HMODULE cryptui = LoadLibrary(TEXT("CRYPTUI.DLL"));
494280297Sjkim        HMODULE kernel = GetModuleHandle(TEXT("KERNEL32.DLL"));
495280297Sjkim        if (cryptui)
496280297Sjkim            ctx->certselectdlg =
497280297Sjkim                (CERTDLG) GetProcAddress(cryptui,
498280297Sjkim                                         "CryptUIDlgSelectCertificateFromStore");
499280297Sjkim        if (kernel)
500280297Sjkim            ctx->getconswindow =
501280297Sjkim                (GETCONSWIN) GetProcAddress(kernel, "GetConsoleWindow");
502280297Sjkim        if (cryptui && !OPENSSL_isservice())
503280297Sjkim            ctx->client_cert_select = cert_select_dialog;
504280297Sjkim    }
505280297Sjkim# endif
506183234Ssimon
507280297Sjkim    return 1;
508183234Ssimon
509280297Sjkim memerr:
510280297Sjkim    CAPIerr(CAPI_F_CAPI_INIT, ERR_R_MALLOC_FAILURE);
511280297Sjkim    return 0;
512183234Ssimon
513280297Sjkim    return 1;
514280297Sjkim}
515183234Ssimon
516183234Ssimonstatic int capi_destroy(ENGINE *e)
517280297Sjkim{
518280297Sjkim    ERR_unload_CAPI_strings();
519280297Sjkim    return 1;
520280297Sjkim}
521183234Ssimon
522183234Ssimonstatic int capi_finish(ENGINE *e)
523280297Sjkim{
524280297Sjkim    CAPI_CTX *ctx;
525280297Sjkim    ctx = ENGINE_get_ex_data(e, capi_idx);
526280297Sjkim    capi_ctx_free(ctx);
527280297Sjkim    ENGINE_set_ex_data(e, capi_idx, NULL);
528280297Sjkim    return 1;
529280297Sjkim}
530183234Ssimon
531280297Sjkim/*
532280297Sjkim * CryptoAPI key application data. This contains a handle to the private key
533280297Sjkim * container (for sign operations) and a handle to the key (for decrypt
534280297Sjkim * operations).
535183234Ssimon */
536183234Ssimon
537280297Sjkimstruct CAPI_KEY_st {
538280297Sjkim    /* Associated certificate context (if any) */
539280297Sjkim    PCCERT_CONTEXT pcert;
540280297Sjkim    HCRYPTPROV hprov;
541280297Sjkim    HCRYPTKEY key;
542280297Sjkim    DWORD keyspec;
543280297Sjkim};
544183234Ssimon
545183234Ssimonstatic int bind_capi(ENGINE *e)
546280297Sjkim{
547280297Sjkim    if (!ENGINE_set_id(e, engine_capi_id)
548280297Sjkim        || !ENGINE_set_name(e, engine_capi_name)
549280297Sjkim        || !ENGINE_set_flags(e, ENGINE_FLAGS_NO_REGISTER_ALL)
550280297Sjkim        || !ENGINE_set_init_function(e, capi_init)
551280297Sjkim        || !ENGINE_set_finish_function(e, capi_finish)
552280297Sjkim        || !ENGINE_set_destroy_function(e, capi_destroy)
553280297Sjkim        || !ENGINE_set_RSA(e, &capi_rsa_method)
554280297Sjkim        || !ENGINE_set_DSA(e, &capi_dsa_method)
555280297Sjkim        || !ENGINE_set_load_privkey_function(e, capi_load_privkey)
556280297Sjkim        || !ENGINE_set_load_ssl_client_cert_function(e,
557280297Sjkim                                                     capi_load_ssl_client_cert)
558280297Sjkim        || !ENGINE_set_cmd_defns(e, capi_cmd_defns)
559280297Sjkim        || !ENGINE_set_ctrl_function(e, capi_ctrl))
560280297Sjkim        return 0;
561280297Sjkim    ERR_load_CAPI_strings();
562183234Ssimon
563280297Sjkim    return 1;
564183234Ssimon
565280297Sjkim}
566183234Ssimon
567280297Sjkim# ifndef OPENSSL_NO_DYNAMIC_ENGINE
568183234Ssimonstatic int bind_helper(ENGINE *e, const char *id)
569280297Sjkim{
570280297Sjkim    if (id && (strcmp(id, engine_capi_id) != 0))
571280297Sjkim        return 0;
572280297Sjkim    if (!bind_capi(e))
573280297Sjkim        return 0;
574280297Sjkim    return 1;
575280297Sjkim}
576280297Sjkim
577183234SsimonIMPLEMENT_DYNAMIC_CHECK_FN()
578280297Sjkim    IMPLEMENT_DYNAMIC_BIND_FN(bind_helper)
579280297Sjkim# else
580183234Ssimonstatic ENGINE *engine_capi(void)
581280297Sjkim{
582280297Sjkim    ENGINE *ret = ENGINE_new();
583280297Sjkim    if (!ret)
584280297Sjkim        return NULL;
585280297Sjkim    if (!bind_capi(ret)) {
586280297Sjkim        ENGINE_free(ret);
587280297Sjkim        return NULL;
588280297Sjkim    }
589280297Sjkim    return ret;
590280297Sjkim}
591183234Ssimon
592183234Ssimonvoid ENGINE_load_capi(void)
593280297Sjkim{
594280297Sjkim    /* Copied from eng_[openssl|dyn].c */
595280297Sjkim    ENGINE *toadd = engine_capi();
596280297Sjkim    if (!toadd)
597280297Sjkim        return;
598280297Sjkim    ENGINE_add(toadd);
599280297Sjkim    ENGINE_free(toadd);
600280297Sjkim    ERR_clear_error();
601280297Sjkim}
602280297Sjkim# endif
603183234Ssimon
604183234Ssimonstatic int lend_tobn(BIGNUM *bn, unsigned char *bin, int binlen)
605280297Sjkim{
606280297Sjkim    int i;
607280297Sjkim    /*
608280297Sjkim     * Reverse buffer in place: since this is a keyblob structure that will
609280297Sjkim     * be freed up after conversion anyway it doesn't matter if we change
610280297Sjkim     * it.
611280297Sjkim     */
612280297Sjkim    for (i = 0; i < binlen / 2; i++) {
613280297Sjkim        unsigned char c;
614280297Sjkim        c = bin[i];
615280297Sjkim        bin[i] = bin[binlen - i - 1];
616280297Sjkim        bin[binlen - i - 1] = c;
617280297Sjkim    }
618183234Ssimon
619280297Sjkim    if (!BN_bin2bn(bin, binlen, bn))
620280297Sjkim        return 0;
621280297Sjkim    return 1;
622280297Sjkim}
623183234Ssimon
624183234Ssimon/* Given a CAPI_KEY get an EVP_PKEY structure */
625183234Ssimon
626280297Sjkimstatic EVP_PKEY *capi_get_pkey(ENGINE *eng, CAPI_KEY * key)
627280297Sjkim{
628280297Sjkim    unsigned char *pubkey = NULL;
629280297Sjkim    DWORD len;
630280297Sjkim    BLOBHEADER *bh;
631280297Sjkim    RSA *rkey = NULL;
632280297Sjkim    DSA *dkey = NULL;
633280297Sjkim    EVP_PKEY *ret = NULL;
634280297Sjkim    if (!CryptExportKey(key->key, 0, PUBLICKEYBLOB, 0, NULL, &len)) {
635280297Sjkim        CAPIerr(CAPI_F_CAPI_GET_PKEY, CAPI_R_PUBKEY_EXPORT_LENGTH_ERROR);
636280297Sjkim        capi_addlasterror();
637280297Sjkim        return NULL;
638280297Sjkim    }
639183234Ssimon
640280297Sjkim    pubkey = OPENSSL_malloc(len);
641183234Ssimon
642280297Sjkim    if (!pubkey)
643280297Sjkim        goto memerr;
644183234Ssimon
645280297Sjkim    if (!CryptExportKey(key->key, 0, PUBLICKEYBLOB, 0, pubkey, &len)) {
646280297Sjkim        CAPIerr(CAPI_F_CAPI_GET_PKEY, CAPI_R_PUBKEY_EXPORT_ERROR);
647280297Sjkim        capi_addlasterror();
648280297Sjkim        goto err;
649280297Sjkim    }
650183234Ssimon
651280297Sjkim    bh = (BLOBHEADER *) pubkey;
652280297Sjkim    if (bh->bType != PUBLICKEYBLOB) {
653280297Sjkim        CAPIerr(CAPI_F_CAPI_GET_PKEY, CAPI_R_INVALID_PUBLIC_KEY_BLOB);
654280297Sjkim        goto err;
655280297Sjkim    }
656280297Sjkim    if (bh->aiKeyAlg == CALG_RSA_SIGN || bh->aiKeyAlg == CALG_RSA_KEYX) {
657280297Sjkim        RSAPUBKEY *rp;
658280297Sjkim        DWORD rsa_modlen;
659280297Sjkim        unsigned char *rsa_modulus;
660280297Sjkim        rp = (RSAPUBKEY *) (bh + 1);
661280297Sjkim        if (rp->magic != 0x31415352) {
662280297Sjkim            char magstr[10];
663280297Sjkim            BIO_snprintf(magstr, 10, "%lx", rp->magic);
664280297Sjkim            CAPIerr(CAPI_F_CAPI_GET_PKEY,
665280297Sjkim                    CAPI_R_INVALID_RSA_PUBLIC_KEY_BLOB_MAGIC_NUMBER);
666280297Sjkim            ERR_add_error_data(2, "magic=0x", magstr);
667280297Sjkim            goto err;
668280297Sjkim        }
669280297Sjkim        rsa_modulus = (unsigned char *)(rp + 1);
670280297Sjkim        rkey = RSA_new_method(eng);
671280297Sjkim        if (!rkey)
672280297Sjkim            goto memerr;
673183234Ssimon
674280297Sjkim        rkey->e = BN_new();
675280297Sjkim        rkey->n = BN_new();
676183234Ssimon
677280297Sjkim        if (!rkey->e || !rkey->n)
678280297Sjkim            goto memerr;
679183234Ssimon
680280297Sjkim        if (!BN_set_word(rkey->e, rp->pubexp))
681280297Sjkim            goto memerr;
682183234Ssimon
683280297Sjkim        rsa_modlen = rp->bitlen / 8;
684280297Sjkim        if (!lend_tobn(rkey->n, rsa_modulus, rsa_modlen))
685280297Sjkim            goto memerr;
686183234Ssimon
687280297Sjkim        RSA_set_ex_data(rkey, rsa_capi_idx, key);
688183234Ssimon
689280297Sjkim        if (!(ret = EVP_PKEY_new()))
690280297Sjkim            goto memerr;
691183234Ssimon
692280297Sjkim        EVP_PKEY_assign_RSA(ret, rkey);
693280297Sjkim        rkey = NULL;
694183234Ssimon
695280297Sjkim    } else if (bh->aiKeyAlg == CALG_DSS_SIGN) {
696280297Sjkim        DSSPUBKEY *dp;
697280297Sjkim        DWORD dsa_plen;
698280297Sjkim        unsigned char *btmp;
699280297Sjkim        dp = (DSSPUBKEY *) (bh + 1);
700280297Sjkim        if (dp->magic != 0x31535344) {
701280297Sjkim            char magstr[10];
702280297Sjkim            BIO_snprintf(magstr, 10, "%lx", dp->magic);
703280297Sjkim            CAPIerr(CAPI_F_CAPI_GET_PKEY,
704280297Sjkim                    CAPI_R_INVALID_DSA_PUBLIC_KEY_BLOB_MAGIC_NUMBER);
705280297Sjkim            ERR_add_error_data(2, "magic=0x", magstr);
706280297Sjkim            goto err;
707280297Sjkim        }
708280297Sjkim        dsa_plen = dp->bitlen / 8;
709280297Sjkim        btmp = (unsigned char *)(dp + 1);
710280297Sjkim        dkey = DSA_new_method(eng);
711280297Sjkim        if (!dkey)
712280297Sjkim            goto memerr;
713280297Sjkim        dkey->p = BN_new();
714280297Sjkim        dkey->q = BN_new();
715280297Sjkim        dkey->g = BN_new();
716280297Sjkim        dkey->pub_key = BN_new();
717280297Sjkim        if (!dkey->p || !dkey->q || !dkey->g || !dkey->pub_key)
718280297Sjkim            goto memerr;
719280297Sjkim        if (!lend_tobn(dkey->p, btmp, dsa_plen))
720280297Sjkim            goto memerr;
721280297Sjkim        btmp += dsa_plen;
722280297Sjkim        if (!lend_tobn(dkey->q, btmp, 20))
723280297Sjkim            goto memerr;
724280297Sjkim        btmp += 20;
725280297Sjkim        if (!lend_tobn(dkey->g, btmp, dsa_plen))
726280297Sjkim            goto memerr;
727280297Sjkim        btmp += dsa_plen;
728280297Sjkim        if (!lend_tobn(dkey->pub_key, btmp, dsa_plen))
729280297Sjkim            goto memerr;
730280297Sjkim        btmp += dsa_plen;
731183234Ssimon
732280297Sjkim        DSA_set_ex_data(dkey, dsa_capi_idx, key);
733183234Ssimon
734280297Sjkim        if (!(ret = EVP_PKEY_new()))
735280297Sjkim            goto memerr;
736183234Ssimon
737280297Sjkim        EVP_PKEY_assign_DSA(ret, dkey);
738280297Sjkim        dkey = NULL;
739280297Sjkim    } else {
740280297Sjkim        char algstr[10];
741280297Sjkim        BIO_snprintf(algstr, 10, "%lx", bh->aiKeyAlg);
742280297Sjkim        CAPIerr(CAPI_F_CAPI_GET_PKEY,
743280297Sjkim                CAPI_R_UNSUPPORTED_PUBLIC_KEY_ALGORITHM);
744280297Sjkim        ERR_add_error_data(2, "aiKeyAlg=0x", algstr);
745280297Sjkim        goto err;
746280297Sjkim    }
747183234Ssimon
748280297Sjkim err:
749280297Sjkim    if (pubkey)
750280297Sjkim        OPENSSL_free(pubkey);
751280297Sjkim    if (!ret) {
752280297Sjkim        if (rkey)
753280297Sjkim            RSA_free(rkey);
754280297Sjkim        if (dkey)
755280297Sjkim            DSA_free(dkey);
756280297Sjkim    }
757183234Ssimon
758280297Sjkim    return ret;
759183234Ssimon
760280297Sjkim memerr:
761280297Sjkim    CAPIerr(CAPI_F_CAPI_GET_PKEY, ERR_R_MALLOC_FAILURE);
762280297Sjkim    goto err;
763183234Ssimon
764280297Sjkim}
765183234Ssimon
766183234Ssimonstatic EVP_PKEY *capi_load_privkey(ENGINE *eng, const char *key_id,
767280297Sjkim                                   UI_METHOD *ui_method, void *callback_data)
768280297Sjkim{
769280297Sjkim    CAPI_CTX *ctx;
770280297Sjkim    CAPI_KEY *key;
771280297Sjkim    EVP_PKEY *ret;
772280297Sjkim    ctx = ENGINE_get_ex_data(eng, capi_idx);
773183234Ssimon
774280297Sjkim    if (!ctx) {
775280297Sjkim        CAPIerr(CAPI_F_CAPI_LOAD_PRIVKEY, CAPI_R_CANT_FIND_CAPI_CONTEXT);
776280297Sjkim        return NULL;
777280297Sjkim    }
778183234Ssimon
779280297Sjkim    key = capi_find_key(ctx, key_id);
780183234Ssimon
781280297Sjkim    if (!key)
782280297Sjkim        return NULL;
783183234Ssimon
784280297Sjkim    ret = capi_get_pkey(eng, key);
785183234Ssimon
786280297Sjkim    if (!ret)
787280297Sjkim        capi_free_key(key);
788280297Sjkim    return ret;
789183234Ssimon
790280297Sjkim}
791183234Ssimon
792183234Ssimon/* CryptoAPI RSA operations */
793183234Ssimon
794183234Ssimonint capi_rsa_priv_enc(int flen, const unsigned char *from,
795280297Sjkim                      unsigned char *to, RSA *rsa, int padding)
796280297Sjkim{
797280297Sjkim    CAPIerr(CAPI_F_CAPI_RSA_PRIV_ENC, CAPI_R_FUNCTION_NOT_SUPPORTED);
798280297Sjkim    return -1;
799280297Sjkim}
800183234Ssimon
801183234Ssimonint capi_rsa_sign(int dtype, const unsigned char *m, unsigned int m_len,
802280297Sjkim                  unsigned char *sigret, unsigned int *siglen, const RSA *rsa)
803280297Sjkim{
804280297Sjkim    ALG_ID alg;
805280297Sjkim    HCRYPTHASH hash;
806280297Sjkim    DWORD slen;
807280297Sjkim    unsigned int i;
808280297Sjkim    int ret = -1;
809280297Sjkim    CAPI_KEY *capi_key;
810280297Sjkim    CAPI_CTX *ctx;
811183234Ssimon
812280297Sjkim    ctx = ENGINE_get_ex_data(rsa->engine, capi_idx);
813183234Ssimon
814280297Sjkim    CAPI_trace(ctx, "Called CAPI_rsa_sign()\n");
815183234Ssimon
816280297Sjkim    capi_key = RSA_get_ex_data(rsa, rsa_capi_idx);
817280297Sjkim    if (!capi_key) {
818280297Sjkim        CAPIerr(CAPI_F_CAPI_RSA_SIGN, CAPI_R_CANT_GET_KEY);
819280297Sjkim        return -1;
820280297Sjkim    }
821183234Ssimon/* Convert the signature type to a CryptoAPI algorithm ID */
822280297Sjkim    switch (dtype) {
823296279Sjkim    case NID_sha256:
824296279Sjkim        alg = CALG_SHA_256;
825296279Sjkim        break;
826296279Sjkim
827296279Sjkim    case NID_sha384:
828296279Sjkim        alg = CALG_SHA_384;
829296279Sjkim        break;
830296279Sjkim
831296279Sjkim    case NID_sha512:
832296279Sjkim        alg = CALG_SHA_512;
833296279Sjkim        break;
834296279Sjkim
835280297Sjkim    case NID_sha1:
836280297Sjkim        alg = CALG_SHA1;
837280297Sjkim        break;
838183234Ssimon
839280297Sjkim    case NID_md5:
840280297Sjkim        alg = CALG_MD5;
841280297Sjkim        break;
842183234Ssimon
843280297Sjkim    case NID_md5_sha1:
844280297Sjkim        alg = CALG_SSL3_SHAMD5;
845280297Sjkim        break;
846280297Sjkim    default:
847280297Sjkim        {
848280297Sjkim            char algstr[10];
849280297Sjkim            BIO_snprintf(algstr, 10, "%lx", dtype);
850280297Sjkim            CAPIerr(CAPI_F_CAPI_RSA_SIGN, CAPI_R_UNSUPPORTED_ALGORITHM_NID);
851280297Sjkim            ERR_add_error_data(2, "NID=0x", algstr);
852280297Sjkim            return -1;
853280297Sjkim        }
854280297Sjkim    }
855183234Ssimon
856183234Ssimon/* Create the hash object */
857280297Sjkim    if (!CryptCreateHash(capi_key->hprov, alg, 0, 0, &hash)) {
858280297Sjkim        CAPIerr(CAPI_F_CAPI_RSA_SIGN, CAPI_R_CANT_CREATE_HASH_OBJECT);
859280297Sjkim        capi_addlasterror();
860280297Sjkim        return -1;
861280297Sjkim    }
862183234Ssimon/* Set the hash value to the value passed */
863183234Ssimon
864280297Sjkim    if (!CryptSetHashParam(hash, HP_HASHVAL, (unsigned char *)m, 0)) {
865280297Sjkim        CAPIerr(CAPI_F_CAPI_RSA_SIGN, CAPI_R_CANT_SET_HASH_VALUE);
866280297Sjkim        capi_addlasterror();
867280297Sjkim        goto err;
868280297Sjkim    }
869183234Ssimon
870183234Ssimon/* Finally sign it */
871280297Sjkim    slen = RSA_size(rsa);
872290207Sjkim    if (!CryptSignHash(hash, capi_key->keyspec, NULL, 0, sigret, &slen)) {
873280297Sjkim        CAPIerr(CAPI_F_CAPI_RSA_SIGN, CAPI_R_ERROR_SIGNING_HASH);
874280297Sjkim        capi_addlasterror();
875280297Sjkim        goto err;
876280297Sjkim    } else {
877280297Sjkim        ret = 1;
878280297Sjkim        /* Inplace byte reversal of signature */
879280297Sjkim        for (i = 0; i < slen / 2; i++) {
880280297Sjkim            unsigned char c;
881280297Sjkim            c = sigret[i];
882280297Sjkim            sigret[i] = sigret[slen - i - 1];
883280297Sjkim            sigret[slen - i - 1] = c;
884280297Sjkim        }
885280297Sjkim        *siglen = slen;
886280297Sjkim    }
887183234Ssimon
888280297Sjkim    /* Now cleanup */
889183234Ssimon
890280297Sjkim err:
891280297Sjkim    CryptDestroyHash(hash);
892183234Ssimon
893280297Sjkim    return ret;
894280297Sjkim}
895183234Ssimon
896183234Ssimonint capi_rsa_priv_dec(int flen, const unsigned char *from,
897280297Sjkim                      unsigned char *to, RSA *rsa, int padding)
898280297Sjkim{
899280297Sjkim    int i;
900280297Sjkim    unsigned char *tmpbuf;
901280297Sjkim    CAPI_KEY *capi_key;
902280297Sjkim    CAPI_CTX *ctx;
903340704Sjkim    DWORD flags = 0;
904340704Sjkim
905280297Sjkim    ctx = ENGINE_get_ex_data(rsa->engine, capi_idx);
906183234Ssimon
907280297Sjkim    CAPI_trace(ctx, "Called capi_rsa_priv_dec()\n");
908183234Ssimon
909280297Sjkim    capi_key = RSA_get_ex_data(rsa, rsa_capi_idx);
910280297Sjkim    if (!capi_key) {
911280297Sjkim        CAPIerr(CAPI_F_CAPI_RSA_PRIV_DEC, CAPI_R_CANT_GET_KEY);
912280297Sjkim        return -1;
913280297Sjkim    }
914183234Ssimon
915340704Sjkim    switch (padding) {
916340704Sjkim    case RSA_PKCS1_PADDING:
917340704Sjkim        /* Nothing to do */
918340704Sjkim        break;
919340704Sjkim#ifdef CRYPT_DECRYPT_RSA_NO_PADDING_CHECK
920340704Sjkim    case RSA_NO_PADDING:
921340704Sjkim        flags = CRYPT_DECRYPT_RSA_NO_PADDING_CHECK;
922340704Sjkim        break;
923340704Sjkim#endif
924340704Sjkim    default:
925340704Sjkim        {
926340704Sjkim            char errstr[10];
927340704Sjkim            BIO_snprintf(errstr, 10, "%d", padding);
928340704Sjkim            CAPIerr(CAPI_F_CAPI_RSA_PRIV_DEC, CAPI_R_UNSUPPORTED_PADDING);
929340704Sjkim            ERR_add_error_data(2, "padding=", errstr);
930340704Sjkim            return -1;
931340704Sjkim        }
932280297Sjkim    }
933183234Ssimon
934280297Sjkim    /* Create temp reverse order version of input */
935280297Sjkim    if (!(tmpbuf = OPENSSL_malloc(flen))) {
936280297Sjkim        CAPIerr(CAPI_F_CAPI_RSA_PRIV_DEC, ERR_R_MALLOC_FAILURE);
937280297Sjkim        return -1;
938280297Sjkim    }
939280297Sjkim    for (i = 0; i < flen; i++)
940280297Sjkim        tmpbuf[flen - i - 1] = from[i];
941183234Ssimon
942280297Sjkim    /* Finally decrypt it */
943340704Sjkim    if (!CryptDecrypt(capi_key->key, 0, TRUE, flags, tmpbuf, &flen)) {
944280297Sjkim        CAPIerr(CAPI_F_CAPI_RSA_PRIV_DEC, CAPI_R_DECRYPT_ERROR);
945280297Sjkim        capi_addlasterror();
946340704Sjkim        OPENSSL_cleanse(tmpbuf, flen);
947280297Sjkim        OPENSSL_free(tmpbuf);
948280297Sjkim        return -1;
949340704Sjkim    } else {
950280297Sjkim        memcpy(to, tmpbuf, flen);
951340704Sjkim    }
952183234Ssimon
953340704Sjkim    OPENSSL_cleanse(tmpbuf, flen);
954280297Sjkim    OPENSSL_free(tmpbuf);
955183234Ssimon
956280297Sjkim    return flen;
957280297Sjkim}
958183234Ssimon
959183234Ssimonstatic int capi_rsa_free(RSA *rsa)
960280297Sjkim{
961280297Sjkim    CAPI_KEY *capi_key;
962280297Sjkim    capi_key = RSA_get_ex_data(rsa, rsa_capi_idx);
963280297Sjkim    capi_free_key(capi_key);
964280297Sjkim    RSA_set_ex_data(rsa, rsa_capi_idx, 0);
965280297Sjkim    return 1;
966280297Sjkim}
967183234Ssimon
968183234Ssimon/* CryptoAPI DSA operations */
969183234Ssimon
970183234Ssimonstatic DSA_SIG *capi_dsa_do_sign(const unsigned char *digest, int dlen,
971280297Sjkim                                 DSA *dsa)
972280297Sjkim{
973280297Sjkim    HCRYPTHASH hash;
974280297Sjkim    DWORD slen;
975280297Sjkim    DSA_SIG *ret = NULL;
976280297Sjkim    CAPI_KEY *capi_key;
977280297Sjkim    CAPI_CTX *ctx;
978280297Sjkim    unsigned char csigbuf[40];
979183234Ssimon
980280297Sjkim    ctx = ENGINE_get_ex_data(dsa->engine, capi_idx);
981183234Ssimon
982280297Sjkim    CAPI_trace(ctx, "Called CAPI_dsa_do_sign()\n");
983183234Ssimon
984280297Sjkim    capi_key = DSA_get_ex_data(dsa, dsa_capi_idx);
985183234Ssimon
986280297Sjkim    if (!capi_key) {
987280297Sjkim        CAPIerr(CAPI_F_CAPI_DSA_DO_SIGN, CAPI_R_CANT_GET_KEY);
988280297Sjkim        return NULL;
989280297Sjkim    }
990183234Ssimon
991280297Sjkim    if (dlen != 20) {
992280297Sjkim        CAPIerr(CAPI_F_CAPI_DSA_DO_SIGN, CAPI_R_INVALID_DIGEST_LENGTH);
993280297Sjkim        return NULL;
994280297Sjkim    }
995183234Ssimon
996280297Sjkim    /* Create the hash object */
997280297Sjkim    if (!CryptCreateHash(capi_key->hprov, CALG_SHA1, 0, 0, &hash)) {
998280297Sjkim        CAPIerr(CAPI_F_CAPI_DSA_DO_SIGN, CAPI_R_CANT_CREATE_HASH_OBJECT);
999280297Sjkim        capi_addlasterror();
1000280297Sjkim        return NULL;
1001280297Sjkim    }
1002183234Ssimon
1003280297Sjkim    /* Set the hash value to the value passed */
1004280297Sjkim    if (!CryptSetHashParam(hash, HP_HASHVAL, (unsigned char *)digest, 0)) {
1005280297Sjkim        CAPIerr(CAPI_F_CAPI_DSA_DO_SIGN, CAPI_R_CANT_SET_HASH_VALUE);
1006280297Sjkim        capi_addlasterror();
1007280297Sjkim        goto err;
1008280297Sjkim    }
1009183234Ssimon
1010280297Sjkim    /* Finally sign it */
1011280297Sjkim    slen = sizeof(csigbuf);
1012290207Sjkim    if (!CryptSignHash(hash, capi_key->keyspec, NULL, 0, csigbuf, &slen)) {
1013280297Sjkim        CAPIerr(CAPI_F_CAPI_DSA_DO_SIGN, CAPI_R_ERROR_SIGNING_HASH);
1014280297Sjkim        capi_addlasterror();
1015280297Sjkim        goto err;
1016280297Sjkim    } else {
1017280297Sjkim        ret = DSA_SIG_new();
1018280297Sjkim        if (!ret)
1019280297Sjkim            goto err;
1020280297Sjkim        ret->r = BN_new();
1021280297Sjkim        ret->s = BN_new();
1022280297Sjkim        if (!ret->r || !ret->s)
1023280297Sjkim            goto err;
1024280297Sjkim        if (!lend_tobn(ret->r, csigbuf, 20)
1025280297Sjkim            || !lend_tobn(ret->s, csigbuf + 20, 20)) {
1026280297Sjkim            DSA_SIG_free(ret);
1027280297Sjkim            ret = NULL;
1028280297Sjkim            goto err;
1029280297Sjkim        }
1030280297Sjkim    }
1031183234Ssimon
1032280297Sjkim    /* Now cleanup */
1033183234Ssimon
1034280297Sjkim err:
1035280297Sjkim    OPENSSL_cleanse(csigbuf, 40);
1036280297Sjkim    CryptDestroyHash(hash);
1037280297Sjkim    return ret;
1038280297Sjkim}
1039183234Ssimon
1040183234Ssimonstatic int capi_dsa_free(DSA *dsa)
1041280297Sjkim{
1042280297Sjkim    CAPI_KEY *capi_key;
1043280297Sjkim    capi_key = DSA_get_ex_data(dsa, dsa_capi_idx);
1044280297Sjkim    capi_free_key(capi_key);
1045280297Sjkim    DSA_set_ex_data(dsa, dsa_capi_idx, 0);
1046280297Sjkim    return 1;
1047280297Sjkim}
1048183234Ssimon
1049280297Sjkimstatic void capi_vtrace(CAPI_CTX * ctx, int level, char *format,
1050280297Sjkim                        va_list argptr)
1051280297Sjkim{
1052280297Sjkim    BIO *out;
1053183234Ssimon
1054280297Sjkim    if (!ctx || (ctx->debug_level < level) || (!ctx->debug_file))
1055280297Sjkim        return;
1056280297Sjkim    out = BIO_new_file(ctx->debug_file, "a+");
1057280297Sjkim    BIO_vprintf(out, format, argptr);
1058280297Sjkim    BIO_free(out);
1059280297Sjkim}
1060183234Ssimon
1061280297Sjkimstatic void CAPI_trace(CAPI_CTX * ctx, char *format, ...)
1062280297Sjkim{
1063280297Sjkim    va_list args;
1064280297Sjkim    va_start(args, format);
1065280297Sjkim    capi_vtrace(ctx, CAPI_DBG_TRACE, format, args);
1066280297Sjkim    va_end(args);
1067280297Sjkim}
1068183234Ssimon
1069183234Ssimonstatic void capi_addlasterror(void)
1070280297Sjkim{
1071280297Sjkim    capi_adderror(GetLastError());
1072280297Sjkim}
1073183234Ssimon
1074183234Ssimonstatic void capi_adderror(DWORD err)
1075280297Sjkim{
1076280297Sjkim    char errstr[10];
1077280297Sjkim    BIO_snprintf(errstr, 10, "%lX", err);
1078280297Sjkim    ERR_add_error_data(2, "Error code= 0x", errstr);
1079280297Sjkim}
1080183234Ssimon
1081290207Sjkimstatic char *wide_to_asc(LPCWSTR wstr)
1082280297Sjkim{
1083280297Sjkim    char *str;
1084280297Sjkim    int len_0, sz;
1085205128Ssimon
1086280297Sjkim    if (!wstr)
1087280297Sjkim        return NULL;
1088280297Sjkim    len_0 = (int)wcslen(wstr) + 1; /* WideCharToMultiByte expects int */
1089280297Sjkim    sz = WideCharToMultiByte(CP_ACP, 0, wstr, len_0, NULL, 0, NULL, NULL);
1090280297Sjkim    if (!sz) {
1091280297Sjkim        CAPIerr(CAPI_F_WIDE_TO_ASC, CAPI_R_WIN32_ERROR);
1092280297Sjkim        return NULL;
1093280297Sjkim    }
1094280297Sjkim    str = OPENSSL_malloc(sz);
1095280297Sjkim    if (!str) {
1096280297Sjkim        CAPIerr(CAPI_F_WIDE_TO_ASC, ERR_R_MALLOC_FAILURE);
1097280297Sjkim        return NULL;
1098280297Sjkim    }
1099280297Sjkim    if (!WideCharToMultiByte(CP_ACP, 0, wstr, len_0, str, sz, NULL, NULL)) {
1100280297Sjkim        OPENSSL_free(str);
1101280297Sjkim        CAPIerr(CAPI_F_WIDE_TO_ASC, CAPI_R_WIN32_ERROR);
1102280297Sjkim        return NULL;
1103280297Sjkim    }
1104280297Sjkim    return str;
1105280297Sjkim}
1106183234Ssimon
1107280297Sjkimstatic int capi_get_provname(CAPI_CTX * ctx, LPSTR * pname, DWORD * ptype,
1108280297Sjkim                             DWORD idx)
1109280297Sjkim{
1110280297Sjkim    DWORD len, err;
1111290207Sjkim    LPTSTR name;
1112280297Sjkim    CAPI_trace(ctx, "capi_get_provname, index=%d\n", idx);
1113290207Sjkim    if (!CryptEnumProviders(idx, NULL, 0, ptype, NULL, &len)) {
1114280297Sjkim        err = GetLastError();
1115280297Sjkim        if (err == ERROR_NO_MORE_ITEMS)
1116280297Sjkim            return 2;
1117280297Sjkim        CAPIerr(CAPI_F_CAPI_GET_PROVNAME, CAPI_R_CRYPTENUMPROVIDERS_ERROR);
1118280297Sjkim        capi_adderror(err);
1119280297Sjkim        return 0;
1120280297Sjkim    }
1121290207Sjkim    if (sizeof(TCHAR) != sizeof(char))
1122290207Sjkim        name = alloca(len);
1123290207Sjkim    else
1124290207Sjkim        name = OPENSSL_malloc(len);
1125306195Sjkim    if (name == NULL) {
1126306195Sjkim        CAPIerr(CAPI_F_CAPI_GET_PROVNAME, ERR_R_MALLOC_FAILURE);
1127306195Sjkim        return 0;
1128306195Sjkim    }
1129290207Sjkim    if (!CryptEnumProviders(idx, NULL, 0, ptype, name, &len)) {
1130280297Sjkim        err = GetLastError();
1131280297Sjkim        if (err == ERROR_NO_MORE_ITEMS)
1132280297Sjkim            return 2;
1133280297Sjkim        CAPIerr(CAPI_F_CAPI_GET_PROVNAME, CAPI_R_CRYPTENUMPROVIDERS_ERROR);
1134280297Sjkim        capi_adderror(err);
1135280297Sjkim        return 0;
1136280297Sjkim    }
1137290207Sjkim    if (sizeof(TCHAR) != sizeof(char))
1138290207Sjkim        *pname = wide_to_asc((WCHAR *)name);
1139290207Sjkim    else
1140290207Sjkim        *pname = (char *)name;
1141290207Sjkim    CAPI_trace(ctx, "capi_get_provname, returned name=%s, type=%d\n", *pname,
1142280297Sjkim               *ptype);
1143183234Ssimon
1144280297Sjkim    return 1;
1145280297Sjkim}
1146183234Ssimon
1147280297Sjkimstatic int capi_list_providers(CAPI_CTX * ctx, BIO *out)
1148280297Sjkim{
1149280297Sjkim    DWORD idx, ptype;
1150280297Sjkim    int ret;
1151280297Sjkim    LPSTR provname = NULL;
1152280297Sjkim    CAPI_trace(ctx, "capi_list_providers\n");
1153280297Sjkim    BIO_printf(out, "Available CSPs:\n");
1154280297Sjkim    for (idx = 0;; idx++) {
1155280297Sjkim        ret = capi_get_provname(ctx, &provname, &ptype, idx);
1156280297Sjkim        if (ret == 2)
1157280297Sjkim            break;
1158280297Sjkim        if (ret == 0)
1159280297Sjkim            break;
1160280297Sjkim        BIO_printf(out, "%d. %s, type %d\n", idx, provname, ptype);
1161280297Sjkim        OPENSSL_free(provname);
1162280297Sjkim    }
1163280297Sjkim    return 1;
1164280297Sjkim}
1165183234Ssimon
1166280297Sjkimstatic int capi_list_containers(CAPI_CTX * ctx, BIO *out)
1167280297Sjkim{
1168280297Sjkim    int ret = 1;
1169280297Sjkim    HCRYPTPROV hprov;
1170280297Sjkim    DWORD err, idx, flags, buflen = 0, clen;
1171280297Sjkim    LPSTR cname;
1172290207Sjkim    LPTSTR cspname = NULL;
1173290207Sjkim
1174280297Sjkim    CAPI_trace(ctx, "Listing containers CSP=%s, type = %d\n", ctx->cspname,
1175280297Sjkim               ctx->csptype);
1176290207Sjkim    if (ctx->cspname && sizeof(TCHAR) != sizeof(char)) {
1177290207Sjkim        if ((clen =
1178290207Sjkim             MultiByteToWideChar(CP_ACP, 0, ctx->cspname, -1, NULL, 0))) {
1179290207Sjkim            cspname = alloca(clen * sizeof(WCHAR));
1180290207Sjkim            MultiByteToWideChar(CP_ACP, 0, ctx->cspname, -1, (WCHAR *)cspname,
1181290207Sjkim                                clen);
1182290207Sjkim        }
1183290207Sjkim        if (!cspname) {
1184290207Sjkim            CAPIerr(CAPI_F_CAPI_LIST_CONTAINERS, ERR_R_MALLOC_FAILURE);
1185290207Sjkim            capi_addlasterror();
1186290207Sjkim            return 0;
1187290207Sjkim        }
1188290207Sjkim    } else
1189290207Sjkim        cspname = (TCHAR *)ctx->cspname;
1190290207Sjkim    if (!CryptAcquireContext
1191290207Sjkim        (&hprov, NULL, cspname, ctx->csptype, CRYPT_VERIFYCONTEXT)) {
1192280297Sjkim        CAPIerr(CAPI_F_CAPI_LIST_CONTAINERS,
1193280297Sjkim                CAPI_R_CRYPTACQUIRECONTEXT_ERROR);
1194280297Sjkim        capi_addlasterror();
1195280297Sjkim        return 0;
1196280297Sjkim    }
1197280297Sjkim    if (!CryptGetProvParam
1198280297Sjkim        (hprov, PP_ENUMCONTAINERS, NULL, &buflen, CRYPT_FIRST)) {
1199280297Sjkim        CAPIerr(CAPI_F_CAPI_LIST_CONTAINERS, CAPI_R_ENUMCONTAINERS_ERROR);
1200280297Sjkim        capi_addlasterror();
1201280297Sjkim        CryptReleaseContext(hprov, 0);
1202280297Sjkim        return 0;
1203280297Sjkim    }
1204280297Sjkim    CAPI_trace(ctx, "Got max container len %d\n", buflen);
1205280297Sjkim    if (buflen == 0)
1206280297Sjkim        buflen = 1024;
1207280297Sjkim    cname = OPENSSL_malloc(buflen);
1208280297Sjkim    if (!cname) {
1209280297Sjkim        CAPIerr(CAPI_F_CAPI_LIST_CONTAINERS, ERR_R_MALLOC_FAILURE);
1210280297Sjkim        goto err;
1211280297Sjkim    }
1212183234Ssimon
1213280297Sjkim    for (idx = 0;; idx++) {
1214280297Sjkim        clen = buflen;
1215280297Sjkim        cname[0] = 0;
1216183234Ssimon
1217280297Sjkim        if (idx == 0)
1218280297Sjkim            flags = CRYPT_FIRST;
1219280297Sjkim        else
1220280297Sjkim            flags = 0;
1221290207Sjkim        if (!CryptGetProvParam
1222290207Sjkim            (hprov, PP_ENUMCONTAINERS, (BYTE *) cname, &clen, flags)) {
1223280297Sjkim            err = GetLastError();
1224280297Sjkim            if (err == ERROR_NO_MORE_ITEMS)
1225280297Sjkim                goto done;
1226280297Sjkim            CAPIerr(CAPI_F_CAPI_LIST_CONTAINERS, CAPI_R_ENUMCONTAINERS_ERROR);
1227280297Sjkim            capi_adderror(err);
1228280297Sjkim            goto err;
1229280297Sjkim        }
1230280297Sjkim        CAPI_trace(ctx, "Container name %s, len=%d, index=%d, flags=%d\n",
1231280297Sjkim                   cname, clen, idx, flags);
1232280297Sjkim        if (!cname[0] && (clen == buflen)) {
1233280297Sjkim            CAPI_trace(ctx, "Enumerate bug: using workaround\n");
1234280297Sjkim            goto done;
1235280297Sjkim        }
1236280297Sjkim        BIO_printf(out, "%d. %s\n", idx, cname);
1237280297Sjkim    }
1238280297Sjkim err:
1239183234Ssimon
1240280297Sjkim    ret = 0;
1241183234Ssimon
1242280297Sjkim done:
1243280297Sjkim    if (cname)
1244280297Sjkim        OPENSSL_free(cname);
1245280297Sjkim    CryptReleaseContext(hprov, 0);
1246183234Ssimon
1247280297Sjkim    return ret;
1248280297Sjkim}
1249183234Ssimon
1250280297SjkimCRYPT_KEY_PROV_INFO *capi_get_prov_info(CAPI_CTX * ctx, PCCERT_CONTEXT cert)
1251280297Sjkim{
1252280297Sjkim    DWORD len;
1253280297Sjkim    CRYPT_KEY_PROV_INFO *pinfo;
1254183234Ssimon
1255280297Sjkim    if (!CertGetCertificateContextProperty
1256280297Sjkim        (cert, CERT_KEY_PROV_INFO_PROP_ID, NULL, &len))
1257280297Sjkim        return NULL;
1258280297Sjkim    pinfo = OPENSSL_malloc(len);
1259280297Sjkim    if (!pinfo) {
1260280297Sjkim        CAPIerr(CAPI_F_CAPI_GET_PROV_INFO, ERR_R_MALLOC_FAILURE);
1261280297Sjkim        return NULL;
1262280297Sjkim    }
1263280297Sjkim    if (!CertGetCertificateContextProperty
1264280297Sjkim        (cert, CERT_KEY_PROV_INFO_PROP_ID, pinfo, &len)) {
1265280297Sjkim        CAPIerr(CAPI_F_CAPI_GET_PROV_INFO,
1266280297Sjkim                CAPI_R_ERROR_GETTING_KEY_PROVIDER_INFO);
1267280297Sjkim        capi_addlasterror();
1268280297Sjkim        OPENSSL_free(pinfo);
1269280297Sjkim        return NULL;
1270280297Sjkim    }
1271280297Sjkim    return pinfo;
1272280297Sjkim}
1273183234Ssimon
1274280297Sjkimstatic void capi_dump_prov_info(CAPI_CTX * ctx, BIO *out,
1275280297Sjkim                                CRYPT_KEY_PROV_INFO * pinfo)
1276280297Sjkim{
1277280297Sjkim    char *provname = NULL, *contname = NULL;
1278280297Sjkim    if (!pinfo) {
1279280297Sjkim        BIO_printf(out, "  No Private Key\n");
1280280297Sjkim        return;
1281280297Sjkim    }
1282280297Sjkim    provname = wide_to_asc(pinfo->pwszProvName);
1283280297Sjkim    contname = wide_to_asc(pinfo->pwszContainerName);
1284280297Sjkim    if (!provname || !contname)
1285280297Sjkim        goto err;
1286183234Ssimon
1287280297Sjkim    BIO_printf(out, "  Private Key Info:\n");
1288280297Sjkim    BIO_printf(out, "    Provider Name:  %s, Provider Type %d\n", provname,
1289280297Sjkim               pinfo->dwProvType);
1290280297Sjkim    BIO_printf(out, "    Container Name: %s, Key Type %d\n", contname,
1291280297Sjkim               pinfo->dwKeySpec);
1292280297Sjkim err:
1293280297Sjkim    if (provname)
1294280297Sjkim        OPENSSL_free(provname);
1295280297Sjkim    if (contname)
1296280297Sjkim        OPENSSL_free(contname);
1297280297Sjkim}
1298183234Ssimon
1299280297Sjkimchar *capi_cert_get_fname(CAPI_CTX * ctx, PCCERT_CONTEXT cert)
1300280297Sjkim{
1301280297Sjkim    LPWSTR wfname;
1302280297Sjkim    DWORD dlen;
1303183234Ssimon
1304280297Sjkim    CAPI_trace(ctx, "capi_cert_get_fname\n");
1305280297Sjkim    if (!CertGetCertificateContextProperty
1306280297Sjkim        (cert, CERT_FRIENDLY_NAME_PROP_ID, NULL, &dlen))
1307280297Sjkim        return NULL;
1308280297Sjkim    wfname = OPENSSL_malloc(dlen);
1309306195Sjkim    if (wfname == NULL) {
1310306195Sjkim        CAPIerr(CAPI_F_CAPI_CERT_GET_FNAME, ERR_R_MALLOC_FAILURE);
1311306195Sjkim        return NULL;
1312306195Sjkim    }
1313280297Sjkim    if (CertGetCertificateContextProperty
1314280297Sjkim        (cert, CERT_FRIENDLY_NAME_PROP_ID, wfname, &dlen)) {
1315280297Sjkim        char *fname = wide_to_asc(wfname);
1316280297Sjkim        OPENSSL_free(wfname);
1317280297Sjkim        return fname;
1318280297Sjkim    }
1319280297Sjkim    CAPIerr(CAPI_F_CAPI_CERT_GET_FNAME, CAPI_R_ERROR_GETTING_FRIENDLY_NAME);
1320280297Sjkim    capi_addlasterror();
1321183234Ssimon
1322280297Sjkim    OPENSSL_free(wfname);
1323280297Sjkim    return NULL;
1324280297Sjkim}
1325183234Ssimon
1326280297Sjkimvoid capi_dump_cert(CAPI_CTX * ctx, BIO *out, PCCERT_CONTEXT cert)
1327280297Sjkim{
1328280297Sjkim    X509 *x;
1329280297Sjkim    unsigned char *p;
1330280297Sjkim    unsigned long flags = ctx->dump_flags;
1331280297Sjkim    if (flags & CAPI_DMP_FNAME) {
1332280297Sjkim        char *fname;
1333280297Sjkim        fname = capi_cert_get_fname(ctx, cert);
1334280297Sjkim        if (fname) {
1335280297Sjkim            BIO_printf(out, "  Friendly Name \"%s\"\n", fname);
1336280297Sjkim            OPENSSL_free(fname);
1337280297Sjkim        } else
1338280297Sjkim            BIO_printf(out, "  <No Friendly Name>\n");
1339280297Sjkim    }
1340183234Ssimon
1341280297Sjkim    p = cert->pbCertEncoded;
1342280297Sjkim    x = d2i_X509(NULL, &p, cert->cbCertEncoded);
1343280297Sjkim    if (!x)
1344280297Sjkim        BIO_printf(out, "  <Can't parse certificate>\n");
1345280297Sjkim    if (flags & CAPI_DMP_SUMMARY) {
1346280297Sjkim        BIO_printf(out, "  Subject: ");
1347280297Sjkim        X509_NAME_print_ex(out, X509_get_subject_name(x), 0, XN_FLAG_ONELINE);
1348280297Sjkim        BIO_printf(out, "\n  Issuer: ");
1349280297Sjkim        X509_NAME_print_ex(out, X509_get_issuer_name(x), 0, XN_FLAG_ONELINE);
1350280297Sjkim        BIO_printf(out, "\n");
1351280297Sjkim    }
1352280297Sjkim    if (flags & CAPI_DMP_FULL)
1353280297Sjkim        X509_print_ex(out, x, XN_FLAG_ONELINE, 0);
1354183234Ssimon
1355280297Sjkim    if (flags & CAPI_DMP_PKEYINFO) {
1356280297Sjkim        CRYPT_KEY_PROV_INFO *pinfo;
1357280297Sjkim        pinfo = capi_get_prov_info(ctx, cert);
1358280297Sjkim        capi_dump_prov_info(ctx, out, pinfo);
1359280297Sjkim        if (pinfo)
1360280297Sjkim            OPENSSL_free(pinfo);
1361280297Sjkim    }
1362183234Ssimon
1363280297Sjkim    if (flags & CAPI_DMP_PEM)
1364280297Sjkim        PEM_write_bio_X509(out, x);
1365280297Sjkim    X509_free(x);
1366280297Sjkim}
1367183234Ssimon
1368280297SjkimHCERTSTORE capi_open_store(CAPI_CTX * ctx, char *storename)
1369280297Sjkim{
1370280297Sjkim    HCERTSTORE hstore;
1371183234Ssimon
1372280297Sjkim    if (!storename)
1373280297Sjkim        storename = ctx->storename;
1374280297Sjkim    if (!storename)
1375280297Sjkim        storename = "MY";
1376280297Sjkim    CAPI_trace(ctx, "Opening certificate store %s\n", storename);
1377183234Ssimon
1378280297Sjkim    hstore = CertOpenStore(CERT_STORE_PROV_SYSTEM_A, 0, 0,
1379280297Sjkim                           ctx->store_flags, storename);
1380280297Sjkim    if (!hstore) {
1381280297Sjkim        CAPIerr(CAPI_F_CAPI_OPEN_STORE, CAPI_R_ERROR_OPENING_STORE);
1382280297Sjkim        capi_addlasterror();
1383280297Sjkim    }
1384280297Sjkim    return hstore;
1385280297Sjkim}
1386183234Ssimon
1387280297Sjkimint capi_list_certs(CAPI_CTX * ctx, BIO *out, char *id)
1388280297Sjkim{
1389280297Sjkim    char *storename;
1390280297Sjkim    int idx;
1391280297Sjkim    int ret = 1;
1392280297Sjkim    HCERTSTORE hstore;
1393280297Sjkim    PCCERT_CONTEXT cert = NULL;
1394183234Ssimon
1395280297Sjkim    storename = ctx->storename;
1396280297Sjkim    if (!storename)
1397280297Sjkim        storename = "MY";
1398280297Sjkim    CAPI_trace(ctx, "Listing certs for store %s\n", storename);
1399183234Ssimon
1400280297Sjkim    hstore = capi_open_store(ctx, storename);
1401280297Sjkim    if (!hstore)
1402280297Sjkim        return 0;
1403280297Sjkim    if (id) {
1404280297Sjkim        cert = capi_find_cert(ctx, id, hstore);
1405280297Sjkim        if (!cert) {
1406280297Sjkim            ret = 0;
1407280297Sjkim            goto err;
1408280297Sjkim        }
1409280297Sjkim        capi_dump_cert(ctx, out, cert);
1410280297Sjkim        CertFreeCertificateContext(cert);
1411280297Sjkim    } else {
1412280297Sjkim        for (idx = 0;; idx++) {
1413280297Sjkim            cert = CertEnumCertificatesInStore(hstore, cert);
1414280297Sjkim            if (!cert)
1415280297Sjkim                break;
1416280297Sjkim            BIO_printf(out, "Certificate %d\n", idx);
1417280297Sjkim            capi_dump_cert(ctx, out, cert);
1418280297Sjkim        }
1419280297Sjkim    }
1420280297Sjkim err:
1421280297Sjkim    CertCloseStore(hstore, 0);
1422280297Sjkim    return ret;
1423280297Sjkim}
1424183234Ssimon
1425280297Sjkimstatic PCCERT_CONTEXT capi_find_cert(CAPI_CTX * ctx, const char *id,
1426280297Sjkim                                     HCERTSTORE hstore)
1427280297Sjkim{
1428280297Sjkim    PCCERT_CONTEXT cert = NULL;
1429280297Sjkim    char *fname = NULL;
1430280297Sjkim    int match;
1431280297Sjkim    switch (ctx->lookup_method) {
1432280297Sjkim    case CAPI_LU_SUBSTR:
1433280297Sjkim        return CertFindCertificateInStore(hstore,
1434280297Sjkim                                          X509_ASN_ENCODING, 0,
1435280297Sjkim                                          CERT_FIND_SUBJECT_STR_A, id, NULL);
1436280297Sjkim    case CAPI_LU_FNAME:
1437280297Sjkim        for (;;) {
1438280297Sjkim            cert = CertEnumCertificatesInStore(hstore, cert);
1439280297Sjkim            if (!cert)
1440280297Sjkim                return NULL;
1441280297Sjkim            fname = capi_cert_get_fname(ctx, cert);
1442280297Sjkim            if (fname) {
1443280297Sjkim                if (strcmp(fname, id))
1444280297Sjkim                    match = 0;
1445280297Sjkim                else
1446280297Sjkim                    match = 1;
1447280297Sjkim                OPENSSL_free(fname);
1448280297Sjkim                if (match)
1449280297Sjkim                    return cert;
1450280297Sjkim            }
1451280297Sjkim        }
1452280297Sjkim    default:
1453280297Sjkim        return NULL;
1454280297Sjkim    }
1455280297Sjkim}
1456183234Ssimon
1457290207Sjkimstatic CAPI_KEY *capi_get_key(CAPI_CTX * ctx, const TCHAR *contname,
1458290207Sjkim                              TCHAR *provname, DWORD ptype, DWORD keyspec)
1459280297Sjkim{
1460280297Sjkim    CAPI_KEY *key;
1461280297Sjkim    DWORD dwFlags = 0;
1462280297Sjkim    key = OPENSSL_malloc(sizeof(CAPI_KEY));
1463306195Sjkim    if (key == NULL) {
1464306195Sjkim        CAPIerr(CAPI_F_CAPI_GET_KEY, ERR_R_MALLOC_FAILURE);
1465306195Sjkim        capi_addlasterror();
1466306195Sjkim        goto err;
1467306195Sjkim    }
1468290207Sjkim    if (sizeof(TCHAR) == sizeof(char))
1469290207Sjkim        CAPI_trace(ctx, "capi_get_key, contname=%s, provname=%s, type=%d\n",
1470290207Sjkim                   contname, provname, ptype);
1471290207Sjkim    else if (ctx && ctx->debug_level >= CAPI_DBG_TRACE && ctx->debug_file) {
1472290207Sjkim        /* above 'if' is optimization to minimize malloc-ations */
1473290207Sjkim        char *_contname = wide_to_asc((WCHAR *)contname);
1474290207Sjkim        char *_provname = wide_to_asc((WCHAR *)provname);
1475290207Sjkim
1476290207Sjkim        CAPI_trace(ctx, "capi_get_key, contname=%s, provname=%s, type=%d\n",
1477290207Sjkim                   _contname, _provname, ptype);
1478290207Sjkim        if (_provname)
1479290207Sjkim            OPENSSL_free(_provname);
1480290207Sjkim        if (_contname)
1481290207Sjkim            OPENSSL_free(_contname);
1482290207Sjkim    }
1483280297Sjkim    if (ctx->store_flags & CERT_SYSTEM_STORE_LOCAL_MACHINE)
1484246772Sjkim        dwFlags = CRYPT_MACHINE_KEYSET;
1485290207Sjkim    if (!CryptAcquireContext(&key->hprov, contname, provname, ptype, dwFlags)) {
1486280297Sjkim        CAPIerr(CAPI_F_CAPI_GET_KEY, CAPI_R_CRYPTACQUIRECONTEXT_ERROR);
1487280297Sjkim        capi_addlasterror();
1488280297Sjkim        goto err;
1489280297Sjkim    }
1490280297Sjkim    if (!CryptGetUserKey(key->hprov, keyspec, &key->key)) {
1491280297Sjkim        CAPIerr(CAPI_F_CAPI_GET_KEY, CAPI_R_GETUSERKEY_ERROR);
1492280297Sjkim        capi_addlasterror();
1493280297Sjkim        CryptReleaseContext(key->hprov, 0);
1494280297Sjkim        goto err;
1495280297Sjkim    }
1496280297Sjkim    key->keyspec = keyspec;
1497280297Sjkim    key->pcert = NULL;
1498280297Sjkim    return key;
1499183234Ssimon
1500280297Sjkim err:
1501280297Sjkim    OPENSSL_free(key);
1502280297Sjkim    return NULL;
1503280297Sjkim}
1504183234Ssimon
1505280297Sjkimstatic CAPI_KEY *capi_get_cert_key(CAPI_CTX * ctx, PCCERT_CONTEXT cert)
1506280297Sjkim{
1507280297Sjkim    CAPI_KEY *key = NULL;
1508280297Sjkim    CRYPT_KEY_PROV_INFO *pinfo = NULL;
1509280297Sjkim    char *provname = NULL, *contname = NULL;
1510280297Sjkim    pinfo = capi_get_prov_info(ctx, cert);
1511280297Sjkim    if (!pinfo)
1512280297Sjkim        goto err;
1513290207Sjkim    if (sizeof(TCHAR) != sizeof(char))
1514290207Sjkim        key = capi_get_key(ctx, (TCHAR *)pinfo->pwszContainerName,
1515290207Sjkim                           (TCHAR *)pinfo->pwszProvName,
1516290207Sjkim                           pinfo->dwProvType, pinfo->dwKeySpec);
1517290207Sjkim    else {
1518290207Sjkim        provname = wide_to_asc(pinfo->pwszProvName);
1519290207Sjkim        contname = wide_to_asc(pinfo->pwszContainerName);
1520290207Sjkim        if (!provname || !contname)
1521290207Sjkim            goto err;
1522290207Sjkim        key = capi_get_key(ctx, (TCHAR *)contname, (TCHAR *)provname,
1523290207Sjkim                           pinfo->dwProvType, pinfo->dwKeySpec);
1524290207Sjkim    }
1525183234Ssimon
1526280297Sjkim err:
1527280297Sjkim    if (pinfo)
1528280297Sjkim        OPENSSL_free(pinfo);
1529280297Sjkim    if (provname)
1530280297Sjkim        OPENSSL_free(provname);
1531280297Sjkim    if (contname)
1532280297Sjkim        OPENSSL_free(contname);
1533280297Sjkim    return key;
1534280297Sjkim}
1535183234Ssimon
1536280297SjkimCAPI_KEY *capi_find_key(CAPI_CTX * ctx, const char *id)
1537280297Sjkim{
1538280297Sjkim    PCCERT_CONTEXT cert;
1539280297Sjkim    HCERTSTORE hstore;
1540280297Sjkim    CAPI_KEY *key = NULL;
1541280297Sjkim    switch (ctx->lookup_method) {
1542280297Sjkim    case CAPI_LU_SUBSTR:
1543280297Sjkim    case CAPI_LU_FNAME:
1544280297Sjkim        hstore = capi_open_store(ctx, NULL);
1545280297Sjkim        if (!hstore)
1546280297Sjkim            return NULL;
1547280297Sjkim        cert = capi_find_cert(ctx, id, hstore);
1548280297Sjkim        if (cert) {
1549280297Sjkim            key = capi_get_cert_key(ctx, cert);
1550280297Sjkim            CertFreeCertificateContext(cert);
1551280297Sjkim        }
1552280297Sjkim        CertCloseStore(hstore, 0);
1553280297Sjkim        break;
1554183234Ssimon
1555280297Sjkim    case CAPI_LU_CONTNAME:
1556290207Sjkim        if (sizeof(TCHAR) != sizeof(char)) {
1557290207Sjkim            WCHAR *contname, *provname;
1558290207Sjkim            DWORD len;
1559290207Sjkim
1560290207Sjkim            if ((len = MultiByteToWideChar(CP_ACP, 0, id, -1, NULL, 0)) &&
1561290207Sjkim                (contname = alloca(len * sizeof(WCHAR)),
1562290207Sjkim                 MultiByteToWideChar(CP_ACP, 0, id, -1, contname, len)) &&
1563290207Sjkim                (len =
1564290207Sjkim                 MultiByteToWideChar(CP_ACP, 0, ctx->cspname, -1, NULL, 0))
1565290207Sjkim                && (provname =
1566290207Sjkim                    alloca(len * sizeof(WCHAR)), MultiByteToWideChar(CP_ACP,
1567290207Sjkim                                                                     0,
1568290207Sjkim                                                                     ctx->cspname,
1569290207Sjkim                                                                     -1,
1570290207Sjkim                                                                     provname,
1571290207Sjkim                                                                     len)))
1572290207Sjkim                key =
1573290207Sjkim                    capi_get_key(ctx, (TCHAR *)contname, (TCHAR *)provname,
1574290207Sjkim                                 ctx->csptype, ctx->keytype);
1575290207Sjkim        } else
1576290207Sjkim            key = capi_get_key(ctx, (TCHAR *)id,
1577290207Sjkim                               (TCHAR *)ctx->cspname,
1578290207Sjkim                               ctx->csptype, ctx->keytype);
1579280297Sjkim        break;
1580280297Sjkim    }
1581183234Ssimon
1582280297Sjkim    return key;
1583280297Sjkim}
1584183234Ssimon
1585280297Sjkimvoid capi_free_key(CAPI_KEY * key)
1586280297Sjkim{
1587280297Sjkim    if (!key)
1588280297Sjkim        return;
1589280297Sjkim    CryptDestroyKey(key->key);
1590280297Sjkim    CryptReleaseContext(key->hprov, 0);
1591280297Sjkim    if (key->pcert)
1592280297Sjkim        CertFreeCertificateContext(key->pcert);
1593280297Sjkim    OPENSSL_free(key);
1594280297Sjkim}
1595183234Ssimon
1596183234Ssimon/* Initialize a CAPI_CTX structure */
1597183234Ssimon
1598183234Ssimonstatic CAPI_CTX *capi_ctx_new()
1599280297Sjkim{
1600280297Sjkim    CAPI_CTX *ctx;
1601280297Sjkim    ctx = OPENSSL_malloc(sizeof(CAPI_CTX));
1602280297Sjkim    if (!ctx) {
1603280297Sjkim        CAPIerr(CAPI_F_CAPI_CTX_NEW, ERR_R_MALLOC_FAILURE);
1604280297Sjkim        return NULL;
1605280297Sjkim    }
1606280297Sjkim    ctx->cspname = NULL;
1607280297Sjkim    ctx->csptype = PROV_RSA_FULL;
1608280297Sjkim    ctx->dump_flags = CAPI_DMP_SUMMARY | CAPI_DMP_FNAME;
1609280297Sjkim    ctx->keytype = AT_KEYEXCHANGE;
1610280297Sjkim    ctx->storename = NULL;
1611280297Sjkim    ctx->ssl_client_store = NULL;
1612280297Sjkim    ctx->store_flags = CERT_STORE_OPEN_EXISTING_FLAG |
1613280297Sjkim        CERT_STORE_READONLY_FLAG | CERT_SYSTEM_STORE_CURRENT_USER;
1614280297Sjkim    ctx->lookup_method = CAPI_LU_SUBSTR;
1615280297Sjkim    ctx->debug_level = 0;
1616280297Sjkim    ctx->debug_file = NULL;
1617280297Sjkim    ctx->client_cert_select = cert_select_simple;
1618280297Sjkim    return ctx;
1619280297Sjkim}
1620183234Ssimon
1621280297Sjkimstatic void capi_ctx_free(CAPI_CTX * ctx)
1622280297Sjkim{
1623280297Sjkim    CAPI_trace(ctx, "Calling capi_ctx_free with %lx\n", ctx);
1624280297Sjkim    if (!ctx)
1625280297Sjkim        return;
1626280297Sjkim    if (ctx->cspname)
1627280297Sjkim        OPENSSL_free(ctx->cspname);
1628280297Sjkim    if (ctx->debug_file)
1629280297Sjkim        OPENSSL_free(ctx->debug_file);
1630280297Sjkim    if (ctx->storename)
1631280297Sjkim        OPENSSL_free(ctx->storename);
1632280297Sjkim    if (ctx->ssl_client_store)
1633280297Sjkim        OPENSSL_free(ctx->ssl_client_store);
1634280297Sjkim    OPENSSL_free(ctx);
1635280297Sjkim}
1636183234Ssimon
1637280297Sjkimstatic int capi_ctx_set_provname(CAPI_CTX * ctx, LPSTR pname, DWORD type,
1638280297Sjkim                                 int check)
1639280297Sjkim{
1640280297Sjkim    CAPI_trace(ctx, "capi_ctx_set_provname, name=%s, type=%d\n", pname, type);
1641280297Sjkim    if (check) {
1642280297Sjkim        HCRYPTPROV hprov;
1643290207Sjkim        LPTSTR name = NULL;
1644290207Sjkim
1645290207Sjkim        if (sizeof(TCHAR) != sizeof(char)) {
1646290207Sjkim            DWORD len;
1647290207Sjkim            if ((len = MultiByteToWideChar(CP_ACP, 0, pname, -1, NULL, 0))) {
1648290207Sjkim                name = alloca(len * sizeof(WCHAR));
1649290207Sjkim                MultiByteToWideChar(CP_ACP, 0, pname, -1, (WCHAR *)name, len);
1650290207Sjkim            }
1651290207Sjkim        } else
1652290207Sjkim            name = (TCHAR *)pname;
1653290207Sjkim
1654290207Sjkim        if (!name || !CryptAcquireContext(&hprov, NULL, name, type,
1655290207Sjkim                                          CRYPT_VERIFYCONTEXT)) {
1656280297Sjkim            CAPIerr(CAPI_F_CAPI_CTX_SET_PROVNAME,
1657280297Sjkim                    CAPI_R_CRYPTACQUIRECONTEXT_ERROR);
1658280297Sjkim            capi_addlasterror();
1659280297Sjkim            return 0;
1660280297Sjkim        }
1661280297Sjkim        CryptReleaseContext(hprov, 0);
1662280297Sjkim    }
1663280297Sjkim    if (ctx->cspname)
1664280297Sjkim        OPENSSL_free(ctx->cspname);
1665280297Sjkim    ctx->cspname = BUF_strdup(pname);
1666280297Sjkim    ctx->csptype = type;
1667280297Sjkim    return 1;
1668280297Sjkim}
1669183234Ssimon
1670280297Sjkimstatic int capi_ctx_set_provname_idx(CAPI_CTX * ctx, int idx)
1671280297Sjkim{
1672280297Sjkim    LPSTR pname;
1673280297Sjkim    DWORD type;
1674280297Sjkim    int res;
1675280297Sjkim    if (capi_get_provname(ctx, &pname, &type, idx) != 1)
1676280297Sjkim        return 0;
1677280297Sjkim    res = capi_ctx_set_provname(ctx, pname, type, 0);
1678280297Sjkim    OPENSSL_free(pname);
1679280297Sjkim    return res;
1680280297Sjkim}
1681183234Ssimon
1682183234Ssimonstatic int cert_issuer_match(STACK_OF(X509_NAME) *ca_dn, X509 *x)
1683280297Sjkim{
1684280297Sjkim    int i;
1685280297Sjkim    X509_NAME *nm;
1686280297Sjkim    /* Special case: empty list: match anything */
1687280297Sjkim    if (sk_X509_NAME_num(ca_dn) <= 0)
1688280297Sjkim        return 1;
1689280297Sjkim    for (i = 0; i < sk_X509_NAME_num(ca_dn); i++) {
1690280297Sjkim        nm = sk_X509_NAME_value(ca_dn, i);
1691280297Sjkim        if (!X509_NAME_cmp(nm, X509_get_issuer_name(x)))
1692280297Sjkim            return 1;
1693280297Sjkim    }
1694280297Sjkim    return 0;
1695280297Sjkim}
1696183234Ssimon
1697183234Ssimonstatic int capi_load_ssl_client_cert(ENGINE *e, SSL *ssl,
1698280297Sjkim                                     STACK_OF(X509_NAME) *ca_dn, X509 **pcert,
1699280297Sjkim                                     EVP_PKEY **pkey, STACK_OF(X509) **pother,
1700280297Sjkim                                     UI_METHOD *ui_method,
1701280297Sjkim                                     void *callback_data)
1702280297Sjkim{
1703280297Sjkim    STACK_OF(X509) *certs = NULL;
1704280297Sjkim    X509 *x;
1705280297Sjkim    char *storename;
1706280297Sjkim    const char *p;
1707280297Sjkim    int i, client_cert_idx;
1708280297Sjkim    HCERTSTORE hstore;
1709280297Sjkim    PCCERT_CONTEXT cert = NULL, excert = NULL;
1710280297Sjkim    CAPI_CTX *ctx;
1711280297Sjkim    CAPI_KEY *key;
1712280297Sjkim    ctx = ENGINE_get_ex_data(e, capi_idx);
1713183234Ssimon
1714280297Sjkim    *pcert = NULL;
1715280297Sjkim    *pkey = NULL;
1716183234Ssimon
1717280297Sjkim    storename = ctx->ssl_client_store;
1718280297Sjkim    if (!storename)
1719280297Sjkim        storename = "MY";
1720183234Ssimon
1721280297Sjkim    hstore = capi_open_store(ctx, storename);
1722280297Sjkim    if (!hstore)
1723280297Sjkim        return 0;
1724280297Sjkim    /* Enumerate all certificates collect any matches */
1725280297Sjkim    for (i = 0;; i++) {
1726280297Sjkim        cert = CertEnumCertificatesInStore(hstore, cert);
1727280297Sjkim        if (!cert)
1728280297Sjkim            break;
1729280297Sjkim        p = cert->pbCertEncoded;
1730280297Sjkim        x = d2i_X509(NULL, &p, cert->cbCertEncoded);
1731280297Sjkim        if (!x) {
1732280297Sjkim            CAPI_trace(ctx, "Can't Parse Certificate %d\n", i);
1733280297Sjkim            continue;
1734280297Sjkim        }
1735280297Sjkim        if (cert_issuer_match(ca_dn, x)
1736280297Sjkim            && X509_check_purpose(x, X509_PURPOSE_SSL_CLIENT, 0)) {
1737280297Sjkim            key = capi_get_cert_key(ctx, cert);
1738280297Sjkim            if (!key) {
1739280297Sjkim                X509_free(x);
1740280297Sjkim                continue;
1741280297Sjkim            }
1742280297Sjkim            /*
1743280297Sjkim             * Match found: attach extra data to it so we can retrieve the
1744280297Sjkim             * key later.
1745280297Sjkim             */
1746280297Sjkim            excert = CertDuplicateCertificateContext(cert);
1747280297Sjkim            key->pcert = excert;
1748280297Sjkim            X509_set_ex_data(x, cert_capi_idx, key);
1749183234Ssimon
1750280297Sjkim            if (!certs)
1751280297Sjkim                certs = sk_X509_new_null();
1752183234Ssimon
1753280297Sjkim            sk_X509_push(certs, x);
1754280297Sjkim        } else
1755280297Sjkim            X509_free(x);
1756183234Ssimon
1757280297Sjkim    }
1758183234Ssimon
1759280297Sjkim    if (cert)
1760280297Sjkim        CertFreeCertificateContext(cert);
1761280297Sjkim    if (hstore)
1762280297Sjkim        CertCloseStore(hstore, 0);
1763183234Ssimon
1764280297Sjkim    if (!certs)
1765280297Sjkim        return 0;
1766183234Ssimon
1767280297Sjkim    /* Select the appropriate certificate */
1768183234Ssimon
1769280297Sjkim    client_cert_idx = ctx->client_cert_select(e, ssl, certs);
1770183234Ssimon
1771280297Sjkim    /* Set the selected certificate and free the rest */
1772183234Ssimon
1773280297Sjkim    for (i = 0; i < sk_X509_num(certs); i++) {
1774280297Sjkim        x = sk_X509_value(certs, i);
1775280297Sjkim        if (i == client_cert_idx)
1776280297Sjkim            *pcert = x;
1777280297Sjkim        else {
1778280297Sjkim            key = X509_get_ex_data(x, cert_capi_idx);
1779280297Sjkim            capi_free_key(key);
1780280297Sjkim            X509_free(x);
1781280297Sjkim        }
1782280297Sjkim    }
1783183234Ssimon
1784280297Sjkim    sk_X509_free(certs);
1785183234Ssimon
1786280297Sjkim    if (!*pcert)
1787280297Sjkim        return 0;
1788183234Ssimon
1789280297Sjkim    /* Setup key for selected certificate */
1790183234Ssimon
1791280297Sjkim    key = X509_get_ex_data(*pcert, cert_capi_idx);
1792280297Sjkim    *pkey = capi_get_pkey(e, key);
1793280297Sjkim    X509_set_ex_data(*pcert, cert_capi_idx, NULL);
1794183234Ssimon
1795280297Sjkim    return 1;
1796183234Ssimon
1797280297Sjkim}
1798183234Ssimon
1799183234Ssimon/* Simple client cert selection function: always select first */
1800183234Ssimon
1801183234Ssimonstatic int cert_select_simple(ENGINE *e, SSL *ssl, STACK_OF(X509) *certs)
1802280297Sjkim{
1803280297Sjkim    return 0;
1804280297Sjkim}
1805183234Ssimon
1806280297Sjkim# ifdef OPENSSL_CAPIENG_DIALOG
1807183234Ssimon
1808280297Sjkim/*
1809280297Sjkim * More complex cert selection function, using standard function
1810183234Ssimon * CryptUIDlgSelectCertificateFromStore() to produce a dialog box.
1811183234Ssimon */
1812183234Ssimon
1813280297Sjkim/*
1814280297Sjkim * Definitions which are in cryptuiapi.h but this is not present in older
1815183234Ssimon * versions of headers.
1816183234Ssimon */
1817183234Ssimon
1818280297Sjkim#  ifndef CRYPTUI_SELECT_LOCATION_COLUMN
1819280297Sjkim#   define CRYPTUI_SELECT_LOCATION_COLUMN                   0x000000010
1820280297Sjkim#   define CRYPTUI_SELECT_INTENDEDUSE_COLUMN                0x000000004
1821280297Sjkim#  endif
1822183234Ssimon
1823280297Sjkim#  define dlg_title L"OpenSSL Application SSL Client Certificate Selection"
1824280297Sjkim#  define dlg_prompt L"Select a certificate to use for authentication"
1825280297Sjkim#  define dlg_columns      CRYPTUI_SELECT_LOCATION_COLUMN \
1826280297Sjkim                        |CRYPTUI_SELECT_INTENDEDUSE_COLUMN
1827183234Ssimon
1828183234Ssimonstatic int cert_select_dialog(ENGINE *e, SSL *ssl, STACK_OF(X509) *certs)
1829280297Sjkim{
1830280297Sjkim    X509 *x;
1831280297Sjkim    HCERTSTORE dstore;
1832280297Sjkim    PCCERT_CONTEXT cert;
1833280297Sjkim    CAPI_CTX *ctx;
1834280297Sjkim    CAPI_KEY *key;
1835280297Sjkim    HWND hwnd;
1836280297Sjkim    int i, idx = -1;
1837280297Sjkim    if (sk_X509_num(certs) == 1)
1838280297Sjkim        return 0;
1839280297Sjkim    ctx = ENGINE_get_ex_data(e, capi_idx);
1840280297Sjkim    /* Create an in memory store of certificates */
1841280297Sjkim    dstore = CertOpenStore(CERT_STORE_PROV_MEMORY, 0, 0,
1842280297Sjkim                           CERT_STORE_CREATE_NEW_FLAG, NULL);
1843280297Sjkim    if (!dstore) {
1844280297Sjkim        CAPIerr(CAPI_F_CERT_SELECT_DIALOG, CAPI_R_ERROR_CREATING_STORE);
1845280297Sjkim        capi_addlasterror();
1846280297Sjkim        goto err;
1847280297Sjkim    }
1848280297Sjkim    /* Add all certificates to store */
1849280297Sjkim    for (i = 0; i < sk_X509_num(certs); i++) {
1850280297Sjkim        x = sk_X509_value(certs, i);
1851280297Sjkim        key = X509_get_ex_data(x, cert_capi_idx);
1852183234Ssimon
1853280297Sjkim        if (!CertAddCertificateContextToStore(dstore, key->pcert,
1854280297Sjkim                                              CERT_STORE_ADD_NEW, NULL)) {
1855280297Sjkim            CAPIerr(CAPI_F_CERT_SELECT_DIALOG, CAPI_R_ERROR_ADDING_CERT);
1856280297Sjkim            capi_addlasterror();
1857280297Sjkim            goto err;
1858280297Sjkim        }
1859183234Ssimon
1860280297Sjkim    }
1861280297Sjkim    hwnd = GetForegroundWindow();
1862280297Sjkim    if (!hwnd)
1863280297Sjkim        hwnd = GetActiveWindow();
1864280297Sjkim    if (!hwnd && ctx->getconswindow)
1865280297Sjkim        hwnd = ctx->getconswindow();
1866280297Sjkim    /* Call dialog to select one */
1867280297Sjkim    cert = ctx->certselectdlg(dstore, hwnd, dlg_title, dlg_prompt,
1868280297Sjkim                              dlg_columns, 0, NULL);
1869183234Ssimon
1870280297Sjkim    /* Find matching cert from list */
1871280297Sjkim    if (cert) {
1872280297Sjkim        for (i = 0; i < sk_X509_num(certs); i++) {
1873280297Sjkim            x = sk_X509_value(certs, i);
1874280297Sjkim            key = X509_get_ex_data(x, cert_capi_idx);
1875280297Sjkim            if (CertCompareCertificate
1876280297Sjkim                (X509_ASN_ENCODING | PKCS_7_ASN_ENCODING, cert->pCertInfo,
1877280297Sjkim                 key->pcert->pCertInfo)) {
1878280297Sjkim                idx = i;
1879280297Sjkim                break;
1880280297Sjkim            }
1881280297Sjkim        }
1882280297Sjkim    }
1883183234Ssimon
1884280297Sjkim err:
1885280297Sjkim    if (dstore)
1886280297Sjkim        CertCloseStore(dstore, 0);
1887280297Sjkim    return idx;
1888183234Ssimon
1889280297Sjkim}
1890280297Sjkim# endif
1891183234Ssimon
1892280297Sjkim#else                           /* !__COMPILE_CAPIENG */
1893280297Sjkim# include <openssl/engine.h>
1894280297Sjkim# ifndef OPENSSL_NO_DYNAMIC_ENGINE
1895183234SsimonOPENSSL_EXPORT
1896280297Sjkim    int bind_engine(ENGINE *e, const char *id, const dynamic_fns *fns);
1897238405SjkimOPENSSL_EXPORT
1898280297Sjkim    int bind_engine(ENGINE *e, const char *id, const dynamic_fns *fns)
1899280297Sjkim{
1900280297Sjkim    return 0;
1901280297Sjkim}
1902280297Sjkim
1903183234SsimonIMPLEMENT_DYNAMIC_CHECK_FN()
1904280297Sjkim# else
1905280297Sjkimvoid ENGINE_load_capi(void)
1906280297Sjkim{
1907280297Sjkim}
1908280297Sjkim# endif
1909183234Ssimon#endif
1910