Commit b3c8dd4e authored by Dr. Stephen Henson's avatar Dr. Stephen Henson
Browse files

Add preliminary SSL client auth callback to CryptoAPI ENGINE.

parent 45d3767d
Loading
Loading
Loading
Loading
+138 −33
Original line number Diff line number Diff line
@@ -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
+2 −1
Original line number Diff line number Diff line
/* 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"},
+1 −0
Original line number Diff line number Diff line
@@ -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