1183234Ssimon/* engines/e_capi.c */
2296341Sdelphij/*
3296341Sdelphij * 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
14296341Sdelphij *    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
62296341Sdelphij# ifndef OPENSSL_NO_CAPIENG
63183234Ssimon
64296341Sdelphij#  include <openssl/rsa.h>
65183234Ssimon
66296341Sdelphij#  include <windows.h>
67183234Ssimon
68296341Sdelphij#  ifndef _WIN32_WINNT
69296341Sdelphij#   define _WIN32_WINNT 0x0400
70296341Sdelphij#  endif
71183234Ssimon
72296341Sdelphij#  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 */
86296341Sdelphij#  if defined(CERT_KEY_PROV_INFO_PROP_ID) && \
87238405Sjkim    defined(CERT_STORE_PROV_SYSTEM_A) && \
88238405Sjkim    defined(CERT_STORE_READONLY_FLAG)
89296341Sdelphij#   define __COMPILE_CAPIENG
90296341Sdelphij#  endif                        /* CERT_KEY_PROV_INFO_PROP_ID */
91296341Sdelphij# endif                         /* OPENSSL_NO_CAPIENG */
92296341Sdelphij#endif                          /* OPENSSL_SYS_WIN32 */
93238405Sjkim
94238405Sjkim#ifdef __COMPILE_CAPIENG
95238405Sjkim
96296341Sdelphij# undef X509_EXTENSIONS
97296341Sdelphij# undef X509_CERT_PAIR
98183234Ssimon
99183234Ssimon/* Definitions which may be missing from earlier version of headers */
100296341Sdelphij# ifndef CERT_STORE_OPEN_EXISTING_FLAG
101296341Sdelphij#  define CERT_STORE_OPEN_EXISTING_FLAG                   0x00004000
102296341Sdelphij# endif
103183234Ssimon
104296341Sdelphij# ifndef CERT_STORE_CREATE_NEW_FLAG
105296341Sdelphij#  define CERT_STORE_CREATE_NEW_FLAG                      0x00002000
106296341Sdelphij# endif
107183234Ssimon
108296341Sdelphij# ifndef CERT_SYSTEM_STORE_CURRENT_USER
109296341Sdelphij#  define CERT_SYSTEM_STORE_CURRENT_USER                  0x00010000
110296341Sdelphij# endif
111206046Ssimon
112296341Sdelphij# include <openssl/engine.h>
113296341Sdelphij# include <openssl/pem.h>
114296341Sdelphij# include <openssl/x509v3.h>
115183234Ssimon
116296341Sdelphij# include "e_capi_err.h"
117296341Sdelphij# 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
128296341Sdelphijstatic void CAPI_trace(CAPI_CTX * ctx, char *format, ...);
129183234Ssimon
130296341Sdelphijstatic int capi_list_providers(CAPI_CTX * ctx, BIO *out);
131296341Sdelphijstatic int capi_list_containers(CAPI_CTX * ctx, BIO *out);
132296341Sdelphijint capi_list_certs(CAPI_CTX * ctx, BIO *out, char *storename);
133296341Sdelphijvoid capi_free_key(CAPI_KEY * key);
134183234Ssimon
135296341Sdelphijstatic PCCERT_CONTEXT capi_find_cert(CAPI_CTX * ctx, const char *id,
136296341Sdelphij                                     HCERTSTORE hstore);
137183234Ssimon
138296341SdelphijCAPI_KEY *capi_find_key(CAPI_CTX * ctx, const char *id);
139183234Ssimon
140183234Ssimonstatic EVP_PKEY *capi_load_privkey(ENGINE *eng, const char *key_id,
141296341Sdelphij                                   UI_METHOD *ui_method, void *callback_data);
142296341Sdelphijstatic int capi_rsa_sign(int dtype, const unsigned char *m,
143296341Sdelphij                         unsigned int m_len, unsigned char *sigret,
144296341Sdelphij                         unsigned int *siglen, const RSA *rsa);
145183234Ssimonstatic int capi_rsa_priv_enc(int flen, const unsigned char *from,
146296341Sdelphij                             unsigned char *to, RSA *rsa, int padding);
147183234Ssimonstatic int capi_rsa_priv_dec(int flen, const unsigned char *from,
148296341Sdelphij                             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,
152296341Sdelphij                                 DSA *dsa);
153183234Ssimonstatic int capi_dsa_free(DSA *dsa);
154183234Ssimon
155183234Ssimonstatic int capi_load_ssl_client_cert(ENGINE *e, SSL *ssl,
156296341Sdelphij                                     STACK_OF(X509_NAME) *ca_dn, X509 **pcert,
157296341Sdelphij                                     EVP_PKEY **pkey, STACK_OF(X509) **pother,
158296341Sdelphij                                     UI_METHOD *ui_method,
159296341Sdelphij                                     void *callback_data);
160183234Ssimon
161183234Ssimonstatic int cert_select_simple(ENGINE *e, SSL *ssl, STACK_OF(X509) *certs);
162296341Sdelphij# ifdef OPENSSL_CAPIENG_DIALOG
163183234Ssimonstatic int cert_select_dialog(ENGINE *e, SSL *ssl, STACK_OF(X509) *certs);
164296341Sdelphij# endif
165183234Ssimon
166296341Sdelphijtypedef PCCERT_CONTEXT(WINAPI *CERTDLG) (HCERTSTORE, HWND, LPCWSTR,
167296341Sdelphij                                         LPCWSTR, DWORD, DWORD, void *);
168296341Sdelphijtypedef HWND(WINAPI *GETCONSWIN) (void);
169183234Ssimon
170296341Sdelphij/*
171296341Sdelphij * This structure contains CAPI ENGINE specific data: it contains various
172296341Sdelphij * global options and affects how other functions behave.
173183234Ssimon */
174183234Ssimon
175296341Sdelphij# define CAPI_DBG_TRACE  2
176296341Sdelphij# define CAPI_DBG_ERROR  1
177183234Ssimon
178183234Ssimonstruct CAPI_CTX_st {
179296341Sdelphij    int debug_level;
180296341Sdelphij    char *debug_file;
181296341Sdelphij    /* Parameters to use for container lookup */
182296341Sdelphij    DWORD keytype;
183296341Sdelphij    LPSTR cspname;
184296341Sdelphij    DWORD csptype;
185296341Sdelphij    /* Certificate store name to use */
186296341Sdelphij    LPSTR storename;
187296341Sdelphij    LPSTR ssl_client_store;
188296341Sdelphij    /* System store flags */
189296341Sdelphij    DWORD store_flags;
190183234Ssimon/* Lookup string meanings in load_private_key */
191183234Ssimon/* Substring of subject: uses "storename" */
192296341Sdelphij# define CAPI_LU_SUBSTR          1
193183234Ssimon/* Friendly name: uses storename */
194296341Sdelphij# define CAPI_LU_FNAME           2
195183234Ssimon/* Container name: uses cspname, keytype */
196296341Sdelphij# define CAPI_LU_CONTNAME        3
197296341Sdelphij    int lookup_method;
198183234Ssimon/* Info to dump with dumpcerts option */
199183234Ssimon/* Issuer and serial name strings */
200296341Sdelphij# define CAPI_DMP_SUMMARY        0x1
201183234Ssimon/* Friendly name */
202296341Sdelphij# define CAPI_DMP_FNAME          0x2
203183234Ssimon/* Full X509_print dump */
204296341Sdelphij# define CAPI_DMP_FULL           0x4
205183234Ssimon/* Dump PEM format certificate */
206296341Sdelphij# define CAPI_DMP_PEM            0x8
207183234Ssimon/* Dump pseudo key (if possible) */
208296341Sdelphij# define CAPI_DMP_PSKEY          0x10
209183234Ssimon/* Dump key info (if possible) */
210296341Sdelphij# define CAPI_DMP_PKEYINFO       0x20
211296341Sdelphij    DWORD dump_flags;
212296341Sdelphij    int (*client_cert_select) (ENGINE *e, SSL *ssl, STACK_OF(X509) *certs);
213296341Sdelphij    CERTDLG certselectdlg;
214296341Sdelphij    GETCONSWIN getconswindow;
215183234Ssimon};
216183234Ssimon
217183234Ssimonstatic CAPI_CTX *capi_ctx_new();
218296341Sdelphijstatic void capi_ctx_free(CAPI_CTX * ctx);
219296341Sdelphijstatic int capi_ctx_set_provname(CAPI_CTX * ctx, LPSTR pname, DWORD type,
220296341Sdelphij                                 int check);
221296341Sdelphijstatic int capi_ctx_set_provname_idx(CAPI_CTX * ctx, int idx);
222183234Ssimon
223296341Sdelphij# define CAPI_CMD_LIST_CERTS             ENGINE_CMD_BASE
224296341Sdelphij# define CAPI_CMD_LOOKUP_CERT            (ENGINE_CMD_BASE + 1)
225296341Sdelphij# define CAPI_CMD_DEBUG_LEVEL            (ENGINE_CMD_BASE + 2)
226296341Sdelphij# define CAPI_CMD_DEBUG_FILE             (ENGINE_CMD_BASE + 3)
227296341Sdelphij# define CAPI_CMD_KEYTYPE                (ENGINE_CMD_BASE + 4)
228296341Sdelphij# define CAPI_CMD_LIST_CSPS              (ENGINE_CMD_BASE + 5)
229296341Sdelphij# define CAPI_CMD_SET_CSP_IDX            (ENGINE_CMD_BASE + 6)
230296341Sdelphij# define CAPI_CMD_SET_CSP_NAME           (ENGINE_CMD_BASE + 7)
231296341Sdelphij# define CAPI_CMD_SET_CSP_TYPE           (ENGINE_CMD_BASE + 8)
232296341Sdelphij# define CAPI_CMD_LIST_CONTAINERS        (ENGINE_CMD_BASE + 9)
233296341Sdelphij# define CAPI_CMD_LIST_OPTIONS           (ENGINE_CMD_BASE + 10)
234296341Sdelphij# define CAPI_CMD_LOOKUP_METHOD          (ENGINE_CMD_BASE + 11)
235296341Sdelphij# define CAPI_CMD_STORE_NAME             (ENGINE_CMD_BASE + 12)
236296341Sdelphij# define CAPI_CMD_STORE_FLAGS            (ENGINE_CMD_BASE + 13)
237183234Ssimon
238183234Ssimonstatic const ENGINE_CMD_DEFN capi_cmd_defns[] = {
239296341Sdelphij    {CAPI_CMD_LIST_CERTS,
240296341Sdelphij     "list_certs",
241296341Sdelphij     "List all certificates in store",
242296341Sdelphij     ENGINE_CMD_FLAG_NO_INPUT},
243296341Sdelphij    {CAPI_CMD_LOOKUP_CERT,
244296341Sdelphij     "lookup_cert",
245296341Sdelphij     "Lookup and output certificates",
246296341Sdelphij     ENGINE_CMD_FLAG_STRING},
247296341Sdelphij    {CAPI_CMD_DEBUG_LEVEL,
248296341Sdelphij     "debug_level",
249296341Sdelphij     "debug level (1=errors, 2=trace)",
250296341Sdelphij     ENGINE_CMD_FLAG_NUMERIC},
251296341Sdelphij    {CAPI_CMD_DEBUG_FILE,
252296341Sdelphij     "debug_file",
253296341Sdelphij     "debugging filename)",
254296341Sdelphij     ENGINE_CMD_FLAG_STRING},
255296341Sdelphij    {CAPI_CMD_KEYTYPE,
256296341Sdelphij     "key_type",
257296341Sdelphij     "Key type: 1=AT_KEYEXCHANGE (default), 2=AT_SIGNATURE",
258296341Sdelphij     ENGINE_CMD_FLAG_NUMERIC},
259296341Sdelphij    {CAPI_CMD_LIST_CSPS,
260296341Sdelphij     "list_csps",
261296341Sdelphij     "List all CSPs",
262296341Sdelphij     ENGINE_CMD_FLAG_NO_INPUT},
263296341Sdelphij    {CAPI_CMD_SET_CSP_IDX,
264296341Sdelphij     "csp_idx",
265296341Sdelphij     "Set CSP by index",
266296341Sdelphij     ENGINE_CMD_FLAG_NUMERIC},
267296341Sdelphij    {CAPI_CMD_SET_CSP_NAME,
268296341Sdelphij     "csp_name",
269296341Sdelphij     "Set CSP name, (default CSP used if not specified)",
270296341Sdelphij     ENGINE_CMD_FLAG_STRING},
271296341Sdelphij    {CAPI_CMD_SET_CSP_TYPE,
272296341Sdelphij     "csp_type",
273296341Sdelphij     "Set CSP type, (default RSA_PROV_FULL)",
274296341Sdelphij     ENGINE_CMD_FLAG_NUMERIC},
275296341Sdelphij    {CAPI_CMD_LIST_CONTAINERS,
276296341Sdelphij     "list_containers",
277296341Sdelphij     "list container names",
278296341Sdelphij     ENGINE_CMD_FLAG_NO_INPUT},
279296341Sdelphij    {CAPI_CMD_LIST_OPTIONS,
280296341Sdelphij     "list_options",
281296341Sdelphij     "Set list options (1=summary,2=friendly name, 4=full printout, 8=PEM output, 16=XXX, "
282296341Sdelphij     "32=private key info)",
283296341Sdelphij     ENGINE_CMD_FLAG_NUMERIC},
284296341Sdelphij    {CAPI_CMD_LOOKUP_METHOD,
285296341Sdelphij     "lookup_method",
286296341Sdelphij     "Set key lookup method (1=substring, 2=friendlyname, 3=container name)",
287296341Sdelphij     ENGINE_CMD_FLAG_NUMERIC},
288296341Sdelphij    {CAPI_CMD_STORE_NAME,
289296341Sdelphij     "store_name",
290296341Sdelphij     "certificate store name, default \"MY\"",
291296341Sdelphij     ENGINE_CMD_FLAG_STRING},
292296341Sdelphij    {CAPI_CMD_STORE_FLAGS,
293296341Sdelphij     "store_flags",
294296341Sdelphij     "Certificate store flags: 1 = system store",
295296341Sdelphij     ENGINE_CMD_FLAG_NUMERIC},
296183234Ssimon
297296341Sdelphij    {0, NULL, NULL, 0}
298296341Sdelphij};
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
305296341Sdelphijstatic int capi_ctrl(ENGINE *e, int cmd, long i, void *p, void (*f) (void))
306296341Sdelphij{
307296341Sdelphij    int ret = 1;
308296341Sdelphij    CAPI_CTX *ctx;
309296341Sdelphij    BIO *out;
310296341Sdelphij    if (capi_idx == -1) {
311296341Sdelphij        CAPIerr(CAPI_F_CAPI_CTRL, CAPI_R_ENGINE_NOT_INITIALIZED);
312296341Sdelphij        return 0;
313296341Sdelphij    }
314296341Sdelphij    ctx = ENGINE_get_ex_data(e, capi_idx);
315296341Sdelphij    out = BIO_new_fp(stdout, BIO_NOCLOSE);
316296341Sdelphij    switch (cmd) {
317296341Sdelphij    case CAPI_CMD_LIST_CSPS:
318296341Sdelphij        ret = capi_list_providers(ctx, out);
319296341Sdelphij        break;
320183234Ssimon
321296341Sdelphij    case CAPI_CMD_LIST_CERTS:
322296341Sdelphij        ret = capi_list_certs(ctx, out, NULL);
323296341Sdelphij        break;
324183234Ssimon
325296341Sdelphij    case CAPI_CMD_LOOKUP_CERT:
326296341Sdelphij        ret = capi_list_certs(ctx, out, p);
327296341Sdelphij        break;
328183234Ssimon
329296341Sdelphij    case CAPI_CMD_LIST_CONTAINERS:
330296341Sdelphij        ret = capi_list_containers(ctx, out);
331296341Sdelphij        break;
332183234Ssimon
333296341Sdelphij    case CAPI_CMD_STORE_NAME:
334296341Sdelphij        if (ctx->storename)
335296341Sdelphij            OPENSSL_free(ctx->storename);
336296341Sdelphij        ctx->storename = BUF_strdup(p);
337296341Sdelphij        CAPI_trace(ctx, "Setting store name to %s\n", p);
338296341Sdelphij        break;
339183234Ssimon
340296341Sdelphij    case CAPI_CMD_STORE_FLAGS:
341296341Sdelphij        if (i & 1) {
342296341Sdelphij            ctx->store_flags |= CERT_SYSTEM_STORE_LOCAL_MACHINE;
343296341Sdelphij            ctx->store_flags &= ~CERT_SYSTEM_STORE_CURRENT_USER;
344296341Sdelphij        } else {
345296341Sdelphij            ctx->store_flags |= CERT_SYSTEM_STORE_CURRENT_USER;
346296341Sdelphij            ctx->store_flags &= ~CERT_SYSTEM_STORE_LOCAL_MACHINE;
347296341Sdelphij        }
348296341Sdelphij        CAPI_trace(ctx, "Setting flags to %d\n", i);
349296341Sdelphij        break;
350183234Ssimon
351296341Sdelphij    case CAPI_CMD_DEBUG_LEVEL:
352296341Sdelphij        ctx->debug_level = (int)i;
353296341Sdelphij        CAPI_trace(ctx, "Setting debug level to %d\n", ctx->debug_level);
354296341Sdelphij        break;
355183234Ssimon
356296341Sdelphij    case CAPI_CMD_DEBUG_FILE:
357296341Sdelphij        ctx->debug_file = BUF_strdup(p);
358296341Sdelphij        CAPI_trace(ctx, "Setting debug file to %s\n", ctx->debug_file);
359296341Sdelphij        break;
360183234Ssimon
361296341Sdelphij    case CAPI_CMD_KEYTYPE:
362296341Sdelphij        ctx->keytype = i;
363296341Sdelphij        CAPI_trace(ctx, "Setting key type to %d\n", ctx->keytype);
364296341Sdelphij        break;
365183234Ssimon
366296341Sdelphij    case CAPI_CMD_SET_CSP_IDX:
367296341Sdelphij        ret = capi_ctx_set_provname_idx(ctx, i);
368296341Sdelphij        break;
369183234Ssimon
370296341Sdelphij    case CAPI_CMD_LIST_OPTIONS:
371296341Sdelphij        ctx->dump_flags = i;
372296341Sdelphij        break;
373183234Ssimon
374296341Sdelphij    case CAPI_CMD_LOOKUP_METHOD:
375296341Sdelphij        if (i < 1 || i > 3) {
376296341Sdelphij            CAPIerr(CAPI_F_CAPI_CTRL, CAPI_R_INVALID_LOOKUP_METHOD);
377296341Sdelphij            return 0;
378296341Sdelphij        }
379296341Sdelphij        ctx->lookup_method = i;
380296341Sdelphij        break;
381183234Ssimon
382296341Sdelphij    case CAPI_CMD_SET_CSP_NAME:
383296341Sdelphij        ret = capi_ctx_set_provname(ctx, p, ctx->csptype, 1);
384296341Sdelphij        break;
385183234Ssimon
386296341Sdelphij    case CAPI_CMD_SET_CSP_TYPE:
387296341Sdelphij        ctx->csptype = i;
388296341Sdelphij        break;
389183234Ssimon
390296341Sdelphij    default:
391296341Sdelphij        CAPIerr(CAPI_F_CAPI_CTRL, CAPI_R_UNKNOWN_COMMAND);
392296341Sdelphij        ret = 0;
393296341Sdelphij    }
394183234Ssimon
395296341Sdelphij    BIO_free(out);
396296341Sdelphij    return ret;
397183234Ssimon
398296341Sdelphij}
399183234Ssimon
400296341Sdelphijstatic RSA_METHOD capi_rsa_method = {
401296341Sdelphij    "CryptoAPI RSA method",
402296341Sdelphij    0,                          /* pub_enc */
403296341Sdelphij    0,                          /* pub_dec */
404296341Sdelphij    capi_rsa_priv_enc,          /* priv_enc */
405296341Sdelphij    capi_rsa_priv_dec,          /* priv_dec */
406296341Sdelphij    0,                          /* rsa_mod_exp */
407296341Sdelphij    0,                          /* bn_mod_exp */
408296341Sdelphij    0,                          /* init */
409296341Sdelphij    capi_rsa_free,              /* finish */
410296341Sdelphij    RSA_FLAG_SIGN_VER,          /* flags */
411296341Sdelphij    NULL,                       /* app_data */
412296341Sdelphij    capi_rsa_sign,              /* rsa_sign */
413296341Sdelphij    0                           /* rsa_verify */
414296341Sdelphij};
415183234Ssimon
416296341Sdelphijstatic DSA_METHOD capi_dsa_method = {
417296341Sdelphij    "CryptoAPI DSA method",
418296341Sdelphij    capi_dsa_do_sign,           /* dsa_do_sign */
419296341Sdelphij    0,                          /* dsa_sign_setup */
420296341Sdelphij    0,                          /* dsa_do_verify */
421296341Sdelphij    0,                          /* dsa_mod_exp */
422296341Sdelphij    0,                          /* bn_mod_exp */
423296341Sdelphij    0,                          /* init */
424296341Sdelphij    capi_dsa_free,              /* finish */
425296341Sdelphij    0,                          /* flags */
426296341Sdelphij    NULL,                       /* app_data */
427296341Sdelphij    0,                          /* dsa_paramgen */
428296341Sdelphij    0                           /* dsa_keygen */
429296341Sdelphij};
430183234Ssimon
431183234Ssimonstatic int capi_init(ENGINE *e)
432296341Sdelphij{
433296341Sdelphij    CAPI_CTX *ctx;
434296341Sdelphij    const RSA_METHOD *ossl_rsa_meth;
435296341Sdelphij    const DSA_METHOD *ossl_dsa_meth;
436183234Ssimon
437296341Sdelphij    if (capi_idx < 0) {
438296341Sdelphij        capi_idx = ENGINE_get_ex_new_index(0, NULL, NULL, NULL, 0);
439296341Sdelphij        if (capi_idx < 0)
440296341Sdelphij            goto memerr;
441237657Sjkim
442296341Sdelphij        cert_capi_idx = X509_get_ex_new_index(0, NULL, NULL, NULL, 0);
443237657Sjkim
444296341Sdelphij        /* Setup RSA_METHOD */
445296341Sdelphij        rsa_capi_idx = RSA_get_ex_new_index(0, NULL, NULL, NULL, 0);
446296341Sdelphij        ossl_rsa_meth = RSA_PKCS1_SSLeay();
447296341Sdelphij        capi_rsa_method.rsa_pub_enc = ossl_rsa_meth->rsa_pub_enc;
448296341Sdelphij        capi_rsa_method.rsa_pub_dec = ossl_rsa_meth->rsa_pub_dec;
449296341Sdelphij        capi_rsa_method.rsa_mod_exp = ossl_rsa_meth->rsa_mod_exp;
450296341Sdelphij        capi_rsa_method.bn_mod_exp = ossl_rsa_meth->bn_mod_exp;
451237657Sjkim
452296341Sdelphij        /* Setup DSA Method */
453296341Sdelphij        dsa_capi_idx = DSA_get_ex_new_index(0, NULL, NULL, NULL, 0);
454296341Sdelphij        ossl_dsa_meth = DSA_OpenSSL();
455296341Sdelphij        capi_dsa_method.dsa_do_verify = ossl_dsa_meth->dsa_do_verify;
456296341Sdelphij        capi_dsa_method.dsa_mod_exp = ossl_dsa_meth->dsa_mod_exp;
457296341Sdelphij        capi_dsa_method.bn_mod_exp = ossl_dsa_meth->bn_mod_exp;
458296341Sdelphij    }
459237657Sjkim
460296341Sdelphij    ctx = capi_ctx_new();
461296341Sdelphij    if (!ctx)
462296341Sdelphij        goto memerr;
463183234Ssimon
464296341Sdelphij    ENGINE_set_ex_data(e, capi_idx, ctx);
465183234Ssimon
466296341Sdelphij# ifdef OPENSSL_CAPIENG_DIALOG
467296341Sdelphij    {
468296341Sdelphij        HMODULE cryptui = LoadLibrary(TEXT("CRYPTUI.DLL"));
469296341Sdelphij        HMODULE kernel = GetModuleHandle(TEXT("KERNEL32.DLL"));
470296341Sdelphij        if (cryptui)
471296341Sdelphij            ctx->certselectdlg =
472296341Sdelphij                (CERTDLG) GetProcAddress(cryptui,
473296341Sdelphij                                         "CryptUIDlgSelectCertificateFromStore");
474296341Sdelphij        if (kernel)
475296341Sdelphij            ctx->getconswindow =
476296341Sdelphij                (GETCONSWIN) GetProcAddress(kernel, "GetConsoleWindow");
477296341Sdelphij        if (cryptui && !OPENSSL_isservice())
478296341Sdelphij            ctx->client_cert_select = cert_select_dialog;
479296341Sdelphij    }
480296341Sdelphij# endif
481183234Ssimon
482296341Sdelphij    return 1;
483183234Ssimon
484296341Sdelphij memerr:
485296341Sdelphij    CAPIerr(CAPI_F_CAPI_INIT, ERR_R_MALLOC_FAILURE);
486296341Sdelphij    return 0;
487183234Ssimon
488296341Sdelphij    return 1;
489296341Sdelphij}
490183234Ssimon
491183234Ssimonstatic int capi_destroy(ENGINE *e)
492296341Sdelphij{
493296341Sdelphij    ERR_unload_CAPI_strings();
494296341Sdelphij    return 1;
495296341Sdelphij}
496183234Ssimon
497183234Ssimonstatic int capi_finish(ENGINE *e)
498296341Sdelphij{
499296341Sdelphij    CAPI_CTX *ctx;
500296341Sdelphij    ctx = ENGINE_get_ex_data(e, capi_idx);
501296341Sdelphij    capi_ctx_free(ctx);
502296341Sdelphij    ENGINE_set_ex_data(e, capi_idx, NULL);
503296341Sdelphij    return 1;
504296341Sdelphij}
505183234Ssimon
506296341Sdelphij/*
507296341Sdelphij * CryptoAPI key application data. This contains a handle to the private key
508296341Sdelphij * container (for sign operations) and a handle to the key (for decrypt
509296341Sdelphij * operations).
510183234Ssimon */
511183234Ssimon
512296341Sdelphijstruct CAPI_KEY_st {
513296341Sdelphij    /* Associated certificate context (if any) */
514296341Sdelphij    PCCERT_CONTEXT pcert;
515296341Sdelphij    HCRYPTPROV hprov;
516296341Sdelphij    HCRYPTKEY key;
517296341Sdelphij    DWORD keyspec;
518296341Sdelphij};
519183234Ssimon
520183234Ssimonstatic int bind_capi(ENGINE *e)
521296341Sdelphij{
522296341Sdelphij    if (!ENGINE_set_id(e, engine_capi_id)
523296341Sdelphij        || !ENGINE_set_name(e, engine_capi_name)
524296341Sdelphij        || !ENGINE_set_flags(e, ENGINE_FLAGS_NO_REGISTER_ALL)
525296341Sdelphij        || !ENGINE_set_init_function(e, capi_init)
526296341Sdelphij        || !ENGINE_set_finish_function(e, capi_finish)
527296341Sdelphij        || !ENGINE_set_destroy_function(e, capi_destroy)
528296341Sdelphij        || !ENGINE_set_RSA(e, &capi_rsa_method)
529296341Sdelphij        || !ENGINE_set_DSA(e, &capi_dsa_method)
530296341Sdelphij        || !ENGINE_set_load_privkey_function(e, capi_load_privkey)
531296341Sdelphij        || !ENGINE_set_load_ssl_client_cert_function(e,
532296341Sdelphij                                                     capi_load_ssl_client_cert)
533296341Sdelphij        || !ENGINE_set_cmd_defns(e, capi_cmd_defns)
534296341Sdelphij        || !ENGINE_set_ctrl_function(e, capi_ctrl))
535296341Sdelphij        return 0;
536296341Sdelphij    ERR_load_CAPI_strings();
537183234Ssimon
538296341Sdelphij    return 1;
539183234Ssimon
540296341Sdelphij}
541183234Ssimon
542296341Sdelphij# ifndef OPENSSL_NO_DYNAMIC_ENGINE
543183234Ssimonstatic int bind_helper(ENGINE *e, const char *id)
544296341Sdelphij{
545296341Sdelphij    if (id && (strcmp(id, engine_capi_id) != 0))
546296341Sdelphij        return 0;
547296341Sdelphij    if (!bind_capi(e))
548296341Sdelphij        return 0;
549296341Sdelphij    return 1;
550296341Sdelphij}
551296341Sdelphij
552183234SsimonIMPLEMENT_DYNAMIC_CHECK_FN()
553296341Sdelphij    IMPLEMENT_DYNAMIC_BIND_FN(bind_helper)
554296341Sdelphij# else
555183234Ssimonstatic ENGINE *engine_capi(void)
556296341Sdelphij{
557296341Sdelphij    ENGINE *ret = ENGINE_new();
558296341Sdelphij    if (!ret)
559296341Sdelphij        return NULL;
560296341Sdelphij    if (!bind_capi(ret)) {
561296341Sdelphij        ENGINE_free(ret);
562296341Sdelphij        return NULL;
563296341Sdelphij    }
564296341Sdelphij    return ret;
565296341Sdelphij}
566183234Ssimon
567183234Ssimonvoid ENGINE_load_capi(void)
568296341Sdelphij{
569296341Sdelphij    /* Copied from eng_[openssl|dyn].c */
570296341Sdelphij    ENGINE *toadd = engine_capi();
571296341Sdelphij    if (!toadd)
572296341Sdelphij        return;
573296341Sdelphij    ENGINE_add(toadd);
574296341Sdelphij    ENGINE_free(toadd);
575296341Sdelphij    ERR_clear_error();
576296341Sdelphij}
577296341Sdelphij# endif
578183234Ssimon
579183234Ssimonstatic int lend_tobn(BIGNUM *bn, unsigned char *bin, int binlen)
580296341Sdelphij{
581296341Sdelphij    int i;
582296341Sdelphij    /*
583296341Sdelphij     * Reverse buffer in place: since this is a keyblob structure that will
584296341Sdelphij     * be freed up after conversion anyway it doesn't matter if we change
585296341Sdelphij     * it.
586296341Sdelphij     */
587296341Sdelphij    for (i = 0; i < binlen / 2; i++) {
588296341Sdelphij        unsigned char c;
589296341Sdelphij        c = bin[i];
590296341Sdelphij        bin[i] = bin[binlen - i - 1];
591296341Sdelphij        bin[binlen - i - 1] = c;
592296341Sdelphij    }
593183234Ssimon
594296341Sdelphij    if (!BN_bin2bn(bin, binlen, bn))
595296341Sdelphij        return 0;
596296341Sdelphij    return 1;
597296341Sdelphij}
598183234Ssimon
599183234Ssimon/* Given a CAPI_KEY get an EVP_PKEY structure */
600183234Ssimon
601296341Sdelphijstatic EVP_PKEY *capi_get_pkey(ENGINE *eng, CAPI_KEY * key)
602296341Sdelphij{
603296341Sdelphij    unsigned char *pubkey = NULL;
604296341Sdelphij    DWORD len;
605296341Sdelphij    BLOBHEADER *bh;
606296341Sdelphij    RSA *rkey = NULL;
607296341Sdelphij    DSA *dkey = NULL;
608296341Sdelphij    EVP_PKEY *ret = NULL;
609296341Sdelphij    if (!CryptExportKey(key->key, 0, PUBLICKEYBLOB, 0, NULL, &len)) {
610296341Sdelphij        CAPIerr(CAPI_F_CAPI_GET_PKEY, CAPI_R_PUBKEY_EXPORT_LENGTH_ERROR);
611296341Sdelphij        capi_addlasterror();
612296341Sdelphij        return NULL;
613296341Sdelphij    }
614183234Ssimon
615296341Sdelphij    pubkey = OPENSSL_malloc(len);
616183234Ssimon
617296341Sdelphij    if (!pubkey)
618296341Sdelphij        goto memerr;
619183234Ssimon
620296341Sdelphij    if (!CryptExportKey(key->key, 0, PUBLICKEYBLOB, 0, pubkey, &len)) {
621296341Sdelphij        CAPIerr(CAPI_F_CAPI_GET_PKEY, CAPI_R_PUBKEY_EXPORT_ERROR);
622296341Sdelphij        capi_addlasterror();
623296341Sdelphij        goto err;
624296341Sdelphij    }
625183234Ssimon
626296341Sdelphij    bh = (BLOBHEADER *) pubkey;
627296341Sdelphij    if (bh->bType != PUBLICKEYBLOB) {
628296341Sdelphij        CAPIerr(CAPI_F_CAPI_GET_PKEY, CAPI_R_INVALID_PUBLIC_KEY_BLOB);
629296341Sdelphij        goto err;
630296341Sdelphij    }
631296341Sdelphij    if (bh->aiKeyAlg == CALG_RSA_SIGN || bh->aiKeyAlg == CALG_RSA_KEYX) {
632296341Sdelphij        RSAPUBKEY *rp;
633296341Sdelphij        DWORD rsa_modlen;
634296341Sdelphij        unsigned char *rsa_modulus;
635296341Sdelphij        rp = (RSAPUBKEY *) (bh + 1);
636296341Sdelphij        if (rp->magic != 0x31415352) {
637296341Sdelphij            char magstr[10];
638296341Sdelphij            BIO_snprintf(magstr, 10, "%lx", rp->magic);
639296341Sdelphij            CAPIerr(CAPI_F_CAPI_GET_PKEY,
640296341Sdelphij                    CAPI_R_INVALID_RSA_PUBLIC_KEY_BLOB_MAGIC_NUMBER);
641296341Sdelphij            ERR_add_error_data(2, "magic=0x", magstr);
642296341Sdelphij            goto err;
643296341Sdelphij        }
644296341Sdelphij        rsa_modulus = (unsigned char *)(rp + 1);
645296341Sdelphij        rkey = RSA_new_method(eng);
646296341Sdelphij        if (!rkey)
647296341Sdelphij            goto memerr;
648183234Ssimon
649296341Sdelphij        rkey->e = BN_new();
650296341Sdelphij        rkey->n = BN_new();
651183234Ssimon
652296341Sdelphij        if (!rkey->e || !rkey->n)
653296341Sdelphij            goto memerr;
654183234Ssimon
655296341Sdelphij        if (!BN_set_word(rkey->e, rp->pubexp))
656296341Sdelphij            goto memerr;
657183234Ssimon
658296341Sdelphij        rsa_modlen = rp->bitlen / 8;
659296341Sdelphij        if (!lend_tobn(rkey->n, rsa_modulus, rsa_modlen))
660296341Sdelphij            goto memerr;
661183234Ssimon
662296341Sdelphij        RSA_set_ex_data(rkey, rsa_capi_idx, key);
663183234Ssimon
664296341Sdelphij        if (!(ret = EVP_PKEY_new()))
665296341Sdelphij            goto memerr;
666183234Ssimon
667296341Sdelphij        EVP_PKEY_assign_RSA(ret, rkey);
668296341Sdelphij        rkey = NULL;
669183234Ssimon
670296341Sdelphij    } else if (bh->aiKeyAlg == CALG_DSS_SIGN) {
671296341Sdelphij        DSSPUBKEY *dp;
672296341Sdelphij        DWORD dsa_plen;
673296341Sdelphij        unsigned char *btmp;
674296341Sdelphij        dp = (DSSPUBKEY *) (bh + 1);
675296341Sdelphij        if (dp->magic != 0x31535344) {
676296341Sdelphij            char magstr[10];
677296341Sdelphij            BIO_snprintf(magstr, 10, "%lx", dp->magic);
678296341Sdelphij            CAPIerr(CAPI_F_CAPI_GET_PKEY,
679296341Sdelphij                    CAPI_R_INVALID_DSA_PUBLIC_KEY_BLOB_MAGIC_NUMBER);
680296341Sdelphij            ERR_add_error_data(2, "magic=0x", magstr);
681296341Sdelphij            goto err;
682296341Sdelphij        }
683296341Sdelphij        dsa_plen = dp->bitlen / 8;
684296341Sdelphij        btmp = (unsigned char *)(dp + 1);
685296341Sdelphij        dkey = DSA_new_method(eng);
686296341Sdelphij        if (!dkey)
687296341Sdelphij            goto memerr;
688296341Sdelphij        dkey->p = BN_new();
689296341Sdelphij        dkey->q = BN_new();
690296341Sdelphij        dkey->g = BN_new();
691296341Sdelphij        dkey->pub_key = BN_new();
692296341Sdelphij        if (!dkey->p || !dkey->q || !dkey->g || !dkey->pub_key)
693296341Sdelphij            goto memerr;
694296341Sdelphij        if (!lend_tobn(dkey->p, btmp, dsa_plen))
695296341Sdelphij            goto memerr;
696296341Sdelphij        btmp += dsa_plen;
697296341Sdelphij        if (!lend_tobn(dkey->q, btmp, 20))
698296341Sdelphij            goto memerr;
699296341Sdelphij        btmp += 20;
700296341Sdelphij        if (!lend_tobn(dkey->g, btmp, dsa_plen))
701296341Sdelphij            goto memerr;
702296341Sdelphij        btmp += dsa_plen;
703296341Sdelphij        if (!lend_tobn(dkey->pub_key, btmp, dsa_plen))
704296341Sdelphij            goto memerr;
705296341Sdelphij        btmp += dsa_plen;
706183234Ssimon
707296341Sdelphij        DSA_set_ex_data(dkey, dsa_capi_idx, key);
708183234Ssimon
709296341Sdelphij        if (!(ret = EVP_PKEY_new()))
710296341Sdelphij            goto memerr;
711183234Ssimon
712296341Sdelphij        EVP_PKEY_assign_DSA(ret, dkey);
713296341Sdelphij        dkey = NULL;
714296341Sdelphij    } else {
715296341Sdelphij        char algstr[10];
716296341Sdelphij        BIO_snprintf(algstr, 10, "%lx", bh->aiKeyAlg);
717296341Sdelphij        CAPIerr(CAPI_F_CAPI_GET_PKEY,
718296341Sdelphij                CAPI_R_UNSUPPORTED_PUBLIC_KEY_ALGORITHM);
719296341Sdelphij        ERR_add_error_data(2, "aiKeyAlg=0x", algstr);
720296341Sdelphij        goto err;
721296341Sdelphij    }
722183234Ssimon
723296341Sdelphij err:
724296341Sdelphij    if (pubkey)
725296341Sdelphij        OPENSSL_free(pubkey);
726296341Sdelphij    if (!ret) {
727296341Sdelphij        if (rkey)
728296341Sdelphij            RSA_free(rkey);
729296341Sdelphij        if (dkey)
730296341Sdelphij            DSA_free(dkey);
731296341Sdelphij    }
732183234Ssimon
733296341Sdelphij    return ret;
734183234Ssimon
735296341Sdelphij memerr:
736296341Sdelphij    CAPIerr(CAPI_F_CAPI_GET_PKEY, ERR_R_MALLOC_FAILURE);
737296341Sdelphij    goto err;
738183234Ssimon
739296341Sdelphij}
740183234Ssimon
741183234Ssimonstatic EVP_PKEY *capi_load_privkey(ENGINE *eng, const char *key_id,
742296341Sdelphij                                   UI_METHOD *ui_method, void *callback_data)
743296341Sdelphij{
744296341Sdelphij    CAPI_CTX *ctx;
745296341Sdelphij    CAPI_KEY *key;
746296341Sdelphij    EVP_PKEY *ret;
747296341Sdelphij    ctx = ENGINE_get_ex_data(eng, capi_idx);
748183234Ssimon
749296341Sdelphij    if (!ctx) {
750296341Sdelphij        CAPIerr(CAPI_F_CAPI_LOAD_PRIVKEY, CAPI_R_CANT_FIND_CAPI_CONTEXT);
751296341Sdelphij        return NULL;
752296341Sdelphij    }
753183234Ssimon
754296341Sdelphij    key = capi_find_key(ctx, key_id);
755183234Ssimon
756296341Sdelphij    if (!key)
757296341Sdelphij        return NULL;
758183234Ssimon
759296341Sdelphij    ret = capi_get_pkey(eng, key);
760183234Ssimon
761296341Sdelphij    if (!ret)
762296341Sdelphij        capi_free_key(key);
763296341Sdelphij    return ret;
764183234Ssimon
765296341Sdelphij}
766183234Ssimon
767183234Ssimon/* CryptoAPI RSA operations */
768183234Ssimon
769183234Ssimonint capi_rsa_priv_enc(int flen, const unsigned char *from,
770296341Sdelphij                      unsigned char *to, RSA *rsa, int padding)
771296341Sdelphij{
772296341Sdelphij    CAPIerr(CAPI_F_CAPI_RSA_PRIV_ENC, CAPI_R_FUNCTION_NOT_SUPPORTED);
773296341Sdelphij    return -1;
774296341Sdelphij}
775183234Ssimon
776183234Ssimonint capi_rsa_sign(int dtype, const unsigned char *m, unsigned int m_len,
777296341Sdelphij                  unsigned char *sigret, unsigned int *siglen, const RSA *rsa)
778296341Sdelphij{
779296341Sdelphij    ALG_ID alg;
780296341Sdelphij    HCRYPTHASH hash;
781296341Sdelphij    DWORD slen;
782296341Sdelphij    unsigned int i;
783296341Sdelphij    int ret = -1;
784296341Sdelphij    CAPI_KEY *capi_key;
785296341Sdelphij    CAPI_CTX *ctx;
786183234Ssimon
787296341Sdelphij    ctx = ENGINE_get_ex_data(rsa->engine, capi_idx);
788183234Ssimon
789296341Sdelphij    CAPI_trace(ctx, "Called CAPI_rsa_sign()\n");
790183234Ssimon
791296341Sdelphij    capi_key = RSA_get_ex_data(rsa, rsa_capi_idx);
792296341Sdelphij    if (!capi_key) {
793296341Sdelphij        CAPIerr(CAPI_F_CAPI_RSA_SIGN, CAPI_R_CANT_GET_KEY);
794296341Sdelphij        return -1;
795296341Sdelphij    }
796183234Ssimon/* Convert the signature type to a CryptoAPI algorithm ID */
797296341Sdelphij    switch (dtype) {
798296341Sdelphij    case NID_sha1:
799296341Sdelphij        alg = CALG_SHA1;
800296341Sdelphij        break;
801183234Ssimon
802296341Sdelphij    case NID_md5:
803296341Sdelphij        alg = CALG_MD5;
804296341Sdelphij        break;
805183234Ssimon
806296341Sdelphij    case NID_md5_sha1:
807296341Sdelphij        alg = CALG_SSL3_SHAMD5;
808296341Sdelphij        break;
809296341Sdelphij    default:
810296341Sdelphij        {
811296341Sdelphij            char algstr[10];
812296341Sdelphij            BIO_snprintf(algstr, 10, "%lx", dtype);
813296341Sdelphij            CAPIerr(CAPI_F_CAPI_RSA_SIGN, CAPI_R_UNSUPPORTED_ALGORITHM_NID);
814296341Sdelphij            ERR_add_error_data(2, "NID=0x", algstr);
815296341Sdelphij            return -1;
816296341Sdelphij        }
817296341Sdelphij    }
818183234Ssimon
819183234Ssimon/* Create the hash object */
820296341Sdelphij    if (!CryptCreateHash(capi_key->hprov, alg, 0, 0, &hash)) {
821296341Sdelphij        CAPIerr(CAPI_F_CAPI_RSA_SIGN, CAPI_R_CANT_CREATE_HASH_OBJECT);
822296341Sdelphij        capi_addlasterror();
823296341Sdelphij        return -1;
824296341Sdelphij    }
825183234Ssimon/* Set the hash value to the value passed */
826183234Ssimon
827296341Sdelphij    if (!CryptSetHashParam(hash, HP_HASHVAL, (unsigned char *)m, 0)) {
828296341Sdelphij        CAPIerr(CAPI_F_CAPI_RSA_SIGN, CAPI_R_CANT_SET_HASH_VALUE);
829296341Sdelphij        capi_addlasterror();
830296341Sdelphij        goto err;
831296341Sdelphij    }
832183234Ssimon
833183234Ssimon/* Finally sign it */
834296341Sdelphij    slen = RSA_size(rsa);
835296341Sdelphij    if (!CryptSignHashA(hash, capi_key->keyspec, NULL, 0, sigret, &slen)) {
836296341Sdelphij        CAPIerr(CAPI_F_CAPI_RSA_SIGN, CAPI_R_ERROR_SIGNING_HASH);
837296341Sdelphij        capi_addlasterror();
838296341Sdelphij        goto err;
839296341Sdelphij    } else {
840296341Sdelphij        ret = 1;
841296341Sdelphij        /* Inplace byte reversal of signature */
842296341Sdelphij        for (i = 0; i < slen / 2; i++) {
843296341Sdelphij            unsigned char c;
844296341Sdelphij            c = sigret[i];
845296341Sdelphij            sigret[i] = sigret[slen - i - 1];
846296341Sdelphij            sigret[slen - i - 1] = c;
847296341Sdelphij        }
848296341Sdelphij        *siglen = slen;
849296341Sdelphij    }
850183234Ssimon
851296341Sdelphij    /* Now cleanup */
852183234Ssimon
853296341Sdelphij err:
854296341Sdelphij    CryptDestroyHash(hash);
855183234Ssimon
856296341Sdelphij    return ret;
857296341Sdelphij}
858183234Ssimon
859183234Ssimonint capi_rsa_priv_dec(int flen, const unsigned char *from,
860296341Sdelphij                      unsigned char *to, RSA *rsa, int padding)
861296341Sdelphij{
862296341Sdelphij    int i;
863296341Sdelphij    unsigned char *tmpbuf;
864296341Sdelphij    CAPI_KEY *capi_key;
865296341Sdelphij    CAPI_CTX *ctx;
866296341Sdelphij    ctx = ENGINE_get_ex_data(rsa->engine, capi_idx);
867183234Ssimon
868296341Sdelphij    CAPI_trace(ctx, "Called capi_rsa_priv_dec()\n");
869183234Ssimon
870296341Sdelphij    capi_key = RSA_get_ex_data(rsa, rsa_capi_idx);
871296341Sdelphij    if (!capi_key) {
872296341Sdelphij        CAPIerr(CAPI_F_CAPI_RSA_PRIV_DEC, CAPI_R_CANT_GET_KEY);
873296341Sdelphij        return -1;
874296341Sdelphij    }
875183234Ssimon
876296341Sdelphij    if (padding != RSA_PKCS1_PADDING) {
877296341Sdelphij        char errstr[10];
878296341Sdelphij        BIO_snprintf(errstr, 10, "%d", padding);
879296341Sdelphij        CAPIerr(CAPI_F_CAPI_RSA_PRIV_DEC, CAPI_R_UNSUPPORTED_PADDING);
880296341Sdelphij        ERR_add_error_data(2, "padding=", errstr);
881296341Sdelphij        return -1;
882296341Sdelphij    }
883183234Ssimon
884296341Sdelphij    /* Create temp reverse order version of input */
885296341Sdelphij    if (!(tmpbuf = OPENSSL_malloc(flen))) {
886296341Sdelphij        CAPIerr(CAPI_F_CAPI_RSA_PRIV_DEC, ERR_R_MALLOC_FAILURE);
887296341Sdelphij        return -1;
888296341Sdelphij    }
889296341Sdelphij    for (i = 0; i < flen; i++)
890296341Sdelphij        tmpbuf[flen - i - 1] = from[i];
891183234Ssimon
892296341Sdelphij    /* Finally decrypt it */
893296341Sdelphij    if (!CryptDecrypt(capi_key->key, 0, TRUE, 0, tmpbuf, &flen)) {
894296341Sdelphij        CAPIerr(CAPI_F_CAPI_RSA_PRIV_DEC, CAPI_R_DECRYPT_ERROR);
895296341Sdelphij        capi_addlasterror();
896296341Sdelphij        OPENSSL_free(tmpbuf);
897296341Sdelphij        return -1;
898296341Sdelphij    } else
899296341Sdelphij        memcpy(to, tmpbuf, flen);
900183234Ssimon
901296341Sdelphij    OPENSSL_free(tmpbuf);
902183234Ssimon
903296341Sdelphij    return flen;
904296341Sdelphij}
905183234Ssimon
906183234Ssimonstatic int capi_rsa_free(RSA *rsa)
907296341Sdelphij{
908296341Sdelphij    CAPI_KEY *capi_key;
909296341Sdelphij    capi_key = RSA_get_ex_data(rsa, rsa_capi_idx);
910296341Sdelphij    capi_free_key(capi_key);
911296341Sdelphij    RSA_set_ex_data(rsa, rsa_capi_idx, 0);
912296341Sdelphij    return 1;
913296341Sdelphij}
914183234Ssimon
915183234Ssimon/* CryptoAPI DSA operations */
916183234Ssimon
917183234Ssimonstatic DSA_SIG *capi_dsa_do_sign(const unsigned char *digest, int dlen,
918296341Sdelphij                                 DSA *dsa)
919296341Sdelphij{
920296341Sdelphij    HCRYPTHASH hash;
921296341Sdelphij    DWORD slen;
922296341Sdelphij    DSA_SIG *ret = NULL;
923296341Sdelphij    CAPI_KEY *capi_key;
924296341Sdelphij    CAPI_CTX *ctx;
925296341Sdelphij    unsigned char csigbuf[40];
926183234Ssimon
927296341Sdelphij    ctx = ENGINE_get_ex_data(dsa->engine, capi_idx);
928183234Ssimon
929296341Sdelphij    CAPI_trace(ctx, "Called CAPI_dsa_do_sign()\n");
930183234Ssimon
931296341Sdelphij    capi_key = DSA_get_ex_data(dsa, dsa_capi_idx);
932183234Ssimon
933296341Sdelphij    if (!capi_key) {
934296341Sdelphij        CAPIerr(CAPI_F_CAPI_DSA_DO_SIGN, CAPI_R_CANT_GET_KEY);
935296341Sdelphij        return NULL;
936296341Sdelphij    }
937183234Ssimon
938296341Sdelphij    if (dlen != 20) {
939296341Sdelphij        CAPIerr(CAPI_F_CAPI_DSA_DO_SIGN, CAPI_R_INVALID_DIGEST_LENGTH);
940296341Sdelphij        return NULL;
941296341Sdelphij    }
942183234Ssimon
943296341Sdelphij    /* Create the hash object */
944296341Sdelphij    if (!CryptCreateHash(capi_key->hprov, CALG_SHA1, 0, 0, &hash)) {
945296341Sdelphij        CAPIerr(CAPI_F_CAPI_DSA_DO_SIGN, CAPI_R_CANT_CREATE_HASH_OBJECT);
946296341Sdelphij        capi_addlasterror();
947296341Sdelphij        return NULL;
948296341Sdelphij    }
949183234Ssimon
950296341Sdelphij    /* Set the hash value to the value passed */
951296341Sdelphij    if (!CryptSetHashParam(hash, HP_HASHVAL, (unsigned char *)digest, 0)) {
952296341Sdelphij        CAPIerr(CAPI_F_CAPI_DSA_DO_SIGN, CAPI_R_CANT_SET_HASH_VALUE);
953296341Sdelphij        capi_addlasterror();
954296341Sdelphij        goto err;
955296341Sdelphij    }
956183234Ssimon
957296341Sdelphij    /* Finally sign it */
958296341Sdelphij    slen = sizeof(csigbuf);
959296341Sdelphij    if (!CryptSignHashA(hash, capi_key->keyspec, NULL, 0, csigbuf, &slen)) {
960296341Sdelphij        CAPIerr(CAPI_F_CAPI_DSA_DO_SIGN, CAPI_R_ERROR_SIGNING_HASH);
961296341Sdelphij        capi_addlasterror();
962296341Sdelphij        goto err;
963296341Sdelphij    } else {
964296341Sdelphij        ret = DSA_SIG_new();
965296341Sdelphij        if (!ret)
966296341Sdelphij            goto err;
967296341Sdelphij        ret->r = BN_new();
968296341Sdelphij        ret->s = BN_new();
969296341Sdelphij        if (!ret->r || !ret->s)
970296341Sdelphij            goto err;
971296341Sdelphij        if (!lend_tobn(ret->r, csigbuf, 20)
972296341Sdelphij            || !lend_tobn(ret->s, csigbuf + 20, 20)) {
973296341Sdelphij            DSA_SIG_free(ret);
974296341Sdelphij            ret = NULL;
975296341Sdelphij            goto err;
976296341Sdelphij        }
977296341Sdelphij    }
978183234Ssimon
979296341Sdelphij    /* Now cleanup */
980183234Ssimon
981296341Sdelphij err:
982296341Sdelphij    OPENSSL_cleanse(csigbuf, 40);
983296341Sdelphij    CryptDestroyHash(hash);
984296341Sdelphij    return ret;
985296341Sdelphij}
986183234Ssimon
987183234Ssimonstatic int capi_dsa_free(DSA *dsa)
988296341Sdelphij{
989296341Sdelphij    CAPI_KEY *capi_key;
990296341Sdelphij    capi_key = DSA_get_ex_data(dsa, dsa_capi_idx);
991296341Sdelphij    capi_free_key(capi_key);
992296341Sdelphij    DSA_set_ex_data(dsa, dsa_capi_idx, 0);
993296341Sdelphij    return 1;
994296341Sdelphij}
995183234Ssimon
996296341Sdelphijstatic void capi_vtrace(CAPI_CTX * ctx, int level, char *format,
997296341Sdelphij                        va_list argptr)
998296341Sdelphij{
999296341Sdelphij    BIO *out;
1000183234Ssimon
1001296341Sdelphij    if (!ctx || (ctx->debug_level < level) || (!ctx->debug_file))
1002296341Sdelphij        return;
1003296341Sdelphij    out = BIO_new_file(ctx->debug_file, "a+");
1004296341Sdelphij    BIO_vprintf(out, format, argptr);
1005296341Sdelphij    BIO_free(out);
1006296341Sdelphij}
1007183234Ssimon
1008296341Sdelphijstatic void CAPI_trace(CAPI_CTX * ctx, char *format, ...)
1009296341Sdelphij{
1010296341Sdelphij    va_list args;
1011296341Sdelphij    va_start(args, format);
1012296341Sdelphij    capi_vtrace(ctx, CAPI_DBG_TRACE, format, args);
1013296341Sdelphij    va_end(args);
1014296341Sdelphij}
1015183234Ssimon
1016183234Ssimonstatic void capi_addlasterror(void)
1017296341Sdelphij{
1018296341Sdelphij    capi_adderror(GetLastError());
1019296341Sdelphij}
1020183234Ssimon
1021183234Ssimonstatic void capi_adderror(DWORD err)
1022296341Sdelphij{
1023296341Sdelphij    char errstr[10];
1024296341Sdelphij    BIO_snprintf(errstr, 10, "%lX", err);
1025296341Sdelphij    ERR_add_error_data(2, "Error code= 0x", errstr);
1026296341Sdelphij}
1027183234Ssimon
1028183234Ssimonstatic char *wide_to_asc(LPWSTR wstr)
1029296341Sdelphij{
1030296341Sdelphij    char *str;
1031296341Sdelphij    int len_0, sz;
1032205128Ssimon
1033296341Sdelphij    if (!wstr)
1034296341Sdelphij        return NULL;
1035296341Sdelphij    len_0 = (int)wcslen(wstr) + 1; /* WideCharToMultiByte expects int */
1036296341Sdelphij    sz = WideCharToMultiByte(CP_ACP, 0, wstr, len_0, NULL, 0, NULL, NULL);
1037296341Sdelphij    if (!sz) {
1038296341Sdelphij        CAPIerr(CAPI_F_WIDE_TO_ASC, CAPI_R_WIN32_ERROR);
1039296341Sdelphij        return NULL;
1040296341Sdelphij    }
1041296341Sdelphij    str = OPENSSL_malloc(sz);
1042296341Sdelphij    if (!str) {
1043296341Sdelphij        CAPIerr(CAPI_F_WIDE_TO_ASC, ERR_R_MALLOC_FAILURE);
1044296341Sdelphij        return NULL;
1045296341Sdelphij    }
1046296341Sdelphij    if (!WideCharToMultiByte(CP_ACP, 0, wstr, len_0, str, sz, NULL, NULL)) {
1047296341Sdelphij        OPENSSL_free(str);
1048296341Sdelphij        CAPIerr(CAPI_F_WIDE_TO_ASC, CAPI_R_WIN32_ERROR);
1049296341Sdelphij        return NULL;
1050296341Sdelphij    }
1051296341Sdelphij    return str;
1052296341Sdelphij}
1053183234Ssimon
1054296341Sdelphijstatic int capi_get_provname(CAPI_CTX * ctx, LPSTR * pname, DWORD * ptype,
1055296341Sdelphij                             DWORD idx)
1056296341Sdelphij{
1057296341Sdelphij    LPSTR name;
1058296341Sdelphij    DWORD len, err;
1059296341Sdelphij    CAPI_trace(ctx, "capi_get_provname, index=%d\n", idx);
1060296341Sdelphij    if (!CryptEnumProvidersA(idx, NULL, 0, ptype, NULL, &len)) {
1061296341Sdelphij        err = GetLastError();
1062296341Sdelphij        if (err == ERROR_NO_MORE_ITEMS)
1063296341Sdelphij            return 2;
1064296341Sdelphij        CAPIerr(CAPI_F_CAPI_GET_PROVNAME, CAPI_R_CRYPTENUMPROVIDERS_ERROR);
1065296341Sdelphij        capi_adderror(err);
1066296341Sdelphij        return 0;
1067296341Sdelphij    }
1068296341Sdelphij    name = OPENSSL_malloc(len);
1069296341Sdelphij    if (!CryptEnumProvidersA(idx, NULL, 0, ptype, name, &len)) {
1070296341Sdelphij        err = GetLastError();
1071296341Sdelphij        if (err == ERROR_NO_MORE_ITEMS)
1072296341Sdelphij            return 2;
1073296341Sdelphij        CAPIerr(CAPI_F_CAPI_GET_PROVNAME, CAPI_R_CRYPTENUMPROVIDERS_ERROR);
1074296341Sdelphij        capi_adderror(err);
1075296341Sdelphij        return 0;
1076296341Sdelphij    }
1077296341Sdelphij    *pname = name;
1078296341Sdelphij    CAPI_trace(ctx, "capi_get_provname, returned name=%s, type=%d\n", name,
1079296341Sdelphij               *ptype);
1080183234Ssimon
1081296341Sdelphij    return 1;
1082296341Sdelphij}
1083183234Ssimon
1084296341Sdelphijstatic int capi_list_providers(CAPI_CTX * ctx, BIO *out)
1085296341Sdelphij{
1086296341Sdelphij    DWORD idx, ptype;
1087296341Sdelphij    int ret;
1088296341Sdelphij    LPSTR provname = NULL;
1089296341Sdelphij    CAPI_trace(ctx, "capi_list_providers\n");
1090296341Sdelphij    BIO_printf(out, "Available CSPs:\n");
1091296341Sdelphij    for (idx = 0;; idx++) {
1092296341Sdelphij        ret = capi_get_provname(ctx, &provname, &ptype, idx);
1093296341Sdelphij        if (ret == 2)
1094296341Sdelphij            break;
1095296341Sdelphij        if (ret == 0)
1096296341Sdelphij            break;
1097296341Sdelphij        BIO_printf(out, "%d. %s, type %d\n", idx, provname, ptype);
1098296341Sdelphij        OPENSSL_free(provname);
1099296341Sdelphij    }
1100296341Sdelphij    return 1;
1101296341Sdelphij}
1102183234Ssimon
1103296341Sdelphijstatic int capi_list_containers(CAPI_CTX * ctx, BIO *out)
1104296341Sdelphij{
1105296341Sdelphij    int ret = 1;
1106296341Sdelphij    HCRYPTPROV hprov;
1107296341Sdelphij    DWORD err, idx, flags, buflen = 0, clen;
1108296341Sdelphij    LPSTR cname;
1109296341Sdelphij    CAPI_trace(ctx, "Listing containers CSP=%s, type = %d\n", ctx->cspname,
1110296341Sdelphij               ctx->csptype);
1111296341Sdelphij    if (!CryptAcquireContextA
1112296341Sdelphij        (&hprov, NULL, ctx->cspname, ctx->csptype, CRYPT_VERIFYCONTEXT)) {
1113296341Sdelphij        CAPIerr(CAPI_F_CAPI_LIST_CONTAINERS,
1114296341Sdelphij                CAPI_R_CRYPTACQUIRECONTEXT_ERROR);
1115296341Sdelphij        capi_addlasterror();
1116296341Sdelphij        return 0;
1117296341Sdelphij    }
1118296341Sdelphij    if (!CryptGetProvParam
1119296341Sdelphij        (hprov, PP_ENUMCONTAINERS, NULL, &buflen, CRYPT_FIRST)) {
1120296341Sdelphij        CAPIerr(CAPI_F_CAPI_LIST_CONTAINERS, CAPI_R_ENUMCONTAINERS_ERROR);
1121296341Sdelphij        capi_addlasterror();
1122296341Sdelphij        CryptReleaseContext(hprov, 0);
1123296341Sdelphij        return 0;
1124296341Sdelphij    }
1125296341Sdelphij    CAPI_trace(ctx, "Got max container len %d\n", buflen);
1126296341Sdelphij    if (buflen == 0)
1127296341Sdelphij        buflen = 1024;
1128296341Sdelphij    cname = OPENSSL_malloc(buflen);
1129296341Sdelphij    if (!cname) {
1130296341Sdelphij        CAPIerr(CAPI_F_CAPI_LIST_CONTAINERS, ERR_R_MALLOC_FAILURE);
1131296341Sdelphij        goto err;
1132296341Sdelphij    }
1133183234Ssimon
1134296341Sdelphij    for (idx = 0;; idx++) {
1135296341Sdelphij        clen = buflen;
1136296341Sdelphij        cname[0] = 0;
1137183234Ssimon
1138296341Sdelphij        if (idx == 0)
1139296341Sdelphij            flags = CRYPT_FIRST;
1140296341Sdelphij        else
1141296341Sdelphij            flags = 0;
1142296341Sdelphij        if (!CryptGetProvParam(hprov, PP_ENUMCONTAINERS, cname, &clen, flags)) {
1143296341Sdelphij            err = GetLastError();
1144296341Sdelphij            if (err == ERROR_NO_MORE_ITEMS)
1145296341Sdelphij                goto done;
1146296341Sdelphij            CAPIerr(CAPI_F_CAPI_LIST_CONTAINERS, CAPI_R_ENUMCONTAINERS_ERROR);
1147296341Sdelphij            capi_adderror(err);
1148296341Sdelphij            goto err;
1149296341Sdelphij        }
1150296341Sdelphij        CAPI_trace(ctx, "Container name %s, len=%d, index=%d, flags=%d\n",
1151296341Sdelphij                   cname, clen, idx, flags);
1152296341Sdelphij        if (!cname[0] && (clen == buflen)) {
1153296341Sdelphij            CAPI_trace(ctx, "Enumerate bug: using workaround\n");
1154296341Sdelphij            goto done;
1155296341Sdelphij        }
1156296341Sdelphij        BIO_printf(out, "%d. %s\n", idx, cname);
1157296341Sdelphij    }
1158296341Sdelphij err:
1159183234Ssimon
1160296341Sdelphij    ret = 0;
1161183234Ssimon
1162296341Sdelphij done:
1163296341Sdelphij    if (cname)
1164296341Sdelphij        OPENSSL_free(cname);
1165296341Sdelphij    CryptReleaseContext(hprov, 0);
1166183234Ssimon
1167296341Sdelphij    return ret;
1168296341Sdelphij}
1169183234Ssimon
1170296341SdelphijCRYPT_KEY_PROV_INFO *capi_get_prov_info(CAPI_CTX * ctx, PCCERT_CONTEXT cert)
1171296341Sdelphij{
1172296341Sdelphij    DWORD len;
1173296341Sdelphij    CRYPT_KEY_PROV_INFO *pinfo;
1174183234Ssimon
1175296341Sdelphij    if (!CertGetCertificateContextProperty
1176296341Sdelphij        (cert, CERT_KEY_PROV_INFO_PROP_ID, NULL, &len))
1177296341Sdelphij        return NULL;
1178296341Sdelphij    pinfo = OPENSSL_malloc(len);
1179296341Sdelphij    if (!pinfo) {
1180296341Sdelphij        CAPIerr(CAPI_F_CAPI_GET_PROV_INFO, ERR_R_MALLOC_FAILURE);
1181296341Sdelphij        return NULL;
1182296341Sdelphij    }
1183296341Sdelphij    if (!CertGetCertificateContextProperty
1184296341Sdelphij        (cert, CERT_KEY_PROV_INFO_PROP_ID, pinfo, &len)) {
1185296341Sdelphij        CAPIerr(CAPI_F_CAPI_GET_PROV_INFO,
1186296341Sdelphij                CAPI_R_ERROR_GETTING_KEY_PROVIDER_INFO);
1187296341Sdelphij        capi_addlasterror();
1188296341Sdelphij        OPENSSL_free(pinfo);
1189296341Sdelphij        return NULL;
1190296341Sdelphij    }
1191296341Sdelphij    return pinfo;
1192296341Sdelphij}
1193183234Ssimon
1194296341Sdelphijstatic void capi_dump_prov_info(CAPI_CTX * ctx, BIO *out,
1195296341Sdelphij                                CRYPT_KEY_PROV_INFO * pinfo)
1196296341Sdelphij{
1197296341Sdelphij    char *provname = NULL, *contname = NULL;
1198296341Sdelphij    if (!pinfo) {
1199296341Sdelphij        BIO_printf(out, "  No Private Key\n");
1200296341Sdelphij        return;
1201296341Sdelphij    }
1202296341Sdelphij    provname = wide_to_asc(pinfo->pwszProvName);
1203296341Sdelphij    contname = wide_to_asc(pinfo->pwszContainerName);
1204296341Sdelphij    if (!provname || !contname)
1205296341Sdelphij        goto err;
1206183234Ssimon
1207296341Sdelphij    BIO_printf(out, "  Private Key Info:\n");
1208296341Sdelphij    BIO_printf(out, "    Provider Name:  %s, Provider Type %d\n", provname,
1209296341Sdelphij               pinfo->dwProvType);
1210296341Sdelphij    BIO_printf(out, "    Container Name: %s, Key Type %d\n", contname,
1211296341Sdelphij               pinfo->dwKeySpec);
1212296341Sdelphij err:
1213296341Sdelphij    if (provname)
1214296341Sdelphij        OPENSSL_free(provname);
1215296341Sdelphij    if (contname)
1216296341Sdelphij        OPENSSL_free(contname);
1217296341Sdelphij}
1218183234Ssimon
1219296341Sdelphijchar *capi_cert_get_fname(CAPI_CTX * ctx, PCCERT_CONTEXT cert)
1220296341Sdelphij{
1221296341Sdelphij    LPWSTR wfname;
1222296341Sdelphij    DWORD dlen;
1223183234Ssimon
1224296341Sdelphij    CAPI_trace(ctx, "capi_cert_get_fname\n");
1225296341Sdelphij    if (!CertGetCertificateContextProperty
1226296341Sdelphij        (cert, CERT_FRIENDLY_NAME_PROP_ID, NULL, &dlen))
1227296341Sdelphij        return NULL;
1228296341Sdelphij    wfname = OPENSSL_malloc(dlen);
1229296341Sdelphij    if (CertGetCertificateContextProperty
1230296341Sdelphij        (cert, CERT_FRIENDLY_NAME_PROP_ID, wfname, &dlen)) {
1231296341Sdelphij        char *fname = wide_to_asc(wfname);
1232296341Sdelphij        OPENSSL_free(wfname);
1233296341Sdelphij        return fname;
1234296341Sdelphij    }
1235296341Sdelphij    CAPIerr(CAPI_F_CAPI_CERT_GET_FNAME, CAPI_R_ERROR_GETTING_FRIENDLY_NAME);
1236296341Sdelphij    capi_addlasterror();
1237183234Ssimon
1238296341Sdelphij    OPENSSL_free(wfname);
1239296341Sdelphij    return NULL;
1240296341Sdelphij}
1241183234Ssimon
1242296341Sdelphijvoid capi_dump_cert(CAPI_CTX * ctx, BIO *out, PCCERT_CONTEXT cert)
1243296341Sdelphij{
1244296341Sdelphij    X509 *x;
1245296341Sdelphij    unsigned char *p;
1246296341Sdelphij    unsigned long flags = ctx->dump_flags;
1247296341Sdelphij    if (flags & CAPI_DMP_FNAME) {
1248296341Sdelphij        char *fname;
1249296341Sdelphij        fname = capi_cert_get_fname(ctx, cert);
1250296341Sdelphij        if (fname) {
1251296341Sdelphij            BIO_printf(out, "  Friendly Name \"%s\"\n", fname);
1252296341Sdelphij            OPENSSL_free(fname);
1253296341Sdelphij        } else
1254296341Sdelphij            BIO_printf(out, "  <No Friendly Name>\n");
1255296341Sdelphij    }
1256183234Ssimon
1257296341Sdelphij    p = cert->pbCertEncoded;
1258296341Sdelphij    x = d2i_X509(NULL, &p, cert->cbCertEncoded);
1259296341Sdelphij    if (!x)
1260296341Sdelphij        BIO_printf(out, "  <Can't parse certificate>\n");
1261296341Sdelphij    if (flags & CAPI_DMP_SUMMARY) {
1262296341Sdelphij        BIO_printf(out, "  Subject: ");
1263296341Sdelphij        X509_NAME_print_ex(out, X509_get_subject_name(x), 0, XN_FLAG_ONELINE);
1264296341Sdelphij        BIO_printf(out, "\n  Issuer: ");
1265296341Sdelphij        X509_NAME_print_ex(out, X509_get_issuer_name(x), 0, XN_FLAG_ONELINE);
1266296341Sdelphij        BIO_printf(out, "\n");
1267296341Sdelphij    }
1268296341Sdelphij    if (flags & CAPI_DMP_FULL)
1269296341Sdelphij        X509_print_ex(out, x, XN_FLAG_ONELINE, 0);
1270183234Ssimon
1271296341Sdelphij    if (flags & CAPI_DMP_PKEYINFO) {
1272296341Sdelphij        CRYPT_KEY_PROV_INFO *pinfo;
1273296341Sdelphij        pinfo = capi_get_prov_info(ctx, cert);
1274296341Sdelphij        capi_dump_prov_info(ctx, out, pinfo);
1275296341Sdelphij        if (pinfo)
1276296341Sdelphij            OPENSSL_free(pinfo);
1277296341Sdelphij    }
1278183234Ssimon
1279296341Sdelphij    if (flags & CAPI_DMP_PEM)
1280296341Sdelphij        PEM_write_bio_X509(out, x);
1281296341Sdelphij    X509_free(x);
1282296341Sdelphij}
1283183234Ssimon
1284296341SdelphijHCERTSTORE capi_open_store(CAPI_CTX * ctx, char *storename)
1285296341Sdelphij{
1286296341Sdelphij    HCERTSTORE hstore;
1287183234Ssimon
1288296341Sdelphij    if (!storename)
1289296341Sdelphij        storename = ctx->storename;
1290296341Sdelphij    if (!storename)
1291296341Sdelphij        storename = "MY";
1292296341Sdelphij    CAPI_trace(ctx, "Opening certificate store %s\n", storename);
1293183234Ssimon
1294296341Sdelphij    hstore = CertOpenStore(CERT_STORE_PROV_SYSTEM_A, 0, 0,
1295296341Sdelphij                           ctx->store_flags, storename);
1296296341Sdelphij    if (!hstore) {
1297296341Sdelphij        CAPIerr(CAPI_F_CAPI_OPEN_STORE, CAPI_R_ERROR_OPENING_STORE);
1298296341Sdelphij        capi_addlasterror();
1299296341Sdelphij    }
1300296341Sdelphij    return hstore;
1301296341Sdelphij}
1302183234Ssimon
1303296341Sdelphijint capi_list_certs(CAPI_CTX * ctx, BIO *out, char *id)
1304296341Sdelphij{
1305296341Sdelphij    char *storename;
1306296341Sdelphij    int idx;
1307296341Sdelphij    int ret = 1;
1308296341Sdelphij    HCERTSTORE hstore;
1309296341Sdelphij    PCCERT_CONTEXT cert = NULL;
1310183234Ssimon
1311296341Sdelphij    storename = ctx->storename;
1312296341Sdelphij    if (!storename)
1313296341Sdelphij        storename = "MY";
1314296341Sdelphij    CAPI_trace(ctx, "Listing certs for store %s\n", storename);
1315183234Ssimon
1316296341Sdelphij    hstore = capi_open_store(ctx, storename);
1317296341Sdelphij    if (!hstore)
1318296341Sdelphij        return 0;
1319296341Sdelphij    if (id) {
1320296341Sdelphij        cert = capi_find_cert(ctx, id, hstore);
1321296341Sdelphij        if (!cert) {
1322296341Sdelphij            ret = 0;
1323296341Sdelphij            goto err;
1324296341Sdelphij        }
1325296341Sdelphij        capi_dump_cert(ctx, out, cert);
1326296341Sdelphij        CertFreeCertificateContext(cert);
1327296341Sdelphij    } else {
1328296341Sdelphij        for (idx = 0;; idx++) {
1329296341Sdelphij            LPWSTR fname = NULL;
1330296341Sdelphij            cert = CertEnumCertificatesInStore(hstore, cert);
1331296341Sdelphij            if (!cert)
1332296341Sdelphij                break;
1333296341Sdelphij            BIO_printf(out, "Certificate %d\n", idx);
1334296341Sdelphij            capi_dump_cert(ctx, out, cert);
1335296341Sdelphij        }
1336296341Sdelphij    }
1337296341Sdelphij err:
1338296341Sdelphij    CertCloseStore(hstore, 0);
1339296341Sdelphij    return ret;
1340296341Sdelphij}
1341183234Ssimon
1342296341Sdelphijstatic PCCERT_CONTEXT capi_find_cert(CAPI_CTX * ctx, const char *id,
1343296341Sdelphij                                     HCERTSTORE hstore)
1344296341Sdelphij{
1345296341Sdelphij    PCCERT_CONTEXT cert = NULL;
1346296341Sdelphij    char *fname = NULL;
1347296341Sdelphij    int match;
1348296341Sdelphij    switch (ctx->lookup_method) {
1349296341Sdelphij    case CAPI_LU_SUBSTR:
1350296341Sdelphij        return CertFindCertificateInStore(hstore,
1351296341Sdelphij                                          X509_ASN_ENCODING, 0,
1352296341Sdelphij                                          CERT_FIND_SUBJECT_STR_A, id, NULL);
1353296341Sdelphij    case CAPI_LU_FNAME:
1354296341Sdelphij        for (;;) {
1355296341Sdelphij            cert = CertEnumCertificatesInStore(hstore, cert);
1356296341Sdelphij            if (!cert)
1357296341Sdelphij                return NULL;
1358296341Sdelphij            fname = capi_cert_get_fname(ctx, cert);
1359296341Sdelphij            if (fname) {
1360296341Sdelphij                if (strcmp(fname, id))
1361296341Sdelphij                    match = 0;
1362296341Sdelphij                else
1363296341Sdelphij                    match = 1;
1364296341Sdelphij                OPENSSL_free(fname);
1365296341Sdelphij                if (match)
1366296341Sdelphij                    return cert;
1367296341Sdelphij            }
1368296341Sdelphij        }
1369296341Sdelphij    default:
1370296341Sdelphij        return NULL;
1371296341Sdelphij    }
1372296341Sdelphij}
1373183234Ssimon
1374296341Sdelphijstatic CAPI_KEY *capi_get_key(CAPI_CTX * ctx, const char *contname,
1375296341Sdelphij                              char *provname, DWORD ptype, DWORD keyspec)
1376296341Sdelphij{
1377296341Sdelphij    CAPI_KEY *key;
1378296341Sdelphij    DWORD dwFlags = 0;
1379296341Sdelphij    key = OPENSSL_malloc(sizeof(CAPI_KEY));
1380296341Sdelphij    CAPI_trace(ctx, "capi_get_key, contname=%s, provname=%s, type=%d\n",
1381296341Sdelphij               contname, provname, ptype);
1382296341Sdelphij    if (ctx->store_flags & CERT_SYSTEM_STORE_LOCAL_MACHINE)
1383246772Sjkim        dwFlags = CRYPT_MACHINE_KEYSET;
1384296341Sdelphij    if (!CryptAcquireContextA
1385296341Sdelphij        (&key->hprov, contname, provname, ptype, dwFlags)) {
1386296341Sdelphij        CAPIerr(CAPI_F_CAPI_GET_KEY, CAPI_R_CRYPTACQUIRECONTEXT_ERROR);
1387296341Sdelphij        capi_addlasterror();
1388296341Sdelphij        goto err;
1389296341Sdelphij    }
1390296341Sdelphij    if (!CryptGetUserKey(key->hprov, keyspec, &key->key)) {
1391296341Sdelphij        CAPIerr(CAPI_F_CAPI_GET_KEY, CAPI_R_GETUSERKEY_ERROR);
1392296341Sdelphij        capi_addlasterror();
1393296341Sdelphij        CryptReleaseContext(key->hprov, 0);
1394296341Sdelphij        goto err;
1395296341Sdelphij    }
1396296341Sdelphij    key->keyspec = keyspec;
1397296341Sdelphij    key->pcert = NULL;
1398296341Sdelphij    return key;
1399183234Ssimon
1400296341Sdelphij err:
1401296341Sdelphij    OPENSSL_free(key);
1402296341Sdelphij    return NULL;
1403296341Sdelphij}
1404183234Ssimon
1405296341Sdelphijstatic CAPI_KEY *capi_get_cert_key(CAPI_CTX * ctx, PCCERT_CONTEXT cert)
1406296341Sdelphij{
1407296341Sdelphij    CAPI_KEY *key = NULL;
1408296341Sdelphij    CRYPT_KEY_PROV_INFO *pinfo = NULL;
1409296341Sdelphij    char *provname = NULL, *contname = NULL;
1410296341Sdelphij    pinfo = capi_get_prov_info(ctx, cert);
1411296341Sdelphij    if (!pinfo)
1412296341Sdelphij        goto err;
1413296341Sdelphij    provname = wide_to_asc(pinfo->pwszProvName);
1414296341Sdelphij    contname = wide_to_asc(pinfo->pwszContainerName);
1415296341Sdelphij    if (!provname || !contname)
1416296341Sdelphij        goto err;
1417296341Sdelphij    key = capi_get_key(ctx, contname, provname,
1418296341Sdelphij                       pinfo->dwProvType, pinfo->dwKeySpec);
1419183234Ssimon
1420296341Sdelphij err:
1421296341Sdelphij    if (pinfo)
1422296341Sdelphij        OPENSSL_free(pinfo);
1423296341Sdelphij    if (provname)
1424296341Sdelphij        OPENSSL_free(provname);
1425296341Sdelphij    if (contname)
1426296341Sdelphij        OPENSSL_free(contname);
1427296341Sdelphij    return key;
1428296341Sdelphij}
1429183234Ssimon
1430296341SdelphijCAPI_KEY *capi_find_key(CAPI_CTX * ctx, const char *id)
1431296341Sdelphij{
1432296341Sdelphij    PCCERT_CONTEXT cert;
1433296341Sdelphij    HCERTSTORE hstore;
1434296341Sdelphij    CAPI_KEY *key = NULL;
1435296341Sdelphij    switch (ctx->lookup_method) {
1436296341Sdelphij    case CAPI_LU_SUBSTR:
1437296341Sdelphij    case CAPI_LU_FNAME:
1438296341Sdelphij        hstore = capi_open_store(ctx, NULL);
1439296341Sdelphij        if (!hstore)
1440296341Sdelphij            return NULL;
1441296341Sdelphij        cert = capi_find_cert(ctx, id, hstore);
1442296341Sdelphij        if (cert) {
1443296341Sdelphij            key = capi_get_cert_key(ctx, cert);
1444296341Sdelphij            CertFreeCertificateContext(cert);
1445296341Sdelphij        }
1446296341Sdelphij        CertCloseStore(hstore, 0);
1447296341Sdelphij        break;
1448183234Ssimon
1449296341Sdelphij    case CAPI_LU_CONTNAME:
1450296341Sdelphij        key = capi_get_key(ctx, id, ctx->cspname, ctx->csptype, ctx->keytype);
1451296341Sdelphij        break;
1452296341Sdelphij    }
1453183234Ssimon
1454296341Sdelphij    return key;
1455296341Sdelphij}
1456183234Ssimon
1457296341Sdelphijvoid capi_free_key(CAPI_KEY * key)
1458296341Sdelphij{
1459296341Sdelphij    if (!key)
1460296341Sdelphij        return;
1461296341Sdelphij    CryptDestroyKey(key->key);
1462296341Sdelphij    CryptReleaseContext(key->hprov, 0);
1463296341Sdelphij    if (key->pcert)
1464296341Sdelphij        CertFreeCertificateContext(key->pcert);
1465296341Sdelphij    OPENSSL_free(key);
1466296341Sdelphij}
1467183234Ssimon
1468183234Ssimon/* Initialize a CAPI_CTX structure */
1469183234Ssimon
1470183234Ssimonstatic CAPI_CTX *capi_ctx_new()
1471296341Sdelphij{
1472296341Sdelphij    CAPI_CTX *ctx;
1473296341Sdelphij    ctx = OPENSSL_malloc(sizeof(CAPI_CTX));
1474296341Sdelphij    if (!ctx) {
1475296341Sdelphij        CAPIerr(CAPI_F_CAPI_CTX_NEW, ERR_R_MALLOC_FAILURE);
1476296341Sdelphij        return NULL;
1477296341Sdelphij    }
1478296341Sdelphij    ctx->cspname = NULL;
1479296341Sdelphij    ctx->csptype = PROV_RSA_FULL;
1480296341Sdelphij    ctx->dump_flags = CAPI_DMP_SUMMARY | CAPI_DMP_FNAME;
1481296341Sdelphij    ctx->keytype = AT_KEYEXCHANGE;
1482296341Sdelphij    ctx->storename = NULL;
1483296341Sdelphij    ctx->ssl_client_store = NULL;
1484296341Sdelphij    ctx->store_flags = CERT_STORE_OPEN_EXISTING_FLAG |
1485296341Sdelphij        CERT_STORE_READONLY_FLAG | CERT_SYSTEM_STORE_CURRENT_USER;
1486296341Sdelphij    ctx->lookup_method = CAPI_LU_SUBSTR;
1487296341Sdelphij    ctx->debug_level = 0;
1488296341Sdelphij    ctx->debug_file = NULL;
1489296341Sdelphij    ctx->client_cert_select = cert_select_simple;
1490296341Sdelphij    return ctx;
1491296341Sdelphij}
1492183234Ssimon
1493296341Sdelphijstatic void capi_ctx_free(CAPI_CTX * ctx)
1494296341Sdelphij{
1495296341Sdelphij    CAPI_trace(ctx, "Calling capi_ctx_free with %lx\n", ctx);
1496296341Sdelphij    if (!ctx)
1497296341Sdelphij        return;
1498296341Sdelphij    if (ctx->cspname)
1499296341Sdelphij        OPENSSL_free(ctx->cspname);
1500296341Sdelphij    if (ctx->debug_file)
1501296341Sdelphij        OPENSSL_free(ctx->debug_file);
1502296341Sdelphij    if (ctx->storename)
1503296341Sdelphij        OPENSSL_free(ctx->storename);
1504296341Sdelphij    if (ctx->ssl_client_store)
1505296341Sdelphij        OPENSSL_free(ctx->ssl_client_store);
1506296341Sdelphij    OPENSSL_free(ctx);
1507296341Sdelphij}
1508183234Ssimon
1509296341Sdelphijstatic int capi_ctx_set_provname(CAPI_CTX * ctx, LPSTR pname, DWORD type,
1510296341Sdelphij                                 int check)
1511296341Sdelphij{
1512296341Sdelphij    CAPI_trace(ctx, "capi_ctx_set_provname, name=%s, type=%d\n", pname, type);
1513296341Sdelphij    if (check) {
1514296341Sdelphij        HCRYPTPROV hprov;
1515296341Sdelphij        if (!CryptAcquireContextA(&hprov, NULL, pname, type,
1516296341Sdelphij                                  CRYPT_VERIFYCONTEXT)) {
1517296341Sdelphij            CAPIerr(CAPI_F_CAPI_CTX_SET_PROVNAME,
1518296341Sdelphij                    CAPI_R_CRYPTACQUIRECONTEXT_ERROR);
1519296341Sdelphij            capi_addlasterror();
1520296341Sdelphij            return 0;
1521296341Sdelphij        }
1522296341Sdelphij        CryptReleaseContext(hprov, 0);
1523296341Sdelphij    }
1524296341Sdelphij    if (ctx->cspname)
1525296341Sdelphij        OPENSSL_free(ctx->cspname);
1526296341Sdelphij    ctx->cspname = BUF_strdup(pname);
1527296341Sdelphij    ctx->csptype = type;
1528296341Sdelphij    return 1;
1529296341Sdelphij}
1530183234Ssimon
1531296341Sdelphijstatic int capi_ctx_set_provname_idx(CAPI_CTX * ctx, int idx)
1532296341Sdelphij{
1533296341Sdelphij    LPSTR pname;
1534296341Sdelphij    DWORD type;
1535296341Sdelphij    int res;
1536296341Sdelphij    if (capi_get_provname(ctx, &pname, &type, idx) != 1)
1537296341Sdelphij        return 0;
1538296341Sdelphij    res = capi_ctx_set_provname(ctx, pname, type, 0);
1539296341Sdelphij    OPENSSL_free(pname);
1540296341Sdelphij    return res;
1541296341Sdelphij}
1542183234Ssimon
1543183234Ssimonstatic int cert_issuer_match(STACK_OF(X509_NAME) *ca_dn, X509 *x)
1544296341Sdelphij{
1545296341Sdelphij    int i;
1546296341Sdelphij    X509_NAME *nm;
1547296341Sdelphij    /* Special case: empty list: match anything */
1548296341Sdelphij    if (sk_X509_NAME_num(ca_dn) <= 0)
1549296341Sdelphij        return 1;
1550296341Sdelphij    for (i = 0; i < sk_X509_NAME_num(ca_dn); i++) {
1551296341Sdelphij        nm = sk_X509_NAME_value(ca_dn, i);
1552296341Sdelphij        if (!X509_NAME_cmp(nm, X509_get_issuer_name(x)))
1553296341Sdelphij            return 1;
1554296341Sdelphij    }
1555296341Sdelphij    return 0;
1556296341Sdelphij}
1557183234Ssimon
1558183234Ssimonstatic int capi_load_ssl_client_cert(ENGINE *e, SSL *ssl,
1559296341Sdelphij                                     STACK_OF(X509_NAME) *ca_dn, X509 **pcert,
1560296341Sdelphij                                     EVP_PKEY **pkey, STACK_OF(X509) **pother,
1561296341Sdelphij                                     UI_METHOD *ui_method,
1562296341Sdelphij                                     void *callback_data)
1563296341Sdelphij{
1564296341Sdelphij    STACK_OF(X509) *certs = NULL;
1565296341Sdelphij    X509 *x;
1566296341Sdelphij    char *storename;
1567296341Sdelphij    const char *p;
1568296341Sdelphij    int i, client_cert_idx;
1569296341Sdelphij    HCERTSTORE hstore;
1570296341Sdelphij    PCCERT_CONTEXT cert = NULL, excert = NULL;
1571296341Sdelphij    CAPI_CTX *ctx;
1572296341Sdelphij    CAPI_KEY *key;
1573296341Sdelphij    ctx = ENGINE_get_ex_data(e, capi_idx);
1574183234Ssimon
1575296341Sdelphij    *pcert = NULL;
1576296341Sdelphij    *pkey = NULL;
1577183234Ssimon
1578296341Sdelphij    storename = ctx->ssl_client_store;
1579296341Sdelphij    if (!storename)
1580296341Sdelphij        storename = "MY";
1581183234Ssimon
1582296341Sdelphij    hstore = capi_open_store(ctx, storename);
1583296341Sdelphij    if (!hstore)
1584296341Sdelphij        return 0;
1585296341Sdelphij    /* Enumerate all certificates collect any matches */
1586296341Sdelphij    for (i = 0;; i++) {
1587296341Sdelphij        cert = CertEnumCertificatesInStore(hstore, cert);
1588296341Sdelphij        if (!cert)
1589296341Sdelphij            break;
1590296341Sdelphij        p = cert->pbCertEncoded;
1591296341Sdelphij        x = d2i_X509(NULL, &p, cert->cbCertEncoded);
1592296341Sdelphij        if (!x) {
1593296341Sdelphij            CAPI_trace(ctx, "Can't Parse Certificate %d\n", i);
1594296341Sdelphij            continue;
1595296341Sdelphij        }
1596296341Sdelphij        if (cert_issuer_match(ca_dn, x)
1597296341Sdelphij            && X509_check_purpose(x, X509_PURPOSE_SSL_CLIENT, 0)) {
1598296341Sdelphij            key = capi_get_cert_key(ctx, cert);
1599296341Sdelphij            if (!key) {
1600296341Sdelphij                X509_free(x);
1601296341Sdelphij                continue;
1602296341Sdelphij            }
1603296341Sdelphij            /*
1604296341Sdelphij             * Match found: attach extra data to it so we can retrieve the
1605296341Sdelphij             * key later.
1606296341Sdelphij             */
1607296341Sdelphij            excert = CertDuplicateCertificateContext(cert);
1608296341Sdelphij            key->pcert = excert;
1609296341Sdelphij            X509_set_ex_data(x, cert_capi_idx, key);
1610183234Ssimon
1611296341Sdelphij            if (!certs)
1612296341Sdelphij                certs = sk_X509_new_null();
1613183234Ssimon
1614296341Sdelphij            sk_X509_push(certs, x);
1615296341Sdelphij        } else
1616296341Sdelphij            X509_free(x);
1617183234Ssimon
1618296341Sdelphij    }
1619183234Ssimon
1620296341Sdelphij    if (cert)
1621296341Sdelphij        CertFreeCertificateContext(cert);
1622296341Sdelphij    if (hstore)
1623296341Sdelphij        CertCloseStore(hstore, 0);
1624183234Ssimon
1625296341Sdelphij    if (!certs)
1626296341Sdelphij        return 0;
1627183234Ssimon
1628296341Sdelphij    /* Select the appropriate certificate */
1629183234Ssimon
1630296341Sdelphij    client_cert_idx = ctx->client_cert_select(e, ssl, certs);
1631183234Ssimon
1632296341Sdelphij    /* Set the selected certificate and free the rest */
1633183234Ssimon
1634296341Sdelphij    for (i = 0; i < sk_X509_num(certs); i++) {
1635296341Sdelphij        x = sk_X509_value(certs, i);
1636296341Sdelphij        if (i == client_cert_idx)
1637296341Sdelphij            *pcert = x;
1638296341Sdelphij        else {
1639296341Sdelphij            key = X509_get_ex_data(x, cert_capi_idx);
1640296341Sdelphij            capi_free_key(key);
1641296341Sdelphij            X509_free(x);
1642296341Sdelphij        }
1643296341Sdelphij    }
1644183234Ssimon
1645296341Sdelphij    sk_X509_free(certs);
1646183234Ssimon
1647296341Sdelphij    if (!*pcert)
1648296341Sdelphij        return 0;
1649183234Ssimon
1650296341Sdelphij    /* Setup key for selected certificate */
1651183234Ssimon
1652296341Sdelphij    key = X509_get_ex_data(*pcert, cert_capi_idx);
1653296341Sdelphij    *pkey = capi_get_pkey(e, key);
1654296341Sdelphij    X509_set_ex_data(*pcert, cert_capi_idx, NULL);
1655183234Ssimon
1656296341Sdelphij    return 1;
1657183234Ssimon
1658296341Sdelphij}
1659183234Ssimon
1660183234Ssimon/* Simple client cert selection function: always select first */
1661183234Ssimon
1662183234Ssimonstatic int cert_select_simple(ENGINE *e, SSL *ssl, STACK_OF(X509) *certs)
1663296341Sdelphij{
1664296341Sdelphij    return 0;
1665296341Sdelphij}
1666183234Ssimon
1667296341Sdelphij# ifdef OPENSSL_CAPIENG_DIALOG
1668183234Ssimon
1669296341Sdelphij/*
1670296341Sdelphij * More complex cert selection function, using standard function
1671183234Ssimon * CryptUIDlgSelectCertificateFromStore() to produce a dialog box.
1672183234Ssimon */
1673183234Ssimon
1674296341Sdelphij/*
1675296341Sdelphij * Definitions which are in cryptuiapi.h but this is not present in older
1676183234Ssimon * versions of headers.
1677183234Ssimon */
1678183234Ssimon
1679296341Sdelphij#  ifndef CRYPTUI_SELECT_LOCATION_COLUMN
1680296341Sdelphij#   define CRYPTUI_SELECT_LOCATION_COLUMN                   0x000000010
1681296341Sdelphij#   define CRYPTUI_SELECT_INTENDEDUSE_COLUMN                0x000000004
1682296341Sdelphij#  endif
1683183234Ssimon
1684296341Sdelphij#  define dlg_title L"OpenSSL Application SSL Client Certificate Selection"
1685296341Sdelphij#  define dlg_prompt L"Select a certificate to use for authentication"
1686296341Sdelphij#  define dlg_columns      CRYPTUI_SELECT_LOCATION_COLUMN \
1687296341Sdelphij                        |CRYPTUI_SELECT_INTENDEDUSE_COLUMN
1688183234Ssimon
1689183234Ssimonstatic int cert_select_dialog(ENGINE *e, SSL *ssl, STACK_OF(X509) *certs)
1690296341Sdelphij{
1691296341Sdelphij    X509 *x;
1692296341Sdelphij    HCERTSTORE dstore;
1693296341Sdelphij    PCCERT_CONTEXT cert;
1694296341Sdelphij    CAPI_CTX *ctx;
1695296341Sdelphij    CAPI_KEY *key;
1696296341Sdelphij    HWND hwnd;
1697296341Sdelphij    int i, idx = -1;
1698296341Sdelphij    if (sk_X509_num(certs) == 1)
1699296341Sdelphij        return 0;
1700296341Sdelphij    ctx = ENGINE_get_ex_data(e, capi_idx);
1701296341Sdelphij    /* Create an in memory store of certificates */
1702296341Sdelphij    dstore = CertOpenStore(CERT_STORE_PROV_MEMORY, 0, 0,
1703296341Sdelphij                           CERT_STORE_CREATE_NEW_FLAG, NULL);
1704296341Sdelphij    if (!dstore) {
1705296341Sdelphij        CAPIerr(CAPI_F_CERT_SELECT_DIALOG, CAPI_R_ERROR_CREATING_STORE);
1706296341Sdelphij        capi_addlasterror();
1707296341Sdelphij        goto err;
1708296341Sdelphij    }
1709296341Sdelphij    /* Add all certificates to store */
1710296341Sdelphij    for (i = 0; i < sk_X509_num(certs); i++) {
1711296341Sdelphij        x = sk_X509_value(certs, i);
1712296341Sdelphij        key = X509_get_ex_data(x, cert_capi_idx);
1713183234Ssimon
1714296341Sdelphij        if (!CertAddCertificateContextToStore(dstore, key->pcert,
1715296341Sdelphij                                              CERT_STORE_ADD_NEW, NULL)) {
1716296341Sdelphij            CAPIerr(CAPI_F_CERT_SELECT_DIALOG, CAPI_R_ERROR_ADDING_CERT);
1717296341Sdelphij            capi_addlasterror();
1718296341Sdelphij            goto err;
1719296341Sdelphij        }
1720183234Ssimon
1721296341Sdelphij    }
1722296341Sdelphij    hwnd = GetForegroundWindow();
1723296341Sdelphij    if (!hwnd)
1724296341Sdelphij        hwnd = GetActiveWindow();
1725296341Sdelphij    if (!hwnd && ctx->getconswindow)
1726296341Sdelphij        hwnd = ctx->getconswindow();
1727296341Sdelphij    /* Call dialog to select one */
1728296341Sdelphij    cert = ctx->certselectdlg(dstore, hwnd, dlg_title, dlg_prompt,
1729296341Sdelphij                              dlg_columns, 0, NULL);
1730183234Ssimon
1731296341Sdelphij    /* Find matching cert from list */
1732296341Sdelphij    if (cert) {
1733296341Sdelphij        for (i = 0; i < sk_X509_num(certs); i++) {
1734296341Sdelphij            x = sk_X509_value(certs, i);
1735296341Sdelphij            key = X509_get_ex_data(x, cert_capi_idx);
1736296341Sdelphij            if (CertCompareCertificate
1737296341Sdelphij                (X509_ASN_ENCODING | PKCS_7_ASN_ENCODING, cert->pCertInfo,
1738296341Sdelphij                 key->pcert->pCertInfo)) {
1739296341Sdelphij                idx = i;
1740296341Sdelphij                break;
1741296341Sdelphij            }
1742296341Sdelphij        }
1743296341Sdelphij    }
1744183234Ssimon
1745296341Sdelphij err:
1746296341Sdelphij    if (dstore)
1747296341Sdelphij        CertCloseStore(dstore, 0);
1748296341Sdelphij    return idx;
1749183234Ssimon
1750296341Sdelphij}
1751296341Sdelphij# endif
1752183234Ssimon
1753296341Sdelphij#else                           /* !__COMPILE_CAPIENG */
1754296341Sdelphij# include <openssl/engine.h>
1755296341Sdelphij# ifndef OPENSSL_NO_DYNAMIC_ENGINE
1756183234SsimonOPENSSL_EXPORT
1757296341Sdelphij    int bind_engine(ENGINE *e, const char *id, const dynamic_fns *fns);
1758238405SjkimOPENSSL_EXPORT
1759296341Sdelphij    int bind_engine(ENGINE *e, const char *id, const dynamic_fns *fns)
1760296341Sdelphij{
1761296341Sdelphij    return 0;
1762296341Sdelphij}
1763296341Sdelphij
1764183234SsimonIMPLEMENT_DYNAMIC_CHECK_FN()
1765296341Sdelphij# else
1766296341Sdelphijvoid ENGINE_load_capi(void)
1767296341Sdelphij{
1768296341Sdelphij}
1769296341Sdelphij# endif
1770183234Ssimon#endif
1771