crypto_cryptoapi.c revision 209158
1218822Sdim/*
238889Sjdp * Crypto wrapper for Microsoft CryptoAPI
3218822Sdim * Copyright (c) 2005-2009, Jouni Malinen <j@w1.fi>
4218822Sdim *
5218822Sdim * This program is free software; you can redistribute it and/or modify
6218822Sdim * it under the terms of the GNU General Public License version 2 as
7218822Sdim * published by the Free Software Foundation.
838889Sjdp *
9218822Sdim * Alternatively, this software may be distributed under the terms of BSD
10218822Sdim * license.
11218822Sdim *
12218822Sdim * See README and COPYING for more details.
1338889Sjdp */
14218822Sdim
15218822Sdim#include "includes.h"
16218822Sdim#include <windows.h>
17218822Sdim#include <wincrypt.h>
18218822Sdim
19130561Sobrien#include "common.h"
20218822Sdim#include "crypto.h"
21218822Sdim
22218822Sdim#ifndef MS_ENH_RSA_AES_PROV
23218822Sdim#ifdef UNICODE
24218822Sdim#define MS_ENH_RSA_AES_PROV \
2533965SjdpL"Microsoft Enhanced RSA and AES Cryptographic Provider (Prototype)"
26218822Sdim#else
27218822Sdim#define MS_ENH_RSA_AES_PROV \
28218822Sdim"Microsoft Enhanced RSA and AES Cryptographic Provider (Prototype)"
29218822Sdim#endif
30218822Sdim#endif /* MS_ENH_RSA_AES_PROV */
31218822Sdim
3233965Sjdp#ifndef CALG_HMAC
33218822Sdim#define CALG_HMAC (ALG_CLASS_HASH | ALG_TYPE_ANY | ALG_SID_HMAC)
3438889Sjdp#endif
35218822Sdim
36218822Sdim#ifdef CONFIG_TLS_INTERNAL
37218822Sdim#ifdef __MINGW32_VERSION
38218822Sdim/*
39218822Sdim * MinGW does not yet include all the needed definitions for CryptoAPI, so
4060484Sobrien * define here whatever extra is needed.
41218822Sdim */
42218822Sdim
43218822Sdimstatic BOOL WINAPI
44218822Sdim(*CryptImportPublicKeyInfo)(HCRYPTPROV hCryptProv, DWORD dwCertEncodingType,
45218822Sdim			    PCERT_PUBLIC_KEY_INFO pInfo, HCRYPTKEY *phKey)
46218822Sdim= NULL; /* to be loaded from crypt32.dll */
47218822Sdim
48218822Sdim
49218822Sdimstatic int mingw_load_crypto_func(void)
50218822Sdim{
51218822Sdim	HINSTANCE dll;
52218822Sdim
53218822Sdim	/* MinGW does not yet have full CryptoAPI support, so load the needed
54218822Sdim	 * function here. */
55218822Sdim
56218822Sdim	if (CryptImportPublicKeyInfo)
57218822Sdim		return 0;
58218822Sdim
59218822Sdim	dll = LoadLibrary("crypt32");
60218822Sdim	if (dll == NULL) {
61218822Sdim		wpa_printf(MSG_DEBUG, "CryptoAPI: Could not load crypt32 "
62218822Sdim			   "library");
63218822Sdim		return -1;
64218822Sdim	}
65218822Sdim
66218822Sdim	CryptImportPublicKeyInfo = GetProcAddress(
67218822Sdim		dll, "CryptImportPublicKeyInfo");
68218822Sdim	if (CryptImportPublicKeyInfo == NULL) {
69218822Sdim		wpa_printf(MSG_DEBUG, "CryptoAPI: Could not get "
70218822Sdim			   "CryptImportPublicKeyInfo() address from "
71218822Sdim			   "crypt32 library");
72218822Sdim		return -1;
73218822Sdim	}
74218822Sdim
75218822Sdim	return 0;
76218822Sdim}
77218822Sdim
7860484Sobrien#else /* __MINGW32_VERSION */
79218822Sdim
80218822Sdimstatic int mingw_load_crypto_func(void)
81218822Sdim{
82218822Sdim	return 0;
83218822Sdim}
8460484Sobrien
8560484Sobrien#endif /* __MINGW32_VERSION */
86218822Sdim#endif /* CONFIG_TLS_INTERNAL */
8760484Sobrien
88218822Sdim
89218822Sdimstatic void cryptoapi_report_error(const char *msg)
90218822Sdim{
91218822Sdim	char *s, *pos;
92218822Sdim	DWORD err = GetLastError();
93218822Sdim
9460484Sobrien	if (FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER |
95218822Sdim			  FORMAT_MESSAGE_FROM_SYSTEM,
96104834Sobrien			  NULL, err, 0, (LPTSTR) &s, 0, NULL) == 0) {
97218822Sdim 		wpa_printf(MSG_DEBUG, "CryptoAPI: %s: %d", msg, (int) err);
98218822Sdim	}
99104834Sobrien
100104834Sobrien	pos = s;
101218822Sdim	while (*pos) {
102218822Sdim		if (*pos == '\n' || *pos == '\r') {
103218822Sdim			*pos = '\0';
104218822Sdim			break;
105218822Sdim		}
106104834Sobrien		pos++;
107104834Sobrien	}
108104834Sobrien
109104834Sobrien	wpa_printf(MSG_DEBUG, "CryptoAPI: %s: %d: (%s)", msg, (int) err, s);
110104834Sobrien	LocalFree(s);
111104834Sobrien}
112218822Sdim
113218822Sdim
114218822Sdimint cryptoapi_hash_vector(ALG_ID alg, size_t hash_len, size_t num_elem,
115218822Sdim			  const u8 *addr[], const size_t *len, u8 *mac)
116218822Sdim{
117218822Sdim	HCRYPTPROV prov;
118104834Sobrien	HCRYPTHASH hash;
119130561Sobrien	size_t i;
120218822Sdim	DWORD hlen;
121218822Sdim	int ret = 0;
122218822Sdim
123218822Sdim	if (!CryptAcquireContext(&prov, NULL, NULL, PROV_RSA_FULL, 0)) {
124218822Sdim		cryptoapi_report_error("CryptAcquireContext");
125218822Sdim		return -1;
126130561Sobrien	}
127218822Sdim
128130561Sobrien	if (!CryptCreateHash(prov, alg, 0, 0, &hash)) {
129218822Sdim		cryptoapi_report_error("CryptCreateHash");
130218822Sdim		CryptReleaseContext(prov, 0);
131218822Sdim		return -1;
132218822Sdim	}
133218822Sdim
134130561Sobrien	for (i = 0; i < num_elem; i++) {
135130561Sobrien		if (!CryptHashData(hash, (BYTE *) addr[i], len[i], 0)) {
136218822Sdim			cryptoapi_report_error("CryptHashData");
137218822Sdim			CryptDestroyHash(hash);
138218822Sdim			CryptReleaseContext(prov, 0);
139218822Sdim		}
140218822Sdim	}
141218822Sdim
142218822Sdim	hlen = hash_len;
143218822Sdim	if (!CryptGetHashParam(hash, HP_HASHVAL, mac, &hlen, 0)) {
144218822Sdim		cryptoapi_report_error("CryptGetHashParam");
145218822Sdim		ret = -1;
146218822Sdim	}
147218822Sdim
148218822Sdim	CryptDestroyHash(hash);
149218822Sdim	CryptReleaseContext(prov, 0);
150218822Sdim
15138889Sjdp	return ret;
152218822Sdim}
153218822Sdim
154218822Sdim
155218822Sdimvoid md4_vector(size_t num_elem, const u8 *addr[], const size_t *len, u8 *mac)
156218822Sdim{
15738889Sjdp	cryptoapi_hash_vector(CALG_MD4, 16, num_elem, addr, len, mac);
158218822Sdim}
159218822Sdim
160218822Sdim
161218822Sdimvoid des_encrypt(const u8 *clear, const u8 *key, u8 *cypher)
162218822Sdim{
163218822Sdim	u8 next, tmp;
164218822Sdim	int i;
165218822Sdim	HCRYPTPROV prov;
166218822Sdim	HCRYPTKEY ckey;
167218822Sdim	DWORD dlen;
168218822Sdim	struct {
169218822Sdim		BLOBHEADER hdr;
170218822Sdim		DWORD len;
171218822Sdim		BYTE key[8];
172218822Sdim	} key_blob;
173218822Sdim	DWORD mode = CRYPT_MODE_ECB;
174218822Sdim
175218822Sdim	key_blob.hdr.bType = PLAINTEXTKEYBLOB;
176218822Sdim	key_blob.hdr.bVersion = CUR_BLOB_VERSION;
177218822Sdim	key_blob.hdr.reserved = 0;
17838889Sjdp	key_blob.hdr.aiKeyAlg = CALG_DES;
179218822Sdim	key_blob.len = 8;
180218822Sdim
181218822Sdim	/* Add parity bits to the key */
182218822Sdim	next = 0;
183218822Sdim	for (i = 0; i < 7; i++) {
184218822Sdim		tmp = key[i];
185218822Sdim		key_blob.key[i] = (tmp >> i) | next | 1;
186218822Sdim		next = tmp << (7 - i);
187218822Sdim	}
188218822Sdim	key_blob.key[i] = next | 1;
189218822Sdim
190218822Sdim	if (!CryptAcquireContext(&prov, NULL, MS_ENHANCED_PROV, PROV_RSA_FULL,
191218822Sdim				 CRYPT_VERIFYCONTEXT)) {
192218822Sdim 		wpa_printf(MSG_DEBUG, "CryptoAPI: CryptAcquireContext failed: "
193218822Sdim			   "%d", (int) GetLastError());
194218822Sdim		return;
195218822Sdim	}
196218822Sdim
197218822Sdim	if (!CryptImportKey(prov, (BYTE *) &key_blob, sizeof(key_blob), 0, 0,
198218822Sdim			    &ckey)) {
199218822Sdim 		wpa_printf(MSG_DEBUG, "CryptoAPI: CryptImportKey failed: %d",
200218822Sdim			   (int) GetLastError());
201218822Sdim		CryptReleaseContext(prov, 0);
202218822Sdim		return;
203218822Sdim	}
204218822Sdim
205218822Sdim	if (!CryptSetKeyParam(ckey, KP_MODE, (BYTE *) &mode, 0)) {
206218822Sdim 		wpa_printf(MSG_DEBUG, "CryptoAPI: CryptSetKeyParam(KP_MODE) "
207218822Sdim			   "failed: %d", (int) GetLastError());
208218822Sdim		CryptDestroyKey(ckey);
209218822Sdim		CryptReleaseContext(prov, 0);
210218822Sdim		return;
211218822Sdim	}
212218822Sdim
213218822Sdim	os_memcpy(cypher, clear, 8);
214218822Sdim	dlen = 8;
215218822Sdim	if (!CryptEncrypt(ckey, 0, FALSE, 0, cypher, &dlen, 8)) {
216218822Sdim		wpa_printf(MSG_DEBUG, "CryptoAPI: CryptEncrypt failed: %d",
217218822Sdim			   (int) GetLastError());
218218822Sdim		os_memset(cypher, 0, 8);
219218822Sdim	}
220218822Sdim
221218822Sdim	CryptDestroyKey(ckey);
222218822Sdim	CryptReleaseContext(prov, 0);
223218822Sdim}
224218822Sdim
225218822Sdim
226218822Sdim#ifdef EAP_TLS_FUNCS
227218822Sdimvoid md5_vector(size_t num_elem, const u8 *addr[], const size_t *len, u8 *mac)
228218822Sdim{
229218822Sdim	cryptoapi_hash_vector(CALG_MD5, 16, num_elem, addr, len, mac);
230218822Sdim}
231218822Sdim
232218822Sdim
233218822Sdimvoid sha1_vector(size_t num_elem, const u8 *addr[], const size_t *len, u8 *mac)
234218822Sdim{
235218822Sdim	cryptoapi_hash_vector(CALG_SHA, 20, num_elem, addr, len, mac);
236218822Sdim}
237218822Sdim
238218822Sdim
239218822Sdimstruct aes_context {
240218822Sdim	HCRYPTPROV prov;
241218822Sdim	HCRYPTKEY ckey;
242218822Sdim};
243218822Sdim
244218822Sdim
245218822Sdimvoid * aes_encrypt_init(const u8 *key, size_t len)
246218822Sdim{
247218822Sdim	struct aes_context *akey;
248218822Sdim	struct {
249218822Sdim		BLOBHEADER hdr;
250218822Sdim		DWORD len;
251218822Sdim		BYTE key[16];
252218822Sdim	} key_blob;
253218822Sdim	DWORD mode = CRYPT_MODE_ECB;
254218822Sdim
255218822Sdim	if (len != 16)
256218822Sdim		return NULL;
257218822Sdim
258218822Sdim	key_blob.hdr.bType = PLAINTEXTKEYBLOB;
259218822Sdim	key_blob.hdr.bVersion = CUR_BLOB_VERSION;
260218822Sdim	key_blob.hdr.reserved = 0;
261218822Sdim	key_blob.hdr.aiKeyAlg = CALG_AES_128;
262218822Sdim	key_blob.len = len;
263218822Sdim	os_memcpy(key_blob.key, key, len);
264218822Sdim
265218822Sdim	akey = os_zalloc(sizeof(*akey));
266218822Sdim	if (akey == NULL)
267218822Sdim		return NULL;
268218822Sdim
269218822Sdim	if (!CryptAcquireContext(&akey->prov, NULL,
270218822Sdim				 MS_ENH_RSA_AES_PROV, PROV_RSA_AES,
271218822Sdim				 CRYPT_VERIFYCONTEXT)) {
272218822Sdim 		wpa_printf(MSG_DEBUG, "CryptoAPI: CryptAcquireContext failed: "
273218822Sdim			   "%d", (int) GetLastError());
274218822Sdim		os_free(akey);
275218822Sdim		return NULL;
276218822Sdim	}
277218822Sdim
278218822Sdim	if (!CryptImportKey(akey->prov, (BYTE *) &key_blob, sizeof(key_blob),
279218822Sdim			    0, 0, &akey->ckey)) {
280218822Sdim 		wpa_printf(MSG_DEBUG, "CryptoAPI: CryptImportKey failed: %d",
281218822Sdim			   (int) GetLastError());
282218822Sdim		CryptReleaseContext(akey->prov, 0);
283218822Sdim		os_free(akey);
284218822Sdim		return NULL;
285218822Sdim	}
286218822Sdim
287218822Sdim	if (!CryptSetKeyParam(akey->ckey, KP_MODE, (BYTE *) &mode, 0)) {
288218822Sdim 		wpa_printf(MSG_DEBUG, "CryptoAPI: CryptSetKeyParam(KP_MODE) "
289218822Sdim			   "failed: %d", (int) GetLastError());
290218822Sdim		CryptDestroyKey(akey->ckey);
291218822Sdim		CryptReleaseContext(akey->prov, 0);
292218822Sdim		os_free(akey);
293218822Sdim		return NULL;
294218822Sdim	}
295218822Sdim
296218822Sdim	return akey;
297218822Sdim}
298218822Sdim
299218822Sdim
300218822Sdimvoid aes_encrypt(void *ctx, const u8 *plain, u8 *crypt)
301218822Sdim{
302218822Sdim	struct aes_context *akey = ctx;
303218822Sdim	DWORD dlen;
304218822Sdim
305218822Sdim	os_memcpy(crypt, plain, 16);
306218822Sdim	dlen = 16;
307218822Sdim	if (!CryptEncrypt(akey->ckey, 0, FALSE, 0, crypt, &dlen, 16)) {
308218822Sdim		wpa_printf(MSG_DEBUG, "CryptoAPI: CryptEncrypt failed: %d",
309218822Sdim			   (int) GetLastError());
310218822Sdim		os_memset(crypt, 0, 16);
311218822Sdim	}
312218822Sdim}
313218822Sdim
314218822Sdim
315218822Sdimvoid aes_encrypt_deinit(void *ctx)
316218822Sdim{
317218822Sdim	struct aes_context *akey = ctx;
318218822Sdim	if (akey) {
319218822Sdim		CryptDestroyKey(akey->ckey);
320218822Sdim		CryptReleaseContext(akey->prov, 0);
321218822Sdim		os_free(akey);
322218822Sdim	}
323218822Sdim}
324218822Sdim
325218822Sdim
326218822Sdimvoid * aes_decrypt_init(const u8 *key, size_t len)
327218822Sdim{
328218822Sdim	return aes_encrypt_init(key, len);
329218822Sdim}
330218822Sdim
331218822Sdim
332218822Sdimvoid aes_decrypt(void *ctx, const u8 *crypt, u8 *plain)
333218822Sdim{
334218822Sdim	struct aes_context *akey = ctx;
335218822Sdim	DWORD dlen;
336218822Sdim
337218822Sdim	os_memcpy(plain, crypt, 16);
338218822Sdim	dlen = 16;
339218822Sdim
340218822Sdim	if (!CryptDecrypt(akey->ckey, 0, FALSE, 0, plain, &dlen)) {
341218822Sdim		wpa_printf(MSG_DEBUG, "CryptoAPI: CryptDecrypt failed: %d",
342218822Sdim			   (int) GetLastError());
343218822Sdim	}
344218822Sdim}
345218822Sdim
346218822Sdim
347218822Sdimvoid aes_decrypt_deinit(void *ctx)
348218822Sdim{
349218822Sdim	aes_encrypt_deinit(ctx);
350218822Sdim}
351218822Sdim
352218822Sdim#ifdef CONFIG_TLS_INTERNAL
353218822Sdim
354218822Sdimstruct crypto_hash {
355218822Sdim	enum crypto_hash_alg alg;
356218822Sdim	int error;
357218822Sdim	HCRYPTPROV prov;
358218822Sdim	HCRYPTHASH hash;
359218822Sdim	HCRYPTKEY key;
360218822Sdim};
361218822Sdim
362218822Sdimstruct crypto_hash * crypto_hash_init(enum crypto_hash_alg alg, const u8 *key,
363218822Sdim				      size_t key_len)
364218822Sdim{
365218822Sdim	struct crypto_hash *ctx;
366218822Sdim	ALG_ID calg;
367218822Sdim	struct {
368218822Sdim		BLOBHEADER hdr;
369218822Sdim		DWORD len;
370218822Sdim		BYTE key[32];
371218822Sdim	} key_blob;
372218822Sdim
373218822Sdim	os_memset(&key_blob, 0, sizeof(key_blob));
374218822Sdim	switch (alg) {
375218822Sdim	case CRYPTO_HASH_ALG_MD5:
376218822Sdim		calg = CALG_MD5;
377218822Sdim		break;
378218822Sdim	case CRYPTO_HASH_ALG_SHA1:
379218822Sdim		calg = CALG_SHA;
38094536Sobrien		break;
381218822Sdim	case CRYPTO_HASH_ALG_HMAC_MD5:
382218822Sdim	case CRYPTO_HASH_ALG_HMAC_SHA1:
383218822Sdim		calg = CALG_HMAC;
384218822Sdim		key_blob.hdr.bType = PLAINTEXTKEYBLOB;
385218822Sdim		key_blob.hdr.bVersion = CUR_BLOB_VERSION;
386218822Sdim		key_blob.hdr.reserved = 0;
387218822Sdim		/*
388218822Sdim		 * Note: RC2 is not really used, but that can be used to
389218822Sdim		 * import HMAC keys of up to 16 byte long.
39038889Sjdp		 * CRYPT_IPSEC_HMAC_KEY flag for CryptImportKey() is needed to
39138889Sjdp		 * be able to import longer keys (HMAC-SHA1 uses 20-byte key).
39238889Sjdp		 */
393218822Sdim		key_blob.hdr.aiKeyAlg = CALG_RC2;
394218822Sdim		key_blob.len = key_len;
395218822Sdim		if (key_len > sizeof(key_blob.key))
396218822Sdim			return NULL;
397218822Sdim		os_memcpy(key_blob.key, key, key_len);
398218822Sdim		break;
399218822Sdim	default:
400218822Sdim		return NULL;
401218822Sdim	}
402130561Sobrien
403218822Sdim	ctx = os_zalloc(sizeof(*ctx));
404218822Sdim	if (ctx == NULL)
405218822Sdim		return NULL;
406218822Sdim
407218822Sdim	ctx->alg = alg;
408218822Sdim
409218822Sdim	if (!CryptAcquireContext(&ctx->prov, NULL, NULL, PROV_RSA_FULL, 0)) {
410218822Sdim		cryptoapi_report_error("CryptAcquireContext");
411218822Sdim		os_free(ctx);
412130561Sobrien		return NULL;
413218822Sdim	}
414218822Sdim
415218822Sdim	if (calg == CALG_HMAC) {
416130561Sobrien#ifndef CRYPT_IPSEC_HMAC_KEY
417218822Sdim#define CRYPT_IPSEC_HMAC_KEY 0x00000100
418218822Sdim#endif
419218822Sdim		if (!CryptImportKey(ctx->prov, (BYTE *) &key_blob,
420218822Sdim				    sizeof(key_blob), 0, CRYPT_IPSEC_HMAC_KEY,
421218822Sdim				    &ctx->key)) {
422218822Sdim			cryptoapi_report_error("CryptImportKey");
423218822Sdim			CryptReleaseContext(ctx->prov, 0);
424218822Sdim			os_free(ctx);
425218822Sdim			return NULL;
426218822Sdim		}
427218822Sdim	}
428218822Sdim
429218822Sdim	if (!CryptCreateHash(ctx->prov, calg, ctx->key, 0, &ctx->hash)) {
430218822Sdim		cryptoapi_report_error("CryptCreateHash");
431218822Sdim		CryptReleaseContext(ctx->prov, 0);
432218822Sdim		os_free(ctx);
433218822Sdim		return NULL;
434218822Sdim	}
435218822Sdim
436218822Sdim	if (calg == CALG_HMAC) {
437218822Sdim		HMAC_INFO info;
438218822Sdim		os_memset(&info, 0, sizeof(info));
439218822Sdim		switch (alg) {
440218822Sdim		case CRYPTO_HASH_ALG_HMAC_MD5:
441218822Sdim			info.HashAlgid = CALG_MD5;
442218822Sdim			break;
443218822Sdim		case CRYPTO_HASH_ALG_HMAC_SHA1:
444218822Sdim			info.HashAlgid = CALG_SHA;
445218822Sdim			break;
446218822Sdim		default:
447130561Sobrien			/* unreachable */
448130561Sobrien			break;
449218822Sdim		}
450218822Sdim
451218822Sdim		if (!CryptSetHashParam(ctx->hash, HP_HMAC_INFO, (BYTE *) &info,
452130561Sobrien				       0)) {
453218822Sdim			cryptoapi_report_error("CryptSetHashParam");
454218822Sdim			CryptDestroyHash(ctx->hash);
455218822Sdim			CryptReleaseContext(ctx->prov, 0);
456218822Sdim			os_free(ctx);
457218822Sdim			return NULL;
458218822Sdim		}
459218822Sdim	}
460218822Sdim
461218822Sdim	return ctx;
462218822Sdim}
463218822Sdim
464218822Sdim
465218822Sdimvoid crypto_hash_update(struct crypto_hash *ctx, const u8 *data, size_t len)
466218822Sdim{
467218822Sdim	if (ctx == NULL || ctx->error)
468218822Sdim		return;
469218822Sdim
47038889Sjdp	if (!CryptHashData(ctx->hash, (BYTE *) data, len, 0)) {
471218822Sdim		cryptoapi_report_error("CryptHashData");
472218822Sdim		ctx->error = 1;
473218822Sdim	}
474218822Sdim}
475218822Sdim
476218822Sdim
477218822Sdimint crypto_hash_finish(struct crypto_hash *ctx, u8 *mac, size_t *len)
478218822Sdim{
479218822Sdim	int ret = 0;
480218822Sdim	DWORD hlen;
481218822Sdim
482218822Sdim	if (ctx == NULL)
483218822Sdim		return -2;
484218822Sdim
485218822Sdim	if (mac == NULL || len == NULL)
486218822Sdim		goto done;
487218822Sdim
48838889Sjdp	if (ctx->error) {
489218822Sdim		ret = -2;
490218822Sdim		goto done;
491218822Sdim	}
49238889Sjdp
493218822Sdim	hlen = *len;
494218822Sdim	if (!CryptGetHashParam(ctx->hash, HP_HASHVAL, mac, &hlen, 0)) {
495218822Sdim		cryptoapi_report_error("CryptGetHashParam");
496218822Sdim		ret = -2;
497218822Sdim	}
498218822Sdim	*len = hlen;
499218822Sdim
500218822Sdimdone:
501218822Sdim	if (ctx->alg == CRYPTO_HASH_ALG_HMAC_SHA1 ||
502218822Sdim	    ctx->alg == CRYPTO_HASH_ALG_HMAC_MD5)
503218822Sdim		CryptDestroyKey(ctx->key);
504218822Sdim
505218822Sdim	os_free(ctx);
506218822Sdim
507218822Sdim	return ret;
508218822Sdim}
509218822Sdim
510218822Sdim
511218822Sdimstruct crypto_cipher {
512218822Sdim	HCRYPTPROV prov;
513218822Sdim	HCRYPTKEY key;
514218822Sdim};
515218822Sdim
516218822Sdim
517218822Sdimstruct crypto_cipher * crypto_cipher_init(enum crypto_cipher_alg alg,
518218822Sdim					  const u8 *iv, const u8 *key,
519218822Sdim					  size_t key_len)
520218822Sdim{
521218822Sdim	struct crypto_cipher *ctx;
522218822Sdim	struct {
523218822Sdim		BLOBHEADER hdr;
524218822Sdim		DWORD len;
525218822Sdim		BYTE key[32];
526218822Sdim	} key_blob;
527218822Sdim	DWORD mode = CRYPT_MODE_CBC;
528218822Sdim
529218822Sdim	key_blob.hdr.bType = PLAINTEXTKEYBLOB;
530218822Sdim	key_blob.hdr.bVersion = CUR_BLOB_VERSION;
531218822Sdim	key_blob.hdr.reserved = 0;
532218822Sdim	key_blob.len = key_len;
533218822Sdim	if (key_len > sizeof(key_blob.key))
534218822Sdim		return NULL;
535218822Sdim	os_memcpy(key_blob.key, key, key_len);
536218822Sdim
537218822Sdim	switch (alg) {
538218822Sdim	case CRYPTO_CIPHER_ALG_AES:
539218822Sdim		if (key_len == 32)
540218822Sdim			key_blob.hdr.aiKeyAlg = CALG_AES_256;
541218822Sdim		else if (key_len == 24)
542218822Sdim			key_blob.hdr.aiKeyAlg = CALG_AES_192;
543218822Sdim		else
544218822Sdim			key_blob.hdr.aiKeyAlg = CALG_AES_128;
545218822Sdim		break;
546218822Sdim	case CRYPTO_CIPHER_ALG_3DES:
547218822Sdim		key_blob.hdr.aiKeyAlg = CALG_3DES;
548218822Sdim		break;
549218822Sdim	case CRYPTO_CIPHER_ALG_DES:
550218822Sdim		key_blob.hdr.aiKeyAlg = CALG_DES;
551218822Sdim		break;
552218822Sdim	case CRYPTO_CIPHER_ALG_RC2:
553218822Sdim		key_blob.hdr.aiKeyAlg = CALG_RC2;
554218822Sdim		break;
555218822Sdim	case CRYPTO_CIPHER_ALG_RC4:
556218822Sdim		key_blob.hdr.aiKeyAlg = CALG_RC4;
557218822Sdim		break;
558218822Sdim	default:
559218822Sdim		return NULL;
560218822Sdim	}
561218822Sdim
562218822Sdim	ctx = os_zalloc(sizeof(*ctx));
563218822Sdim	if (ctx == NULL)
564218822Sdim		return NULL;
565218822Sdim
566218822Sdim	if (!CryptAcquireContext(&ctx->prov, NULL, MS_ENH_RSA_AES_PROV,
567218822Sdim				 PROV_RSA_AES, CRYPT_VERIFYCONTEXT)) {
568218822Sdim		cryptoapi_report_error("CryptAcquireContext");
569218822Sdim		goto fail1;
570218822Sdim	}
571218822Sdim
572218822Sdim	if (!CryptImportKey(ctx->prov, (BYTE *) &key_blob,
573218822Sdim			    sizeof(key_blob), 0, 0, &ctx->key)) {
574218822Sdim 		cryptoapi_report_error("CryptImportKey");
575218822Sdim		goto fail2;
576218822Sdim	}
577218822Sdim
578218822Sdim	if (!CryptSetKeyParam(ctx->key, KP_MODE, (BYTE *) &mode, 0)) {
579218822Sdim 		cryptoapi_report_error("CryptSetKeyParam(KP_MODE)");
580218822Sdim		goto fail3;
581218822Sdim	}
582218822Sdim
583218822Sdim	if (iv && !CryptSetKeyParam(ctx->key, KP_IV, (BYTE *) iv, 0)) {
584218822Sdim 		cryptoapi_report_error("CryptSetKeyParam(KP_IV)");
585218822Sdim		goto fail3;
586218822Sdim	}
587218822Sdim
588218822Sdim	return ctx;
589218822Sdim
590218822Sdimfail3:
591218822Sdim	CryptDestroyKey(ctx->key);
592218822Sdimfail2:
593218822Sdim	CryptReleaseContext(ctx->prov, 0);
594218822Sdimfail1:
595218822Sdim	os_free(ctx);
596218822Sdim	return NULL;
597218822Sdim}
598218822Sdim
599218822Sdim
600218822Sdimint crypto_cipher_encrypt(struct crypto_cipher *ctx, const u8 *plain,
601218822Sdim			  u8 *crypt, size_t len)
602218822Sdim{
603218822Sdim	DWORD dlen;
604218822Sdim
605218822Sdim	os_memcpy(crypt, plain, len);
606218822Sdim	dlen = len;
607218822Sdim	if (!CryptEncrypt(ctx->key, 0, FALSE, 0, crypt, &dlen, len)) {
608218822Sdim 		cryptoapi_report_error("CryptEncrypt");
609218822Sdim		os_memset(crypt, 0, len);
610218822Sdim		return -1;
611218822Sdim	}
612218822Sdim
613218822Sdim	return 0;
614218822Sdim}
615218822Sdim
616218822Sdim
617218822Sdimint crypto_cipher_decrypt(struct crypto_cipher *ctx, const u8 *crypt,
618218822Sdim			  u8 *plain, size_t len)
619218822Sdim{
620218822Sdim	DWORD dlen;
621218822Sdim
622218822Sdim	os_memcpy(plain, crypt, len);
623218822Sdim	dlen = len;
624218822Sdim	if (!CryptDecrypt(ctx->key, 0, FALSE, 0, plain, &dlen)) {
625218822Sdim 		cryptoapi_report_error("CryptDecrypt");
626218822Sdim		return -1;
627218822Sdim	}
628218822Sdim
629218822Sdim	return 0;
630218822Sdim}
631218822Sdim
632218822Sdim
633218822Sdimvoid crypto_cipher_deinit(struct crypto_cipher *ctx)
634218822Sdim{
635218822Sdim	CryptDestroyKey(ctx->key);
636218822Sdim	CryptReleaseContext(ctx->prov, 0);
637218822Sdim	os_free(ctx);
638218822Sdim}
639218822Sdim
640218822Sdim
641218822Sdimstruct crypto_public_key {
642218822Sdim	HCRYPTPROV prov;
643218822Sdim	HCRYPTKEY rsa;
644218822Sdim};
645218822Sdim
646218822Sdimstruct crypto_private_key {
647218822Sdim	HCRYPTPROV prov;
648218822Sdim	HCRYPTKEY rsa;
649218822Sdim};
650218822Sdim
651218822Sdim
652218822Sdimstruct crypto_public_key * crypto_public_key_import(const u8 *key, size_t len)
653218822Sdim{
654218822Sdim	/* Use crypto_public_key_from_cert() instead. */
655218822Sdim	return NULL;
656218822Sdim}
657218822Sdim
658218822Sdim
659218822Sdimstruct crypto_private_key * crypto_private_key_import(const u8 *key,
660218822Sdim						      size_t len)
661218822Sdim{
662218822Sdim	/* TODO */
663218822Sdim	return NULL;
664218822Sdim}
665218822Sdim
666218822Sdim
667218822Sdimstruct crypto_public_key * crypto_public_key_from_cert(const u8 *buf,
668218822Sdim						       size_t len)
669218822Sdim{
670218822Sdim	struct crypto_public_key *pk;
671218822Sdim	PCCERT_CONTEXT cc;
672218822Sdim
673218822Sdim	pk = os_zalloc(sizeof(*pk));
674218822Sdim	if (pk == NULL)
675218822Sdim		return NULL;
676218822Sdim
677218822Sdim	cc = CertCreateCertificateContext(X509_ASN_ENCODING |
678218822Sdim					  PKCS_7_ASN_ENCODING, buf, len);
679218822Sdim	if (!cc) {
680218822Sdim 		cryptoapi_report_error("CryptCreateCertificateContext");
681218822Sdim		os_free(pk);
682218822Sdim		return NULL;
683218822Sdim	}
684218822Sdim
685218822Sdim	if (!CryptAcquireContext(&pk->prov, NULL, MS_DEF_PROV, PROV_RSA_FULL,
686218822Sdim				 0)) {
687218822Sdim 		cryptoapi_report_error("CryptAcquireContext");
688218822Sdim		os_free(pk);
689218822Sdim		CertFreeCertificateContext(cc);
690218822Sdim		return NULL;
691218822Sdim	}
692218822Sdim
693218822Sdim	if (!CryptImportPublicKeyInfo(pk->prov, X509_ASN_ENCODING |
694218822Sdim				      PKCS_7_ASN_ENCODING,
695218822Sdim				      &cc->pCertInfo->SubjectPublicKeyInfo,
696218822Sdim				      &pk->rsa)) {
697218822Sdim 		cryptoapi_report_error("CryptImportPublicKeyInfo");
698218822Sdim		CryptReleaseContext(pk->prov, 0);
699218822Sdim		os_free(pk);
700218822Sdim		CertFreeCertificateContext(cc);
701218822Sdim		return NULL;
702218822Sdim	}
703218822Sdim
704218822Sdim	CertFreeCertificateContext(cc);
705218822Sdim
706218822Sdim	return pk;
707218822Sdim}
70894536Sobrien
70938889Sjdp
71038889Sjdpint crypto_public_key_encrypt_pkcs1_v15(struct crypto_public_key *key,
71138889Sjdp					const u8 *in, size_t inlen,
712218822Sdim					u8 *out, size_t *outlen)
71338889Sjdp{
71438889Sjdp	DWORD clen;
71538889Sjdp	u8 *tmp;
71638889Sjdp	size_t i;
71738889Sjdp
71838889Sjdp	if (*outlen < inlen)
719218822Sdim		return -1;
720218822Sdim	tmp = malloc(*outlen);
72138889Sjdp	if (tmp == NULL)
722218822Sdim		return -1;
72338889Sjdp
724218822Sdim	os_memcpy(tmp, in, inlen);
725218822Sdim	clen = inlen;
726218822Sdim	if (!CryptEncrypt(key->rsa, 0, TRUE, 0, tmp, &clen, *outlen)) {
72738889Sjdp		wpa_printf(MSG_DEBUG, "CryptoAPI: Failed to encrypt using "
72838889Sjdp			   "public key: %d", (int) GetLastError());
72938889Sjdp		os_free(tmp);
73038889Sjdp		return -1;
73138889Sjdp	}
73238889Sjdp
73338889Sjdp	*outlen = clen;
73438889Sjdp
73538889Sjdp	/* Reverse the output */
736218822Sdim	for (i = 0; i < *outlen; i++)
73738889Sjdp		out[i] = tmp[*outlen - 1 - i];
73838889Sjdp
73938889Sjdp	os_free(tmp);
74038889Sjdp
74138889Sjdp	return 0;
74238889Sjdp}
74338889Sjdp
74438889Sjdp
74538889Sjdpint crypto_private_key_sign_pkcs1(struct crypto_private_key *key,
74638889Sjdp				  const u8 *in, size_t inlen,
747218822Sdim				  u8 *out, size_t *outlen)
748218822Sdim{
749218822Sdim	/* TODO */
750218822Sdim	return -1;
751218822Sdim}
752218822Sdim
753218822Sdim
754218822Sdimvoid crypto_public_key_free(struct crypto_public_key *key)
755218822Sdim{
756218822Sdim	if (key) {
757218822Sdim		CryptDestroyKey(key->rsa);
758218822Sdim		CryptReleaseContext(key->prov, 0);
759218822Sdim		os_free(key);
760218822Sdim	}
761218822Sdim}
762218822Sdim
763218822Sdim
764218822Sdimvoid crypto_private_key_free(struct crypto_private_key *key)
765218822Sdim{
766218822Sdim	if (key) {
767218822Sdim		CryptDestroyKey(key->rsa);
768218822Sdim		CryptReleaseContext(key->prov, 0);
769218822Sdim		os_free(key);
770218822Sdim	}
77138889Sjdp}
772218822Sdim
773218822Sdim
77438889Sjdpint crypto_global_init(void)
775218822Sdim{
77638889Sjdp	return mingw_load_crypto_func();
777218822Sdim}
778218822Sdim
779218822Sdim
780218822Sdimvoid crypto_global_deinit(void)
781218822Sdim{
782218822Sdim}
783218822Sdim
784218822Sdim#endif /* CONFIG_TLS_INTERNAL */
785218822Sdim
786218822Sdim#endif /* EAP_TLS_FUNCS */
787218822Sdim