tlsv1_cred.c 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493
  1. /*
  2. * TLSv1 credentials
  3. * Copyright (c) 2006-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. #include "includes.h"
  15. #include "common.h"
  16. #include "base64.h"
  17. #include "crypto/crypto.h"
  18. #include "x509v3.h"
  19. #include "tlsv1_cred.h"
  20. struct tlsv1_credentials * tlsv1_cred_alloc(void)
  21. {
  22. struct tlsv1_credentials *cred;
  23. cred = os_zalloc(sizeof(*cred));
  24. return cred;
  25. }
  26. void tlsv1_cred_free(struct tlsv1_credentials *cred)
  27. {
  28. if (cred == NULL)
  29. return;
  30. x509_certificate_chain_free(cred->trusted_certs);
  31. x509_certificate_chain_free(cred->cert);
  32. crypto_private_key_free(cred->key);
  33. os_free(cred->dh_p);
  34. os_free(cred->dh_g);
  35. os_free(cred);
  36. }
  37. static int tlsv1_add_cert_der(struct x509_certificate **chain,
  38. const u8 *buf, size_t len)
  39. {
  40. struct x509_certificate *cert;
  41. char name[128];
  42. cert = x509_certificate_parse(buf, len);
  43. if (cert == NULL) {
  44. wpa_printf(MSG_INFO, "TLSv1: %s - failed to parse certificate",
  45. __func__);
  46. return -1;
  47. }
  48. cert->next = *chain;
  49. *chain = cert;
  50. x509_name_string(&cert->subject, name, sizeof(name));
  51. wpa_printf(MSG_DEBUG, "TLSv1: Added certificate: %s", name);
  52. return 0;
  53. }
  54. static const char *pem_cert_begin = "-----BEGIN CERTIFICATE-----";
  55. static const char *pem_cert_end = "-----END CERTIFICATE-----";
  56. static const char *pem_key_begin = "-----BEGIN RSA PRIVATE KEY-----";
  57. static const char *pem_key_end = "-----END RSA PRIVATE KEY-----";
  58. static const char *pem_key2_begin = "-----BEGIN PRIVATE KEY-----";
  59. static const char *pem_key2_end = "-----END PRIVATE KEY-----";
  60. static const char *pem_key_enc_begin = "-----BEGIN ENCRYPTED PRIVATE KEY-----";
  61. static const char *pem_key_enc_end = "-----END ENCRYPTED PRIVATE KEY-----";
  62. static const u8 * search_tag(const char *tag, const u8 *buf, size_t len)
  63. {
  64. size_t i, plen;
  65. plen = os_strlen(tag);
  66. if (len < plen)
  67. return NULL;
  68. for (i = 0; i < len - plen; i++) {
  69. if (os_memcmp(buf + i, tag, plen) == 0)
  70. return buf + i;
  71. }
  72. return NULL;
  73. }
  74. static int tlsv1_add_cert(struct x509_certificate **chain,
  75. const u8 *buf, size_t len)
  76. {
  77. const u8 *pos, *end;
  78. unsigned char *der;
  79. size_t der_len;
  80. pos = search_tag(pem_cert_begin, buf, len);
  81. if (!pos) {
  82. wpa_printf(MSG_DEBUG, "TLSv1: No PEM certificate tag found - "
  83. "assume DER format");
  84. return tlsv1_add_cert_der(chain, buf, len);
  85. }
  86. wpa_printf(MSG_DEBUG, "TLSv1: Converting PEM format certificate into "
  87. "DER format");
  88. while (pos) {
  89. pos += os_strlen(pem_cert_begin);
  90. end = search_tag(pem_cert_end, pos, buf + len - pos);
  91. if (end == NULL) {
  92. wpa_printf(MSG_INFO, "TLSv1: Could not find PEM "
  93. "certificate end tag (%s)", pem_cert_end);
  94. return -1;
  95. }
  96. der = base64_decode(pos, end - pos, &der_len);
  97. if (der == NULL) {
  98. wpa_printf(MSG_INFO, "TLSv1: Could not decode PEM "
  99. "certificate");
  100. return -1;
  101. }
  102. if (tlsv1_add_cert_der(chain, der, der_len) < 0) {
  103. wpa_printf(MSG_INFO, "TLSv1: Failed to parse PEM "
  104. "certificate after DER conversion");
  105. os_free(der);
  106. return -1;
  107. }
  108. os_free(der);
  109. end += os_strlen(pem_cert_end);
  110. pos = search_tag(pem_cert_begin, end, buf + len - end);
  111. }
  112. return 0;
  113. }
  114. static int tlsv1_set_cert_chain(struct x509_certificate **chain,
  115. const char *cert, const u8 *cert_blob,
  116. size_t cert_blob_len)
  117. {
  118. if (cert_blob)
  119. return tlsv1_add_cert(chain, cert_blob, cert_blob_len);
  120. if (cert) {
  121. u8 *buf;
  122. size_t len;
  123. int ret;
  124. buf = (u8 *) os_readfile(cert, &len);
  125. if (buf == NULL) {
  126. wpa_printf(MSG_INFO, "TLSv1: Failed to read '%s'",
  127. cert);
  128. return -1;
  129. }
  130. ret = tlsv1_add_cert(chain, buf, len);
  131. os_free(buf);
  132. return ret;
  133. }
  134. return 0;
  135. }
  136. /**
  137. * tlsv1_set_ca_cert - Set trusted CA certificate(s)
  138. * @cred: TLSv1 credentials from tlsv1_cred_alloc()
  139. * @cert: File or reference name for X.509 certificate in PEM or DER format
  140. * @cert_blob: cert as inlined data or %NULL if not used
  141. * @cert_blob_len: ca_cert_blob length
  142. * @path: Path to CA certificates (not yet supported)
  143. * Returns: 0 on success, -1 on failure
  144. */
  145. int tlsv1_set_ca_cert(struct tlsv1_credentials *cred, const char *cert,
  146. const u8 *cert_blob, size_t cert_blob_len,
  147. const char *path)
  148. {
  149. if (tlsv1_set_cert_chain(&cred->trusted_certs, cert,
  150. cert_blob, cert_blob_len) < 0)
  151. return -1;
  152. if (path) {
  153. /* TODO: add support for reading number of certificate files */
  154. wpa_printf(MSG_INFO, "TLSv1: Use of CA certificate directory "
  155. "not yet supported");
  156. return -1;
  157. }
  158. return 0;
  159. }
  160. /**
  161. * tlsv1_set_cert - Set certificate
  162. * @cred: TLSv1 credentials from tlsv1_cred_alloc()
  163. * @cert: File or reference name for X.509 certificate in PEM or DER format
  164. * @cert_blob: cert as inlined data or %NULL if not used
  165. * @cert_blob_len: cert_blob length
  166. * Returns: 0 on success, -1 on failure
  167. */
  168. int tlsv1_set_cert(struct tlsv1_credentials *cred, const char *cert,
  169. const u8 *cert_blob, size_t cert_blob_len)
  170. {
  171. return tlsv1_set_cert_chain(&cred->cert, cert,
  172. cert_blob, cert_blob_len);
  173. }
  174. static struct crypto_private_key * tlsv1_set_key_pem(const u8 *key, size_t len)
  175. {
  176. const u8 *pos, *end;
  177. unsigned char *der;
  178. size_t der_len;
  179. struct crypto_private_key *pkey;
  180. pos = search_tag(pem_key_begin, key, len);
  181. if (!pos) {
  182. pos = search_tag(pem_key2_begin, key, len);
  183. if (!pos)
  184. return NULL;
  185. pos += os_strlen(pem_key2_begin);
  186. end = search_tag(pem_key2_end, pos, key + len - pos);
  187. if (!end)
  188. return NULL;
  189. } else {
  190. pos += os_strlen(pem_key_begin);
  191. end = search_tag(pem_key_end, pos, key + len - pos);
  192. if (!end)
  193. return NULL;
  194. }
  195. der = base64_decode(pos, end - pos, &der_len);
  196. if (!der)
  197. return NULL;
  198. pkey = crypto_private_key_import(der, der_len, NULL);
  199. os_free(der);
  200. return pkey;
  201. }
  202. static struct crypto_private_key * tlsv1_set_key_enc_pem(const u8 *key,
  203. size_t len,
  204. const char *passwd)
  205. {
  206. const u8 *pos, *end;
  207. unsigned char *der;
  208. size_t der_len;
  209. struct crypto_private_key *pkey;
  210. if (passwd == NULL)
  211. return NULL;
  212. pos = search_tag(pem_key_enc_begin, key, len);
  213. if (!pos)
  214. return NULL;
  215. pos += os_strlen(pem_key_enc_begin);
  216. end = search_tag(pem_key_enc_end, pos, key + len - pos);
  217. if (!end)
  218. return NULL;
  219. der = base64_decode(pos, end - pos, &der_len);
  220. if (!der)
  221. return NULL;
  222. pkey = crypto_private_key_import(der, der_len, passwd);
  223. os_free(der);
  224. return pkey;
  225. }
  226. static int tlsv1_set_key(struct tlsv1_credentials *cred,
  227. const u8 *key, size_t len, const char *passwd)
  228. {
  229. cred->key = crypto_private_key_import(key, len, passwd);
  230. if (cred->key == NULL)
  231. cred->key = tlsv1_set_key_pem(key, len);
  232. if (cred->key == NULL)
  233. cred->key = tlsv1_set_key_enc_pem(key, len, passwd);
  234. if (cred->key == NULL) {
  235. wpa_printf(MSG_INFO, "TLSv1: Failed to parse private key");
  236. return -1;
  237. }
  238. return 0;
  239. }
  240. /**
  241. * tlsv1_set_private_key - Set private key
  242. * @cred: TLSv1 credentials from tlsv1_cred_alloc()
  243. * @private_key: File or reference name for the key in PEM or DER format
  244. * @private_key_passwd: Passphrase for decrypted private key, %NULL if no
  245. * passphrase is used.
  246. * @private_key_blob: private_key as inlined data or %NULL if not used
  247. * @private_key_blob_len: private_key_blob length
  248. * Returns: 0 on success, -1 on failure
  249. */
  250. int tlsv1_set_private_key(struct tlsv1_credentials *cred,
  251. const char *private_key,
  252. const char *private_key_passwd,
  253. const u8 *private_key_blob,
  254. size_t private_key_blob_len)
  255. {
  256. crypto_private_key_free(cred->key);
  257. cred->key = NULL;
  258. if (private_key_blob)
  259. return tlsv1_set_key(cred, private_key_blob,
  260. private_key_blob_len,
  261. private_key_passwd);
  262. if (private_key) {
  263. u8 *buf;
  264. size_t len;
  265. int ret;
  266. buf = (u8 *) os_readfile(private_key, &len);
  267. if (buf == NULL) {
  268. wpa_printf(MSG_INFO, "TLSv1: Failed to read '%s'",
  269. private_key);
  270. return -1;
  271. }
  272. ret = tlsv1_set_key(cred, buf, len, private_key_passwd);
  273. os_free(buf);
  274. return ret;
  275. }
  276. return 0;
  277. }
  278. static int tlsv1_set_dhparams_der(struct tlsv1_credentials *cred,
  279. const u8 *dh, size_t len)
  280. {
  281. struct asn1_hdr hdr;
  282. const u8 *pos, *end;
  283. pos = dh;
  284. end = dh + len;
  285. /*
  286. * DHParameter ::= SEQUENCE {
  287. * prime INTEGER, -- p
  288. * base INTEGER, -- g
  289. * privateValueLength INTEGER OPTIONAL }
  290. */
  291. /* DHParamer ::= SEQUENCE */
  292. if (asn1_get_next(pos, len, &hdr) < 0 ||
  293. hdr.class != ASN1_CLASS_UNIVERSAL ||
  294. hdr.tag != ASN1_TAG_SEQUENCE) {
  295. wpa_printf(MSG_DEBUG, "DH: DH parameters did not start with a "
  296. "valid SEQUENCE - found class %d tag 0x%x",
  297. hdr.class, hdr.tag);
  298. return -1;
  299. }
  300. pos = hdr.payload;
  301. /* prime INTEGER */
  302. if (asn1_get_next(pos, end - pos, &hdr) < 0)
  303. return -1;
  304. if (hdr.class != ASN1_CLASS_UNIVERSAL ||
  305. hdr.tag != ASN1_TAG_INTEGER) {
  306. wpa_printf(MSG_DEBUG, "DH: No INTEGER tag found for p; "
  307. "class=%d tag=0x%x", hdr.class, hdr.tag);
  308. return -1;
  309. }
  310. wpa_hexdump(MSG_MSGDUMP, "DH: prime (p)", hdr.payload, hdr.length);
  311. if (hdr.length == 0)
  312. return -1;
  313. os_free(cred->dh_p);
  314. cred->dh_p = os_malloc(hdr.length);
  315. if (cred->dh_p == NULL)
  316. return -1;
  317. os_memcpy(cred->dh_p, hdr.payload, hdr.length);
  318. cred->dh_p_len = hdr.length;
  319. pos = hdr.payload + hdr.length;
  320. /* base INTEGER */
  321. if (asn1_get_next(pos, end - pos, &hdr) < 0)
  322. return -1;
  323. if (hdr.class != ASN1_CLASS_UNIVERSAL ||
  324. hdr.tag != ASN1_TAG_INTEGER) {
  325. wpa_printf(MSG_DEBUG, "DH: No INTEGER tag found for g; "
  326. "class=%d tag=0x%x", hdr.class, hdr.tag);
  327. return -1;
  328. }
  329. wpa_hexdump(MSG_MSGDUMP, "DH: base (g)", hdr.payload, hdr.length);
  330. if (hdr.length == 0)
  331. return -1;
  332. os_free(cred->dh_g);
  333. cred->dh_g = os_malloc(hdr.length);
  334. if (cred->dh_g == NULL)
  335. return -1;
  336. os_memcpy(cred->dh_g, hdr.payload, hdr.length);
  337. cred->dh_g_len = hdr.length;
  338. return 0;
  339. }
  340. static const char *pem_dhparams_begin = "-----BEGIN DH PARAMETERS-----";
  341. static const char *pem_dhparams_end = "-----END DH PARAMETERS-----";
  342. static int tlsv1_set_dhparams_blob(struct tlsv1_credentials *cred,
  343. const u8 *buf, size_t len)
  344. {
  345. const u8 *pos, *end;
  346. unsigned char *der;
  347. size_t der_len;
  348. pos = search_tag(pem_dhparams_begin, buf, len);
  349. if (!pos) {
  350. wpa_printf(MSG_DEBUG, "TLSv1: No PEM dhparams tag found - "
  351. "assume DER format");
  352. return tlsv1_set_dhparams_der(cred, buf, len);
  353. }
  354. wpa_printf(MSG_DEBUG, "TLSv1: Converting PEM format dhparams into DER "
  355. "format");
  356. pos += os_strlen(pem_dhparams_begin);
  357. end = search_tag(pem_dhparams_end, pos, buf + len - pos);
  358. if (end == NULL) {
  359. wpa_printf(MSG_INFO, "TLSv1: Could not find PEM dhparams end "
  360. "tag (%s)", pem_dhparams_end);
  361. return -1;
  362. }
  363. der = base64_decode(pos, end - pos, &der_len);
  364. if (der == NULL) {
  365. wpa_printf(MSG_INFO, "TLSv1: Could not decode PEM dhparams");
  366. return -1;
  367. }
  368. if (tlsv1_set_dhparams_der(cred, der, der_len) < 0) {
  369. wpa_printf(MSG_INFO, "TLSv1: Failed to parse PEM dhparams "
  370. "DER conversion");
  371. os_free(der);
  372. return -1;
  373. }
  374. os_free(der);
  375. return 0;
  376. }
  377. /**
  378. * tlsv1_set_dhparams - Set Diffie-Hellman parameters
  379. * @cred: TLSv1 credentials from tlsv1_cred_alloc()
  380. * @dh_file: File or reference name for the DH params in PEM or DER format
  381. * @dh_blob: DH params as inlined data or %NULL if not used
  382. * @dh_blob_len: dh_blob length
  383. * Returns: 0 on success, -1 on failure
  384. */
  385. int tlsv1_set_dhparams(struct tlsv1_credentials *cred, const char *dh_file,
  386. const u8 *dh_blob, size_t dh_blob_len)
  387. {
  388. if (dh_blob)
  389. return tlsv1_set_dhparams_blob(cred, dh_blob, dh_blob_len);
  390. if (dh_file) {
  391. u8 *buf;
  392. size_t len;
  393. int ret;
  394. buf = (u8 *) os_readfile(dh_file, &len);
  395. if (buf == NULL) {
  396. wpa_printf(MSG_INFO, "TLSv1: Failed to read '%s'",
  397. dh_file);
  398. return -1;
  399. }
  400. ret = tlsv1_set_dhparams_blob(cred, buf, len);
  401. os_free(buf);
  402. return ret;
  403. }
  404. return 0;
  405. }