aboutsummaryrefslogtreecommitdiff
path: root/contrib/wpa_supplicant/crypto_cryptoapi.c
diff options
context:
space:
mode:
Diffstat (limited to 'contrib/wpa_supplicant/crypto_cryptoapi.c')
-rw-r--r--contrib/wpa_supplicant/crypto_cryptoapi.c801
1 files changed, 801 insertions, 0 deletions
diff --git a/contrib/wpa_supplicant/crypto_cryptoapi.c b/contrib/wpa_supplicant/crypto_cryptoapi.c
new file mode 100644
index 000000000000..bb0573078d24
--- /dev/null
+++ b/contrib/wpa_supplicant/crypto_cryptoapi.c
@@ -0,0 +1,801 @@
+/*
+ * WPA Supplicant / Crypto wrapper for Microsoft CryptoAPI
+ * Copyright (c) 2005-2006, Jouni Malinen <j@w1.fi>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * Alternatively, this software may be distributed under the terms of BSD
+ * license.
+ *
+ * See README and COPYING for more details.
+ */
+
+#include "includes.h"
+#include <windows.h>
+#include <wincrypt.h>
+
+#include "common.h"
+#include "crypto.h"
+
+#ifndef MS_ENH_RSA_AES_PROV
+#ifdef UNICODE
+#define MS_ENH_RSA_AES_PROV \
+L"Microsoft Enhanced RSA and AES Cryptographic Provider (Prototype)"
+#else
+#define MS_ENH_RSA_AES_PROV \
+"Microsoft Enhanced RSA and AES Cryptographic Provider (Prototype)"
+#endif
+#endif /* MS_ENH_RSA_AES_PROV */
+
+#ifndef CALG_HMAC
+#define CALG_HMAC (ALG_CLASS_HASH | ALG_TYPE_ANY | ALG_SID_HMAC)
+#endif
+
+#ifdef CONFIG_TLS_INTERNAL
+#ifdef __MINGW32_VERSION
+/*
+ * MinGW does not yet include all the needed definitions for CryptoAPI, so
+ * define here whatever extra is needed.
+ */
+
+static PCCERT_CONTEXT WINAPI
+(*CertCreateCertificateContext)(DWORD dwCertEncodingType,
+ const BYTE *pbCertEncoded,
+ DWORD cbCertEncoded)
+= NULL; /* to be loaded from crypt32.dll */
+
+static BOOL WINAPI
+(*CryptImportPublicKeyInfo)(HCRYPTPROV hCryptProv, DWORD dwCertEncodingType,
+ PCERT_PUBLIC_KEY_INFO pInfo, HCRYPTKEY *phKey)
+= NULL; /* to be loaded from crypt32.dll */
+
+
+static int mingw_load_crypto_func(void)
+{
+ HINSTANCE dll;
+
+ /* MinGW does not yet have full CryptoAPI support, so load the needed
+ * function here. */
+
+ if (CertCreateCertificateContext)
+ return 0;
+
+ dll = LoadLibrary("crypt32");
+ if (dll == NULL) {
+ wpa_printf(MSG_DEBUG, "CryptoAPI: Could not load crypt32 "
+ "library");
+ return -1;
+ }
+
+ CertCreateCertificateContext = (void *) GetProcAddress(
+ dll, "CertCreateCertificateContext");
+ if (CertCreateCertificateContext == NULL) {
+ wpa_printf(MSG_DEBUG, "CryptoAPI: Could not get "
+ "CertCreateCertificateContext() address from "
+ "crypt32 library");
+ return -1;
+ }
+
+ CryptImportPublicKeyInfo = GetProcAddress(
+ dll, "CryptImportPublicKeyInfo");
+ if (CryptImportPublicKeyInfo == NULL) {
+ wpa_printf(MSG_DEBUG, "CryptoAPI: Could not get "
+ "CryptImportPublicKeyInfo() address from "
+ "crypt32 library");
+ return -1;
+ }
+
+ return 0;
+}
+
+#else /* __MINGW32_VERSION */
+
+static int mingw_load_crypto_func(void)
+{
+ return 0;
+}
+
+#endif /* __MINGW32_VERSION */
+#endif /* CONFIG_TLS_INTERNAL */
+
+
+static void cryptoapi_report_error(const char *msg)
+{
+ char *s, *pos;
+ DWORD err = GetLastError();
+
+ if (FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER |
+ FORMAT_MESSAGE_FROM_SYSTEM,
+ NULL, err, 0, (LPTSTR) &s, 0, NULL) == 0) {
+ wpa_printf(MSG_DEBUG, "CryptoAPI: %s: %d", msg, (int) err);
+ }
+
+ pos = s;
+ while (*pos) {
+ if (*pos == '\n' || *pos == '\r') {
+ *pos = '\0';
+ break;
+ }
+ pos++;
+ }
+
+ wpa_printf(MSG_DEBUG, "CryptoAPI: %s: %d: (%s)", msg, (int) err, s);
+ LocalFree(s);
+}
+
+
+int cryptoapi_hash_vector(ALG_ID alg, size_t hash_len, size_t num_elem,
+ const u8 *addr[], const size_t *len, u8 *mac)
+{
+ HCRYPTPROV prov;
+ HCRYPTHASH hash;
+ size_t i;
+ DWORD hlen;
+ int ret = 0;
+
+ if (!CryptAcquireContext(&prov, NULL, NULL, PROV_RSA_FULL, 0)) {
+ cryptoapi_report_error("CryptAcquireContext");
+ return -1;
+ }
+
+ if (!CryptCreateHash(prov, alg, 0, 0, &hash)) {
+ cryptoapi_report_error("CryptCreateHash");
+ CryptReleaseContext(prov, 0);
+ return -1;
+ }
+
+ for (i = 0; i < num_elem; i++) {
+ if (!CryptHashData(hash, (BYTE *) addr[i], len[i], 0)) {
+ cryptoapi_report_error("CryptHashData");
+ CryptDestroyHash(hash);
+ CryptReleaseContext(prov, 0);
+ }
+ }
+
+ hlen = hash_len;
+ if (!CryptGetHashParam(hash, HP_HASHVAL, mac, &hlen, 0)) {
+ cryptoapi_report_error("CryptGetHashParam");
+ ret = -1;
+ }
+
+ CryptDestroyHash(hash);
+ CryptReleaseContext(prov, 0);
+
+ return ret;
+}
+
+
+void md4_vector(size_t num_elem, const u8 *addr[], const size_t *len, u8 *mac)
+{
+ cryptoapi_hash_vector(CALG_MD4, 16, num_elem, addr, len, mac);
+}
+
+
+void des_encrypt(const u8 *clear, const u8 *key, u8 *cypher)
+{
+ u8 next, tmp;
+ int i;
+ HCRYPTPROV prov;
+ HCRYPTKEY ckey;
+ DWORD dlen;
+ struct {
+ BLOBHEADER hdr;
+ DWORD len;
+ BYTE key[8];
+ } key_blob;
+ DWORD mode = CRYPT_MODE_ECB;
+
+ key_blob.hdr.bType = PLAINTEXTKEYBLOB;
+ key_blob.hdr.bVersion = CUR_BLOB_VERSION;
+ key_blob.hdr.reserved = 0;
+ key_blob.hdr.aiKeyAlg = CALG_DES;
+ key_blob.len = 8;
+
+ /* Add parity bits to the key */
+ next = 0;
+ for (i = 0; i < 7; i++) {
+ tmp = key[i];
+ key_blob.key[i] = (tmp >> i) | next | 1;
+ next = tmp << (7 - i);
+ }
+ key_blob.key[i] = next | 1;
+
+ if (!CryptAcquireContext(&prov, NULL, MS_ENHANCED_PROV, PROV_RSA_FULL,
+ CRYPT_VERIFYCONTEXT)) {
+ wpa_printf(MSG_DEBUG, "CryptoAPI: CryptAcquireContext failed: "
+ "%d", (int) GetLastError());
+ return;
+ }
+
+ if (!CryptImportKey(prov, (BYTE *) &key_blob, sizeof(key_blob), 0, 0,
+ &ckey)) {
+ wpa_printf(MSG_DEBUG, "CryptoAPI: CryptImportKey failed: %d",
+ (int) GetLastError());
+ CryptReleaseContext(prov, 0);
+ return;
+ }
+
+ if (!CryptSetKeyParam(ckey, KP_MODE, (BYTE *) &mode, 0)) {
+ wpa_printf(MSG_DEBUG, "CryptoAPI: CryptSetKeyParam(KP_MODE) "
+ "failed: %d", (int) GetLastError());
+ CryptDestroyKey(ckey);
+ CryptReleaseContext(prov, 0);
+ return;
+ }
+
+ os_memcpy(cypher, clear, 8);
+ dlen = 8;
+ if (!CryptEncrypt(ckey, 0, FALSE, 0, cypher, &dlen, 8)) {
+ wpa_printf(MSG_DEBUG, "CryptoAPI: CryptEncrypt failed: %d",
+ (int) GetLastError());
+ os_memset(cypher, 0, 8);
+ }
+
+ CryptDestroyKey(ckey);
+ CryptReleaseContext(prov, 0);
+}
+
+
+#ifdef EAP_TLS_FUNCS
+void md5_vector(size_t num_elem, const u8 *addr[], const size_t *len, u8 *mac)
+{
+ cryptoapi_hash_vector(CALG_MD5, 16, num_elem, addr, len, mac);
+}
+
+
+void sha1_vector(size_t num_elem, const u8 *addr[], const size_t *len, u8 *mac)
+{
+ cryptoapi_hash_vector(CALG_SHA, 20, num_elem, addr, len, mac);
+}
+
+
+struct aes_context {
+ HCRYPTPROV prov;
+ HCRYPTKEY ckey;
+};
+
+
+void * aes_encrypt_init(const u8 *key, size_t len)
+{
+ struct aes_context *akey;
+ struct {
+ BLOBHEADER hdr;
+ DWORD len;
+ BYTE key[16];
+ } key_blob;
+ DWORD mode = CRYPT_MODE_ECB;
+
+ if (len != 16)
+ return NULL;
+
+ key_blob.hdr.bType = PLAINTEXTKEYBLOB;
+ key_blob.hdr.bVersion = CUR_BLOB_VERSION;
+ key_blob.hdr.reserved = 0;
+ key_blob.hdr.aiKeyAlg = CALG_AES_128;
+ key_blob.len = len;
+ os_memcpy(key_blob.key, key, len);
+
+ akey = os_zalloc(sizeof(*akey));
+ if (akey == NULL)
+ return NULL;
+
+ if (!CryptAcquireContext(&akey->prov, NULL,
+ MS_ENH_RSA_AES_PROV, PROV_RSA_AES,
+ CRYPT_VERIFYCONTEXT)) {
+ wpa_printf(MSG_DEBUG, "CryptoAPI: CryptAcquireContext failed: "
+ "%d", (int) GetLastError());
+ os_free(akey);
+ return NULL;
+ }
+
+ if (!CryptImportKey(akey->prov, (BYTE *) &key_blob, sizeof(key_blob),
+ 0, 0, &akey->ckey)) {
+ wpa_printf(MSG_DEBUG, "CryptoAPI: CryptImportKey failed: %d",
+ (int) GetLastError());
+ CryptReleaseContext(akey->prov, 0);
+ os_free(akey);
+ return NULL;
+ }
+
+ if (!CryptSetKeyParam(akey->ckey, KP_MODE, (BYTE *) &mode, 0)) {
+ wpa_printf(MSG_DEBUG, "CryptoAPI: CryptSetKeyParam(KP_MODE) "
+ "failed: %d", (int) GetLastError());
+ CryptDestroyKey(akey->ckey);
+ CryptReleaseContext(akey->prov, 0);
+ os_free(akey);
+ return NULL;
+ }
+
+ return akey;
+}
+
+
+void aes_encrypt(void *ctx, const u8 *plain, u8 *crypt)
+{
+ struct aes_context *akey = ctx;
+ DWORD dlen;
+
+ os_memcpy(crypt, plain, 16);
+ dlen = 16;
+ if (!CryptEncrypt(akey->ckey, 0, FALSE, 0, crypt, &dlen, 16)) {
+ wpa_printf(MSG_DEBUG, "CryptoAPI: CryptEncrypt failed: %d",
+ (int) GetLastError());
+ os_memset(crypt, 0, 16);
+ }
+}
+
+
+void aes_encrypt_deinit(void *ctx)
+{
+ struct aes_context *akey = ctx;
+ if (akey) {
+ CryptDestroyKey(akey->ckey);
+ CryptReleaseContext(akey->prov, 0);
+ os_free(akey);
+ }
+}
+
+
+void * aes_decrypt_init(const u8 *key, size_t len)
+{
+ return aes_encrypt_init(key, len);
+}
+
+
+void aes_decrypt(void *ctx, const u8 *crypt, u8 *plain)
+{
+ struct aes_context *akey = ctx;
+ DWORD dlen;
+
+ os_memcpy(plain, crypt, 16);
+ dlen = 16;
+
+ if (!CryptDecrypt(akey->ckey, 0, FALSE, 0, plain, &dlen)) {
+ wpa_printf(MSG_DEBUG, "CryptoAPI: CryptDecrypt failed: %d",
+ (int) GetLastError());
+ }
+}
+
+
+void aes_decrypt_deinit(void *ctx)
+{
+ aes_encrypt_deinit(ctx);
+}
+
+#ifdef CONFIG_TLS_INTERNAL
+
+struct crypto_hash {
+ enum crypto_hash_alg alg;
+ int error;
+ HCRYPTPROV prov;
+ HCRYPTHASH hash;
+ HCRYPTKEY key;
+};
+
+struct crypto_hash * crypto_hash_init(enum crypto_hash_alg alg, const u8 *key,
+ size_t key_len)
+{
+ struct crypto_hash *ctx;
+ ALG_ID calg;
+ struct {
+ BLOBHEADER hdr;
+ DWORD len;
+ BYTE key[32];
+ } key_blob;
+
+ os_memset(&key_blob, 0, sizeof(key_blob));
+ switch (alg) {
+ case CRYPTO_HASH_ALG_MD5:
+ calg = CALG_MD5;
+ break;
+ case CRYPTO_HASH_ALG_SHA1:
+ calg = CALG_SHA;
+ break;
+ case CRYPTO_HASH_ALG_HMAC_MD5:
+ case CRYPTO_HASH_ALG_HMAC_SHA1:
+ calg = CALG_HMAC;
+ key_blob.hdr.bType = PLAINTEXTKEYBLOB;
+ key_blob.hdr.bVersion = CUR_BLOB_VERSION;
+ key_blob.hdr.reserved = 0;
+ /*
+ * Note: RC2 is not really used, but that can be used to
+ * import HMAC keys of up to 16 byte long.
+ * CRYPT_IPSEC_HMAC_KEY flag for CryptImportKey() is needed to
+ * be able to import longer keys (HMAC-SHA1 uses 20-byte key).
+ */
+ key_blob.hdr.aiKeyAlg = CALG_RC2;
+ key_blob.len = key_len;
+ if (key_len > sizeof(key_blob.key))
+ return NULL;
+ os_memcpy(key_blob.key, key, key_len);
+ break;
+ default:
+ return NULL;
+ }
+
+ ctx = os_zalloc(sizeof(*ctx));
+ if (ctx == NULL)
+ return NULL;
+
+ ctx->alg = alg;
+
+ if (!CryptAcquireContext(&ctx->prov, NULL, NULL, PROV_RSA_FULL, 0)) {
+ cryptoapi_report_error("CryptAcquireContext");
+ os_free(ctx);
+ return NULL;
+ }
+
+ if (calg == CALG_HMAC) {
+#ifndef CRYPT_IPSEC_HMAC_KEY
+#define CRYPT_IPSEC_HMAC_KEY 0x00000100
+#endif
+ if (!CryptImportKey(ctx->prov, (BYTE *) &key_blob,
+ sizeof(key_blob), 0, CRYPT_IPSEC_HMAC_KEY,
+ &ctx->key)) {
+ cryptoapi_report_error("CryptImportKey");
+ CryptReleaseContext(ctx->prov, 0);
+ os_free(ctx);
+ return NULL;
+ }
+ }
+
+ if (!CryptCreateHash(ctx->prov, calg, ctx->key, 0, &ctx->hash)) {
+ cryptoapi_report_error("CryptCreateHash");
+ CryptReleaseContext(ctx->prov, 0);
+ os_free(ctx);
+ return NULL;
+ }
+
+ if (calg == CALG_HMAC) {
+ HMAC_INFO info;
+ os_memset(&info, 0, sizeof(info));
+ switch (alg) {
+ case CRYPTO_HASH_ALG_HMAC_MD5:
+ info.HashAlgid = CALG_MD5;
+ break;
+ case CRYPTO_HASH_ALG_HMAC_SHA1:
+ info.HashAlgid = CALG_SHA;
+ break;
+ default:
+ /* unreachable */
+ break;
+ }
+
+ if (!CryptSetHashParam(ctx->hash, HP_HMAC_INFO, (BYTE *) &info,
+ 0)) {
+ cryptoapi_report_error("CryptSetHashParam");
+ CryptDestroyHash(ctx->hash);
+ CryptReleaseContext(ctx->prov, 0);
+ os_free(ctx);
+ return NULL;
+ }
+ }
+
+ return ctx;
+}
+
+
+void crypto_hash_update(struct crypto_hash *ctx, const u8 *data, size_t len)
+{
+ if (ctx == NULL || ctx->error)
+ return;
+
+ if (!CryptHashData(ctx->hash, (BYTE *) data, len, 0)) {
+ cryptoapi_report_error("CryptHashData");
+ ctx->error = 1;
+ }
+}
+
+
+int crypto_hash_finish(struct crypto_hash *ctx, u8 *mac, size_t *len)
+{
+ int ret = 0;
+ DWORD hlen;
+
+ if (ctx == NULL)
+ return -2;
+
+ if (mac == NULL || len == NULL)
+ goto done;
+
+ if (ctx->error) {
+ ret = -2;
+ goto done;
+ }
+
+ hlen = *len;
+ if (!CryptGetHashParam(ctx->hash, HP_HASHVAL, mac, &hlen, 0)) {
+ cryptoapi_report_error("CryptGetHashParam");
+ ret = -2;
+ }
+ *len = hlen;
+
+done:
+ if (ctx->alg == CRYPTO_HASH_ALG_HMAC_SHA1 ||
+ ctx->alg == CRYPTO_HASH_ALG_HMAC_MD5)
+ CryptDestroyKey(ctx->key);
+
+ os_free(ctx);
+
+ return ret;
+}
+
+
+struct crypto_cipher {
+ HCRYPTPROV prov;
+ HCRYPTKEY key;
+};
+
+
+struct crypto_cipher * crypto_cipher_init(enum crypto_cipher_alg alg,
+ const u8 *iv, const u8 *key,
+ size_t key_len)
+{
+ struct crypto_cipher *ctx;
+ struct {
+ BLOBHEADER hdr;
+ DWORD len;
+ BYTE key[32];
+ } key_blob;
+ DWORD mode = CRYPT_MODE_CBC;
+
+ key_blob.hdr.bType = PLAINTEXTKEYBLOB;
+ key_blob.hdr.bVersion = CUR_BLOB_VERSION;
+ key_blob.hdr.reserved = 0;
+ key_blob.len = key_len;
+ if (key_len > sizeof(key_blob.key))
+ return NULL;
+ os_memcpy(key_blob.key, key, key_len);
+
+ switch (alg) {
+ case CRYPTO_CIPHER_ALG_AES:
+ if (key_len == 32)
+ key_blob.hdr.aiKeyAlg = CALG_AES_256;
+ else if (key_len == 24)
+ key_blob.hdr.aiKeyAlg = CALG_AES_192;
+ else
+ key_blob.hdr.aiKeyAlg = CALG_AES_128;
+ break;
+ case CRYPTO_CIPHER_ALG_3DES:
+ key_blob.hdr.aiKeyAlg = CALG_3DES;
+ break;
+ case CRYPTO_CIPHER_ALG_DES:
+ key_blob.hdr.aiKeyAlg = CALG_DES;
+ break;
+ case CRYPTO_CIPHER_ALG_RC2:
+ key_blob.hdr.aiKeyAlg = CALG_RC2;
+ break;
+ case CRYPTO_CIPHER_ALG_RC4:
+ key_blob.hdr.aiKeyAlg = CALG_RC4;
+ break;
+ default:
+ return NULL;
+ }
+
+ ctx = os_zalloc(sizeof(*ctx));
+ if (ctx == NULL)
+ return NULL;
+
+ if (!CryptAcquireContext(&ctx->prov, NULL, MS_ENH_RSA_AES_PROV,
+ PROV_RSA_AES, CRYPT_VERIFYCONTEXT)) {
+ cryptoapi_report_error("CryptAcquireContext");
+ goto fail1;
+ }
+
+ if (!CryptImportKey(ctx->prov, (BYTE *) &key_blob,
+ sizeof(key_blob), 0, 0, &ctx->key)) {
+ cryptoapi_report_error("CryptImportKey");
+ goto fail2;
+ }
+
+ if (!CryptSetKeyParam(ctx->key, KP_MODE, (BYTE *) &mode, 0)) {
+ cryptoapi_report_error("CryptSetKeyParam(KP_MODE)");
+ goto fail3;
+ }
+
+ if (iv && !CryptSetKeyParam(ctx->key, KP_IV, (BYTE *) iv, 0)) {
+ cryptoapi_report_error("CryptSetKeyParam(KP_IV)");
+ goto fail3;
+ }
+
+ return ctx;
+
+fail3:
+ CryptDestroyKey(ctx->key);
+fail2:
+ CryptReleaseContext(ctx->prov, 0);
+fail1:
+ os_free(ctx);
+ return NULL;
+}
+
+
+int crypto_cipher_encrypt(struct crypto_cipher *ctx, const u8 *plain,
+ u8 *crypt, size_t len)
+{
+ DWORD dlen;
+
+ os_memcpy(crypt, plain, len);
+ dlen = len;
+ if (!CryptEncrypt(ctx->key, 0, FALSE, 0, crypt, &dlen, len)) {
+ cryptoapi_report_error("CryptEncrypt");
+ os_memset(crypt, 0, len);
+ return -1;
+ }
+
+ return 0;
+}
+
+
+int crypto_cipher_decrypt(struct crypto_cipher *ctx, const u8 *crypt,
+ u8 *plain, size_t len)
+{
+ DWORD dlen;
+
+ os_memcpy(plain, crypt, len);
+ dlen = len;
+ if (!CryptDecrypt(ctx->key, 0, FALSE, 0, plain, &dlen)) {
+ cryptoapi_report_error("CryptDecrypt");
+ return -1;
+ }
+
+ return 0;
+}
+
+
+void crypto_cipher_deinit(struct crypto_cipher *ctx)
+{
+ CryptDestroyKey(ctx->key);
+ CryptReleaseContext(ctx->prov, 0);
+ os_free(ctx);
+}
+
+
+struct crypto_public_key {
+ HCRYPTPROV prov;
+ HCRYPTKEY rsa;
+};
+
+struct crypto_private_key {
+ HCRYPTPROV prov;
+ HCRYPTKEY rsa;
+};
+
+
+struct crypto_public_key * crypto_public_key_import(const u8 *key, size_t len)
+{
+ /* Use crypto_public_key_from_cert() instead. */
+ return NULL;
+}
+
+
+struct crypto_private_key * crypto_private_key_import(const u8 *key,
+ size_t len)
+{
+ /* TODO */
+ return NULL;
+}
+
+
+struct crypto_public_key * crypto_public_key_from_cert(const u8 *buf,
+ size_t len)
+{
+ struct crypto_public_key *pk;
+ PCCERT_CONTEXT cc;
+
+ pk = os_zalloc(sizeof(*pk));
+ if (pk == NULL)
+ return NULL;
+
+ cc = CertCreateCertificateContext(X509_ASN_ENCODING |
+ PKCS_7_ASN_ENCODING, buf, len);
+ if (!cc) {
+ cryptoapi_report_error("CryptCreateCertificateContext");
+ os_free(pk);
+ return NULL;
+ }
+
+ if (!CryptAcquireContext(&pk->prov, NULL, MS_DEF_PROV, PROV_RSA_FULL,
+ 0)) {
+ cryptoapi_report_error("CryptAcquireContext");
+ os_free(pk);
+ CertFreeCertificateContext(cc);
+ return NULL;
+ }
+
+ if (!CryptImportPublicKeyInfo(pk->prov, X509_ASN_ENCODING |
+ PKCS_7_ASN_ENCODING,
+ &cc->pCertInfo->SubjectPublicKeyInfo,
+ &pk->rsa)) {
+ cryptoapi_report_error("CryptImportPublicKeyInfo");
+ CryptReleaseContext(pk->prov, 0);
+ os_free(pk);
+ CertFreeCertificateContext(cc);
+ return NULL;
+ }
+
+ CertFreeCertificateContext(cc);
+
+ return pk;
+}
+
+
+int crypto_public_key_encrypt_pkcs1_v15(struct crypto_public_key *key,
+ const u8 *in, size_t inlen,
+ u8 *out, size_t *outlen)
+{
+ DWORD clen;
+ u8 *tmp;
+ size_t i;
+
+ if (*outlen < inlen)
+ return -1;
+ tmp = malloc(*outlen);
+ if (tmp == NULL)
+ return -1;
+
+ os_memcpy(tmp, in, inlen);
+ clen = inlen;
+ if (!CryptEncrypt(key->rsa, 0, TRUE, 0, tmp, &clen, *outlen)) {
+ wpa_printf(MSG_DEBUG, "CryptoAPI: Failed to encrypt using "
+ "public key: %d", (int) GetLastError());
+ os_free(tmp);
+ return -1;
+ }
+
+ *outlen = clen;
+
+ /* Reverse the output */
+ for (i = 0; i < *outlen; i++)
+ out[i] = tmp[*outlen - 1 - i];
+
+ os_free(tmp);
+
+ return 0;
+}
+
+
+int crypto_private_key_sign_pkcs1(struct crypto_private_key *key,
+ const u8 *in, size_t inlen,
+ u8 *out, size_t *outlen)
+{
+ /* TODO */
+ return -1;
+}
+
+
+void crypto_public_key_free(struct crypto_public_key *key)
+{
+ if (key) {
+ CryptDestroyKey(key->rsa);
+ CryptReleaseContext(key->prov, 0);
+ os_free(key);
+ }
+}
+
+
+void crypto_private_key_free(struct crypto_private_key *key)
+{
+ if (key) {
+ CryptDestroyKey(key->rsa);
+ CryptReleaseContext(key->prov, 0);
+ os_free(key);
+ }
+}
+
+
+int crypto_global_init(void)
+{
+ return mingw_load_crypto_func();
+}
+
+
+void crypto_global_deinit(void)
+{
+}
+
+#endif /* CONFIG_TLS_INTERNAL */
+
+#endif /* EAP_TLS_FUNCS */