Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0-or-later
0002 /*******************************************************************************
0003  * This file houses the main functions for the iSCSI CHAP support
0004  *
0005  * (c) Copyright 2007-2013 Datera, Inc.
0006  *
0007  * Author: Nicholas A. Bellinger <nab@linux-iscsi.org>
0008  *
0009  ******************************************************************************/
0010 
0011 #include <crypto/hash.h>
0012 #include <linux/kernel.h>
0013 #include <linux/string.h>
0014 #include <linux/err.h>
0015 #include <linux/random.h>
0016 #include <linux/scatterlist.h>
0017 #include <target/iscsi/iscsi_target_core.h>
0018 #include "iscsi_target_nego.h"
0019 #include "iscsi_target_auth.h"
0020 
0021 static char *chap_get_digest_name(const int digest_type)
0022 {
0023     switch (digest_type) {
0024     case CHAP_DIGEST_MD5:
0025         return "md5";
0026     case CHAP_DIGEST_SHA1:
0027         return "sha1";
0028     case CHAP_DIGEST_SHA256:
0029         return "sha256";
0030     case CHAP_DIGEST_SHA3_256:
0031         return "sha3-256";
0032     default:
0033         return NULL;
0034     }
0035 }
0036 
0037 static int chap_gen_challenge(
0038     struct iscsit_conn *conn,
0039     int caller,
0040     char *c_str,
0041     unsigned int *c_len)
0042 {
0043     int ret;
0044     unsigned char *challenge_asciihex;
0045     struct iscsi_chap *chap = conn->auth_protocol;
0046 
0047     challenge_asciihex = kzalloc(chap->challenge_len * 2 + 1, GFP_KERNEL);
0048     if (!challenge_asciihex)
0049         return -ENOMEM;
0050 
0051     memset(chap->challenge, 0, MAX_CHAP_CHALLENGE_LEN);
0052 
0053     ret = get_random_bytes_wait(chap->challenge, chap->challenge_len);
0054     if (unlikely(ret))
0055         goto out;
0056 
0057     bin2hex(challenge_asciihex, chap->challenge,
0058                 chap->challenge_len);
0059     /*
0060      * Set CHAP_C, and copy the generated challenge into c_str.
0061      */
0062     *c_len += sprintf(c_str + *c_len, "CHAP_C=0x%s", challenge_asciihex);
0063     *c_len += 1;
0064 
0065     pr_debug("[%s] Sending CHAP_C=0x%s\n\n", (caller) ? "server" : "client",
0066             challenge_asciihex);
0067 
0068 out:
0069     kfree(challenge_asciihex);
0070     return ret;
0071 }
0072 
0073 static int chap_test_algorithm(const char *name)
0074 {
0075     struct crypto_shash *tfm;
0076 
0077     tfm = crypto_alloc_shash(name, 0, 0);
0078     if (IS_ERR(tfm))
0079         return -1;
0080 
0081     crypto_free_shash(tfm);
0082     return 0;
0083 }
0084 
0085 static int chap_check_algorithm(const char *a_str)
0086 {
0087     char *tmp, *orig, *token, *digest_name;
0088     long digest_type;
0089     int r = CHAP_DIGEST_UNKNOWN;
0090 
0091     tmp = kstrdup(a_str, GFP_KERNEL);
0092     if (!tmp) {
0093         pr_err("Memory allocation failed for CHAP_A temporary buffer\n");
0094         return CHAP_DIGEST_UNKNOWN;
0095     }
0096     orig = tmp;
0097 
0098     token = strsep(&tmp, "=");
0099     if (!token)
0100         goto out;
0101 
0102     if (strcmp(token, "CHAP_A")) {
0103         pr_err("Unable to locate CHAP_A key\n");
0104         goto out;
0105     }
0106     while (token) {
0107         token = strsep(&tmp, ",");
0108         if (!token)
0109             goto out;
0110 
0111         if (kstrtol(token, 10, &digest_type))
0112             continue;
0113 
0114         digest_name = chap_get_digest_name(digest_type);
0115         if (!digest_name)
0116             continue;
0117 
0118         pr_debug("Selected %s Algorithm\n", digest_name);
0119         if (chap_test_algorithm(digest_name) < 0) {
0120             pr_err("failed to allocate %s algo\n", digest_name);
0121         } else {
0122             r = digest_type;
0123             goto out;
0124         }
0125     }
0126 out:
0127     kfree(orig);
0128     return r;
0129 }
0130 
0131 static void chap_close(struct iscsit_conn *conn)
0132 {
0133     kfree(conn->auth_protocol);
0134     conn->auth_protocol = NULL;
0135 }
0136 
0137 static struct iscsi_chap *chap_server_open(
0138     struct iscsit_conn *conn,
0139     struct iscsi_node_auth *auth,
0140     const char *a_str,
0141     char *aic_str,
0142     unsigned int *aic_len)
0143 {
0144     int digest_type;
0145     struct iscsi_chap *chap;
0146 
0147     if (!(auth->naf_flags & NAF_USERID_SET) ||
0148         !(auth->naf_flags & NAF_PASSWORD_SET)) {
0149         pr_err("CHAP user or password not set for"
0150                 " Initiator ACL\n");
0151         return NULL;
0152     }
0153 
0154     conn->auth_protocol = kzalloc(sizeof(struct iscsi_chap), GFP_KERNEL);
0155     if (!conn->auth_protocol)
0156         return NULL;
0157 
0158     chap = conn->auth_protocol;
0159     digest_type = chap_check_algorithm(a_str);
0160     switch (digest_type) {
0161     case CHAP_DIGEST_MD5:
0162         chap->digest_size = MD5_SIGNATURE_SIZE;
0163         break;
0164     case CHAP_DIGEST_SHA1:
0165         chap->digest_size = SHA1_SIGNATURE_SIZE;
0166         break;
0167     case CHAP_DIGEST_SHA256:
0168         chap->digest_size = SHA256_SIGNATURE_SIZE;
0169         break;
0170     case CHAP_DIGEST_SHA3_256:
0171         chap->digest_size = SHA3_256_SIGNATURE_SIZE;
0172         break;
0173     case CHAP_DIGEST_UNKNOWN:
0174     default:
0175         pr_err("Unsupported CHAP_A value\n");
0176         chap_close(conn);
0177         return NULL;
0178     }
0179 
0180     chap->digest_name = chap_get_digest_name(digest_type);
0181 
0182     /* Tie the challenge length to the digest size */
0183     chap->challenge_len = chap->digest_size;
0184 
0185     pr_debug("[server] Got CHAP_A=%d\n", digest_type);
0186     *aic_len = sprintf(aic_str, "CHAP_A=%d", digest_type);
0187     *aic_len += 1;
0188     pr_debug("[server] Sending CHAP_A=%d\n", digest_type);
0189 
0190     /*
0191      * Set Identifier.
0192      */
0193     chap->id = conn->tpg->tpg_chap_id++;
0194     *aic_len += sprintf(aic_str + *aic_len, "CHAP_I=%d", chap->id);
0195     *aic_len += 1;
0196     pr_debug("[server] Sending CHAP_I=%d\n", chap->id);
0197     /*
0198      * Generate Challenge.
0199      */
0200     if (chap_gen_challenge(conn, 1, aic_str, aic_len) < 0) {
0201         chap_close(conn);
0202         return NULL;
0203     }
0204 
0205     return chap;
0206 }
0207 
0208 static const char base64_lookup_table[] =
0209     "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
0210 
0211 static int chap_base64_decode(u8 *dst, const char *src, size_t len)
0212 {
0213     int i, bits = 0, ac = 0;
0214     const char *p;
0215     u8 *cp = dst;
0216 
0217     for (i = 0; i < len; i++) {
0218         if (src[i] == '=')
0219             return cp - dst;
0220 
0221         p = strchr(base64_lookup_table, src[i]);
0222         if (p == NULL || src[i] == 0)
0223             return -2;
0224 
0225         ac <<= 6;
0226         ac += (p - base64_lookup_table);
0227         bits += 6;
0228         if (bits >= 8) {
0229             *cp++ = (ac >> (bits - 8)) & 0xff;
0230             ac &= ~(BIT(16) - BIT(bits - 8));
0231             bits -= 8;
0232         }
0233     }
0234     if (ac)
0235         return -1;
0236 
0237     return cp - dst;
0238 }
0239 
0240 static int chap_server_compute_hash(
0241     struct iscsit_conn *conn,
0242     struct iscsi_node_auth *auth,
0243     char *nr_in_ptr,
0244     char *nr_out_ptr,
0245     unsigned int *nr_out_len)
0246 {
0247     unsigned long id;
0248     unsigned char id_as_uchar;
0249     unsigned char type;
0250     unsigned char identifier[10], *initiatorchg = NULL;
0251     unsigned char *initiatorchg_binhex = NULL;
0252     unsigned char *digest = NULL;
0253     unsigned char *response = NULL;
0254     unsigned char *client_digest = NULL;
0255     unsigned char *server_digest = NULL;
0256     unsigned char chap_n[MAX_CHAP_N_SIZE], chap_r[MAX_RESPONSE_LENGTH];
0257     size_t compare_len;
0258     struct iscsi_chap *chap = conn->auth_protocol;
0259     struct crypto_shash *tfm = NULL;
0260     struct shash_desc *desc = NULL;
0261     int auth_ret = -1, ret, initiatorchg_len;
0262 
0263     digest = kzalloc(chap->digest_size, GFP_KERNEL);
0264     if (!digest) {
0265         pr_err("Unable to allocate the digest buffer\n");
0266         goto out;
0267     }
0268 
0269     response = kzalloc(chap->digest_size * 2 + 2, GFP_KERNEL);
0270     if (!response) {
0271         pr_err("Unable to allocate the response buffer\n");
0272         goto out;
0273     }
0274 
0275     client_digest = kzalloc(chap->digest_size, GFP_KERNEL);
0276     if (!client_digest) {
0277         pr_err("Unable to allocate the client_digest buffer\n");
0278         goto out;
0279     }
0280 
0281     server_digest = kzalloc(chap->digest_size, GFP_KERNEL);
0282     if (!server_digest) {
0283         pr_err("Unable to allocate the server_digest buffer\n");
0284         goto out;
0285     }
0286 
0287     memset(identifier, 0, 10);
0288     memset(chap_n, 0, MAX_CHAP_N_SIZE);
0289     memset(chap_r, 0, MAX_RESPONSE_LENGTH);
0290 
0291     initiatorchg = kzalloc(CHAP_CHALLENGE_STR_LEN, GFP_KERNEL);
0292     if (!initiatorchg) {
0293         pr_err("Unable to allocate challenge buffer\n");
0294         goto out;
0295     }
0296 
0297     initiatorchg_binhex = kzalloc(CHAP_CHALLENGE_STR_LEN, GFP_KERNEL);
0298     if (!initiatorchg_binhex) {
0299         pr_err("Unable to allocate initiatorchg_binhex buffer\n");
0300         goto out;
0301     }
0302     /*
0303      * Extract CHAP_N.
0304      */
0305     if (extract_param(nr_in_ptr, "CHAP_N", MAX_CHAP_N_SIZE, chap_n,
0306                 &type) < 0) {
0307         pr_err("Could not find CHAP_N.\n");
0308         goto out;
0309     }
0310     if (type == HEX) {
0311         pr_err("Could not find CHAP_N.\n");
0312         goto out;
0313     }
0314 
0315     /* Include the terminating NULL in the compare */
0316     compare_len = strlen(auth->userid) + 1;
0317     if (strncmp(chap_n, auth->userid, compare_len) != 0) {
0318         pr_err("CHAP_N values do not match!\n");
0319         goto out;
0320     }
0321     pr_debug("[server] Got CHAP_N=%s\n", chap_n);
0322     /*
0323      * Extract CHAP_R.
0324      */
0325     if (extract_param(nr_in_ptr, "CHAP_R", MAX_RESPONSE_LENGTH, chap_r,
0326                 &type) < 0) {
0327         pr_err("Could not find CHAP_R.\n");
0328         goto out;
0329     }
0330 
0331     switch (type) {
0332     case HEX:
0333         if (strlen(chap_r) != chap->digest_size * 2) {
0334             pr_err("Malformed CHAP_R\n");
0335             goto out;
0336         }
0337         if (hex2bin(client_digest, chap_r, chap->digest_size) < 0) {
0338             pr_err("Malformed CHAP_R: invalid HEX\n");
0339             goto out;
0340         }
0341         break;
0342     case BASE64:
0343         if (chap_base64_decode(client_digest, chap_r, strlen(chap_r)) !=
0344             chap->digest_size) {
0345             pr_err("Malformed CHAP_R: invalid BASE64\n");
0346             goto out;
0347         }
0348         break;
0349     default:
0350         pr_err("Could not find CHAP_R\n");
0351         goto out;
0352     }
0353 
0354     pr_debug("[server] Got CHAP_R=%s\n", chap_r);
0355 
0356     tfm = crypto_alloc_shash(chap->digest_name, 0, 0);
0357     if (IS_ERR(tfm)) {
0358         tfm = NULL;
0359         pr_err("Unable to allocate struct crypto_shash\n");
0360         goto out;
0361     }
0362 
0363     desc = kmalloc(sizeof(*desc) + crypto_shash_descsize(tfm), GFP_KERNEL);
0364     if (!desc) {
0365         pr_err("Unable to allocate struct shash_desc\n");
0366         goto out;
0367     }
0368 
0369     desc->tfm = tfm;
0370 
0371     ret = crypto_shash_init(desc);
0372     if (ret < 0) {
0373         pr_err("crypto_shash_init() failed\n");
0374         goto out;
0375     }
0376 
0377     ret = crypto_shash_update(desc, &chap->id, 1);
0378     if (ret < 0) {
0379         pr_err("crypto_shash_update() failed for id\n");
0380         goto out;
0381     }
0382 
0383     ret = crypto_shash_update(desc, (char *)&auth->password,
0384                   strlen(auth->password));
0385     if (ret < 0) {
0386         pr_err("crypto_shash_update() failed for password\n");
0387         goto out;
0388     }
0389 
0390     ret = crypto_shash_finup(desc, chap->challenge,
0391                  chap->challenge_len, server_digest);
0392     if (ret < 0) {
0393         pr_err("crypto_shash_finup() failed for challenge\n");
0394         goto out;
0395     }
0396 
0397     bin2hex(response, server_digest, chap->digest_size);
0398     pr_debug("[server] %s Server Digest: %s\n",
0399         chap->digest_name, response);
0400 
0401     if (memcmp(server_digest, client_digest, chap->digest_size) != 0) {
0402         pr_debug("[server] %s Digests do not match!\n\n",
0403             chap->digest_name);
0404         goto out;
0405     } else
0406         pr_debug("[server] %s Digests match, CHAP connection"
0407                 " successful.\n\n", chap->digest_name);
0408     /*
0409      * One way authentication has succeeded, return now if mutual
0410      * authentication is not enabled.
0411      */
0412     if (!auth->authenticate_target) {
0413         auth_ret = 0;
0414         goto out;
0415     }
0416     /*
0417      * Get CHAP_I.
0418      */
0419     ret = extract_param(nr_in_ptr, "CHAP_I", 10, identifier, &type);
0420     if (ret == -ENOENT) {
0421         pr_debug("Could not find CHAP_I. Initiator uses One way authentication.\n");
0422         auth_ret = 0;
0423         goto out;
0424     }
0425     if (ret < 0) {
0426         pr_err("Could not find CHAP_I.\n");
0427         goto out;
0428     }
0429 
0430     if (type == HEX)
0431         ret = kstrtoul(&identifier[2], 0, &id);
0432     else
0433         ret = kstrtoul(identifier, 0, &id);
0434 
0435     if (ret < 0) {
0436         pr_err("kstrtoul() failed for CHAP identifier: %d\n", ret);
0437         goto out;
0438     }
0439     if (id > 255) {
0440         pr_err("chap identifier: %lu greater than 255\n", id);
0441         goto out;
0442     }
0443     /*
0444      * RFC 1994 says Identifier is no more than octet (8 bits).
0445      */
0446     pr_debug("[server] Got CHAP_I=%lu\n", id);
0447     /*
0448      * Get CHAP_C.
0449      */
0450     if (extract_param(nr_in_ptr, "CHAP_C", CHAP_CHALLENGE_STR_LEN,
0451             initiatorchg, &type) < 0) {
0452         pr_err("Could not find CHAP_C.\n");
0453         goto out;
0454     }
0455 
0456     switch (type) {
0457     case HEX:
0458         initiatorchg_len = DIV_ROUND_UP(strlen(initiatorchg), 2);
0459         if (!initiatorchg_len) {
0460             pr_err("Unable to convert incoming challenge\n");
0461             goto out;
0462         }
0463         if (initiatorchg_len > 1024) {
0464             pr_err("CHAP_C exceeds maximum binary size of 1024 bytes\n");
0465             goto out;
0466         }
0467 
0468         if (hex2bin(initiatorchg_binhex, initiatorchg,
0469                 initiatorchg_len) < 0) {
0470             pr_err("Malformed CHAP_C: invalid HEX\n");
0471             goto out;
0472         }
0473         break;
0474     case BASE64:
0475         initiatorchg_len = chap_base64_decode(initiatorchg_binhex,
0476                               initiatorchg,
0477                               strlen(initiatorchg));
0478         if (initiatorchg_len < 0) {
0479             pr_err("Malformed CHAP_C: invalid BASE64\n");
0480             goto out;
0481         }
0482         if (!initiatorchg_len) {
0483             pr_err("Unable to convert incoming challenge\n");
0484             goto out;
0485         }
0486         if (initiatorchg_len > 1024) {
0487             pr_err("CHAP_C exceeds maximum binary size of 1024 bytes\n");
0488             goto out;
0489         }
0490         break;
0491     default:
0492         pr_err("Could not find CHAP_C.\n");
0493         goto out;
0494     }
0495 
0496     pr_debug("[server] Got CHAP_C=%s\n", initiatorchg);
0497     /*
0498      * During mutual authentication, the CHAP_C generated by the
0499      * initiator must not match the original CHAP_C generated by
0500      * the target.
0501      */
0502     if (initiatorchg_len == chap->challenge_len &&
0503                 !memcmp(initiatorchg_binhex, chap->challenge,
0504                 initiatorchg_len)) {
0505         pr_err("initiator CHAP_C matches target CHAP_C, failing"
0506                " login attempt\n");
0507         goto out;
0508     }
0509     /*
0510      * Generate CHAP_N and CHAP_R for mutual authentication.
0511      */
0512     ret = crypto_shash_init(desc);
0513     if (ret < 0) {
0514         pr_err("crypto_shash_init() failed\n");
0515         goto out;
0516     }
0517 
0518     /* To handle both endiannesses */
0519     id_as_uchar = id;
0520     ret = crypto_shash_update(desc, &id_as_uchar, 1);
0521     if (ret < 0) {
0522         pr_err("crypto_shash_update() failed for id\n");
0523         goto out;
0524     }
0525 
0526     ret = crypto_shash_update(desc, auth->password_mutual,
0527                   strlen(auth->password_mutual));
0528     if (ret < 0) {
0529         pr_err("crypto_shash_update() failed for"
0530                 " password_mutual\n");
0531         goto out;
0532     }
0533     /*
0534      * Convert received challenge to binary hex.
0535      */
0536     ret = crypto_shash_finup(desc, initiatorchg_binhex, initiatorchg_len,
0537                  digest);
0538     if (ret < 0) {
0539         pr_err("crypto_shash_finup() failed for ma challenge\n");
0540         goto out;
0541     }
0542 
0543     /*
0544      * Generate CHAP_N and CHAP_R.
0545      */
0546     *nr_out_len = sprintf(nr_out_ptr, "CHAP_N=%s", auth->userid_mutual);
0547     *nr_out_len += 1;
0548     pr_debug("[server] Sending CHAP_N=%s\n", auth->userid_mutual);
0549     /*
0550      * Convert response from binary hex to ascii hext.
0551      */
0552     bin2hex(response, digest, chap->digest_size);
0553     *nr_out_len += sprintf(nr_out_ptr + *nr_out_len, "CHAP_R=0x%s",
0554             response);
0555     *nr_out_len += 1;
0556     pr_debug("[server] Sending CHAP_R=0x%s\n", response);
0557     auth_ret = 0;
0558 out:
0559     kfree_sensitive(desc);
0560     if (tfm)
0561         crypto_free_shash(tfm);
0562     kfree(initiatorchg);
0563     kfree(initiatorchg_binhex);
0564     kfree(digest);
0565     kfree(response);
0566     kfree(server_digest);
0567     kfree(client_digest);
0568     return auth_ret;
0569 }
0570 
0571 u32 chap_main_loop(
0572     struct iscsit_conn *conn,
0573     struct iscsi_node_auth *auth,
0574     char *in_text,
0575     char *out_text,
0576     int *in_len,
0577     int *out_len)
0578 {
0579     struct iscsi_chap *chap = conn->auth_protocol;
0580 
0581     if (!chap) {
0582         chap = chap_server_open(conn, auth, in_text, out_text, out_len);
0583         if (!chap)
0584             return 2;
0585         chap->chap_state = CHAP_STAGE_SERVER_AIC;
0586         return 0;
0587     } else if (chap->chap_state == CHAP_STAGE_SERVER_AIC) {
0588         convert_null_to_semi(in_text, *in_len);
0589         if (chap_server_compute_hash(conn, auth, in_text, out_text,
0590                 out_len) < 0) {
0591             chap_close(conn);
0592             return 2;
0593         }
0594         if (auth->authenticate_target)
0595             chap->chap_state = CHAP_STAGE_SERVER_NR;
0596         else
0597             *out_len = 0;
0598         chap_close(conn);
0599         return 1;
0600     }
0601 
0602     return 2;
0603 }