18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later 28c2ecf20Sopenharmony_ci/******************************************************************************* 38c2ecf20Sopenharmony_ci * This file houses the main functions for the iSCSI CHAP support 48c2ecf20Sopenharmony_ci * 58c2ecf20Sopenharmony_ci * (c) Copyright 2007-2013 Datera, Inc. 68c2ecf20Sopenharmony_ci * 78c2ecf20Sopenharmony_ci * Author: Nicholas A. Bellinger <nab@linux-iscsi.org> 88c2ecf20Sopenharmony_ci * 98c2ecf20Sopenharmony_ci ******************************************************************************/ 108c2ecf20Sopenharmony_ci 118c2ecf20Sopenharmony_ci#include <crypto/hash.h> 128c2ecf20Sopenharmony_ci#include <linux/kernel.h> 138c2ecf20Sopenharmony_ci#include <linux/string.h> 148c2ecf20Sopenharmony_ci#include <linux/err.h> 158c2ecf20Sopenharmony_ci#include <linux/random.h> 168c2ecf20Sopenharmony_ci#include <linux/scatterlist.h> 178c2ecf20Sopenharmony_ci#include <target/iscsi/iscsi_target_core.h> 188c2ecf20Sopenharmony_ci#include "iscsi_target_nego.h" 198c2ecf20Sopenharmony_ci#include "iscsi_target_auth.h" 208c2ecf20Sopenharmony_ci 218c2ecf20Sopenharmony_cistatic char *chap_get_digest_name(const int digest_type) 228c2ecf20Sopenharmony_ci{ 238c2ecf20Sopenharmony_ci switch (digest_type) { 248c2ecf20Sopenharmony_ci case CHAP_DIGEST_MD5: 258c2ecf20Sopenharmony_ci return "md5"; 268c2ecf20Sopenharmony_ci case CHAP_DIGEST_SHA1: 278c2ecf20Sopenharmony_ci return "sha1"; 288c2ecf20Sopenharmony_ci case CHAP_DIGEST_SHA256: 298c2ecf20Sopenharmony_ci return "sha256"; 308c2ecf20Sopenharmony_ci case CHAP_DIGEST_SHA3_256: 318c2ecf20Sopenharmony_ci return "sha3-256"; 328c2ecf20Sopenharmony_ci default: 338c2ecf20Sopenharmony_ci return NULL; 348c2ecf20Sopenharmony_ci } 358c2ecf20Sopenharmony_ci} 368c2ecf20Sopenharmony_ci 378c2ecf20Sopenharmony_cistatic int chap_gen_challenge( 388c2ecf20Sopenharmony_ci struct iscsi_conn *conn, 398c2ecf20Sopenharmony_ci int caller, 408c2ecf20Sopenharmony_ci char *c_str, 418c2ecf20Sopenharmony_ci unsigned int *c_len) 428c2ecf20Sopenharmony_ci{ 438c2ecf20Sopenharmony_ci int ret; 448c2ecf20Sopenharmony_ci unsigned char *challenge_asciihex; 458c2ecf20Sopenharmony_ci struct iscsi_chap *chap = conn->auth_protocol; 468c2ecf20Sopenharmony_ci 478c2ecf20Sopenharmony_ci challenge_asciihex = kzalloc(chap->challenge_len * 2 + 1, GFP_KERNEL); 488c2ecf20Sopenharmony_ci if (!challenge_asciihex) 498c2ecf20Sopenharmony_ci return -ENOMEM; 508c2ecf20Sopenharmony_ci 518c2ecf20Sopenharmony_ci memset(chap->challenge, 0, MAX_CHAP_CHALLENGE_LEN); 528c2ecf20Sopenharmony_ci 538c2ecf20Sopenharmony_ci ret = get_random_bytes_wait(chap->challenge, chap->challenge_len); 548c2ecf20Sopenharmony_ci if (unlikely(ret)) 558c2ecf20Sopenharmony_ci goto out; 568c2ecf20Sopenharmony_ci 578c2ecf20Sopenharmony_ci bin2hex(challenge_asciihex, chap->challenge, 588c2ecf20Sopenharmony_ci chap->challenge_len); 598c2ecf20Sopenharmony_ci /* 608c2ecf20Sopenharmony_ci * Set CHAP_C, and copy the generated challenge into c_str. 618c2ecf20Sopenharmony_ci */ 628c2ecf20Sopenharmony_ci *c_len += sprintf(c_str + *c_len, "CHAP_C=0x%s", challenge_asciihex); 638c2ecf20Sopenharmony_ci *c_len += 1; 648c2ecf20Sopenharmony_ci 658c2ecf20Sopenharmony_ci pr_debug("[%s] Sending CHAP_C=0x%s\n\n", (caller) ? "server" : "client", 668c2ecf20Sopenharmony_ci challenge_asciihex); 678c2ecf20Sopenharmony_ci 688c2ecf20Sopenharmony_ciout: 698c2ecf20Sopenharmony_ci kfree(challenge_asciihex); 708c2ecf20Sopenharmony_ci return ret; 718c2ecf20Sopenharmony_ci} 728c2ecf20Sopenharmony_ci 738c2ecf20Sopenharmony_cistatic int chap_test_algorithm(const char *name) 748c2ecf20Sopenharmony_ci{ 758c2ecf20Sopenharmony_ci struct crypto_shash *tfm; 768c2ecf20Sopenharmony_ci 778c2ecf20Sopenharmony_ci tfm = crypto_alloc_shash(name, 0, 0); 788c2ecf20Sopenharmony_ci if (IS_ERR(tfm)) 798c2ecf20Sopenharmony_ci return -1; 808c2ecf20Sopenharmony_ci 818c2ecf20Sopenharmony_ci crypto_free_shash(tfm); 828c2ecf20Sopenharmony_ci return 0; 838c2ecf20Sopenharmony_ci} 848c2ecf20Sopenharmony_ci 858c2ecf20Sopenharmony_cistatic int chap_check_algorithm(const char *a_str) 868c2ecf20Sopenharmony_ci{ 878c2ecf20Sopenharmony_ci char *tmp, *orig, *token, *digest_name; 888c2ecf20Sopenharmony_ci long digest_type; 898c2ecf20Sopenharmony_ci int r = CHAP_DIGEST_UNKNOWN; 908c2ecf20Sopenharmony_ci 918c2ecf20Sopenharmony_ci tmp = kstrdup(a_str, GFP_KERNEL); 928c2ecf20Sopenharmony_ci if (!tmp) { 938c2ecf20Sopenharmony_ci pr_err("Memory allocation failed for CHAP_A temporary buffer\n"); 948c2ecf20Sopenharmony_ci return CHAP_DIGEST_UNKNOWN; 958c2ecf20Sopenharmony_ci } 968c2ecf20Sopenharmony_ci orig = tmp; 978c2ecf20Sopenharmony_ci 988c2ecf20Sopenharmony_ci token = strsep(&tmp, "="); 998c2ecf20Sopenharmony_ci if (!token) 1008c2ecf20Sopenharmony_ci goto out; 1018c2ecf20Sopenharmony_ci 1028c2ecf20Sopenharmony_ci if (strcmp(token, "CHAP_A")) { 1038c2ecf20Sopenharmony_ci pr_err("Unable to locate CHAP_A key\n"); 1048c2ecf20Sopenharmony_ci goto out; 1058c2ecf20Sopenharmony_ci } 1068c2ecf20Sopenharmony_ci while (token) { 1078c2ecf20Sopenharmony_ci token = strsep(&tmp, ","); 1088c2ecf20Sopenharmony_ci if (!token) 1098c2ecf20Sopenharmony_ci goto out; 1108c2ecf20Sopenharmony_ci 1118c2ecf20Sopenharmony_ci if (kstrtol(token, 10, &digest_type)) 1128c2ecf20Sopenharmony_ci continue; 1138c2ecf20Sopenharmony_ci 1148c2ecf20Sopenharmony_ci digest_name = chap_get_digest_name(digest_type); 1158c2ecf20Sopenharmony_ci if (!digest_name) 1168c2ecf20Sopenharmony_ci continue; 1178c2ecf20Sopenharmony_ci 1188c2ecf20Sopenharmony_ci pr_debug("Selected %s Algorithm\n", digest_name); 1198c2ecf20Sopenharmony_ci if (chap_test_algorithm(digest_name) < 0) { 1208c2ecf20Sopenharmony_ci pr_err("failed to allocate %s algo\n", digest_name); 1218c2ecf20Sopenharmony_ci } else { 1228c2ecf20Sopenharmony_ci r = digest_type; 1238c2ecf20Sopenharmony_ci goto out; 1248c2ecf20Sopenharmony_ci } 1258c2ecf20Sopenharmony_ci } 1268c2ecf20Sopenharmony_ciout: 1278c2ecf20Sopenharmony_ci kfree(orig); 1288c2ecf20Sopenharmony_ci return r; 1298c2ecf20Sopenharmony_ci} 1308c2ecf20Sopenharmony_ci 1318c2ecf20Sopenharmony_cistatic void chap_close(struct iscsi_conn *conn) 1328c2ecf20Sopenharmony_ci{ 1338c2ecf20Sopenharmony_ci kfree(conn->auth_protocol); 1348c2ecf20Sopenharmony_ci conn->auth_protocol = NULL; 1358c2ecf20Sopenharmony_ci} 1368c2ecf20Sopenharmony_ci 1378c2ecf20Sopenharmony_cistatic struct iscsi_chap *chap_server_open( 1388c2ecf20Sopenharmony_ci struct iscsi_conn *conn, 1398c2ecf20Sopenharmony_ci struct iscsi_node_auth *auth, 1408c2ecf20Sopenharmony_ci const char *a_str, 1418c2ecf20Sopenharmony_ci char *aic_str, 1428c2ecf20Sopenharmony_ci unsigned int *aic_len) 1438c2ecf20Sopenharmony_ci{ 1448c2ecf20Sopenharmony_ci int digest_type; 1458c2ecf20Sopenharmony_ci struct iscsi_chap *chap; 1468c2ecf20Sopenharmony_ci 1478c2ecf20Sopenharmony_ci if (!(auth->naf_flags & NAF_USERID_SET) || 1488c2ecf20Sopenharmony_ci !(auth->naf_flags & NAF_PASSWORD_SET)) { 1498c2ecf20Sopenharmony_ci pr_err("CHAP user or password not set for" 1508c2ecf20Sopenharmony_ci " Initiator ACL\n"); 1518c2ecf20Sopenharmony_ci return NULL; 1528c2ecf20Sopenharmony_ci } 1538c2ecf20Sopenharmony_ci 1548c2ecf20Sopenharmony_ci conn->auth_protocol = kzalloc(sizeof(struct iscsi_chap), GFP_KERNEL); 1558c2ecf20Sopenharmony_ci if (!conn->auth_protocol) 1568c2ecf20Sopenharmony_ci return NULL; 1578c2ecf20Sopenharmony_ci 1588c2ecf20Sopenharmony_ci chap = conn->auth_protocol; 1598c2ecf20Sopenharmony_ci digest_type = chap_check_algorithm(a_str); 1608c2ecf20Sopenharmony_ci switch (digest_type) { 1618c2ecf20Sopenharmony_ci case CHAP_DIGEST_MD5: 1628c2ecf20Sopenharmony_ci chap->digest_size = MD5_SIGNATURE_SIZE; 1638c2ecf20Sopenharmony_ci break; 1648c2ecf20Sopenharmony_ci case CHAP_DIGEST_SHA1: 1658c2ecf20Sopenharmony_ci chap->digest_size = SHA1_SIGNATURE_SIZE; 1668c2ecf20Sopenharmony_ci break; 1678c2ecf20Sopenharmony_ci case CHAP_DIGEST_SHA256: 1688c2ecf20Sopenharmony_ci chap->digest_size = SHA256_SIGNATURE_SIZE; 1698c2ecf20Sopenharmony_ci break; 1708c2ecf20Sopenharmony_ci case CHAP_DIGEST_SHA3_256: 1718c2ecf20Sopenharmony_ci chap->digest_size = SHA3_256_SIGNATURE_SIZE; 1728c2ecf20Sopenharmony_ci break; 1738c2ecf20Sopenharmony_ci case CHAP_DIGEST_UNKNOWN: 1748c2ecf20Sopenharmony_ci default: 1758c2ecf20Sopenharmony_ci pr_err("Unsupported CHAP_A value\n"); 1768c2ecf20Sopenharmony_ci chap_close(conn); 1778c2ecf20Sopenharmony_ci return NULL; 1788c2ecf20Sopenharmony_ci } 1798c2ecf20Sopenharmony_ci 1808c2ecf20Sopenharmony_ci chap->digest_name = chap_get_digest_name(digest_type); 1818c2ecf20Sopenharmony_ci 1828c2ecf20Sopenharmony_ci /* Tie the challenge length to the digest size */ 1838c2ecf20Sopenharmony_ci chap->challenge_len = chap->digest_size; 1848c2ecf20Sopenharmony_ci 1858c2ecf20Sopenharmony_ci pr_debug("[server] Got CHAP_A=%d\n", digest_type); 1868c2ecf20Sopenharmony_ci *aic_len = sprintf(aic_str, "CHAP_A=%d", digest_type); 1878c2ecf20Sopenharmony_ci *aic_len += 1; 1888c2ecf20Sopenharmony_ci pr_debug("[server] Sending CHAP_A=%d\n", digest_type); 1898c2ecf20Sopenharmony_ci 1908c2ecf20Sopenharmony_ci /* 1918c2ecf20Sopenharmony_ci * Set Identifier. 1928c2ecf20Sopenharmony_ci */ 1938c2ecf20Sopenharmony_ci chap->id = conn->tpg->tpg_chap_id++; 1948c2ecf20Sopenharmony_ci *aic_len += sprintf(aic_str + *aic_len, "CHAP_I=%d", chap->id); 1958c2ecf20Sopenharmony_ci *aic_len += 1; 1968c2ecf20Sopenharmony_ci pr_debug("[server] Sending CHAP_I=%d\n", chap->id); 1978c2ecf20Sopenharmony_ci /* 1988c2ecf20Sopenharmony_ci * Generate Challenge. 1998c2ecf20Sopenharmony_ci */ 2008c2ecf20Sopenharmony_ci if (chap_gen_challenge(conn, 1, aic_str, aic_len) < 0) { 2018c2ecf20Sopenharmony_ci chap_close(conn); 2028c2ecf20Sopenharmony_ci return NULL; 2038c2ecf20Sopenharmony_ci } 2048c2ecf20Sopenharmony_ci 2058c2ecf20Sopenharmony_ci return chap; 2068c2ecf20Sopenharmony_ci} 2078c2ecf20Sopenharmony_ci 2088c2ecf20Sopenharmony_cistatic int chap_server_compute_hash( 2098c2ecf20Sopenharmony_ci struct iscsi_conn *conn, 2108c2ecf20Sopenharmony_ci struct iscsi_node_auth *auth, 2118c2ecf20Sopenharmony_ci char *nr_in_ptr, 2128c2ecf20Sopenharmony_ci char *nr_out_ptr, 2138c2ecf20Sopenharmony_ci unsigned int *nr_out_len) 2148c2ecf20Sopenharmony_ci{ 2158c2ecf20Sopenharmony_ci unsigned long id; 2168c2ecf20Sopenharmony_ci unsigned char id_as_uchar; 2178c2ecf20Sopenharmony_ci unsigned char type; 2188c2ecf20Sopenharmony_ci unsigned char identifier[10], *initiatorchg = NULL; 2198c2ecf20Sopenharmony_ci unsigned char *initiatorchg_binhex = NULL; 2208c2ecf20Sopenharmony_ci unsigned char *digest = NULL; 2218c2ecf20Sopenharmony_ci unsigned char *response = NULL; 2228c2ecf20Sopenharmony_ci unsigned char *client_digest = NULL; 2238c2ecf20Sopenharmony_ci unsigned char *server_digest = NULL; 2248c2ecf20Sopenharmony_ci unsigned char chap_n[MAX_CHAP_N_SIZE], chap_r[MAX_RESPONSE_LENGTH]; 2258c2ecf20Sopenharmony_ci size_t compare_len; 2268c2ecf20Sopenharmony_ci struct iscsi_chap *chap = conn->auth_protocol; 2278c2ecf20Sopenharmony_ci struct crypto_shash *tfm = NULL; 2288c2ecf20Sopenharmony_ci struct shash_desc *desc = NULL; 2298c2ecf20Sopenharmony_ci int auth_ret = -1, ret, initiatorchg_len; 2308c2ecf20Sopenharmony_ci 2318c2ecf20Sopenharmony_ci digest = kzalloc(chap->digest_size, GFP_KERNEL); 2328c2ecf20Sopenharmony_ci if (!digest) { 2338c2ecf20Sopenharmony_ci pr_err("Unable to allocate the digest buffer\n"); 2348c2ecf20Sopenharmony_ci goto out; 2358c2ecf20Sopenharmony_ci } 2368c2ecf20Sopenharmony_ci 2378c2ecf20Sopenharmony_ci response = kzalloc(chap->digest_size * 2 + 2, GFP_KERNEL); 2388c2ecf20Sopenharmony_ci if (!response) { 2398c2ecf20Sopenharmony_ci pr_err("Unable to allocate the response buffer\n"); 2408c2ecf20Sopenharmony_ci goto out; 2418c2ecf20Sopenharmony_ci } 2428c2ecf20Sopenharmony_ci 2438c2ecf20Sopenharmony_ci client_digest = kzalloc(chap->digest_size, GFP_KERNEL); 2448c2ecf20Sopenharmony_ci if (!client_digest) { 2458c2ecf20Sopenharmony_ci pr_err("Unable to allocate the client_digest buffer\n"); 2468c2ecf20Sopenharmony_ci goto out; 2478c2ecf20Sopenharmony_ci } 2488c2ecf20Sopenharmony_ci 2498c2ecf20Sopenharmony_ci server_digest = kzalloc(chap->digest_size, GFP_KERNEL); 2508c2ecf20Sopenharmony_ci if (!server_digest) { 2518c2ecf20Sopenharmony_ci pr_err("Unable to allocate the server_digest buffer\n"); 2528c2ecf20Sopenharmony_ci goto out; 2538c2ecf20Sopenharmony_ci } 2548c2ecf20Sopenharmony_ci 2558c2ecf20Sopenharmony_ci memset(identifier, 0, 10); 2568c2ecf20Sopenharmony_ci memset(chap_n, 0, MAX_CHAP_N_SIZE); 2578c2ecf20Sopenharmony_ci memset(chap_r, 0, MAX_RESPONSE_LENGTH); 2588c2ecf20Sopenharmony_ci 2598c2ecf20Sopenharmony_ci initiatorchg = kzalloc(CHAP_CHALLENGE_STR_LEN, GFP_KERNEL); 2608c2ecf20Sopenharmony_ci if (!initiatorchg) { 2618c2ecf20Sopenharmony_ci pr_err("Unable to allocate challenge buffer\n"); 2628c2ecf20Sopenharmony_ci goto out; 2638c2ecf20Sopenharmony_ci } 2648c2ecf20Sopenharmony_ci 2658c2ecf20Sopenharmony_ci initiatorchg_binhex = kzalloc(CHAP_CHALLENGE_STR_LEN, GFP_KERNEL); 2668c2ecf20Sopenharmony_ci if (!initiatorchg_binhex) { 2678c2ecf20Sopenharmony_ci pr_err("Unable to allocate initiatorchg_binhex buffer\n"); 2688c2ecf20Sopenharmony_ci goto out; 2698c2ecf20Sopenharmony_ci } 2708c2ecf20Sopenharmony_ci /* 2718c2ecf20Sopenharmony_ci * Extract CHAP_N. 2728c2ecf20Sopenharmony_ci */ 2738c2ecf20Sopenharmony_ci if (extract_param(nr_in_ptr, "CHAP_N", MAX_CHAP_N_SIZE, chap_n, 2748c2ecf20Sopenharmony_ci &type) < 0) { 2758c2ecf20Sopenharmony_ci pr_err("Could not find CHAP_N.\n"); 2768c2ecf20Sopenharmony_ci goto out; 2778c2ecf20Sopenharmony_ci } 2788c2ecf20Sopenharmony_ci if (type == HEX) { 2798c2ecf20Sopenharmony_ci pr_err("Could not find CHAP_N.\n"); 2808c2ecf20Sopenharmony_ci goto out; 2818c2ecf20Sopenharmony_ci } 2828c2ecf20Sopenharmony_ci 2838c2ecf20Sopenharmony_ci /* Include the terminating NULL in the compare */ 2848c2ecf20Sopenharmony_ci compare_len = strlen(auth->userid) + 1; 2858c2ecf20Sopenharmony_ci if (strncmp(chap_n, auth->userid, compare_len) != 0) { 2868c2ecf20Sopenharmony_ci pr_err("CHAP_N values do not match!\n"); 2878c2ecf20Sopenharmony_ci goto out; 2888c2ecf20Sopenharmony_ci } 2898c2ecf20Sopenharmony_ci pr_debug("[server] Got CHAP_N=%s\n", chap_n); 2908c2ecf20Sopenharmony_ci /* 2918c2ecf20Sopenharmony_ci * Extract CHAP_R. 2928c2ecf20Sopenharmony_ci */ 2938c2ecf20Sopenharmony_ci if (extract_param(nr_in_ptr, "CHAP_R", MAX_RESPONSE_LENGTH, chap_r, 2948c2ecf20Sopenharmony_ci &type) < 0) { 2958c2ecf20Sopenharmony_ci pr_err("Could not find CHAP_R.\n"); 2968c2ecf20Sopenharmony_ci goto out; 2978c2ecf20Sopenharmony_ci } 2988c2ecf20Sopenharmony_ci if (type != HEX) { 2998c2ecf20Sopenharmony_ci pr_err("Could not find CHAP_R.\n"); 3008c2ecf20Sopenharmony_ci goto out; 3018c2ecf20Sopenharmony_ci } 3028c2ecf20Sopenharmony_ci if (strlen(chap_r) != chap->digest_size * 2) { 3038c2ecf20Sopenharmony_ci pr_err("Malformed CHAP_R\n"); 3048c2ecf20Sopenharmony_ci goto out; 3058c2ecf20Sopenharmony_ci } 3068c2ecf20Sopenharmony_ci if (hex2bin(client_digest, chap_r, chap->digest_size) < 0) { 3078c2ecf20Sopenharmony_ci pr_err("Malformed CHAP_R\n"); 3088c2ecf20Sopenharmony_ci goto out; 3098c2ecf20Sopenharmony_ci } 3108c2ecf20Sopenharmony_ci 3118c2ecf20Sopenharmony_ci pr_debug("[server] Got CHAP_R=%s\n", chap_r); 3128c2ecf20Sopenharmony_ci 3138c2ecf20Sopenharmony_ci tfm = crypto_alloc_shash(chap->digest_name, 0, 0); 3148c2ecf20Sopenharmony_ci if (IS_ERR(tfm)) { 3158c2ecf20Sopenharmony_ci tfm = NULL; 3168c2ecf20Sopenharmony_ci pr_err("Unable to allocate struct crypto_shash\n"); 3178c2ecf20Sopenharmony_ci goto out; 3188c2ecf20Sopenharmony_ci } 3198c2ecf20Sopenharmony_ci 3208c2ecf20Sopenharmony_ci desc = kmalloc(sizeof(*desc) + crypto_shash_descsize(tfm), GFP_KERNEL); 3218c2ecf20Sopenharmony_ci if (!desc) { 3228c2ecf20Sopenharmony_ci pr_err("Unable to allocate struct shash_desc\n"); 3238c2ecf20Sopenharmony_ci goto out; 3248c2ecf20Sopenharmony_ci } 3258c2ecf20Sopenharmony_ci 3268c2ecf20Sopenharmony_ci desc->tfm = tfm; 3278c2ecf20Sopenharmony_ci 3288c2ecf20Sopenharmony_ci ret = crypto_shash_init(desc); 3298c2ecf20Sopenharmony_ci if (ret < 0) { 3308c2ecf20Sopenharmony_ci pr_err("crypto_shash_init() failed\n"); 3318c2ecf20Sopenharmony_ci goto out; 3328c2ecf20Sopenharmony_ci } 3338c2ecf20Sopenharmony_ci 3348c2ecf20Sopenharmony_ci ret = crypto_shash_update(desc, &chap->id, 1); 3358c2ecf20Sopenharmony_ci if (ret < 0) { 3368c2ecf20Sopenharmony_ci pr_err("crypto_shash_update() failed for id\n"); 3378c2ecf20Sopenharmony_ci goto out; 3388c2ecf20Sopenharmony_ci } 3398c2ecf20Sopenharmony_ci 3408c2ecf20Sopenharmony_ci ret = crypto_shash_update(desc, (char *)&auth->password, 3418c2ecf20Sopenharmony_ci strlen(auth->password)); 3428c2ecf20Sopenharmony_ci if (ret < 0) { 3438c2ecf20Sopenharmony_ci pr_err("crypto_shash_update() failed for password\n"); 3448c2ecf20Sopenharmony_ci goto out; 3458c2ecf20Sopenharmony_ci } 3468c2ecf20Sopenharmony_ci 3478c2ecf20Sopenharmony_ci ret = crypto_shash_finup(desc, chap->challenge, 3488c2ecf20Sopenharmony_ci chap->challenge_len, server_digest); 3498c2ecf20Sopenharmony_ci if (ret < 0) { 3508c2ecf20Sopenharmony_ci pr_err("crypto_shash_finup() failed for challenge\n"); 3518c2ecf20Sopenharmony_ci goto out; 3528c2ecf20Sopenharmony_ci } 3538c2ecf20Sopenharmony_ci 3548c2ecf20Sopenharmony_ci bin2hex(response, server_digest, chap->digest_size); 3558c2ecf20Sopenharmony_ci pr_debug("[server] %s Server Digest: %s\n", 3568c2ecf20Sopenharmony_ci chap->digest_name, response); 3578c2ecf20Sopenharmony_ci 3588c2ecf20Sopenharmony_ci if (memcmp(server_digest, client_digest, chap->digest_size) != 0) { 3598c2ecf20Sopenharmony_ci pr_debug("[server] %s Digests do not match!\n\n", 3608c2ecf20Sopenharmony_ci chap->digest_name); 3618c2ecf20Sopenharmony_ci goto out; 3628c2ecf20Sopenharmony_ci } else 3638c2ecf20Sopenharmony_ci pr_debug("[server] %s Digests match, CHAP connection" 3648c2ecf20Sopenharmony_ci " successful.\n\n", chap->digest_name); 3658c2ecf20Sopenharmony_ci /* 3668c2ecf20Sopenharmony_ci * One way authentication has succeeded, return now if mutual 3678c2ecf20Sopenharmony_ci * authentication is not enabled. 3688c2ecf20Sopenharmony_ci */ 3698c2ecf20Sopenharmony_ci if (!auth->authenticate_target) { 3708c2ecf20Sopenharmony_ci auth_ret = 0; 3718c2ecf20Sopenharmony_ci goto out; 3728c2ecf20Sopenharmony_ci } 3738c2ecf20Sopenharmony_ci /* 3748c2ecf20Sopenharmony_ci * Get CHAP_I. 3758c2ecf20Sopenharmony_ci */ 3768c2ecf20Sopenharmony_ci if (extract_param(nr_in_ptr, "CHAP_I", 10, identifier, &type) < 0) { 3778c2ecf20Sopenharmony_ci pr_err("Could not find CHAP_I.\n"); 3788c2ecf20Sopenharmony_ci goto out; 3798c2ecf20Sopenharmony_ci } 3808c2ecf20Sopenharmony_ci 3818c2ecf20Sopenharmony_ci if (type == HEX) 3828c2ecf20Sopenharmony_ci ret = kstrtoul(&identifier[2], 0, &id); 3838c2ecf20Sopenharmony_ci else 3848c2ecf20Sopenharmony_ci ret = kstrtoul(identifier, 0, &id); 3858c2ecf20Sopenharmony_ci 3868c2ecf20Sopenharmony_ci if (ret < 0) { 3878c2ecf20Sopenharmony_ci pr_err("kstrtoul() failed for CHAP identifier: %d\n", ret); 3888c2ecf20Sopenharmony_ci goto out; 3898c2ecf20Sopenharmony_ci } 3908c2ecf20Sopenharmony_ci if (id > 255) { 3918c2ecf20Sopenharmony_ci pr_err("chap identifier: %lu greater than 255\n", id); 3928c2ecf20Sopenharmony_ci goto out; 3938c2ecf20Sopenharmony_ci } 3948c2ecf20Sopenharmony_ci /* 3958c2ecf20Sopenharmony_ci * RFC 1994 says Identifier is no more than octet (8 bits). 3968c2ecf20Sopenharmony_ci */ 3978c2ecf20Sopenharmony_ci pr_debug("[server] Got CHAP_I=%lu\n", id); 3988c2ecf20Sopenharmony_ci /* 3998c2ecf20Sopenharmony_ci * Get CHAP_C. 4008c2ecf20Sopenharmony_ci */ 4018c2ecf20Sopenharmony_ci if (extract_param(nr_in_ptr, "CHAP_C", CHAP_CHALLENGE_STR_LEN, 4028c2ecf20Sopenharmony_ci initiatorchg, &type) < 0) { 4038c2ecf20Sopenharmony_ci pr_err("Could not find CHAP_C.\n"); 4048c2ecf20Sopenharmony_ci goto out; 4058c2ecf20Sopenharmony_ci } 4068c2ecf20Sopenharmony_ci 4078c2ecf20Sopenharmony_ci if (type != HEX) { 4088c2ecf20Sopenharmony_ci pr_err("Could not find CHAP_C.\n"); 4098c2ecf20Sopenharmony_ci goto out; 4108c2ecf20Sopenharmony_ci } 4118c2ecf20Sopenharmony_ci initiatorchg_len = DIV_ROUND_UP(strlen(initiatorchg), 2); 4128c2ecf20Sopenharmony_ci if (!initiatorchg_len) { 4138c2ecf20Sopenharmony_ci pr_err("Unable to convert incoming challenge\n"); 4148c2ecf20Sopenharmony_ci goto out; 4158c2ecf20Sopenharmony_ci } 4168c2ecf20Sopenharmony_ci if (initiatorchg_len > 1024) { 4178c2ecf20Sopenharmony_ci pr_err("CHAP_C exceeds maximum binary size of 1024 bytes\n"); 4188c2ecf20Sopenharmony_ci goto out; 4198c2ecf20Sopenharmony_ci } 4208c2ecf20Sopenharmony_ci if (hex2bin(initiatorchg_binhex, initiatorchg, initiatorchg_len) < 0) { 4218c2ecf20Sopenharmony_ci pr_err("Malformed CHAP_C\n"); 4228c2ecf20Sopenharmony_ci goto out; 4238c2ecf20Sopenharmony_ci } 4248c2ecf20Sopenharmony_ci pr_debug("[server] Got CHAP_C=%s\n", initiatorchg); 4258c2ecf20Sopenharmony_ci /* 4268c2ecf20Sopenharmony_ci * During mutual authentication, the CHAP_C generated by the 4278c2ecf20Sopenharmony_ci * initiator must not match the original CHAP_C generated by 4288c2ecf20Sopenharmony_ci * the target. 4298c2ecf20Sopenharmony_ci */ 4308c2ecf20Sopenharmony_ci if (initiatorchg_len == chap->challenge_len && 4318c2ecf20Sopenharmony_ci !memcmp(initiatorchg_binhex, chap->challenge, 4328c2ecf20Sopenharmony_ci initiatorchg_len)) { 4338c2ecf20Sopenharmony_ci pr_err("initiator CHAP_C matches target CHAP_C, failing" 4348c2ecf20Sopenharmony_ci " login attempt\n"); 4358c2ecf20Sopenharmony_ci goto out; 4368c2ecf20Sopenharmony_ci } 4378c2ecf20Sopenharmony_ci /* 4388c2ecf20Sopenharmony_ci * Generate CHAP_N and CHAP_R for mutual authentication. 4398c2ecf20Sopenharmony_ci */ 4408c2ecf20Sopenharmony_ci ret = crypto_shash_init(desc); 4418c2ecf20Sopenharmony_ci if (ret < 0) { 4428c2ecf20Sopenharmony_ci pr_err("crypto_shash_init() failed\n"); 4438c2ecf20Sopenharmony_ci goto out; 4448c2ecf20Sopenharmony_ci } 4458c2ecf20Sopenharmony_ci 4468c2ecf20Sopenharmony_ci /* To handle both endiannesses */ 4478c2ecf20Sopenharmony_ci id_as_uchar = id; 4488c2ecf20Sopenharmony_ci ret = crypto_shash_update(desc, &id_as_uchar, 1); 4498c2ecf20Sopenharmony_ci if (ret < 0) { 4508c2ecf20Sopenharmony_ci pr_err("crypto_shash_update() failed for id\n"); 4518c2ecf20Sopenharmony_ci goto out; 4528c2ecf20Sopenharmony_ci } 4538c2ecf20Sopenharmony_ci 4548c2ecf20Sopenharmony_ci ret = crypto_shash_update(desc, auth->password_mutual, 4558c2ecf20Sopenharmony_ci strlen(auth->password_mutual)); 4568c2ecf20Sopenharmony_ci if (ret < 0) { 4578c2ecf20Sopenharmony_ci pr_err("crypto_shash_update() failed for" 4588c2ecf20Sopenharmony_ci " password_mutual\n"); 4598c2ecf20Sopenharmony_ci goto out; 4608c2ecf20Sopenharmony_ci } 4618c2ecf20Sopenharmony_ci /* 4628c2ecf20Sopenharmony_ci * Convert received challenge to binary hex. 4638c2ecf20Sopenharmony_ci */ 4648c2ecf20Sopenharmony_ci ret = crypto_shash_finup(desc, initiatorchg_binhex, initiatorchg_len, 4658c2ecf20Sopenharmony_ci digest); 4668c2ecf20Sopenharmony_ci if (ret < 0) { 4678c2ecf20Sopenharmony_ci pr_err("crypto_shash_finup() failed for ma challenge\n"); 4688c2ecf20Sopenharmony_ci goto out; 4698c2ecf20Sopenharmony_ci } 4708c2ecf20Sopenharmony_ci 4718c2ecf20Sopenharmony_ci /* 4728c2ecf20Sopenharmony_ci * Generate CHAP_N and CHAP_R. 4738c2ecf20Sopenharmony_ci */ 4748c2ecf20Sopenharmony_ci *nr_out_len = sprintf(nr_out_ptr, "CHAP_N=%s", auth->userid_mutual); 4758c2ecf20Sopenharmony_ci *nr_out_len += 1; 4768c2ecf20Sopenharmony_ci pr_debug("[server] Sending CHAP_N=%s\n", auth->userid_mutual); 4778c2ecf20Sopenharmony_ci /* 4788c2ecf20Sopenharmony_ci * Convert response from binary hex to ascii hext. 4798c2ecf20Sopenharmony_ci */ 4808c2ecf20Sopenharmony_ci bin2hex(response, digest, chap->digest_size); 4818c2ecf20Sopenharmony_ci *nr_out_len += sprintf(nr_out_ptr + *nr_out_len, "CHAP_R=0x%s", 4828c2ecf20Sopenharmony_ci response); 4838c2ecf20Sopenharmony_ci *nr_out_len += 1; 4848c2ecf20Sopenharmony_ci pr_debug("[server] Sending CHAP_R=0x%s\n", response); 4858c2ecf20Sopenharmony_ci auth_ret = 0; 4868c2ecf20Sopenharmony_ciout: 4878c2ecf20Sopenharmony_ci kfree_sensitive(desc); 4888c2ecf20Sopenharmony_ci if (tfm) 4898c2ecf20Sopenharmony_ci crypto_free_shash(tfm); 4908c2ecf20Sopenharmony_ci kfree(initiatorchg); 4918c2ecf20Sopenharmony_ci kfree(initiatorchg_binhex); 4928c2ecf20Sopenharmony_ci kfree(digest); 4938c2ecf20Sopenharmony_ci kfree(response); 4948c2ecf20Sopenharmony_ci kfree(server_digest); 4958c2ecf20Sopenharmony_ci kfree(client_digest); 4968c2ecf20Sopenharmony_ci return auth_ret; 4978c2ecf20Sopenharmony_ci} 4988c2ecf20Sopenharmony_ci 4998c2ecf20Sopenharmony_ciu32 chap_main_loop( 5008c2ecf20Sopenharmony_ci struct iscsi_conn *conn, 5018c2ecf20Sopenharmony_ci struct iscsi_node_auth *auth, 5028c2ecf20Sopenharmony_ci char *in_text, 5038c2ecf20Sopenharmony_ci char *out_text, 5048c2ecf20Sopenharmony_ci int *in_len, 5058c2ecf20Sopenharmony_ci int *out_len) 5068c2ecf20Sopenharmony_ci{ 5078c2ecf20Sopenharmony_ci struct iscsi_chap *chap = conn->auth_protocol; 5088c2ecf20Sopenharmony_ci 5098c2ecf20Sopenharmony_ci if (!chap) { 5108c2ecf20Sopenharmony_ci chap = chap_server_open(conn, auth, in_text, out_text, out_len); 5118c2ecf20Sopenharmony_ci if (!chap) 5128c2ecf20Sopenharmony_ci return 2; 5138c2ecf20Sopenharmony_ci chap->chap_state = CHAP_STAGE_SERVER_AIC; 5148c2ecf20Sopenharmony_ci return 0; 5158c2ecf20Sopenharmony_ci } else if (chap->chap_state == CHAP_STAGE_SERVER_AIC) { 5168c2ecf20Sopenharmony_ci convert_null_to_semi(in_text, *in_len); 5178c2ecf20Sopenharmony_ci if (chap_server_compute_hash(conn, auth, in_text, out_text, 5188c2ecf20Sopenharmony_ci out_len) < 0) { 5198c2ecf20Sopenharmony_ci chap_close(conn); 5208c2ecf20Sopenharmony_ci return 2; 5218c2ecf20Sopenharmony_ci } 5228c2ecf20Sopenharmony_ci if (auth->authenticate_target) 5238c2ecf20Sopenharmony_ci chap->chap_state = CHAP_STAGE_SERVER_NR; 5248c2ecf20Sopenharmony_ci else 5258c2ecf20Sopenharmony_ci *out_len = 0; 5268c2ecf20Sopenharmony_ci chap_close(conn); 5278c2ecf20Sopenharmony_ci return 1; 5288c2ecf20Sopenharmony_ci } 5298c2ecf20Sopenharmony_ci 5308c2ecf20Sopenharmony_ci return 2; 5318c2ecf20Sopenharmony_ci} 532