// SPDX-License-Identifier: GPL-2.0-or-later /******************************************************************************* * This file houses the main functions for the iSCSI CHAP support * * (c) Copyright 2007-2013 Datera, Inc. * * Author: Nicholas A. Bellinger <nab@linux-iscsi.org> *
******************************************************************************/
if (!(auth->naf_flags & NAF_USERID_SET) ||
!(auth->naf_flags & NAF_PASSWORD_SET)) {
pr_err("CHAP user or password not set for" " Initiator ACL\n"); return NULL;
}
conn->auth_protocol = kzalloc(sizeof(struct iscsi_chap), GFP_KERNEL); if (!conn->auth_protocol) return NULL;
chap = conn->auth_protocol;
digest_type = chap_check_algorithm(a_str); switch (digest_type) { case CHAP_DIGEST_MD5:
chap->digest_size = MD5_SIGNATURE_SIZE; break; case CHAP_DIGEST_SHA1:
chap->digest_size = SHA1_SIGNATURE_SIZE; break; case CHAP_DIGEST_SHA256:
chap->digest_size = SHA256_SIGNATURE_SIZE; break; case CHAP_DIGEST_SHA3_256:
chap->digest_size = SHA3_256_SIGNATURE_SIZE; break; case CHAP_DIGEST_UNKNOWN: default:
pr_err("Unsupported CHAP_A value\n");
chap_close(conn); return NULL;
}
initiatorchg = kzalloc(CHAP_CHALLENGE_STR_LEN, GFP_KERNEL); if (!initiatorchg) {
pr_err("Unable to allocate challenge buffer\n"); goto out;
}
initiatorchg_binhex = kzalloc(CHAP_CHALLENGE_STR_LEN, GFP_KERNEL); if (!initiatorchg_binhex) {
pr_err("Unable to allocate initiatorchg_binhex buffer\n"); goto out;
} /* * Extract CHAP_N.
*/ if (extract_param(nr_in_ptr, "CHAP_N", MAX_CHAP_N_SIZE, chap_n,
&type) < 0) {
pr_err("Could not find CHAP_N.\n"); goto out;
} if (type == HEX) {
pr_err("Could not find CHAP_N.\n"); goto out;
}
/* Include the terminating NULL in the compare */
compare_len = strlen(auth->userid) + 1; if (strncmp(chap_n, auth->userid, compare_len) != 0) {
pr_err("CHAP_N values do not match!\n"); goto out;
}
pr_debug("[server] Got CHAP_N=%s\n", chap_n); /* * Extract CHAP_R.
*/ if (extract_param(nr_in_ptr, "CHAP_R", MAX_RESPONSE_LENGTH, chap_r,
&type) < 0) {
pr_err("Could not find CHAP_R.\n"); goto out;
}
switch (type) { case HEX: if (strlen(chap_r) != chap->digest_size * 2) {
pr_err("Malformed CHAP_R\n"); goto out;
} if (hex2bin(client_digest, chap_r, chap->digest_size) < 0) {
pr_err("Malformed CHAP_R: invalid HEX\n"); goto out;
} break; case BASE64: if (chap_base64_decode(client_digest, chap_r, strlen(chap_r)) !=
chap->digest_size) {
pr_err("Malformed CHAP_R: invalid BASE64\n"); goto out;
} break; default:
pr_err("Could not find CHAP_R\n"); goto out;
}
pr_debug("[server] Got CHAP_R=%s\n", chap_r);
tfm = crypto_alloc_shash(chap->digest_name, 0, 0); if (IS_ERR(tfm)) {
tfm = NULL;
pr_err("Unable to allocate struct crypto_shash\n"); goto out;
}
desc = kmalloc(sizeof(*desc) + crypto_shash_descsize(tfm), GFP_KERNEL); if (!desc) {
pr_err("Unable to allocate struct shash_desc\n"); goto out;
}
desc->tfm = tfm;
ret = crypto_shash_init(desc); if (ret < 0) {
pr_err("crypto_shash_init() failed\n"); goto out;
}
ret = crypto_shash_update(desc, &chap->id, 1); if (ret < 0) {
pr_err("crypto_shash_update() failed for id\n"); goto out;
}
ret = crypto_shash_update(desc, (char *)&auth->password,
strlen(auth->password)); if (ret < 0) {
pr_err("crypto_shash_update() failed for password\n"); goto out;
}
ret = crypto_shash_finup(desc, chap->challenge,
chap->challenge_len, server_digest); if (ret < 0) {
pr_err("crypto_shash_finup() failed for challenge\n"); goto out;
}
bin2hex(response, server_digest, chap->digest_size);
pr_debug("[server] %s Server Digest: %s\n",
chap->digest_name, response);
if (memcmp(server_digest, client_digest, chap->digest_size) != 0) {
pr_debug("[server] %s Digests do not match!\n\n",
chap->digest_name); goto out;
} else
pr_debug("[server] %s Digests match, CHAP connection" " successful.\n\n", chap->digest_name); /* * One way authentication has succeeded, return now if mutual * authentication is not enabled.
*/ if (!auth->authenticate_target) {
auth_ret = 0; goto out;
} /* * Get CHAP_I.
*/
ret = extract_param(nr_in_ptr, "CHAP_I", 10, identifier, &type); if (ret == -ENOENT) {
pr_debug("Could not find CHAP_I. Initiator uses One way authentication.\n");
auth_ret = 0; goto out;
} if (ret < 0) {
pr_err("Could not find CHAP_I.\n"); goto out;
}
if (type == HEX)
ret = kstrtoul(&identifier[2], 0, &id); else
ret = kstrtoul(identifier, 0, &id);
if (ret < 0) {
pr_err("kstrtoul() failed for CHAP identifier: %d\n", ret); goto out;
} if (id > 255) {
pr_err("chap identifier: %lu greater than 255\n", id); goto out;
} /* * RFC 1994 says Identifier is no more than octet (8 bits).
*/
pr_debug("[server] Got CHAP_I=%lu\n", id); /* * Get CHAP_C.
*/ if (extract_param(nr_in_ptr, "CHAP_C", CHAP_CHALLENGE_STR_LEN,
initiatorchg, &type) < 0) {
pr_err("Could not find CHAP_C.\n"); goto out;
}
switch (type) { case HEX:
initiatorchg_len = DIV_ROUND_UP(strlen(initiatorchg), 2); if (!initiatorchg_len) {
pr_err("Unable to convert incoming challenge\n"); goto out;
} if (initiatorchg_len > 1024) {
pr_err("CHAP_C exceeds maximum binary size of 1024 bytes\n"); goto out;
}
if (hex2bin(initiatorchg_binhex, initiatorchg,
initiatorchg_len) < 0) {
pr_err("Malformed CHAP_C: invalid HEX\n"); goto out;
} break; case BASE64:
initiatorchg_len = chap_base64_decode(initiatorchg_binhex,
initiatorchg,
strlen(initiatorchg)); if (initiatorchg_len < 0) {
pr_err("Malformed CHAP_C: invalid BASE64\n"); goto out;
} if (!initiatorchg_len) {
pr_err("Unable to convert incoming challenge\n"); goto out;
} if (initiatorchg_len > 1024) {
pr_err("CHAP_C exceeds maximum binary size of 1024 bytes\n"); goto out;
} break; default:
pr_err("Could not find CHAP_C.\n"); goto out;
}
pr_debug("[server] Got CHAP_C=%s\n", initiatorchg); /* * During mutual authentication, the CHAP_C generated by the * initiator must not match the original CHAP_C generated by * the target.
*/ if (initiatorchg_len == chap->challenge_len &&
!memcmp(initiatorchg_binhex, chap->challenge,
initiatorchg_len)) {
pr_err("initiator CHAP_C matches target CHAP_C, failing" " login attempt\n"); goto out;
} /* * Generate CHAP_N and CHAP_R for mutual authentication.
*/
ret = crypto_shash_init(desc); if (ret < 0) {
pr_err("crypto_shash_init() failed\n"); goto out;
}
/* To handle both endiannesses */
id_as_uchar = id;
ret = crypto_shash_update(desc, &id_as_uchar, 1); if (ret < 0) {
pr_err("crypto_shash_update() failed for id\n"); goto out;
}
ret = crypto_shash_update(desc, auth->password_mutual,
strlen(auth->password_mutual)); if (ret < 0) {
pr_err("crypto_shash_update() failed for" " password_mutual\n"); goto out;
} /* * Convert received challenge to binary hex.
*/
ret = crypto_shash_finup(desc, initiatorchg_binhex, initiatorchg_len,
digest); if (ret < 0) {
pr_err("crypto_shash_finup() failed for ma challenge\n"); goto out;
}
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.