1/* 2 * Crypto wrapper for Microsoft CryptoAPI 3 * Copyright (c) 2005-2009, Jouni Malinen <j@w1.fi> 4 * 5 * This program is free software; you can redistribute it and/or modify 6 * it under the terms of the GNU General Public License version 2 as 7 * published by the Free Software Foundation. 8 * 9 * Alternatively, this software may be distributed under the terms of BSD 10 * license. 11 * 12 * See README and COPYING for more details. 13 */ 14 15#include "includes.h" 16#include <windows.h> 17#include <wincrypt.h> 18 19#include "common.h" 20#include "crypto.h" 21 22#ifndef MS_ENH_RSA_AES_PROV 23#ifdef UNICODE 24#define MS_ENH_RSA_AES_PROV \ 25L"Microsoft Enhanced RSA and AES Cryptographic Provider (Prototype)" 26#else 27#define MS_ENH_RSA_AES_PROV \ 28"Microsoft Enhanced RSA and AES Cryptographic Provider (Prototype)" 29#endif 30#endif /* MS_ENH_RSA_AES_PROV */ 31 32#ifndef CALG_HMAC 33#define CALG_HMAC (ALG_CLASS_HASH | ALG_TYPE_ANY | ALG_SID_HMAC) 34#endif 35 36#ifdef CONFIG_TLS_INTERNAL 37#ifdef __MINGW32_VERSION 38/* 39 * MinGW does not yet include all the needed definitions for CryptoAPI, so 40 * define here whatever extra is needed. 41 */ 42 43static BOOL WINAPI 44(*CryptImportPublicKeyInfo)(HCRYPTPROV hCryptProv, DWORD dwCertEncodingType, 45 PCERT_PUBLIC_KEY_INFO pInfo, HCRYPTKEY *phKey) 46= NULL; /* to be loaded from crypt32.dll */ 47 48 49static int mingw_load_crypto_func(void) 50{ 51 HINSTANCE dll; 52 53 /* MinGW does not yet have full CryptoAPI support, so load the needed 54 * function here. */ 55 56 if (CryptImportPublicKeyInfo) 57 return 0; 58 59 dll = LoadLibrary("crypt32"); 60 if (dll == NULL) { 61 wpa_printf(MSG_DEBUG, "CryptoAPI: Could not load crypt32 " 62 "library"); 63 return -1; 64 } 65 66 CryptImportPublicKeyInfo = GetProcAddress( 67 dll, "CryptImportPublicKeyInfo"); 68 if (CryptImportPublicKeyInfo == NULL) { 69 wpa_printf(MSG_DEBUG, "CryptoAPI: Could not get " 70 "CryptImportPublicKeyInfo() address from " 71 "crypt32 library"); 72 return -1; 73 } 74 75 return 0; 76} 77 78#else /* __MINGW32_VERSION */ 79 80static int mingw_load_crypto_func(void) 81{ 82 return 0; 83} 84 85#endif /* __MINGW32_VERSION */ 86#endif /* CONFIG_TLS_INTERNAL */ 87 88 89static void cryptoapi_report_error(const char *msg) 90{ 91 char *s, *pos; 92 DWORD err = GetLastError(); 93 94 if (FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | 95 FORMAT_MESSAGE_FROM_SYSTEM, 96 NULL, err, 0, (LPTSTR) &s, 0, NULL) == 0) { 97 wpa_printf(MSG_DEBUG, "CryptoAPI: %s: %d", msg, (int) err); 98 } 99 100 pos = s; 101 while (*pos) { 102 if (*pos == '\n' || *pos == '\r') { 103 *pos = '\0'; 104 break; 105 } 106 pos++; 107 } 108 109 wpa_printf(MSG_DEBUG, "CryptoAPI: %s: %d: (%s)", msg, (int) err, s); 110 LocalFree(s); 111} 112 113 114int cryptoapi_hash_vector(ALG_ID alg, size_t hash_len, size_t num_elem, 115 const u8 *addr[], const size_t *len, u8 *mac) 116{ 117 HCRYPTPROV prov; 118 HCRYPTHASH hash; 119 size_t i; 120 DWORD hlen; 121 int ret = 0; 122 123 if (!CryptAcquireContext(&prov, NULL, NULL, PROV_RSA_FULL, 0)) { 124 cryptoapi_report_error("CryptAcquireContext"); 125 return -1; 126 } 127 128 if (!CryptCreateHash(prov, alg, 0, 0, &hash)) { 129 cryptoapi_report_error("CryptCreateHash"); 130 CryptReleaseContext(prov, 0); 131 return -1; 132 } 133 134 for (i = 0; i < num_elem; i++) { 135 if (!CryptHashData(hash, (BYTE *) addr[i], len[i], 0)) { 136 cryptoapi_report_error("CryptHashData"); 137 CryptDestroyHash(hash); 138 CryptReleaseContext(prov, 0); 139 } 140 } 141 142 hlen = hash_len; 143 if (!CryptGetHashParam(hash, HP_HASHVAL, mac, &hlen, 0)) { 144 cryptoapi_report_error("CryptGetHashParam"); 145 ret = -1; 146 } 147 148 CryptDestroyHash(hash); 149 CryptReleaseContext(prov, 0); 150 151 return ret; 152} 153 154 155void md4_vector(size_t num_elem, const u8 *addr[], const size_t *len, u8 *mac) 156{ 157 cryptoapi_hash_vector(CALG_MD4, 16, num_elem, addr, len, mac); 158} 159 160 161void des_encrypt(const u8 *clear, const u8 *key, u8 *cypher) 162{ 163 u8 next, tmp; 164 int i; 165 HCRYPTPROV prov; 166 HCRYPTKEY ckey; 167 DWORD dlen; 168 struct { 169 BLOBHEADER hdr; 170 DWORD len; 171 BYTE key[8]; 172 } key_blob; 173 DWORD mode = CRYPT_MODE_ECB; 174 175 key_blob.hdr.bType = PLAINTEXTKEYBLOB; 176 key_blob.hdr.bVersion = CUR_BLOB_VERSION; 177 key_blob.hdr.reserved = 0; 178 key_blob.hdr.aiKeyAlg = CALG_DES; 179 key_blob.len = 8; 180 181 /* Add parity bits to the key */ 182 next = 0; 183 for (i = 0; i < 7; i++) { 184 tmp = key[i]; 185 key_blob.key[i] = (tmp >> i) | next | 1; 186 next = tmp << (7 - i); 187 } 188 key_blob.key[i] = next | 1; 189 190 if (!CryptAcquireContext(&prov, NULL, MS_ENHANCED_PROV, PROV_RSA_FULL, 191 CRYPT_VERIFYCONTEXT)) { 192 wpa_printf(MSG_DEBUG, "CryptoAPI: CryptAcquireContext failed: " 193 "%d", (int) GetLastError()); 194 return; 195 } 196 197 if (!CryptImportKey(prov, (BYTE *) &key_blob, sizeof(key_blob), 0, 0, 198 &ckey)) { 199 wpa_printf(MSG_DEBUG, "CryptoAPI: CryptImportKey failed: %d", 200 (int) GetLastError()); 201 CryptReleaseContext(prov, 0); 202 return; 203 } 204 205 if (!CryptSetKeyParam(ckey, KP_MODE, (BYTE *) &mode, 0)) { 206 wpa_printf(MSG_DEBUG, "CryptoAPI: CryptSetKeyParam(KP_MODE) " 207 "failed: %d", (int) GetLastError()); 208 CryptDestroyKey(ckey); 209 CryptReleaseContext(prov, 0); 210 return; 211 } 212 213 os_memcpy(cypher, clear, 8); 214 dlen = 8; 215 if (!CryptEncrypt(ckey, 0, FALSE, 0, cypher, &dlen, 8)) { 216 wpa_printf(MSG_DEBUG, "CryptoAPI: CryptEncrypt failed: %d", 217 (int) GetLastError()); 218 os_memset(cypher, 0, 8); 219 } 220 221 CryptDestroyKey(ckey); 222 CryptReleaseContext(prov, 0); 223} 224 225 226#ifdef EAP_TLS_FUNCS 227void md5_vector(size_t num_elem, const u8 *addr[], const size_t *len, u8 *mac) 228{ 229 cryptoapi_hash_vector(CALG_MD5, 16, num_elem, addr, len, mac); 230} 231 232 233void sha1_vector(size_t num_elem, const u8 *addr[], const size_t *len, u8 *mac) 234{ 235 cryptoapi_hash_vector(CALG_SHA, 20, num_elem, addr, len, mac); 236} 237 238 239struct aes_context { 240 HCRYPTPROV prov; 241 HCRYPTKEY ckey; 242}; 243 244 245void * aes_encrypt_init(const u8 *key, size_t len) 246{ 247 struct aes_context *akey; 248 struct { 249 BLOBHEADER hdr; 250 DWORD len; 251 BYTE key[16]; 252 } key_blob; 253 DWORD mode = CRYPT_MODE_ECB; 254 255 if (len != 16) 256 return NULL; 257 258 key_blob.hdr.bType = PLAINTEXTKEYBLOB; 259 key_blob.hdr.bVersion = CUR_BLOB_VERSION; 260 key_blob.hdr.reserved = 0; 261 key_blob.hdr.aiKeyAlg = CALG_AES_128; 262 key_blob.len = len; 263 os_memcpy(key_blob.key, key, len); 264 265 akey = os_zalloc(sizeof(*akey)); 266 if (akey == NULL) 267 return NULL; 268 269 if (!CryptAcquireContext(&akey->prov, NULL, 270 MS_ENH_RSA_AES_PROV, PROV_RSA_AES, 271 CRYPT_VERIFYCONTEXT)) { 272 wpa_printf(MSG_DEBUG, "CryptoAPI: CryptAcquireContext failed: " 273 "%d", (int) GetLastError()); 274 os_free(akey); 275 return NULL; 276 } 277 278 if (!CryptImportKey(akey->prov, (BYTE *) &key_blob, sizeof(key_blob), 279 0, 0, &akey->ckey)) { 280 wpa_printf(MSG_DEBUG, "CryptoAPI: CryptImportKey failed: %d", 281 (int) GetLastError()); 282 CryptReleaseContext(akey->prov, 0); 283 os_free(akey); 284 return NULL; 285 } 286 287 if (!CryptSetKeyParam(akey->ckey, KP_MODE, (BYTE *) &mode, 0)) { 288 wpa_printf(MSG_DEBUG, "CryptoAPI: CryptSetKeyParam(KP_MODE) " 289 "failed: %d", (int) GetLastError()); 290 CryptDestroyKey(akey->ckey); 291 CryptReleaseContext(akey->prov, 0); 292 os_free(akey); 293 return NULL; 294 } 295 296 return akey; 297} 298 299 300void aes_encrypt(void *ctx, const u8 *plain, u8 *crypt) 301{ 302 struct aes_context *akey = ctx; 303 DWORD dlen; 304 305 os_memcpy(crypt, plain, 16); 306 dlen = 16; 307 if (!CryptEncrypt(akey->ckey, 0, FALSE, 0, crypt, &dlen, 16)) { 308 wpa_printf(MSG_DEBUG, "CryptoAPI: CryptEncrypt failed: %d", 309 (int) GetLastError()); 310 os_memset(crypt, 0, 16); 311 } 312} 313 314 315void aes_encrypt_deinit(void *ctx) 316{ 317 struct aes_context *akey = ctx; 318 if (akey) { 319 CryptDestroyKey(akey->ckey); 320 CryptReleaseContext(akey->prov, 0); 321 os_free(akey); 322 } 323} 324 325 326void * aes_decrypt_init(const u8 *key, size_t len) 327{ 328 return aes_encrypt_init(key, len); 329} 330 331 332void aes_decrypt(void *ctx, const u8 *crypt, u8 *plain) 333{ 334 struct aes_context *akey = ctx; 335 DWORD dlen; 336 337 os_memcpy(plain, crypt, 16); 338 dlen = 16; 339 340 if (!CryptDecrypt(akey->ckey, 0, FALSE, 0, plain, &dlen)) { 341 wpa_printf(MSG_DEBUG, "CryptoAPI: CryptDecrypt failed: %d", 342 (int) GetLastError()); 343 } 344} 345 346 347void aes_decrypt_deinit(void *ctx) 348{ 349 aes_encrypt_deinit(ctx); 350} 351 352#ifdef CONFIG_TLS_INTERNAL 353 354struct crypto_hash { 355 enum crypto_hash_alg alg; 356 int error; 357 HCRYPTPROV prov; 358 HCRYPTHASH hash; 359 HCRYPTKEY key; 360}; 361 362struct crypto_hash * crypto_hash_init(enum crypto_hash_alg alg, const u8 *key, 363 size_t key_len) 364{ 365 struct crypto_hash *ctx; 366 ALG_ID calg; 367 struct { 368 BLOBHEADER hdr; 369 DWORD len; 370 BYTE key[32]; 371 } key_blob; 372 373 os_memset(&key_blob, 0, sizeof(key_blob)); 374 switch (alg) { 375 case CRYPTO_HASH_ALG_MD5: 376 calg = CALG_MD5; 377 break; 378 case CRYPTO_HASH_ALG_SHA1: 379 calg = CALG_SHA; 380 break; 381 case CRYPTO_HASH_ALG_HMAC_MD5: 382 case CRYPTO_HASH_ALG_HMAC_SHA1: 383 calg = CALG_HMAC; 384 key_blob.hdr.bType = PLAINTEXTKEYBLOB; 385 key_blob.hdr.bVersion = CUR_BLOB_VERSION; 386 key_blob.hdr.reserved = 0; 387 /* 388 * Note: RC2 is not really used, but that can be used to 389 * import HMAC keys of up to 16 byte long. 390 * CRYPT_IPSEC_HMAC_KEY flag for CryptImportKey() is needed to 391 * be able to import longer keys (HMAC-SHA1 uses 20-byte key). 392 */ 393 key_blob.hdr.aiKeyAlg = CALG_RC2; 394 key_blob.len = key_len; 395 if (key_len > sizeof(key_blob.key)) 396 return NULL; 397 os_memcpy(key_blob.key, key, key_len); 398 break; 399 default: 400 return NULL; 401 } 402 403 ctx = os_zalloc(sizeof(*ctx)); 404 if (ctx == NULL) 405 return NULL; 406 407 ctx->alg = alg; 408 409 if (!CryptAcquireContext(&ctx->prov, NULL, NULL, PROV_RSA_FULL, 0)) { 410 cryptoapi_report_error("CryptAcquireContext"); 411 os_free(ctx); 412 return NULL; 413 } 414 415 if (calg == CALG_HMAC) { 416#ifndef CRYPT_IPSEC_HMAC_KEY 417#define CRYPT_IPSEC_HMAC_KEY 0x00000100 418#endif 419 if (!CryptImportKey(ctx->prov, (BYTE *) &key_blob, 420 sizeof(key_blob), 0, CRYPT_IPSEC_HMAC_KEY, 421 &ctx->key)) { 422 cryptoapi_report_error("CryptImportKey"); 423 CryptReleaseContext(ctx->prov, 0); 424 os_free(ctx); 425 return NULL; 426 } 427 } 428 429 if (!CryptCreateHash(ctx->prov, calg, ctx->key, 0, &ctx->hash)) { 430 cryptoapi_report_error("CryptCreateHash"); 431 CryptReleaseContext(ctx->prov, 0); 432 os_free(ctx); 433 return NULL; 434 } 435 436 if (calg == CALG_HMAC) { 437 HMAC_INFO info; 438 os_memset(&info, 0, sizeof(info)); 439 switch (alg) { 440 case CRYPTO_HASH_ALG_HMAC_MD5: 441 info.HashAlgid = CALG_MD5; 442 break; 443 case CRYPTO_HASH_ALG_HMAC_SHA1: 444 info.HashAlgid = CALG_SHA; 445 break; 446 default: 447 /* unreachable */ 448 break; 449 } 450 451 if (!CryptSetHashParam(ctx->hash, HP_HMAC_INFO, (BYTE *) &info, 452 0)) { 453 cryptoapi_report_error("CryptSetHashParam"); 454 CryptDestroyHash(ctx->hash); 455 CryptReleaseContext(ctx->prov, 0); 456 os_free(ctx); 457 return NULL; 458 } 459 } 460 461 return ctx; 462} 463 464 465void crypto_hash_update(struct crypto_hash *ctx, const u8 *data, size_t len) 466{ 467 if (ctx == NULL || ctx->error) 468 return; 469 470 if (!CryptHashData(ctx->hash, (BYTE *) data, len, 0)) { 471 cryptoapi_report_error("CryptHashData"); 472 ctx->error = 1; 473 } 474} 475 476 477int crypto_hash_finish(struct crypto_hash *ctx, u8 *mac, size_t *len) 478{ 479 int ret = 0; 480 DWORD hlen; 481 482 if (ctx == NULL) 483 return -2; 484 485 if (mac == NULL || len == NULL) 486 goto done; 487 488 if (ctx->error) { 489 ret = -2; 490 goto done; 491 } 492 493 hlen = *len; 494 if (!CryptGetHashParam(ctx->hash, HP_HASHVAL, mac, &hlen, 0)) { 495 cryptoapi_report_error("CryptGetHashParam"); 496 ret = -2; 497 } 498 *len = hlen; 499 500done: 501 if (ctx->alg == CRYPTO_HASH_ALG_HMAC_SHA1 || 502 ctx->alg == CRYPTO_HASH_ALG_HMAC_MD5) 503 CryptDestroyKey(ctx->key); 504 505 os_free(ctx); 506 507 return ret; 508} 509 510 511struct crypto_cipher { 512 HCRYPTPROV prov; 513 HCRYPTKEY key; 514}; 515 516 517struct crypto_cipher * crypto_cipher_init(enum crypto_cipher_alg alg, 518 const u8 *iv, const u8 *key, 519 size_t key_len) 520{ 521 struct crypto_cipher *ctx; 522 struct { 523 BLOBHEADER hdr; 524 DWORD len; 525 BYTE key[32]; 526 } key_blob; 527 DWORD mode = CRYPT_MODE_CBC; 528 529 key_blob.hdr.bType = PLAINTEXTKEYBLOB; 530 key_blob.hdr.bVersion = CUR_BLOB_VERSION; 531 key_blob.hdr.reserved = 0; 532 key_blob.len = key_len; 533 if (key_len > sizeof(key_blob.key)) 534 return NULL; 535 os_memcpy(key_blob.key, key, key_len); 536 537 switch (alg) { 538 case CRYPTO_CIPHER_ALG_AES: 539 if (key_len == 32) 540 key_blob.hdr.aiKeyAlg = CALG_AES_256; 541 else if (key_len == 24) 542 key_blob.hdr.aiKeyAlg = CALG_AES_192; 543 else 544 key_blob.hdr.aiKeyAlg = CALG_AES_128; 545 break; 546 case CRYPTO_CIPHER_ALG_3DES: 547 key_blob.hdr.aiKeyAlg = CALG_3DES; 548 break; 549 case CRYPTO_CIPHER_ALG_DES: 550 key_blob.hdr.aiKeyAlg = CALG_DES; 551 break; 552 case CRYPTO_CIPHER_ALG_RC2: 553 key_blob.hdr.aiKeyAlg = CALG_RC2; 554 break; 555 case CRYPTO_CIPHER_ALG_RC4: 556 key_blob.hdr.aiKeyAlg = CALG_RC4; 557 break; 558 default: 559 return NULL; 560 } 561 562 ctx = os_zalloc(sizeof(*ctx)); 563 if (ctx == NULL) 564 return NULL; 565 566 if (!CryptAcquireContext(&ctx->prov, NULL, MS_ENH_RSA_AES_PROV, 567 PROV_RSA_AES, CRYPT_VERIFYCONTEXT)) { 568 cryptoapi_report_error("CryptAcquireContext"); 569 goto fail1; 570 } 571 572 if (!CryptImportKey(ctx->prov, (BYTE *) &key_blob, 573 sizeof(key_blob), 0, 0, &ctx->key)) { 574 cryptoapi_report_error("CryptImportKey"); 575 goto fail2; 576 } 577 578 if (!CryptSetKeyParam(ctx->key, KP_MODE, (BYTE *) &mode, 0)) { 579 cryptoapi_report_error("CryptSetKeyParam(KP_MODE)"); 580 goto fail3; 581 } 582 583 if (iv && !CryptSetKeyParam(ctx->key, KP_IV, (BYTE *) iv, 0)) { 584 cryptoapi_report_error("CryptSetKeyParam(KP_IV)"); 585 goto fail3; 586 } 587 588 return ctx; 589 590fail3: 591 CryptDestroyKey(ctx->key); 592fail2: 593 CryptReleaseContext(ctx->prov, 0); 594fail1: 595 os_free(ctx); 596 return NULL; 597} 598 599 600int crypto_cipher_encrypt(struct crypto_cipher *ctx, const u8 *plain, 601 u8 *crypt, size_t len) 602{ 603 DWORD dlen; 604 605 os_memcpy(crypt, plain, len); 606 dlen = len; 607 if (!CryptEncrypt(ctx->key, 0, FALSE, 0, crypt, &dlen, len)) { 608 cryptoapi_report_error("CryptEncrypt"); 609 os_memset(crypt, 0, len); 610 return -1; 611 } 612 613 return 0; 614} 615 616 617int crypto_cipher_decrypt(struct crypto_cipher *ctx, const u8 *crypt, 618 u8 *plain, size_t len) 619{ 620 DWORD dlen; 621 622 os_memcpy(plain, crypt, len); 623 dlen = len; 624 if (!CryptDecrypt(ctx->key, 0, FALSE, 0, plain, &dlen)) { 625 cryptoapi_report_error("CryptDecrypt"); 626 return -1; 627 } 628 629 return 0; 630} 631 632 633void crypto_cipher_deinit(struct crypto_cipher *ctx) 634{ 635 CryptDestroyKey(ctx->key); 636 CryptReleaseContext(ctx->prov, 0); 637 os_free(ctx); 638} 639 640 641struct crypto_public_key { 642 HCRYPTPROV prov; 643 HCRYPTKEY rsa; 644}; 645 646struct crypto_private_key { 647 HCRYPTPROV prov; 648 HCRYPTKEY rsa; 649}; 650 651 652struct crypto_public_key * crypto_public_key_import(const u8 *key, size_t len) 653{ 654 /* Use crypto_public_key_from_cert() instead. */ 655 return NULL; 656} 657 658 659struct crypto_private_key * crypto_private_key_import(const u8 *key, 660 size_t len) 661{ 662 /* TODO */ 663 return NULL; 664} 665 666 667struct crypto_public_key * crypto_public_key_from_cert(const u8 *buf, 668 size_t len) 669{ 670 struct crypto_public_key *pk; 671 PCCERT_CONTEXT cc; 672 673 pk = os_zalloc(sizeof(*pk)); 674 if (pk == NULL) 675 return NULL; 676 677 cc = CertCreateCertificateContext(X509_ASN_ENCODING | 678 PKCS_7_ASN_ENCODING, buf, len); 679 if (!cc) { 680 cryptoapi_report_error("CryptCreateCertificateContext"); 681 os_free(pk); 682 return NULL; 683 } 684 685 if (!CryptAcquireContext(&pk->prov, NULL, MS_DEF_PROV, PROV_RSA_FULL, 686 0)) { 687 cryptoapi_report_error("CryptAcquireContext"); 688 os_free(pk); 689 CertFreeCertificateContext(cc); 690 return NULL; 691 } 692 693 if (!CryptImportPublicKeyInfo(pk->prov, X509_ASN_ENCODING | 694 PKCS_7_ASN_ENCODING, 695 &cc->pCertInfo->SubjectPublicKeyInfo, 696 &pk->rsa)) { 697 cryptoapi_report_error("CryptImportPublicKeyInfo"); 698 CryptReleaseContext(pk->prov, 0); 699 os_free(pk); 700 CertFreeCertificateContext(cc); 701 return NULL; 702 } 703 704 CertFreeCertificateContext(cc); 705 706 return pk; 707} 708 709 710int crypto_public_key_encrypt_pkcs1_v15(struct crypto_public_key *key, 711 const u8 *in, size_t inlen, 712 u8 *out, size_t *outlen) 713{ 714 DWORD clen; 715 u8 *tmp; 716 size_t i; 717 718 if (*outlen < inlen) 719 return -1; 720 tmp = malloc(*outlen); 721 if (tmp == NULL) 722 return -1; 723 724 os_memcpy(tmp, in, inlen); 725 clen = inlen; 726 if (!CryptEncrypt(key->rsa, 0, TRUE, 0, tmp, &clen, *outlen)) { 727 wpa_printf(MSG_DEBUG, "CryptoAPI: Failed to encrypt using " 728 "public key: %d", (int) GetLastError()); 729 os_free(tmp); 730 return -1; 731 } 732 733 *outlen = clen; 734 735 /* Reverse the output */ 736 for (i = 0; i < *outlen; i++) 737 out[i] = tmp[*outlen - 1 - i]; 738 739 os_free(tmp); 740 741 return 0; 742} 743 744 745int crypto_private_key_sign_pkcs1(struct crypto_private_key *key, 746 const u8 *in, size_t inlen, 747 u8 *out, size_t *outlen) 748{ 749 /* TODO */ 750 return -1; 751} 752 753 754void crypto_public_key_free(struct crypto_public_key *key) 755{ 756 if (key) { 757 CryptDestroyKey(key->rsa); 758 CryptReleaseContext(key->prov, 0); 759 os_free(key); 760 } 761} 762 763 764void crypto_private_key_free(struct crypto_private_key *key) 765{ 766 if (key) { 767 CryptDestroyKey(key->rsa); 768 CryptReleaseContext(key->prov, 0); 769 os_free(key); 770 } 771} 772 773 774int crypto_global_init(void) 775{ 776 return mingw_load_crypto_func(); 777} 778 779 780void crypto_global_deinit(void) 781{ 782} 783 784#endif /* CONFIG_TLS_INTERNAL */ 785 786#endif /* EAP_TLS_FUNCS */ 787