On 2004-10-13 19:09, James Yonan wrote: > Also... Would it be a lot of work to get your contribution to build with > MinGW/gcc?
Hi! Here is a reworked version of my CryptoAPI patch, that also builds with MinGW. I changed the name of the new source file to 'cryptoapi.c', since there seems to be some interest in other CryptoAPI usage in the code also; such new features can go into this file. -----8<----------8<----------8<----------8<----------8<----------8<----------8<----- diff -uN openvpn-2.0_beta12.orig/cryptoapi.c openvpn-2.0_beta12/cryptoapi.c --- openvpn-2.0_beta12.orig/cryptoapi.c 1970-01-01 01:00:00.000000000 +0100 +++ openvpn-2.0_beta12/cryptoapi.c 2004-10-18 11:54:40.000000000 +0200 @@ -0,0 +1,466 @@ +/* + * Copyright (c) 2004 Peter 'Luna' Runestig <pe...@runestig.com> + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modifi- + * cation, are permitted provided that the following conditions are met: + * + * o Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * o Redistributions in binary form must reproduce the above copyright no- + * tice, this list of conditions and the following disclaimer in the do- + * cumentation and/or other materials provided with the distribution. + * + * o The names of the contributors may not be used to endorse or promote + * products derived from this software without specific prior written + * permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LI- + * ABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUEN- + * TIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEV- + * ER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABI- + * LITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF + * THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +#include <windows.h> +#include <wincrypt.h> +#include <stdio.h> +#include <ctype.h> +#include <assert.h> +#include <openssl\ssl.h> +#include <openssl\err.h> + +#ifdef __MINGW32_VERSION +/* MinGW w32api is incomplete when it comes to CryptoAPI, as per version 3.1 + * anyway. This is a hack around that problem. */ +#define CALG_SSL3_SHAMD5 (ALG_CLASS_HASH | ALG_TYPE_ANY | ALG_SID_SSL3SHAMD5) +#define CERT_SYSTEM_STORE_LOCATION_SHIFT 16 +#define CERT_SYSTEM_STORE_CURRENT_USER_ID 1 +#define CERT_SYSTEM_STORE_CURRENT_USER (CERT_SYSTEM_STORE_CURRENT_USER_ID << CERT_SYSTEM_STORE_LOCATION_SHIFT) +#define CERT_STORE_READONLY_FLAG 0x00008000 +#define CERT_STORE_OPEN_EXISTING_FLAG 0x00004000 +#define CRYPT_ACQUIRE_COMPARE_KEY_FLAG 0x00000004 +static HINSTANCE crypt32dll = NULL; +static BOOL WINAPI (*CryptAcquireCertificatePrivateKey) (PCCERT_CONTEXT pCert, DWORD dwFlags, + void *pvReserved, HCRYPTPROV *phCryptProv, DWORD *pdwKeySpec, BOOL *pfCallerFreeProv) = NULL; +#endif + +/* Size of an SSL signature: MD5+SHA1 */ +#define SSL_SIG_LENGTH 36 + +/* try to funnel any Windows/CryptoAPI error messages to OpenSSL ERR_... */ +#define ERR_LIB_CRYPTOAPI (ERR_LIB_USER + 69) /* 69 is just a number... */ +#define CRYPTOAPIerr(f) err_put_ms_error(GetLastError(), (f), __FILE__, __LINE__) +#define CRYPTOAPI_F_CERT_OPEN_SYSTEM_STORE 100 +#define CRYPTOAPI_F_CERT_FIND_CERTIFICATE_IN_STORE 101 +#define CRYPTOAPI_F_CRYPT_ACQUIRE_CERTIFICATE_PRIVATE_KEY 102 +#define CRYPTOAPI_F_CRYPT_CREATE_HASH 103 +#define CRYPTOAPI_F_CRYPT_GET_HASH_PARAM 104 +#define CRYPTOAPI_F_CRYPT_SET_HASH_PARAM 105 +#define CRYPTOAPI_F_CRYPT_SIGN_HASH 106 +#define CRYPTOAPI_F_LOAD_LIBRARY 107 +#define CRYPTOAPI_F_GET_PROC_ADDRESS 108 + +static ERR_STRING_DATA CRYPTOAPI_str_functs[] = { + { ERR_PACK(ERR_LIB_CRYPTOAPI, 0, 0), "microsoft cryptoapi"}, + { ERR_PACK(0, CRYPTOAPI_F_CERT_OPEN_SYSTEM_STORE, 0), "CertOpenSystemStore" }, + { ERR_PACK(0, CRYPTOAPI_F_CERT_FIND_CERTIFICATE_IN_STORE, 0), "CertFindCertificateInStore" }, + { ERR_PACK(0, CRYPTOAPI_F_CRYPT_ACQUIRE_CERTIFICATE_PRIVATE_KEY, 0), "CryptAcquireCertificatePrivateKey" }, + { ERR_PACK(0, CRYPTOAPI_F_CRYPT_CREATE_HASH, 0), "CryptCreateHash" }, + { ERR_PACK(0, CRYPTOAPI_F_CRYPT_GET_HASH_PARAM, 0), "CryptGetHashParam" }, + { ERR_PACK(0, CRYPTOAPI_F_CRYPT_SET_HASH_PARAM, 0), "CryptSetHashParam" }, + { ERR_PACK(0, CRYPTOAPI_F_CRYPT_SIGN_HASH, 0), "CryptSignHash" }, + { ERR_PACK(0, CRYPTOAPI_F_LOAD_LIBRARY, 0), "LoadLibrary" }, + { ERR_PACK(0, CRYPTOAPI_F_GET_PROC_ADDRESS, 0), "GetProcAddress" }, + { 0, NULL } +}; + +typedef struct _CAPI_DATA { + const CERT_CONTEXT *cert_context; + HCRYPTPROV crypt_prov; + DWORD key_spec; + BOOL free_crypt_prov; +} CAPI_DATA; + +static char *ms_error_text(DWORD ms_err) +{ + LPVOID lpMsgBuf = NULL; + char *rv = NULL; + + FormatMessage( + FORMAT_MESSAGE_ALLOCATE_BUFFER | + FORMAT_MESSAGE_FROM_SYSTEM | + FORMAT_MESSAGE_IGNORE_INSERTS, + NULL, ms_err, + MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), // Default language + (LPTSTR) &lpMsgBuf, 0, NULL); + if (lpMsgBuf) { + char *p; + rv = strdup(lpMsgBuf); + LocalFree(lpMsgBuf); + /* trim to the left */ + if (rv) + for (p = rv + strlen(rv) - 1; p >= rv; p--) { + if (isspace(*p)) + *p = '\0'; + else + break; + } + } + return rv; +} + +static void err_put_ms_error(DWORD ms_err, int func, const char *file, int line) +{ + static int init = 0; +# define ERR_MAP_SZ 16 + static struct { + int err; + DWORD ms_err; /* I don't think we get more than 16 *different* errors */ + } err_map[ERR_MAP_SZ]; /* in here, before we give up the whole thing... */ + int i; + + if (ms_err == 0) + /* 0 is not an error */ + return; + if (!init) { + ERR_load_strings(ERR_LIB_CRYPTOAPI, CRYPTOAPI_str_functs); + memset(&err_map, 0, sizeof(err_map)); + init++; + } + /* since MS error codes are 32 bit, and the ones in the ERR_... system is + * only 12, we must have a mapping table between them. */ + for (i = 0; i < ERR_MAP_SZ; i++) { + if (err_map[i].ms_err == ms_err) { + ERR_PUT_error(ERR_LIB_CRYPTOAPI, func, err_map[i].err, file, line); + break; + } else if (err_map[i].ms_err == 0 ) { + /* end of table, add new entry */ + ERR_STRING_DATA *esd = calloc(2, sizeof(*esd)); + if (esd == NULL) + break; + err_map[i].ms_err = ms_err; + err_map[i].err = esd->error = i + 100; + esd->string = ms_error_text(ms_err); + ERR_load_strings(ERR_LIB_CRYPTOAPI, esd); + ERR_PUT_error(ERR_LIB_CRYPTOAPI, func, err_map[i].err, file, line); + break; + } + } +} + +/* encrypt */ +static int rsa_pub_enc(int flen, const unsigned char *from, unsigned char *to, RSA *rsa, int padding) +{ + /* I haven't been able to trigger this one, but I want to know if it happens... */ + assert(0); + + return 0; +} + +/* verify arbitrary data */ +static int rsa_pub_dec(int flen, const unsigned char *from, unsigned char *to, RSA *rsa, int padding) +{ + /* I haven't been able to trigger this one, but I want to know if it happens... */ + assert(0); + + return 0; +} + +/* sign arbitrary data */ +static int rsa_priv_enc(int flen, const unsigned char *from, unsigned char *to, RSA *rsa, int padding) +{ + CAPI_DATA *cd = (CAPI_DATA *) rsa->meth->app_data; + HCRYPTHASH hash; + DWORD hash_size, len, i; + unsigned char *buf; + + if (cd == NULL) { + RSAerr(RSA_F_RSA_EAY_PRIVATE_ENCRYPT, ERR_R_PASSED_NULL_PARAMETER); + return 0; + } + if (padding != RSA_PKCS1_PADDING) { + /* AFAICS, CryptSignHash() *always* uses PKCS1 padding. */ + RSAerr(RSA_F_RSA_EAY_PRIVATE_ENCRYPT, RSA_R_UNKNOWN_PADDING_TYPE); + return 0; + } + /* Unfortunately, there is no "CryptSign()" function in CryptoAPI, that would + * be way to straightforward for M$, I guess... So we have to do it this + * tricky way instead, by creating a "Hash", and load the already-made hash + * from 'from' into it. */ + /* For now, we only support NID_md5_sha1 */ + if (flen != SSL_SIG_LENGTH) { + RSAerr(RSA_F_RSA_EAY_PRIVATE_ENCRYPT, RSA_R_INVALID_MESSAGE_LENGTH); + return 0; + } + if (!CryptCreateHash(cd->crypt_prov, CALG_SSL3_SHAMD5, 0, 0, &hash)) { + CRYPTOAPIerr(CRYPTOAPI_F_CRYPT_CREATE_HASH); + return 0; + } + len = sizeof(hash_size); + if (!CryptGetHashParam(hash, HP_HASHSIZE, (BYTE *) &hash_size, &len, 0)) { + CRYPTOAPIerr(CRYPTOAPI_F_CRYPT_GET_HASH_PARAM); + CryptDestroyHash(hash); + return 0; + } + if ((int) hash_size != flen) { + RSAerr(RSA_F_RSA_EAY_PRIVATE_ENCRYPT, RSA_R_INVALID_MESSAGE_LENGTH); + CryptDestroyHash(hash); + return 0; + } + if (!CryptSetHashParam(hash, HP_HASHVAL, (BYTE * ) from, 0)) { + CRYPTOAPIerr(CRYPTOAPI_F_CRYPT_SET_HASH_PARAM); + CryptDestroyHash(hash); + return 0; + } + + len = RSA_size(rsa); + buf = malloc(len); + if (buf == NULL) { + RSAerr(RSA_F_RSA_EAY_PRIVATE_ENCRYPT, ERR_R_MALLOC_FAILURE); + CryptDestroyHash(hash); + return 0; + } + if (!CryptSignHash(hash, cd->key_spec, NULL, 0, buf, &len)) { + CRYPTOAPIerr(CRYPTOAPI_F_CRYPT_SIGN_HASH); + CryptDestroyHash(hash); + free(buf); + return 0; + } + /* and now, we have to reverse the byte-order in the result from CryptSignHash()... */ + for (i = 0; i < len; i++) + to[i] = buf[len - i - 1]; + free(buf); + + CryptDestroyHash(hash); + return len; +} + +/* decrypt */ +static int rsa_priv_dec(int flen, const unsigned char *from, unsigned char *to, RSA *rsa, int padding) +{ + /* I haven't been able to trigger this one, but I want to know if it happens... */ + assert(0); + + return 0; +} + +/* called at RSA_new */ +static int init(RSA *rsa) +{ + + return 0; +} + +/* called at RSA_free */ +static int finish(RSA *rsa) +{ + CAPI_DATA *cd = (CAPI_DATA *) rsa->meth->app_data; + + if (cd == NULL) + return 0; + if (cd->crypt_prov && cd->free_crypt_prov) + CryptReleaseContext(cd->crypt_prov, 0); + if (cd->cert_context) + CertFreeCertificateContext(cd->cert_context); + free(rsa->meth->app_data); + free((char *) rsa->meth); + rsa->meth = NULL; + return 1; +} + +static const CERT_CONTEXT *find_certificate_in_store(const char *cert_prop, HCERTSTORE cert_store) +{ + /* Find, and use, the desired certificate from the store. The + * 'cert_prop' certificate search string can look like this: + * SUBJ:<certificate substring to match> + * THUMB:<certificate thumbprint hex value>, e.g. + * THUMB:f6 49 24 41 01 b4 fb 44 0c ce f4 36 ae d0 c4 c9 df 7a b6 28 + */ + const CERT_CONTEXT *rv = NULL; + + if (!strncmp(cert_prop, "SUBJ:", 5)) { + unsigned short wbuf[255]; + + /* skip the tag */ + cert_prop += 5; + MultiByteToWideChar(CP_ACP, 0, cert_prop, -1, wbuf, sizeof(wbuf)); + rv = CertFindCertificateInStore(cert_store, X509_ASN_ENCODING | PKCS_7_ASN_ENCODING, + 0, CERT_FIND_SUBJECT_STR, wbuf, NULL); + + } else if (!strncmp(cert_prop, "THUMB:", 6)) { + unsigned char hash[255]; + char *p; + int i, x = 0; + CRYPT_HASH_BLOB blob; + + /* skip the tag */ + cert_prop += 6; + for (p = (char *) cert_prop, i = 0; *p && i < sizeof(hash); i++) { + if (*p >= '0' && *p <= '9') + x = (*p - '0') << 4; + else if (*p >= 'A' && *p <= 'F') + x = (*p - 'A' + 10) << 4; + else if (*p >= 'a' && *p <= 'f') + x = (*p - 'a' + 10) << 4; + if (!*++p) /* unexpected end of string */ + break; + if (*p >= '0' && *p <= '9') + x += *p - '0'; + else if (*p >= 'A' && *p <= 'F') + x += *p - 'A' + 10; + else if (*p >= 'a' && *p <= 'f') + x += *p - 'a' + 10; + hash[i] = x; + /* skip any space(s) between hex numbers */ + for (p++; *p && *p == ' '; p++); + } + blob.cbData = i; + blob.pbData = (unsigned char *) &hash; + rv = CertFindCertificateInStore(cert_store, X509_ASN_ENCODING | PKCS_7_ASN_ENCODING, + 0, CERT_FIND_HASH, &blob, NULL); + + } + + return rv; +} + +int SSL_CTX_use_CryptoAPI_certificate(SSL_CTX *ssl_ctx, const char *cert_prop) +{ + HCERTSTORE cs; + X509 *cert = NULL; + RSA *rsa = NULL, *pub_rsa; + CAPI_DATA *cd = calloc(1, sizeof(*cd)); + RSA_METHOD *my_rsa_method = calloc(1, sizeof(*my_rsa_method)); + + if (cd == NULL || my_rsa_method == NULL) { + SSLerr(SSL_F_SSL_CTX_USE_CERTIFICATE_FILE, ERR_R_MALLOC_FAILURE); + goto err; + } + /* search CURRENT_USER first, then LOCAL_MACHINE */ + cs = CertOpenStore((LPCSTR) CERT_STORE_PROV_SYSTEM, 0, 0, CERT_SYSTEM_STORE_CURRENT_USER | + CERT_STORE_OPEN_EXISTING_FLAG | CERT_STORE_READONLY_FLAG, L"MY"); + if (cs == NULL) { + CRYPTOAPIerr(CRYPTOAPI_F_CERT_OPEN_SYSTEM_STORE); + goto err; + } + cd->cert_context = find_certificate_in_store(cert_prop, cs); + CertCloseStore(cs, 0); + if (!cd->cert_context) { + cs = CertOpenStore((LPCSTR) CERT_STORE_PROV_SYSTEM, 0, 0, CERT_SYSTEM_STORE_LOCAL_MACHINE | + CERT_STORE_OPEN_EXISTING_FLAG | CERT_STORE_READONLY_FLAG, L"MY"); + if (cs == NULL) { + CRYPTOAPIerr(CRYPTOAPI_F_CERT_OPEN_SYSTEM_STORE); + goto err; + } + cd->cert_context = find_certificate_in_store(cert_prop, cs); + CertCloseStore(cs, 0); + if (cd->cert_context == NULL) { + CRYPTOAPIerr(CRYPTOAPI_F_CERT_FIND_CERTIFICATE_IN_STORE); + goto err; + } + } + + /* cert_context->pbCertEncoded is the cert X509 DER encoded. */ + cert = d2i_X509(NULL, (unsigned char **) &cd->cert_context->pbCertEncoded, + cd->cert_context->cbCertEncoded); + if (cert == NULL) { + SSLerr(SSL_F_SSL_CTX_USE_CERTIFICATE_FILE, ERR_R_ASN1_LIB); + goto err; + } + + /* set up stuff to use the private key */ +#ifdef __MINGW32_VERSION + /* MinGW w32api is incomplete when it comes to CryptoAPI, as per version 3.1 + * anyway. This is a hack around that problem. */ + if (crypt32dll == NULL) { + crypt32dll = LoadLibrary("crypt32"); + if (crypt32dll == NULL) { + CRYPTOAPIerr(CRYPTOAPI_F_LOAD_LIBRARY); + goto err; + } + } + if (CryptAcquireCertificatePrivateKey == NULL) { + CryptAcquireCertificatePrivateKey = GetProcAddress(crypt32dll, + "CryptAcquireCertificatePrivateKey"); + if (CryptAcquireCertificatePrivateKey == NULL) { + CRYPTOAPIerr(CRYPTOAPI_F_GET_PROC_ADDRESS); + goto err; + } + } +#endif + if (!CryptAcquireCertificatePrivateKey(cd->cert_context, CRYPT_ACQUIRE_COMPARE_KEY_FLAG, + NULL, &cd->crypt_prov, &cd->key_spec, &cd->free_crypt_prov)) { + /* if we don't have a smart card reader here, and we try to access a + * smart card certificate, we get: + * "Error 1223: The operation was canceled by the user." */ + CRYPTOAPIerr(CRYPTOAPI_F_CRYPT_ACQUIRE_CERTIFICATE_PRIVATE_KEY); + goto err; + } + /* here we don't need to do CryptGetUserKey() or anything; all necessary key + * info is in cd->cert_context, and then, in cd->crypt_prov. */ + + my_rsa_method->name = "Microsoft CryptoAPI RSA Method"; + my_rsa_method->rsa_pub_enc = rsa_pub_enc; + my_rsa_method->rsa_pub_dec = rsa_pub_dec; + my_rsa_method->rsa_priv_enc = rsa_priv_enc; + my_rsa_method->rsa_priv_dec = rsa_priv_dec; + /* my_rsa_method->init = init; */ + my_rsa_method->finish = finish; + my_rsa_method->flags = RSA_METHOD_FLAG_NO_CHECK; + my_rsa_method->app_data = (char *) cd; + + rsa = RSA_new(); + if (rsa == NULL) { + SSLerr(SSL_F_SSL_CTX_USE_CERTIFICATE_FILE, ERR_R_MALLOC_FAILURE); + goto err; + } + + /* cert->cert_info->key->pkey is NULL until we call SSL_CTX_use_certificate(), + * so we do it here then... */ + if (!SSL_CTX_use_certificate(ssl_ctx, cert)) + goto err; + /* the public key */ + pub_rsa = cert->cert_info->key->pkey->pkey.rsa; + /* SSL_CTX_use_certificate() increased the reference count in 'cert', so + * we decrease it here with X509_free(), or it will never be cleaned up. */ + X509_free(cert); + cert = NULL; + + /* I'm not sure about what we have to fill in in the RSA, trying out stuff... */ + /* rsa->n indicates the key size */ + rsa->n = BN_dup(pub_rsa->n); + rsa->flags |= RSA_FLAG_EXT_PKEY; + if (!RSA_set_method(rsa, my_rsa_method)) + goto err; + + if (!SSL_CTX_use_RSAPrivateKey(ssl_ctx, rsa)) + goto err; + /* SSL_CTX_use_RSAPrivateKey() increased the reference count in 'rsa', so + * we decrease it here with RSA_free(), or it will never be cleaned up. */ + RSA_free(rsa); + return 1; + + err: + if (cert) + X509_free(cert); + if (rsa) + RSA_free(rsa); + else { + if (my_rsa_method) + free(my_rsa_method); + if (cd) { + if (cd->free_crypt_prov && cd->crypt_prov) + CryptReleaseContext(cd->crypt_prov, 0); + if (cd->cert_context) + CertFreeCertificateContext(cd->cert_context); + free(cd); + } + } + return 0; +} diff -uN openvpn-2.0_beta12.orig/cryptoapi.h openvpn-2.0_beta12/cryptoapi.h --- openvpn-2.0_beta12.orig/cryptoapi.h 1970-01-01 01:00:00.000000000 +0100 +++ openvpn-2.0_beta12/cryptoapi.h 2004-10-18 21:30:16.000000000 +0200 @@ -0,0 +1,7 @@ +#ifndef _CRYPTOAPI_H_ +#define _CRYPTOAPI_H_ + +int SSL_CTX_use_CryptoAPI_certificate(SSL_CTX *ssl_ctx, const char *cert_prop); + + +#endif /* !_CRYPTOAPI_H_ */ diff -uN openvpn-2.0_beta12.orig/init.c openvpn-2.0_beta12/init.c --- openvpn-2.0_beta12.orig/init.c 2004-10-17 09:07:32.000000000 +0200 +++ openvpn-2.0_beta12/init.c 2004-10-18 21:33:37.000000000 +0200 @@ -1119,11 +1119,11 @@ options->pkcs12_file, options->cipher_list, #if P2MP - !options->client_cert_not_required + !options->client_cert_not_required, #else - true + true, #endif - ); + options); /* Get cipher & hash algorithms */ init_key_type (&c->c1.ks.key_type, options->ciphername, diff -uN openvpn-2.0_beta12.orig/makefile.w32 openvpn-2.0_beta12/makefile.w32 --- openvpn-2.0_beta12.orig/makefile.w32 2004-10-17 02:10:06.000000000 +0200 +++ openvpn-2.0_beta12/makefile.w32 2004-10-19 08:55:25.031998400 +0200 @@ -34,7 +34,7 @@ INCLUDE_DIRS = -I${OPENSSL}/include -I${LZO}/include -LIBS = -llzo -lws2_32 -lgdi32 -liphlpapi -lwinmm +LIBS = -llzo -lcrypt32 -lws2_32 -lgdi32 -liphlpapi -lwinmm LIB_DIRS = -L${OPENSSL}/out -L${LZO}/src/.libs @@ -48,6 +48,7 @@ tap-win32/common.h \ config-win32.h \ crypto.h \ + cryptoapi.h \ errlevel.h \ error.h \ event.h \ @@ -104,6 +105,7 @@ OBJS = base64.o \ buffer.o \ crypto.o \ + cryptoapi.o \ error.o \ event.o \ fdmisc.o \ diff -uN openvpn-2.0_beta12.orig/options.c openvpn-2.0_beta12/options.c --- openvpn-2.0_beta12.orig/options.c 2004-10-17 10:32:14.000000000 +0200 +++ openvpn-2.0_beta12/options.c 2004-10-18 20:47:20.000000000 +0200 @@ -963,6 +963,7 @@ SHOW_STR (cert_file); SHOW_STR (priv_key_file); SHOW_STR (pkcs12_file); + SHOW_STR (cryptoapi_cert); SHOW_STR (cipher_list); SHOW_STR (tls_verify); SHOW_STR (tls_remote); @@ -3545,6 +3546,12 @@ VERIFY_PERMISSION (OPT_P_GENERAL); options->cert_file = p[1]; } + else if (streq (p[0], "cryptoapicert") && p[1]) + { + ++i; + VERIFY_PERMISSION (OPT_P_GENERAL); + options->cryptoapi_cert = p[1]; + } else if (streq (p[0], "key") && p[1]) { ++i; diff -uN openvpn-2.0_beta12.orig/options.h openvpn-2.0_beta12/options.h --- openvpn-2.0_beta12.orig/options.h 2004-10-17 02:10:06.000000000 +0200 +++ openvpn-2.0_beta12/options.h 2004-10-18 20:47:21.000000000 +0200 @@ -311,6 +311,7 @@ const char *ca_file; const char *dh_file; const char *cert_file; + const char *cryptoapi_cert; const char *priv_key_file; const char *pkcs12_file; const char *cipher_list; diff -uN openvpn-2.0_beta12.orig/ssl.c openvpn-2.0_beta12/ssl.c --- openvpn-2.0_beta12.orig/ssl.c 2004-10-14 23:30:52.000000000 +0200 +++ openvpn-2.0_beta12/ssl.c 2004-10-18 21:28:09.000000000 +0200 @@ -55,6 +55,8 @@ #include "memdbg.h" +#include "cryptoapi.h" + #ifdef MEASURE_TLS_HANDSHAKE_STATS static int tls_handshake_success; /* GLOBAL */ @@ -640,7 +642,8 @@ const char *priv_key_file, const char *pkcs12_file, const char *cipher_list, - const bool require_peer_cert) + const bool require_peer_cert, + const struct options *options) { SSL_CTX *ctx; DH *dh; @@ -740,23 +743,37 @@ { /* Use seperate PEM files for key, cert and CA certs */ - /* Load Certificate */ - if (cert_file) + if (options->cryptoapi_cert) { - if (!SSL_CTX_use_certificate_file (ctx, cert_file, SSL_FILETYPE_PEM)) - msg (M_SSLERR, "Cannot load certificate file %s", cert_file); + /* Load Certificate and Private Key */ + if (!SSL_CTX_use_CryptoAPI_certificate (ctx, options->cryptoapi_cert)) + msg (M_SSLERR, "Cannot load certificate \"%s\" from Microsoft Certificate Store", + options->cryptoapi_cert); } - - /* Load Private Key */ - if (priv_key_file) + else { - if (!SSL_CTX_use_PrivateKey_file (ctx, priv_key_file, SSL_FILETYPE_PEM)) - msg (M_SSLERR, "Cannot load private key file %s", priv_key_file); - warn_if_group_others_accessible (priv_key_file); - - /* Check Private Key */ - if (!SSL_CTX_check_private_key (ctx)) - msg (M_SSLERR, "Private key does not match the certificate"); + /* Load Certificate */ + if (cert_file) + { + if (!SSL_CTX_use_certificate_file (ctx, cert_file, SSL_FILETYPE_PEM)) + msg (M_SSLERR, "Cannot load certificate file %s", cert_file); + + /* Enable the use of certificate chains */ + if (!SSL_CTX_use_certificate_chain_file (ctx, cert_file)) + msg (M_SSLERR, "Cannot load certificate chain file %s (SSL_use_certificate_chain_file)", cert_file); + } + + /* Load Private Key */ + if (priv_key_file) + { + if (!SSL_CTX_use_PrivateKey_file (ctx, priv_key_file, SSL_FILETYPE_PEM)) + msg (M_SSLERR, "Cannot load private key file %s", priv_key_file); + warn_if_group_others_accessible (priv_key_file); + + /* Check Private Key */ + if (!SSL_CTX_check_private_key (ctx)) + msg (M_SSLERR, "Private key does not match the certificate"); + } } /* Load CA file for verifying peer supplied certificate */ @@ -773,12 +790,6 @@ SSL_CTX_set_client_CA_list (ctx, cert_names); } - if (cert_file) - { - /* Enable the use of certificate chains */ - if (!SSL_CTX_use_certificate_chain_file (ctx, cert_file)) - msg (M_SSLERR, "Cannot load certificate chain file %s (SSL_use_certificate_chain_file)", cert_file); - } } /* Require peer certificate verification */ diff -uN openvpn-2.0_beta12.orig/ssl.h openvpn-2.0_beta12/ssl.h --- openvpn-2.0_beta12.orig/ssl.h 2004-10-11 23:42:50.000000000 +0200 +++ openvpn-2.0_beta12/ssl.h 2004-10-18 21:27:30.000000000 +0200 @@ -42,6 +42,7 @@ #include "socket.h" #include "mtu.h" #include "thread.h" +#include "options.h" /* * OpenVPN TLS-over-UDP Protocol. @@ -470,7 +471,8 @@ const char *pkcs12_file, const char *priv_key_file, const char *cipher_list, - const bool require_peer_cert); + const bool require_peer_cert, + const struct options *options); struct tls_multi *tls_multi_init (struct tls_options *tls_options); -----8<----------8<----------8<----------8<----------8<----------8<----------8<----- Cheers, - Peter -- Peter 'Luna' Runestig (fd. Altberg), Sweden <pe...@runestig.com> PGP Key ID: 0xD07BBE13 Fingerprint: 7B5C 1F48 2997 C061 DE4B 42EA CB99 A35C D07B BE13 AOL Instant Messenger Screen name: PRunestig Yahoo! Messenger profile name: altberg