iscsi_target_auth.c 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490
  1. /*******************************************************************************
  2. * This file houses the main functions for the iSCSI CHAP support
  3. *
  4. * \u00a9 Copyright 2007-2011 RisingTide Systems LLC.
  5. *
  6. * Licensed to the Linux Foundation under the General Public License (GPL) version 2.
  7. *
  8. * Author: Nicholas A. Bellinger <nab@linux-iscsi.org>
  9. *
  10. * This program is free software; you can redistribute it and/or modify
  11. * it under the terms of the GNU General Public License as published by
  12. * the Free Software Foundation; either version 2 of the License, or
  13. * (at your option) any later version.
  14. *
  15. * This program is distributed in the hope that it will be useful,
  16. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  17. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  18. * GNU General Public License for more details.
  19. ******************************************************************************/
  20. #include <linux/string.h>
  21. #include <linux/crypto.h>
  22. #include <linux/err.h>
  23. #include <linux/scatterlist.h>
  24. #include "iscsi_target_core.h"
  25. #include "iscsi_target_nego.h"
  26. #include "iscsi_target_auth.h"
  27. static unsigned char chap_asciihex_to_binaryhex(unsigned char val[2])
  28. {
  29. unsigned char result = 0;
  30. /*
  31. * MSB
  32. */
  33. if ((val[0] >= 'a') && (val[0] <= 'f'))
  34. result = ((val[0] - 'a' + 10) & 0xf) << 4;
  35. else
  36. if ((val[0] >= 'A') && (val[0] <= 'F'))
  37. result = ((val[0] - 'A' + 10) & 0xf) << 4;
  38. else /* digit */
  39. result = ((val[0] - '0') & 0xf) << 4;
  40. /*
  41. * LSB
  42. */
  43. if ((val[1] >= 'a') && (val[1] <= 'f'))
  44. result |= ((val[1] - 'a' + 10) & 0xf);
  45. else
  46. if ((val[1] >= 'A') && (val[1] <= 'F'))
  47. result |= ((val[1] - 'A' + 10) & 0xf);
  48. else /* digit */
  49. result |= ((val[1] - '0') & 0xf);
  50. return result;
  51. }
  52. static int chap_string_to_hex(unsigned char *dst, unsigned char *src, int len)
  53. {
  54. int i, j = 0;
  55. for (i = 0; i < len; i += 2) {
  56. dst[j++] = (unsigned char) chap_asciihex_to_binaryhex(&src[i]);
  57. }
  58. dst[j] = '\0';
  59. return j;
  60. }
  61. static void chap_binaryhex_to_asciihex(char *dst, char *src, int src_len)
  62. {
  63. int i;
  64. for (i = 0; i < src_len; i++) {
  65. sprintf(&dst[i*2], "%02x", (int) src[i] & 0xff);
  66. }
  67. }
  68. static void chap_set_random(char *data, int length)
  69. {
  70. long r;
  71. unsigned n;
  72. while (length > 0) {
  73. get_random_bytes(&r, sizeof(long));
  74. r = r ^ (r >> 8);
  75. r = r ^ (r >> 4);
  76. n = r & 0x7;
  77. get_random_bytes(&r, sizeof(long));
  78. r = r ^ (r >> 8);
  79. r = r ^ (r >> 5);
  80. n = (n << 3) | (r & 0x7);
  81. get_random_bytes(&r, sizeof(long));
  82. r = r ^ (r >> 8);
  83. r = r ^ (r >> 5);
  84. n = (n << 2) | (r & 0x3);
  85. *data++ = n;
  86. length--;
  87. }
  88. }
  89. static void chap_gen_challenge(
  90. struct iscsi_conn *conn,
  91. int caller,
  92. char *c_str,
  93. unsigned int *c_len)
  94. {
  95. unsigned char challenge_asciihex[CHAP_CHALLENGE_LENGTH * 2 + 1];
  96. struct iscsi_chap *chap = (struct iscsi_chap *) conn->auth_protocol;
  97. memset(challenge_asciihex, 0, CHAP_CHALLENGE_LENGTH * 2 + 1);
  98. chap_set_random(chap->challenge, CHAP_CHALLENGE_LENGTH);
  99. chap_binaryhex_to_asciihex(challenge_asciihex, chap->challenge,
  100. CHAP_CHALLENGE_LENGTH);
  101. /*
  102. * Set CHAP_C, and copy the generated challenge into c_str.
  103. */
  104. *c_len += sprintf(c_str + *c_len, "CHAP_C=0x%s", challenge_asciihex);
  105. *c_len += 1;
  106. pr_debug("[%s] Sending CHAP_C=0x%s\n\n", (caller) ? "server" : "client",
  107. challenge_asciihex);
  108. }
  109. static struct iscsi_chap *chap_server_open(
  110. struct iscsi_conn *conn,
  111. struct iscsi_node_auth *auth,
  112. const char *a_str,
  113. char *aic_str,
  114. unsigned int *aic_len)
  115. {
  116. struct iscsi_chap *chap;
  117. if (!(auth->naf_flags & NAF_USERID_SET) ||
  118. !(auth->naf_flags & NAF_PASSWORD_SET)) {
  119. pr_err("CHAP user or password not set for"
  120. " Initiator ACL\n");
  121. return NULL;
  122. }
  123. conn->auth_protocol = kzalloc(sizeof(struct iscsi_chap), GFP_KERNEL);
  124. if (!conn->auth_protocol)
  125. return NULL;
  126. chap = (struct iscsi_chap *) conn->auth_protocol;
  127. /*
  128. * We only support MD5 MDA presently.
  129. */
  130. if (strncmp(a_str, "CHAP_A=5", 8)) {
  131. pr_err("CHAP_A is not MD5.\n");
  132. return NULL;
  133. }
  134. pr_debug("[server] Got CHAP_A=5\n");
  135. /*
  136. * Send back CHAP_A set to MD5.
  137. */
  138. *aic_len = sprintf(aic_str, "CHAP_A=5");
  139. *aic_len += 1;
  140. chap->digest_type = CHAP_DIGEST_MD5;
  141. pr_debug("[server] Sending CHAP_A=%d\n", chap->digest_type);
  142. /*
  143. * Set Identifier.
  144. */
  145. chap->id = ISCSI_TPG_C(conn)->tpg_chap_id++;
  146. *aic_len += sprintf(aic_str + *aic_len, "CHAP_I=%d", chap->id);
  147. *aic_len += 1;
  148. pr_debug("[server] Sending CHAP_I=%d\n", chap->id);
  149. /*
  150. * Generate Challenge.
  151. */
  152. chap_gen_challenge(conn, 1, aic_str, aic_len);
  153. return chap;
  154. }
  155. static void chap_close(struct iscsi_conn *conn)
  156. {
  157. kfree(conn->auth_protocol);
  158. conn->auth_protocol = NULL;
  159. }
  160. static int chap_server_compute_md5(
  161. struct iscsi_conn *conn,
  162. struct iscsi_node_auth *auth,
  163. char *nr_in_ptr,
  164. char *nr_out_ptr,
  165. unsigned int *nr_out_len)
  166. {
  167. char *endptr;
  168. unsigned char id, digest[MD5_SIGNATURE_SIZE];
  169. unsigned char type, response[MD5_SIGNATURE_SIZE * 2 + 2];
  170. unsigned char identifier[10], *challenge = NULL;
  171. unsigned char *challenge_binhex = NULL;
  172. unsigned char client_digest[MD5_SIGNATURE_SIZE];
  173. unsigned char server_digest[MD5_SIGNATURE_SIZE];
  174. unsigned char chap_n[MAX_CHAP_N_SIZE], chap_r[MAX_RESPONSE_LENGTH];
  175. struct iscsi_chap *chap = (struct iscsi_chap *) conn->auth_protocol;
  176. struct crypto_hash *tfm;
  177. struct hash_desc desc;
  178. struct scatterlist sg;
  179. int auth_ret = -1, ret, challenge_len;
  180. memset(identifier, 0, 10);
  181. memset(chap_n, 0, MAX_CHAP_N_SIZE);
  182. memset(chap_r, 0, MAX_RESPONSE_LENGTH);
  183. memset(digest, 0, MD5_SIGNATURE_SIZE);
  184. memset(response, 0, MD5_SIGNATURE_SIZE * 2 + 2);
  185. memset(client_digest, 0, MD5_SIGNATURE_SIZE);
  186. memset(server_digest, 0, MD5_SIGNATURE_SIZE);
  187. challenge = kzalloc(CHAP_CHALLENGE_STR_LEN, GFP_KERNEL);
  188. if (!challenge) {
  189. pr_err("Unable to allocate challenge buffer\n");
  190. goto out;
  191. }
  192. challenge_binhex = kzalloc(CHAP_CHALLENGE_STR_LEN, GFP_KERNEL);
  193. if (!challenge_binhex) {
  194. pr_err("Unable to allocate challenge_binhex buffer\n");
  195. goto out;
  196. }
  197. /*
  198. * Extract CHAP_N.
  199. */
  200. if (extract_param(nr_in_ptr, "CHAP_N", MAX_CHAP_N_SIZE, chap_n,
  201. &type) < 0) {
  202. pr_err("Could not find CHAP_N.\n");
  203. goto out;
  204. }
  205. if (type == HEX) {
  206. pr_err("Could not find CHAP_N.\n");
  207. goto out;
  208. }
  209. if (memcmp(chap_n, auth->userid, strlen(auth->userid)) != 0) {
  210. pr_err("CHAP_N values do not match!\n");
  211. goto out;
  212. }
  213. pr_debug("[server] Got CHAP_N=%s\n", chap_n);
  214. /*
  215. * Extract CHAP_R.
  216. */
  217. if (extract_param(nr_in_ptr, "CHAP_R", MAX_RESPONSE_LENGTH, chap_r,
  218. &type) < 0) {
  219. pr_err("Could not find CHAP_R.\n");
  220. goto out;
  221. }
  222. if (type != HEX) {
  223. pr_err("Could not find CHAP_R.\n");
  224. goto out;
  225. }
  226. pr_debug("[server] Got CHAP_R=%s\n", chap_r);
  227. chap_string_to_hex(client_digest, chap_r, strlen(chap_r));
  228. tfm = crypto_alloc_hash("md5", 0, CRYPTO_ALG_ASYNC);
  229. if (IS_ERR(tfm)) {
  230. pr_err("Unable to allocate struct crypto_hash\n");
  231. goto out;
  232. }
  233. desc.tfm = tfm;
  234. desc.flags = 0;
  235. ret = crypto_hash_init(&desc);
  236. if (ret < 0) {
  237. pr_err("crypto_hash_init() failed\n");
  238. crypto_free_hash(tfm);
  239. goto out;
  240. }
  241. sg_init_one(&sg, (void *)&chap->id, 1);
  242. ret = crypto_hash_update(&desc, &sg, 1);
  243. if (ret < 0) {
  244. pr_err("crypto_hash_update() failed for id\n");
  245. crypto_free_hash(tfm);
  246. goto out;
  247. }
  248. sg_init_one(&sg, (void *)&auth->password, strlen(auth->password));
  249. ret = crypto_hash_update(&desc, &sg, strlen(auth->password));
  250. if (ret < 0) {
  251. pr_err("crypto_hash_update() failed for password\n");
  252. crypto_free_hash(tfm);
  253. goto out;
  254. }
  255. sg_init_one(&sg, (void *)chap->challenge, CHAP_CHALLENGE_LENGTH);
  256. ret = crypto_hash_update(&desc, &sg, CHAP_CHALLENGE_LENGTH);
  257. if (ret < 0) {
  258. pr_err("crypto_hash_update() failed for challenge\n");
  259. crypto_free_hash(tfm);
  260. goto out;
  261. }
  262. ret = crypto_hash_final(&desc, server_digest);
  263. if (ret < 0) {
  264. pr_err("crypto_hash_final() failed for server digest\n");
  265. crypto_free_hash(tfm);
  266. goto out;
  267. }
  268. crypto_free_hash(tfm);
  269. chap_binaryhex_to_asciihex(response, server_digest, MD5_SIGNATURE_SIZE);
  270. pr_debug("[server] MD5 Server Digest: %s\n", response);
  271. if (memcmp(server_digest, client_digest, MD5_SIGNATURE_SIZE) != 0) {
  272. pr_debug("[server] MD5 Digests do not match!\n\n");
  273. goto out;
  274. } else
  275. pr_debug("[server] MD5 Digests match, CHAP connetication"
  276. " successful.\n\n");
  277. /*
  278. * One way authentication has succeeded, return now if mutual
  279. * authentication is not enabled.
  280. */
  281. if (!auth->authenticate_target) {
  282. kfree(challenge);
  283. kfree(challenge_binhex);
  284. return 0;
  285. }
  286. /*
  287. * Get CHAP_I.
  288. */
  289. if (extract_param(nr_in_ptr, "CHAP_I", 10, identifier, &type) < 0) {
  290. pr_err("Could not find CHAP_I.\n");
  291. goto out;
  292. }
  293. if (type == HEX)
  294. id = (unsigned char)simple_strtoul((char *)&identifier[2],
  295. &endptr, 0);
  296. else
  297. id = (unsigned char)simple_strtoul(identifier, &endptr, 0);
  298. /*
  299. * RFC 1994 says Identifier is no more than octet (8 bits).
  300. */
  301. pr_debug("[server] Got CHAP_I=%d\n", id);
  302. /*
  303. * Get CHAP_C.
  304. */
  305. if (extract_param(nr_in_ptr, "CHAP_C", CHAP_CHALLENGE_STR_LEN,
  306. challenge, &type) < 0) {
  307. pr_err("Could not find CHAP_C.\n");
  308. goto out;
  309. }
  310. if (type != HEX) {
  311. pr_err("Could not find CHAP_C.\n");
  312. goto out;
  313. }
  314. pr_debug("[server] Got CHAP_C=%s\n", challenge);
  315. challenge_len = chap_string_to_hex(challenge_binhex, challenge,
  316. strlen(challenge));
  317. if (!challenge_len) {
  318. pr_err("Unable to convert incoming challenge\n");
  319. goto out;
  320. }
  321. /*
  322. * Generate CHAP_N and CHAP_R for mutual authentication.
  323. */
  324. tfm = crypto_alloc_hash("md5", 0, CRYPTO_ALG_ASYNC);
  325. if (IS_ERR(tfm)) {
  326. pr_err("Unable to allocate struct crypto_hash\n");
  327. goto out;
  328. }
  329. desc.tfm = tfm;
  330. desc.flags = 0;
  331. ret = crypto_hash_init(&desc);
  332. if (ret < 0) {
  333. pr_err("crypto_hash_init() failed\n");
  334. crypto_free_hash(tfm);
  335. goto out;
  336. }
  337. sg_init_one(&sg, (void *)&id, 1);
  338. ret = crypto_hash_update(&desc, &sg, 1);
  339. if (ret < 0) {
  340. pr_err("crypto_hash_update() failed for id\n");
  341. crypto_free_hash(tfm);
  342. goto out;
  343. }
  344. sg_init_one(&sg, (void *)auth->password_mutual,
  345. strlen(auth->password_mutual));
  346. ret = crypto_hash_update(&desc, &sg, strlen(auth->password_mutual));
  347. if (ret < 0) {
  348. pr_err("crypto_hash_update() failed for"
  349. " password_mutual\n");
  350. crypto_free_hash(tfm);
  351. goto out;
  352. }
  353. /*
  354. * Convert received challenge to binary hex.
  355. */
  356. sg_init_one(&sg, (void *)challenge_binhex, challenge_len);
  357. ret = crypto_hash_update(&desc, &sg, challenge_len);
  358. if (ret < 0) {
  359. pr_err("crypto_hash_update() failed for ma challenge\n");
  360. crypto_free_hash(tfm);
  361. goto out;
  362. }
  363. ret = crypto_hash_final(&desc, digest);
  364. if (ret < 0) {
  365. pr_err("crypto_hash_final() failed for ma digest\n");
  366. crypto_free_hash(tfm);
  367. goto out;
  368. }
  369. crypto_free_hash(tfm);
  370. /*
  371. * Generate CHAP_N and CHAP_R.
  372. */
  373. *nr_out_len = sprintf(nr_out_ptr, "CHAP_N=%s", auth->userid_mutual);
  374. *nr_out_len += 1;
  375. pr_debug("[server] Sending CHAP_N=%s\n", auth->userid_mutual);
  376. /*
  377. * Convert response from binary hex to ascii hext.
  378. */
  379. chap_binaryhex_to_asciihex(response, digest, MD5_SIGNATURE_SIZE);
  380. *nr_out_len += sprintf(nr_out_ptr + *nr_out_len, "CHAP_R=0x%s",
  381. response);
  382. *nr_out_len += 1;
  383. pr_debug("[server] Sending CHAP_R=0x%s\n", response);
  384. auth_ret = 0;
  385. out:
  386. kfree(challenge);
  387. kfree(challenge_binhex);
  388. return auth_ret;
  389. }
  390. static int chap_got_response(
  391. struct iscsi_conn *conn,
  392. struct iscsi_node_auth *auth,
  393. char *nr_in_ptr,
  394. char *nr_out_ptr,
  395. unsigned int *nr_out_len)
  396. {
  397. struct iscsi_chap *chap = (struct iscsi_chap *) conn->auth_protocol;
  398. switch (chap->digest_type) {
  399. case CHAP_DIGEST_MD5:
  400. if (chap_server_compute_md5(conn, auth, nr_in_ptr,
  401. nr_out_ptr, nr_out_len) < 0)
  402. return -1;
  403. return 0;
  404. default:
  405. pr_err("Unknown CHAP digest type %d!\n",
  406. chap->digest_type);
  407. return -1;
  408. }
  409. }
  410. u32 chap_main_loop(
  411. struct iscsi_conn *conn,
  412. struct iscsi_node_auth *auth,
  413. char *in_text,
  414. char *out_text,
  415. int *in_len,
  416. int *out_len)
  417. {
  418. struct iscsi_chap *chap = (struct iscsi_chap *) conn->auth_protocol;
  419. if (!chap) {
  420. chap = chap_server_open(conn, auth, in_text, out_text, out_len);
  421. if (!chap)
  422. return 2;
  423. chap->chap_state = CHAP_STAGE_SERVER_AIC;
  424. return 0;
  425. } else if (chap->chap_state == CHAP_STAGE_SERVER_AIC) {
  426. convert_null_to_semi(in_text, *in_len);
  427. if (chap_got_response(conn, auth, in_text, out_text,
  428. out_len) < 0) {
  429. chap_close(conn);
  430. return 2;
  431. }
  432. if (auth->authenticate_target)
  433. chap->chap_state = CHAP_STAGE_SERVER_NR;
  434. else
  435. *out_len = 0;
  436. chap_close(conn);
  437. return 1;
  438. }
  439. return 2;
  440. }