summaryrefslogtreecommitdiffstats
path: root/engines
diff options
context:
space:
mode:
authorDr. Stephen Henson <steve@openssl.org>2008-06-03 23:54:31 +0000
committerDr. Stephen Henson <steve@openssl.org>2008-06-03 23:54:31 +0000
commit7d537d4fc77931181e1e8ff24e7bd5bc856b45f4 (patch)
treee53a617e3e7746d3146e883494c9af726eb75bbb /engines
parentca89fc1fb4457de749f65996ca130be0d1807887 (diff)
Add initial support for multiple SSL client certifcate selection in
CryptoAPI ENGINE.
Diffstat (limited to 'engines')
-rw-r--r--engines/e_capi.c66
1 files changed, 54 insertions, 12 deletions
diff --git a/engines/e_capi.c b/engines/e_capi.c
index 4245a37d5f..f56f8b53f0 100644
--- a/engines/e_capi.c
+++ b/engines/e_capi.c
@@ -238,6 +238,7 @@ static const ENGINE_CMD_DEFN capi_cmd_defns[] = {
static int capi_idx = -1;
static int rsa_capi_idx = -1;
static int dsa_capi_idx = -1;
+static int cert_capi_idx = -1;
static int capi_ctrl(ENGINE *e, int cmd, long i, void *p, void (*f)(void))
{
@@ -365,6 +366,7 @@ static int capi_init(ENGINE *e)
const RSA_METHOD *ossl_rsa_meth;
const DSA_METHOD *ossl_dsa_meth;
capi_idx = ENGINE_get_ex_new_index(0, NULL, NULL, NULL, 0);
+ cert_capi_idx = X509_get_ex_new_index(0, NULL, NULL, NULL, 0);
ctx = capi_ctx_new();
if (!ctx || (capi_idx < 0))
@@ -418,6 +420,8 @@ static int capi_finish(ENGINE *e)
struct CAPI_KEY_st
{
+ /* Associated certificate context (if any) */
+ PCERT_CONTEXT pcert;
HCRYPTPROV hprov;
HCRYPTKEY key;
DWORD keyspec;
@@ -1329,6 +1333,7 @@ static CAPI_KEY *capi_get_key(CAPI_CTX *ctx, const char *contname, char *provnam
goto err;
}
key->keyspec = keyspec;
+ key->pcert = NULL;
return key;
err:
@@ -1398,6 +1403,8 @@ void capi_free_key(CAPI_KEY *key)
return;
CryptDestroyKey(key->key);
CryptReleaseContext(key->hprov, 0);
+ if (key->pcert)
+ CertFreeCertificateContext(key->pcert);
OPENSSL_free(key);
}
@@ -1486,23 +1493,25 @@ static int cert_issuer_match(STACK_OF(X509_NAME) *ca_dn, X509 *x)
return 0;
}
+static int client_cert_select(ENGINE *e, SSL *ssl, STACK_OF(X509) *certs)
+ {
+fprintf(stderr, "%d certificates\n", sk_X509_num(certs));
+ return 0;
+ }
+
static int capi_load_ssl_client_cert(ENGINE *e, SSL *ssl,
STACK_OF(X509_NAME) *ca_dn, X509 **pcert, EVP_PKEY **pkey,
STACK_OF(X509) **pother, UI_METHOD *ui_method, void *callback_data)
{
-#if 0
- /* For now just one matching key/cert */
STACK_OF(X509) *certs = NULL;
- STACK_OF(EVP_PKEY) *keys = NULL;
-#endif
X509 *x;
- EVP_PKEY *pk;
char *storename;
const char *p;
- int i;
+ int i, client_cert_idx;
HCERTSTORE hstore;
- PCCERT_CONTEXT cert = NULL;
+ PCCERT_CONTEXT cert = NULL, excert = NULL;
CAPI_CTX *ctx;
+ CAPI_KEY *key;
ctx = ENGINE_get_ex_data(e, capi_idx);
*pcert = NULL;
@@ -1516,7 +1525,7 @@ static int capi_load_ssl_client_cert(ENGINE *e, SSL *ssl,
if (!hstore)
return 0;
/* Enumerate all certificates looking for a match */
- for(i = 0;!*pcert;i++)
+ for(i = 0;;i++)
{
cert = CertEnumCertificatesInStore(hstore, cert);
if (!cert)
@@ -1530,9 +1539,17 @@ static int capi_load_ssl_client_cert(ENGINE *e, SSL *ssl,
}
if (cert_issuer_match(ca_dn, x))
{
- CAPI_KEY *key = capi_get_cert_key(ctx, cert);
+ key = capi_get_cert_key(ctx, cert);
if (!key)
continue;
+ excert = CertDuplicateCertificateContext(cert);
+ X509_set_ex_data(x, cert_capi_idx, key);
+
+ if (!certs)
+ certs = sk_X509_new_null();
+
+ sk_X509_push(certs, x);
+#if 0
pk = capi_get_pkey(e, key);
if (!pk)
{
@@ -1541,6 +1558,7 @@ static int capi_load_ssl_client_cert(ENGINE *e, SSL *ssl,
}
*pcert = x;
*pkey = pk;
+#endif
}
else
X509_free(x);
@@ -1550,11 +1568,35 @@ static int capi_load_ssl_client_cert(ENGINE *e, SSL *ssl,
if (cert)
CertFreeCertificateContext(cert);
- if (*pcert)
- return 1;
- else
+ if (!certs)
return 0;
+ client_cert_idx = client_cert_select(e, ssl, certs);
+
+ for(i = 0; i < sk_X509_num(certs); i++)
+ {
+ x = sk_X509_value(certs, i);
+ if (i == client_cert_idx)
+ *pcert = x;
+ else
+ {
+ key = X509_get_ex_data(x, cert_capi_idx);
+ capi_free_key(key);
+ X509_free(x);
+ }
+ }
+
+ sk_X509_free(certs);
+
+ if (!*pcert)
+ return 0;
+
+ key = X509_get_ex_data(*pcert, cert_capi_idx);
+ *pkey = capi_get_pkey(e, key);
+ X509_set_ex_data(*pcert, cert_capi_idx, NULL);
+
+ return 1;
+
}
#endif