crypto_libtomcrypt.c 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736
  1. /*
  2. * WPA Supplicant / Crypto wrapper for LibTomCrypt (for internal TLSv1)
  3. * Copyright (c) 2005-2006, 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. #include "includes.h"
  15. #include <tomcrypt.h>
  16. #include "common.h"
  17. #include "rc4.h"
  18. #include "crypto.h"
  19. #ifndef mp_init_multi
  20. #define mp_init_multi ltc_init_multi
  21. #define mp_clear_multi ltc_deinit_multi
  22. #define mp_unsigned_bin_size(a) ltc_mp.unsigned_size(a)
  23. #define mp_to_unsigned_bin(a, b) ltc_mp.unsigned_write(a, b)
  24. #define mp_read_unsigned_bin(a, b, c) ltc_mp.unsigned_read(a, b, c)
  25. #define mp_exptmod(a,b,c,d) ltc_mp.exptmod(a,b,c,d)
  26. #endif
  27. void md4_vector(size_t num_elem, const u8 *addr[], const size_t *len, u8 *mac)
  28. {
  29. hash_state md;
  30. size_t i;
  31. md4_init(&md);
  32. for (i = 0; i < num_elem; i++)
  33. md4_process(&md, addr[i], len[i]);
  34. md4_done(&md, mac);
  35. }
  36. void des_encrypt(const u8 *clear, const u8 *key, u8 *cypher)
  37. {
  38. u8 pkey[8], next, tmp;
  39. int i;
  40. symmetric_key skey;
  41. /* Add parity bits to the key */
  42. next = 0;
  43. for (i = 0; i < 7; i++) {
  44. tmp = key[i];
  45. pkey[i] = (tmp >> i) | next | 1;
  46. next = tmp << (7 - i);
  47. }
  48. pkey[i] = next | 1;
  49. des_setup(pkey, 8, 0, &skey);
  50. des_ecb_encrypt(clear, cypher, &skey);
  51. des_done(&skey);
  52. }
  53. #ifdef EAP_TLS_FUNCS
  54. void md5_vector(size_t num_elem, const u8 *addr[], const size_t *len, u8 *mac)
  55. {
  56. hash_state md;
  57. size_t i;
  58. md5_init(&md);
  59. for (i = 0; i < num_elem; i++)
  60. md5_process(&md, addr[i], len[i]);
  61. md5_done(&md, mac);
  62. }
  63. void sha1_vector(size_t num_elem, const u8 *addr[], const size_t *len, u8 *mac)
  64. {
  65. hash_state md;
  66. size_t i;
  67. sha1_init(&md);
  68. for (i = 0; i < num_elem; i++)
  69. sha1_process(&md, addr[i], len[i]);
  70. sha1_done(&md, mac);
  71. }
  72. void * aes_encrypt_init(const u8 *key, size_t len)
  73. {
  74. symmetric_key *skey;
  75. skey = os_malloc(sizeof(*skey));
  76. if (skey == NULL)
  77. return NULL;
  78. if (aes_setup(key, len, 0, skey) != CRYPT_OK) {
  79. os_free(skey);
  80. return NULL;
  81. }
  82. return skey;
  83. }
  84. void aes_encrypt(void *ctx, const u8 *plain, u8 *crypt)
  85. {
  86. symmetric_key *skey = ctx;
  87. aes_ecb_encrypt(plain, crypt, skey);
  88. }
  89. void aes_encrypt_deinit(void *ctx)
  90. {
  91. symmetric_key *skey = ctx;
  92. aes_done(skey);
  93. os_free(skey);
  94. }
  95. void * aes_decrypt_init(const u8 *key, size_t len)
  96. {
  97. symmetric_key *skey;
  98. skey = os_malloc(sizeof(*skey));
  99. if (skey == NULL)
  100. return NULL;
  101. if (aes_setup(key, len, 0, skey) != CRYPT_OK) {
  102. os_free(skey);
  103. return NULL;
  104. }
  105. return skey;
  106. }
  107. void aes_decrypt(void *ctx, const u8 *crypt, u8 *plain)
  108. {
  109. symmetric_key *skey = ctx;
  110. aes_ecb_encrypt(plain, (u8 *) crypt, skey);
  111. }
  112. void aes_decrypt_deinit(void *ctx)
  113. {
  114. symmetric_key *skey = ctx;
  115. aes_done(skey);
  116. os_free(skey);
  117. }
  118. #ifdef CONFIG_TLS_INTERNAL
  119. struct crypto_hash {
  120. enum crypto_hash_alg alg;
  121. int error;
  122. union {
  123. hash_state md;
  124. hmac_state hmac;
  125. } u;
  126. };
  127. struct crypto_hash * crypto_hash_init(enum crypto_hash_alg alg, const u8 *key,
  128. size_t key_len)
  129. {
  130. struct crypto_hash *ctx;
  131. ctx = os_zalloc(sizeof(*ctx));
  132. if (ctx == NULL)
  133. return NULL;
  134. ctx->alg = alg;
  135. switch (alg) {
  136. case CRYPTO_HASH_ALG_MD5:
  137. if (md5_init(&ctx->u.md) != CRYPT_OK)
  138. goto fail;
  139. break;
  140. case CRYPTO_HASH_ALG_SHA1:
  141. if (sha1_init(&ctx->u.md) != CRYPT_OK)
  142. goto fail;
  143. break;
  144. case CRYPTO_HASH_ALG_HMAC_MD5:
  145. if (hmac_init(&ctx->u.hmac, find_hash("md5"), key, key_len) !=
  146. CRYPT_OK)
  147. goto fail;
  148. break;
  149. case CRYPTO_HASH_ALG_HMAC_SHA1:
  150. if (hmac_init(&ctx->u.hmac, find_hash("sha1"), key, key_len) !=
  151. CRYPT_OK)
  152. goto fail;
  153. break;
  154. default:
  155. goto fail;
  156. }
  157. return ctx;
  158. fail:
  159. os_free(ctx);
  160. return NULL;
  161. }
  162. void crypto_hash_update(struct crypto_hash *ctx, const u8 *data, size_t len)
  163. {
  164. if (ctx == NULL || ctx->error)
  165. return;
  166. switch (ctx->alg) {
  167. case CRYPTO_HASH_ALG_MD5:
  168. ctx->error = md5_process(&ctx->u.md, data, len) != CRYPT_OK;
  169. break;
  170. case CRYPTO_HASH_ALG_SHA1:
  171. ctx->error = sha1_process(&ctx->u.md, data, len) != CRYPT_OK;
  172. break;
  173. case CRYPTO_HASH_ALG_HMAC_MD5:
  174. case CRYPTO_HASH_ALG_HMAC_SHA1:
  175. ctx->error = hmac_process(&ctx->u.hmac, data, len) != CRYPT_OK;
  176. break;
  177. }
  178. }
  179. int crypto_hash_finish(struct crypto_hash *ctx, u8 *mac, size_t *len)
  180. {
  181. int ret = 0;
  182. unsigned long clen;
  183. if (ctx == NULL)
  184. return -2;
  185. if (mac == NULL || len == NULL) {
  186. os_free(ctx);
  187. return 0;
  188. }
  189. if (ctx->error) {
  190. os_free(ctx);
  191. return -2;
  192. }
  193. switch (ctx->alg) {
  194. case CRYPTO_HASH_ALG_MD5:
  195. if (*len < 16) {
  196. *len = 16;
  197. os_free(ctx);
  198. return -1;
  199. }
  200. *len = 16;
  201. if (md5_done(&ctx->u.md, mac) != CRYPT_OK)
  202. ret = -2;
  203. break;
  204. case CRYPTO_HASH_ALG_SHA1:
  205. if (*len < 20) {
  206. *len = 20;
  207. os_free(ctx);
  208. return -1;
  209. }
  210. *len = 20;
  211. if (sha1_done(&ctx->u.md, mac) != CRYPT_OK)
  212. ret = -2;
  213. break;
  214. case CRYPTO_HASH_ALG_HMAC_SHA1:
  215. if (*len < 20) {
  216. *len = 20;
  217. os_free(ctx);
  218. return -1;
  219. }
  220. /* continue */
  221. case CRYPTO_HASH_ALG_HMAC_MD5:
  222. if (*len < 16) {
  223. *len = 16;
  224. os_free(ctx);
  225. return -1;
  226. }
  227. clen = *len;
  228. if (hmac_done(&ctx->u.hmac, mac, &clen) != CRYPT_OK) {
  229. os_free(ctx);
  230. return -1;
  231. }
  232. *len = clen;
  233. break;
  234. default:
  235. ret = -2;
  236. break;
  237. }
  238. os_free(ctx);
  239. return ret;
  240. }
  241. struct crypto_cipher {
  242. int rc4;
  243. union {
  244. symmetric_CBC cbc;
  245. struct {
  246. size_t used_bytes;
  247. u8 key[16];
  248. size_t keylen;
  249. } rc4;
  250. } u;
  251. };
  252. struct crypto_cipher * crypto_cipher_init(enum crypto_cipher_alg alg,
  253. const u8 *iv, const u8 *key,
  254. size_t key_len)
  255. {
  256. struct crypto_cipher *ctx;
  257. int idx, res, rc4 = 0;
  258. switch (alg) {
  259. case CRYPTO_CIPHER_ALG_AES:
  260. idx = find_cipher("aes");
  261. break;
  262. case CRYPTO_CIPHER_ALG_3DES:
  263. idx = find_cipher("3des");
  264. break;
  265. case CRYPTO_CIPHER_ALG_DES:
  266. idx = find_cipher("des");
  267. break;
  268. case CRYPTO_CIPHER_ALG_RC2:
  269. idx = find_cipher("rc2");
  270. break;
  271. case CRYPTO_CIPHER_ALG_RC4:
  272. idx = -1;
  273. rc4 = 1;
  274. break;
  275. default:
  276. return NULL;
  277. }
  278. ctx = os_zalloc(sizeof(*ctx));
  279. if (ctx == NULL)
  280. return NULL;
  281. if (rc4) {
  282. ctx->rc4 = 1;
  283. if (key_len > sizeof(ctx->u.rc4.key)) {
  284. os_free(ctx);
  285. return NULL;
  286. }
  287. ctx->u.rc4.keylen = key_len;
  288. os_memcpy(ctx->u.rc4.key, key, key_len);
  289. } else {
  290. res = cbc_start(idx, iv, key, key_len, 0, &ctx->u.cbc);
  291. if (res != CRYPT_OK) {
  292. wpa_printf(MSG_DEBUG, "LibTomCrypt: Cipher start "
  293. "failed: %s", error_to_string(res));
  294. os_free(ctx);
  295. return NULL;
  296. }
  297. }
  298. return ctx;
  299. }
  300. int crypto_cipher_encrypt(struct crypto_cipher *ctx, const u8 *plain,
  301. u8 *crypt, size_t len)
  302. {
  303. int res;
  304. if (ctx->rc4) {
  305. if (plain != crypt)
  306. os_memcpy(crypt, plain, len);
  307. rc4_skip(ctx->u.rc4.key, ctx->u.rc4.keylen,
  308. ctx->u.rc4.used_bytes, crypt, len);
  309. ctx->u.rc4.used_bytes += len;
  310. return 0;
  311. }
  312. res = cbc_encrypt(plain, crypt, len, &ctx->u.cbc);
  313. if (res != CRYPT_OK) {
  314. wpa_printf(MSG_DEBUG, "LibTomCrypt: CBC encryption "
  315. "failed: %s", error_to_string(res));
  316. return -1;
  317. }
  318. return 0;
  319. }
  320. int crypto_cipher_decrypt(struct crypto_cipher *ctx, const u8 *crypt,
  321. u8 *plain, size_t len)
  322. {
  323. int res;
  324. if (ctx->rc4) {
  325. if (plain != crypt)
  326. os_memcpy(plain, crypt, len);
  327. rc4_skip(ctx->u.rc4.key, ctx->u.rc4.keylen,
  328. ctx->u.rc4.used_bytes, plain, len);
  329. ctx->u.rc4.used_bytes += len;
  330. return 0;
  331. }
  332. res = cbc_decrypt(crypt, plain, len, &ctx->u.cbc);
  333. if (res != CRYPT_OK) {
  334. wpa_printf(MSG_DEBUG, "LibTomCrypt: CBC decryption "
  335. "failed: %s", error_to_string(res));
  336. return -1;
  337. }
  338. return 0;
  339. }
  340. void crypto_cipher_deinit(struct crypto_cipher *ctx)
  341. {
  342. if (!ctx->rc4)
  343. cbc_done(&ctx->u.cbc);
  344. os_free(ctx);
  345. }
  346. struct crypto_public_key {
  347. rsa_key rsa;
  348. };
  349. struct crypto_private_key {
  350. rsa_key rsa;
  351. };
  352. struct crypto_public_key * crypto_public_key_import(const u8 *key, size_t len)
  353. {
  354. int res;
  355. struct crypto_public_key *pk;
  356. pk = os_zalloc(sizeof(*pk));
  357. if (pk == NULL)
  358. return NULL;
  359. res = rsa_import(key, len, &pk->rsa);
  360. if (res != CRYPT_OK) {
  361. wpa_printf(MSG_ERROR, "LibTomCrypt: Failed to import "
  362. "public key (res=%d '%s')",
  363. res, error_to_string(res));
  364. os_free(pk);
  365. return NULL;
  366. }
  367. if (pk->rsa.type != PK_PUBLIC) {
  368. wpa_printf(MSG_ERROR, "LibTomCrypt: Public key was not of "
  369. "correct type");
  370. rsa_free(&pk->rsa);
  371. os_free(pk);
  372. return NULL;
  373. }
  374. return pk;
  375. }
  376. struct crypto_private_key * crypto_private_key_import(const u8 *key,
  377. size_t len)
  378. {
  379. int res;
  380. struct crypto_private_key *pk;
  381. pk = os_zalloc(sizeof(*pk));
  382. if (pk == NULL)
  383. return NULL;
  384. res = rsa_import(key, len, &pk->rsa);
  385. if (res != CRYPT_OK) {
  386. wpa_printf(MSG_ERROR, "LibTomCrypt: Failed to import "
  387. "private key (res=%d '%s')",
  388. res, error_to_string(res));
  389. os_free(pk);
  390. return NULL;
  391. }
  392. if (pk->rsa.type != PK_PRIVATE) {
  393. wpa_printf(MSG_ERROR, "LibTomCrypt: Private key was not of "
  394. "correct type");
  395. rsa_free(&pk->rsa);
  396. os_free(pk);
  397. return NULL;
  398. }
  399. return pk;
  400. }
  401. struct crypto_public_key * crypto_public_key_from_cert(const u8 *buf,
  402. size_t len)
  403. {
  404. /* No X.509 support in LibTomCrypt */
  405. return NULL;
  406. }
  407. static int pkcs1_generate_encryption_block(u8 block_type, size_t modlen,
  408. const u8 *in, size_t inlen,
  409. u8 *out, size_t *outlen)
  410. {
  411. size_t ps_len;
  412. u8 *pos;
  413. /*
  414. * PKCS #1 v1.5, 8.1:
  415. *
  416. * EB = 00 || BT || PS || 00 || D
  417. * BT = 00 or 01 for private-key operation; 02 for public-key operation
  418. * PS = k-3-||D||; at least eight octets
  419. * (BT=0: PS=0x00, BT=1: PS=0xff, BT=2: PS=pseudorandom non-zero)
  420. * k = length of modulus in octets (modlen)
  421. */
  422. if (modlen < 12 || modlen > *outlen || inlen > modlen - 11) {
  423. wpa_printf(MSG_DEBUG, "PKCS #1: %s - Invalid buffer "
  424. "lengths (modlen=%lu outlen=%lu inlen=%lu)",
  425. __func__, (unsigned long) modlen,
  426. (unsigned long) *outlen,
  427. (unsigned long) inlen);
  428. return -1;
  429. }
  430. pos = out;
  431. *pos++ = 0x00;
  432. *pos++ = block_type; /* BT */
  433. ps_len = modlen - inlen - 3;
  434. switch (block_type) {
  435. case 0:
  436. os_memset(pos, 0x00, ps_len);
  437. pos += ps_len;
  438. break;
  439. case 1:
  440. os_memset(pos, 0xff, ps_len);
  441. pos += ps_len;
  442. break;
  443. case 2:
  444. if (os_get_random(pos, ps_len) < 0) {
  445. wpa_printf(MSG_DEBUG, "PKCS #1: %s - Failed to get "
  446. "random data for PS", __func__);
  447. return -1;
  448. }
  449. while (ps_len--) {
  450. if (*pos == 0x00)
  451. *pos = 0x01;
  452. pos++;
  453. }
  454. break;
  455. default:
  456. wpa_printf(MSG_DEBUG, "PKCS #1: %s - Unsupported block type "
  457. "%d", __func__, block_type);
  458. return -1;
  459. }
  460. *pos++ = 0x00;
  461. os_memcpy(pos, in, inlen); /* D */
  462. return 0;
  463. }
  464. static int crypto_rsa_encrypt_pkcs1(int block_type, rsa_key *key, int key_type,
  465. const u8 *in, size_t inlen,
  466. u8 *out, size_t *outlen)
  467. {
  468. unsigned long len, modlen;
  469. int res;
  470. modlen = mp_unsigned_bin_size(key->N);
  471. if (pkcs1_generate_encryption_block(block_type, modlen, in, inlen,
  472. out, outlen) < 0)
  473. return -1;
  474. len = *outlen;
  475. res = rsa_exptmod(out, modlen, out, &len, key_type, key);
  476. if (res != CRYPT_OK) {
  477. wpa_printf(MSG_DEBUG, "LibTomCrypt: rsa_exptmod failed: %s",
  478. error_to_string(res));
  479. return -1;
  480. }
  481. *outlen = len;
  482. return 0;
  483. }
  484. int crypto_public_key_encrypt_pkcs1_v15(struct crypto_public_key *key,
  485. const u8 *in, size_t inlen,
  486. u8 *out, size_t *outlen)
  487. {
  488. return crypto_rsa_encrypt_pkcs1(2, &key->rsa, PK_PUBLIC, in, inlen,
  489. out, outlen);
  490. }
  491. int crypto_private_key_sign_pkcs1(struct crypto_private_key *key,
  492. const u8 *in, size_t inlen,
  493. u8 *out, size_t *outlen)
  494. {
  495. return crypto_rsa_encrypt_pkcs1(1, &key->rsa, PK_PRIVATE, in, inlen,
  496. out, outlen);
  497. }
  498. void crypto_public_key_free(struct crypto_public_key *key)
  499. {
  500. if (key) {
  501. rsa_free(&key->rsa);
  502. os_free(key);
  503. }
  504. }
  505. void crypto_private_key_free(struct crypto_private_key *key)
  506. {
  507. if (key) {
  508. rsa_free(&key->rsa);
  509. os_free(key);
  510. }
  511. }
  512. int crypto_public_key_decrypt_pkcs1(struct crypto_public_key *key,
  513. const u8 *crypt, size_t crypt_len,
  514. u8 *plain, size_t *plain_len)
  515. {
  516. int res;
  517. unsigned long len;
  518. u8 *pos;
  519. len = *plain_len;
  520. res = rsa_exptmod(crypt, crypt_len, plain, &len, PK_PUBLIC,
  521. &key->rsa);
  522. if (res != CRYPT_OK) {
  523. wpa_printf(MSG_DEBUG, "LibTomCrypt: rsa_exptmod failed: %s",
  524. error_to_string(res));
  525. return -1;
  526. }
  527. /*
  528. * PKCS #1 v1.5, 8.1:
  529. *
  530. * EB = 00 || BT || PS || 00 || D
  531. * BT = 01
  532. * PS = k-3-||D|| times FF
  533. * k = length of modulus in octets
  534. */
  535. if (len < 3 + 8 + 16 /* min hash len */ ||
  536. plain[0] != 0x00 || plain[1] != 0x01 || plain[2] != 0xff) {
  537. wpa_printf(MSG_INFO, "LibTomCrypt: Invalid signature EB "
  538. "structure");
  539. return -1;
  540. }
  541. pos = plain + 3;
  542. while (pos < plain + len && *pos == 0xff)
  543. pos++;
  544. if (pos - plain - 2 < 8) {
  545. /* PKCS #1 v1.5, 8.1: At least eight octets long PS */
  546. wpa_printf(MSG_INFO, "LibTomCrypt: Too short signature "
  547. "padding");
  548. return -1;
  549. }
  550. if (pos + 16 /* min hash len */ >= plain + len || *pos != 0x00) {
  551. wpa_printf(MSG_INFO, "LibTomCrypt: Invalid signature EB "
  552. "structure (2)");
  553. return -1;
  554. }
  555. pos++;
  556. len -= pos - plain;
  557. /* Strip PKCS #1 header */
  558. os_memmove(plain, pos, len);
  559. *plain_len = len;
  560. return 0;
  561. }
  562. int crypto_global_init(void)
  563. {
  564. ltc_mp = tfm_desc;
  565. /* TODO: only register algorithms that are really needed */
  566. if (register_hash(&md4_desc) < 0 ||
  567. register_hash(&md5_desc) < 0 ||
  568. register_hash(&sha1_desc) < 0 ||
  569. register_cipher(&aes_desc) < 0 ||
  570. register_cipher(&des_desc) < 0 ||
  571. register_cipher(&des3_desc) < 0) {
  572. wpa_printf(MSG_ERROR, "TLSv1: Failed to register "
  573. "hash/cipher functions");
  574. return -1;
  575. }
  576. return 0;
  577. }
  578. void crypto_global_deinit(void)
  579. {
  580. }
  581. #ifdef EAP_FAST
  582. int crypto_mod_exp(const u8 *base, size_t base_len,
  583. const u8 *power, size_t power_len,
  584. const u8 *modulus, size_t modulus_len,
  585. u8 *result, size_t *result_len)
  586. {
  587. void *b, *p, *m, *r;
  588. if (mp_init_multi(&b, &p, &m, &r, NULL) != CRYPT_OK)
  589. return -1;
  590. if (mp_read_unsigned_bin(b, (u8 *) base, base_len) != CRYPT_OK ||
  591. mp_read_unsigned_bin(p, (u8 *) power, power_len) != CRYPT_OK ||
  592. mp_read_unsigned_bin(m, (u8 *) modulus, modulus_len) != CRYPT_OK)
  593. goto fail;
  594. if (mp_exptmod(b, p, m, r) != CRYPT_OK)
  595. goto fail;
  596. *result_len = mp_unsigned_bin_size(r);
  597. if (mp_to_unsigned_bin(r, result) != CRYPT_OK)
  598. goto fail;
  599. mp_clear_multi(b, p, m, r, NULL);
  600. return 0;
  601. fail:
  602. mp_clear_multi(b, p, m, r, NULL);
  603. return -1;
  604. }
  605. #endif /* EAP_FAST */
  606. #endif /* CONFIG_TLS_INTERNAL */
  607. #endif /* EAP_TLS_FUNCS */