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