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