RFC7143 allows both Base64 and Hex encoding for CHAP binary entities like Challenge and Response. Currently Linux iSCSI target supports only Hex encoding. This patch adds a support of Base64 encoded CHAP Challenge and CHAP Response that are required for CHAP tests in Windows HLK. Signed-off-by: Dmitry Bogdanov <d.bogdanov@xxxxxxxxx> --- drivers/target/iscsi/iscsi_target_auth.c | 114 ++++++++++++++++++----- drivers/target/iscsi/iscsi_target_nego.c | 3 + drivers/target/iscsi/iscsi_target_nego.h | 1 + 3 files changed, 94 insertions(+), 24 deletions(-) diff --git a/drivers/target/iscsi/iscsi_target_auth.c b/drivers/target/iscsi/iscsi_target_auth.c index 6e5611d8f51b..a5b72968f356 100644 --- a/drivers/target/iscsi/iscsi_target_auth.c +++ b/drivers/target/iscsi/iscsi_target_auth.c @@ -205,6 +205,38 @@ static struct iscsi_chap *chap_server_open( return chap; } +static const char base64_lookup_table[] = + "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; + +static int chap_base64_decode(u8 *dst, const char *src, size_t len) +{ + int i, bits = 0, ac = 0; + const char *p; + u8 *cp = dst; + + for (i = 0; i < len; i++) { + if (src[i] == '=') + return cp - dst; + + p = strchr(base64_lookup_table, src[i]); + if (p == NULL || src[i] == 0) + return -2; + + ac <<= 6; + ac += (p - base64_lookup_table); + bits += 6; + if (bits >= 8) { + *cp++ = (ac >> (bits - 8)) & 0xff; + ac &= ~(BIT(16) - BIT(bits - 8)); + bits -= 8; + } + } + if (ac) + return -1; + + return cp - dst; +} + static int chap_server_compute_hash( struct iscsit_conn *conn, struct iscsi_node_auth *auth, @@ -295,16 +327,27 @@ static int chap_server_compute_hash( pr_err("Could not find CHAP_R.\n"); goto out; } - if (type != HEX) { - pr_err("Could not find CHAP_R.\n"); - goto out; - } - 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\n"); + + 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; } @@ -404,23 +447,46 @@ static int chap_server_compute_hash( goto out; } - if (type != HEX) { + 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; } - 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\n"); - goto out; - } + pr_debug("[server] Got CHAP_C=%s\n", initiatorchg); /* * During mutual authentication, the CHAP_C generated by the diff --git a/drivers/target/iscsi/iscsi_target_nego.c b/drivers/target/iscsi/iscsi_target_nego.c index fb93a1173954..767646438391 100644 --- a/drivers/target/iscsi/iscsi_target_nego.c +++ b/drivers/target/iscsi/iscsi_target_nego.c @@ -76,6 +76,9 @@ int extract_param( if (*ptr == '0' && (*(ptr+1) == 'x' || *(ptr+1) == 'X')) { ptr += 2; /* skip 0x */ *type = HEX; + } else if (*ptr == '0' && (*(ptr+1) == 'b' || *(ptr+1) == 'B')) { + ptr += 2; /* skip 0b */ + *type = BASE64; } else *type = DECIMAL; diff --git a/drivers/target/iscsi/iscsi_target_nego.h b/drivers/target/iscsi/iscsi_target_nego.h index ed30b9ee75e6..21d3cab90d08 100644 --- a/drivers/target/iscsi/iscsi_target_nego.h +++ b/drivers/target/iscsi/iscsi_target_nego.h @@ -4,6 +4,7 @@ #define DECIMAL 0 #define HEX 1 +#define BASE64 2 struct iscsit_conn; struct iscsi_login; -- 2.25.1