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