]> git.ipfire.org Git - thirdparty/linux.git/commitdiff
scsi: target: iscsi: Support base64 in CHAP
authorDmitry Bogdanov <d.bogdanov@yadro.com>
Mon, 18 Jul 2022 15:25:53 +0000 (18:25 +0300)
committerMartin K. Petersen <martin.petersen@oracle.com>
Wed, 27 Jul 2022 02:13:28 +0000 (22:13 -0400)
RFC7143 allows both Base64 and Hex encoding for CHAP binary entities like
Challenge and Response. Currently the Linux iSCSI target supports only Hex
encoding.

Add support for Base64 encoded CHAP Challenge and CHAP Response required
for CHAP tests in Windows HLK.

Link: https://lore.kernel.org/r/20220718152555.17084-3-d.bogdanov@yadro.com
Reviewed-by: Mike Christie <michael.christie@oracle.com>
Signed-off-by: Dmitry Bogdanov <d.bogdanov@yadro.com>
Signed-off-by: Martin K. Petersen <martin.petersen@oracle.com>
drivers/target/iscsi/iscsi_target_auth.c
drivers/target/iscsi/iscsi_target_nego.c
drivers/target/iscsi/iscsi_target_nego.h

index 6e5611d8f51bf74e49f00c8f11d3fbc89e87c5c8..a5b72968f356a7ebdba4b4851f204574406a4118 100644 (file)
@@ -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
index fb93a1173954b73ad848ad1270cb1929c5647b10..767646438391830f8c637b22470b16fb3fbb9bf7 100644 (file)
@@ -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;
 
index ed30b9ee75e67bf0a191762d915b0a8a8bfb6879..21d3cab90d086492cde9c1d7e9642142974145e4 100644 (file)
@@ -4,6 +4,7 @@
 
 #define DECIMAL         0
 #define HEX             1
+#define BASE64          2
 
 struct iscsit_conn;
 struct iscsi_login;