Add preliminary SSL client auth callback to CryptoAPI ENGINE.
This commit is contained in:
parent
45d3767d28
commit
b3c8dd4eab
3 changed files with 141 additions and 34 deletions
163
engines/e_capi.c
163
engines/e_capi.c
|
@ -54,6 +54,8 @@
|
|||
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <windows.h>
|
||||
#include <wincrypt.h>
|
||||
#include <openssl/crypto.h>
|
||||
#include <openssl/buffer.h>
|
||||
#include <openssl/engine.h>
|
||||
|
@ -68,8 +70,6 @@
|
|||
#define _WIN32_WINNT 0x400
|
||||
#endif
|
||||
|
||||
#include <windows.h>
|
||||
#include <wincrypt.h>
|
||||
|
||||
#include "e_capi_err.h"
|
||||
#include "e_capi_err.c"
|
||||
|
@ -109,6 +109,10 @@ static DSA_SIG *capi_dsa_do_sign(const unsigned char *digest, int dlen,
|
|||
DSA *dsa);
|
||||
static int capi_dsa_free(DSA *dsa);
|
||||
|
||||
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);
|
||||
|
||||
/* This structure contains CAPI ENGINE specific data:
|
||||
* it contains various global options and affects how
|
||||
* other functions behave.
|
||||
|
@ -126,6 +130,7 @@ struct CAPI_CTX_st {
|
|||
DWORD csptype;
|
||||
/* Certificate store name to use */
|
||||
LPTSTR storename;
|
||||
LPTSTR ssl_client_store;
|
||||
|
||||
/* Lookup string meanings in load_private_key */
|
||||
/* Substring of subject: uses "storename" */
|
||||
|
@ -428,6 +433,8 @@ static int bind_capi(ENGINE *e)
|
|||
|| !ENGINE_set_RSA(e, &capi_rsa_method)
|
||||
|| !ENGINE_set_DSA(e, &capi_dsa_method)
|
||||
|| !ENGINE_set_load_privkey_function(e, capi_load_privkey)
|
||||
|| !ENGINE_set_load_ssl_client_cert_function(e,
|
||||
capi_load_ssl_client_cert)
|
||||
|| !ENGINE_set_cmd_defns(e, capi_cmd_defns)
|
||||
|| !ENGINE_set_ctrl_function(e, capi_ctrl))
|
||||
return 0;
|
||||
|
@ -494,34 +501,19 @@ static int lend_tobn(BIGNUM *bn, unsigned char *bin, int binlen)
|
|||
return 1;
|
||||
}
|
||||
|
||||
static EVP_PKEY *capi_load_privkey(ENGINE *eng, const char *key_id,
|
||||
UI_METHOD *ui_method, void *callback_data)
|
||||
/* Given a CAPI_KEY get an EVP_PKEY structure */
|
||||
|
||||
static EVP_PKEY *capi_get_pkey(ENGINE *eng, CAPI_KEY *key)
|
||||
{
|
||||
EVP_PKEY *ret = NULL;
|
||||
CAPI_CTX *ctx;
|
||||
CAPI_KEY *key;
|
||||
unsigned char *pubkey = NULL;
|
||||
DWORD len;
|
||||
BLOBHEADER *bh;
|
||||
RSA *rkey = NULL;
|
||||
DSA *dkey = NULL;
|
||||
ctx = ENGINE_get_ex_data(eng, capi_idx);
|
||||
|
||||
if (!ctx)
|
||||
{
|
||||
CAPIerr(CAPI_F_CAPI_LOAD_PRIVKEY, CAPI_R_CANT_FIND_CAPI_CONTEXT);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
key = capi_find_key(ctx, key_id);
|
||||
|
||||
if (!key)
|
||||
return NULL;
|
||||
|
||||
len = 0;
|
||||
EVP_PKEY *ret = NULL;
|
||||
if (!CryptExportKey(key->key, 0, PUBLICKEYBLOB, 0, NULL, &len))
|
||||
{
|
||||
CAPIerr(CAPI_F_CAPI_LOAD_PRIVKEY, CAPI_R_PUBKEY_EXPORT_LENGTH_ERROR);
|
||||
CAPIerr(CAPI_F_CAPI_GET_PKEY, CAPI_R_PUBKEY_EXPORT_LENGTH_ERROR);
|
||||
capi_addlasterror();
|
||||
return NULL;
|
||||
}
|
||||
|
@ -533,7 +525,7 @@ static EVP_PKEY *capi_load_privkey(ENGINE *eng, const char *key_id,
|
|||
|
||||
if (!CryptExportKey(key->key, 0, PUBLICKEYBLOB, 0, pubkey, &len))
|
||||
{
|
||||
CAPIerr(CAPI_F_CAPI_LOAD_PRIVKEY, CAPI_R_PUBKEY_EXPORT_ERROR);
|
||||
CAPIerr(CAPI_F_CAPI_GET_PKEY, CAPI_R_PUBKEY_EXPORT_ERROR);
|
||||
capi_addlasterror();
|
||||
goto err;
|
||||
}
|
||||
|
@ -541,7 +533,7 @@ static EVP_PKEY *capi_load_privkey(ENGINE *eng, const char *key_id,
|
|||
bh = (BLOBHEADER *)pubkey;
|
||||
if (bh->bType != PUBLICKEYBLOB)
|
||||
{
|
||||
CAPIerr(CAPI_F_CAPI_LOAD_PRIVKEY, CAPI_R_INVALID_PUBLIC_KEY_BLOB);
|
||||
CAPIerr(CAPI_F_CAPI_GET_PKEY, CAPI_R_INVALID_PUBLIC_KEY_BLOB);
|
||||
goto err;
|
||||
}
|
||||
if (bh->aiKeyAlg == CALG_RSA_SIGN || bh->aiKeyAlg == CALG_RSA_KEYX)
|
||||
|
@ -554,7 +546,7 @@ static EVP_PKEY *capi_load_privkey(ENGINE *eng, const char *key_id,
|
|||
{
|
||||
char magstr[10];
|
||||
BIO_snprintf(magstr, 10, "%lx", rp->magic);
|
||||
CAPIerr(CAPI_F_CAPI_LOAD_PRIVKEY, CAPI_R_INVALID_RSA_PUBLIC_KEY_BLOB_MAGIC_NUMBER);
|
||||
CAPIerr(CAPI_F_CAPI_GET_PKEY, CAPI_R_INVALID_RSA_PUBLIC_KEY_BLOB_MAGIC_NUMBER);
|
||||
ERR_add_error_data(2, "magic=0x", magstr);
|
||||
goto err;
|
||||
}
|
||||
|
@ -595,7 +587,7 @@ static EVP_PKEY *capi_load_privkey(ENGINE *eng, const char *key_id,
|
|||
{
|
||||
char magstr[10];
|
||||
BIO_snprintf(magstr, 10, "%lx", dp->magic);
|
||||
CAPIerr(CAPI_F_CAPI_LOAD_PRIVKEY, CAPI_R_INVALID_DSA_PUBLIC_KEY_BLOB_MAGIC_NUMBER);
|
||||
CAPIerr(CAPI_F_CAPI_GET_PKEY, CAPI_R_INVALID_DSA_PUBLIC_KEY_BLOB_MAGIC_NUMBER);
|
||||
ERR_add_error_data(2, "magic=0x", magstr);
|
||||
goto err;
|
||||
}
|
||||
|
@ -635,11 +627,12 @@ static EVP_PKEY *capi_load_privkey(ENGINE *eng, const char *key_id,
|
|||
{
|
||||
char algstr[10];
|
||||
BIO_snprintf(algstr, 10, "%lx", bh->aiKeyAlg);
|
||||
CAPIerr(CAPI_F_CAPI_LOAD_PRIVKEY, CAPI_R_UNSUPPORTED_PUBLIC_KEY_ALGORITHM);
|
||||
CAPIerr(CAPI_F_CAPI_GET_PKEY, CAPI_R_UNSUPPORTED_PUBLIC_KEY_ALGORITHM);
|
||||
ERR_add_error_data(2, "aiKeyAlg=0x", algstr);
|
||||
goto err;
|
||||
}
|
||||
|
||||
|
||||
err:
|
||||
if (pubkey)
|
||||
OPENSSL_free(pubkey);
|
||||
|
@ -649,8 +642,6 @@ static EVP_PKEY *capi_load_privkey(ENGINE *eng, const char *key_id,
|
|||
RSA_free(rkey);
|
||||
if (dkey)
|
||||
DSA_free(dkey);
|
||||
if (key)
|
||||
capi_free_key(key);
|
||||
}
|
||||
|
||||
return ret;
|
||||
|
@ -661,6 +652,33 @@ memerr:
|
|||
|
||||
}
|
||||
|
||||
static EVP_PKEY *capi_load_privkey(ENGINE *eng, const char *key_id,
|
||||
UI_METHOD *ui_method, void *callback_data)
|
||||
{
|
||||
CAPI_CTX *ctx;
|
||||
CAPI_KEY *key;
|
||||
EVP_PKEY *ret;
|
||||
ctx = ENGINE_get_ex_data(eng, capi_idx);
|
||||
|
||||
if (!ctx)
|
||||
{
|
||||
CAPIerr(CAPI_F_CAPI_LOAD_PRIVKEY, CAPI_R_CANT_FIND_CAPI_CONTEXT);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
key = capi_find_key(ctx, key_id);
|
||||
|
||||
if (!key)
|
||||
return NULL;
|
||||
|
||||
ret = capi_get_pkey(eng, key);
|
||||
|
||||
if (!ret)
|
||||
capi_free_key(key);
|
||||
return ret;
|
||||
|
||||
}
|
||||
|
||||
/* CryptoAPI RSA operations */
|
||||
|
||||
int capi_rsa_priv_enc(int flen, const unsigned char *from,
|
||||
|
@ -1401,6 +1419,7 @@ static CAPI_CTX *capi_ctx_new()
|
|||
ctx->dump_flags = CAPI_DMP_SUMMARY|CAPI_DMP_FNAME;
|
||||
ctx->keytype = AT_KEYEXCHANGE;
|
||||
ctx->storename = NULL;
|
||||
ctx->ssl_client_store = NULL;
|
||||
ctx->lookup_method = CAPI_LU_SUBSTR;
|
||||
ctx->debug_level = 0;
|
||||
ctx->debug_file = NULL;
|
||||
|
@ -1418,6 +1437,8 @@ static void capi_ctx_free(CAPI_CTX *ctx)
|
|||
OPENSSL_free(ctx->debug_file);
|
||||
if (ctx->storename)
|
||||
OPENSSL_free(ctx->storename);
|
||||
if (ctx->ssl_client_store)
|
||||
OPENSSL_free(ctx->ssl_client_store);
|
||||
OPENSSL_free(ctx);
|
||||
}
|
||||
|
||||
|
@ -1450,5 +1471,89 @@ static int capi_ctx_set_provname_idx(CAPI_CTX *ctx, int idx)
|
|||
return capi_ctx_set_provname(ctx, pname, type, 0);
|
||||
}
|
||||
|
||||
static int cert_issuer_match(STACK_OF(X509_NAME) *ca_dn, X509 *x)
|
||||
{
|
||||
int i;
|
||||
X509_NAME *nm;
|
||||
for (i = 0; i < sk_X509_NAME_num(ca_dn); i++)
|
||||
{
|
||||
nm = sk_X509_NAME_value(ca_dn, i);
|
||||
if (!X509_NAME_cmp(nm, X509_get_issuer_name(x)))
|
||||
return 1;
|
||||
}
|
||||
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;
|
||||
HCERTSTORE hstore;
|
||||
PCCERT_CONTEXT cert = NULL;
|
||||
CAPI_CTX *ctx;
|
||||
ctx = ENGINE_get_ex_data(e, capi_idx);
|
||||
|
||||
*pcert = NULL;
|
||||
*pkey = NULL;
|
||||
|
||||
storename = ctx->ssl_client_store;
|
||||
if (!storename)
|
||||
storename = "MY";
|
||||
|
||||
hstore = capi_open_store(ctx, storename);
|
||||
if (!hstore)
|
||||
return 0;
|
||||
/* Enumerate all certificates looking for a match */
|
||||
for(i = 0;!*pcert;i++)
|
||||
{
|
||||
cert = CertEnumCertificatesInStore(hstore, cert);
|
||||
if (!cert)
|
||||
break;
|
||||
p = cert->pbCertEncoded;
|
||||
x = d2i_X509(NULL, &p, cert->cbCertEncoded);
|
||||
if (!x)
|
||||
{
|
||||
CAPI_trace(ctx, "Can't Parse Certificate %d\n", i);
|
||||
continue;
|
||||
}
|
||||
if (cert_issuer_match(ca_dn, x))
|
||||
{
|
||||
CAPI_KEY *key = capi_get_cert_key(ctx, cert);
|
||||
if (!key)
|
||||
continue;
|
||||
pk = capi_get_pkey(e, key);
|
||||
if (!pk)
|
||||
{
|
||||
capi_free_key(key);
|
||||
continue;
|
||||
}
|
||||
*pcert = x;
|
||||
*pkey = pk;
|
||||
}
|
||||
else
|
||||
X509_free(x);
|
||||
|
||||
}
|
||||
|
||||
if (cert)
|
||||
CertFreeCertificateContext(cert);
|
||||
|
||||
if (*pcert)
|
||||
return 1;
|
||||
else
|
||||
return 0;
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
#endif
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
/* e_capi_err.c */
|
||||
/* ====================================================================
|
||||
* Copyright (c) 1999-2008 The OpenSSL Project. All rights reserved.
|
||||
* Copyright (c) 1999-2007 The OpenSSL Project. All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
|
@ -76,6 +76,7 @@ static ERR_STRING_DATA CAPI_str_functs[]=
|
|||
{ERR_FUNC(CAPI_F_CAPI_CTX_SET_PROVNAME), "CAPI_CTX_SET_PROVNAME"},
|
||||
{ERR_FUNC(CAPI_F_CAPI_DSA_DO_SIGN), "CAPI_DSA_DO_SIGN"},
|
||||
{ERR_FUNC(CAPI_F_CAPI_GET_KEY), "CAPI_GET_KEY"},
|
||||
{ERR_FUNC(CAPI_F_CAPI_GET_PKEY), "CAPI_GET_PKEY"},
|
||||
{ERR_FUNC(CAPI_F_CAPI_GET_PROVNAME), "CAPI_GET_PROVNAME"},
|
||||
{ERR_FUNC(CAPI_F_CAPI_GET_PROV_INFO), "CAPI_GET_PROV_INFO"},
|
||||
{ERR_FUNC(CAPI_F_CAPI_INIT), "CAPI_INIT"},
|
||||
|
|
|
@ -73,6 +73,7 @@ static void ERR_CAPI_error(int function, int reason, char *file, int line);
|
|||
#define CAPI_F_CAPI_CTX_SET_PROVNAME 102
|
||||
#define CAPI_F_CAPI_DSA_DO_SIGN 114
|
||||
#define CAPI_F_CAPI_GET_KEY 103
|
||||
#define CAPI_F_CAPI_GET_PKEY 115
|
||||
#define CAPI_F_CAPI_GET_PROVNAME 104
|
||||
#define CAPI_F_CAPI_GET_PROV_INFO 105
|
||||
#define CAPI_F_CAPI_INIT 106
|
||||
|
|
Loading…
Reference in a new issue