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