Add initial support for multiple SSL client certifcate selection in

CryptoAPI ENGINE.
This commit is contained in:
Dr. Stephen Henson 2008-06-03 23:54:31 +00:00
parent ca89fc1fb4
commit 7d537d4fc7

View file

@ -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