linux/drivers/target/iscsi/iscsi_target_auth.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0-or-later
   2/*******************************************************************************
   3 * This file houses the main functions for the iSCSI CHAP support
   4 *
   5 * (c) Copyright 2007-2013 Datera, Inc.
   6 *
   7 * Author: Nicholas A. Bellinger <nab@linux-iscsi.org>
   8 *
   9 ******************************************************************************/
  10
  11#include <crypto/hash.h>
  12#include <linux/kernel.h>
  13#include <linux/string.h>
  14#include <linux/err.h>
  15#include <linux/random.h>
  16#include <linux/scatterlist.h>
  17#include <target/iscsi/iscsi_target_core.h>
  18#include "iscsi_target_nego.h"
  19#include "iscsi_target_auth.h"
  20
  21static char *chap_get_digest_name(const int digest_type)
  22{
  23        switch (digest_type) {
  24        case CHAP_DIGEST_MD5:
  25                return "md5";
  26        case CHAP_DIGEST_SHA1:
  27                return "sha1";
  28        case CHAP_DIGEST_SHA256:
  29                return "sha256";
  30        case CHAP_DIGEST_SHA3_256:
  31                return "sha3-256";
  32        default:
  33                return NULL;
  34        }
  35}
  36
  37static int chap_gen_challenge(
  38        struct iscsi_conn *conn,
  39        int caller,
  40        char *c_str,
  41        unsigned int *c_len)
  42{
  43        int ret;
  44        unsigned char *challenge_asciihex;
  45        struct iscsi_chap *chap = conn->auth_protocol;
  46
  47        challenge_asciihex = kzalloc(chap->challenge_len * 2 + 1, GFP_KERNEL);
  48        if (!challenge_asciihex)
  49                return -ENOMEM;
  50
  51        memset(chap->challenge, 0, MAX_CHAP_CHALLENGE_LEN);
  52
  53        ret = get_random_bytes_wait(chap->challenge, chap->challenge_len);
  54        if (unlikely(ret))
  55                goto out;
  56
  57        bin2hex(challenge_asciihex, chap->challenge,
  58                                chap->challenge_len);
  59        /*
  60         * Set CHAP_C, and copy the generated challenge into c_str.
  61         */
  62        *c_len += sprintf(c_str + *c_len, "CHAP_C=0x%s", challenge_asciihex);
  63        *c_len += 1;
  64
  65        pr_debug("[%s] Sending CHAP_C=0x%s\n\n", (caller) ? "server" : "client",
  66                        challenge_asciihex);
  67
  68out:
  69        kfree(challenge_asciihex);
  70        return ret;
  71}
  72
  73static int chap_test_algorithm(const char *name)
  74{
  75        struct crypto_shash *tfm;
  76
  77        tfm = crypto_alloc_shash(name, 0, 0);
  78        if (IS_ERR(tfm))
  79                return -1;
  80
  81        crypto_free_shash(tfm);
  82        return 0;
  83}
  84
  85static int chap_check_algorithm(const char *a_str)
  86{
  87        char *tmp, *orig, *token, *digest_name;
  88        long digest_type;
  89        int r = CHAP_DIGEST_UNKNOWN;
  90
  91        tmp = kstrdup(a_str, GFP_KERNEL);
  92        if (!tmp) {
  93                pr_err("Memory allocation failed for CHAP_A temporary buffer\n");
  94                return CHAP_DIGEST_UNKNOWN;
  95        }
  96        orig = tmp;
  97
  98        token = strsep(&tmp, "=");
  99        if (!token)
 100                goto out;
 101
 102        if (strcmp(token, "CHAP_A")) {
 103                pr_err("Unable to locate CHAP_A key\n");
 104                goto out;
 105        }
 106        while (token) {
 107                token = strsep(&tmp, ",");
 108                if (!token)
 109                        goto out;
 110
 111                if (kstrtol(token, 10, &digest_type))
 112                        continue;
 113
 114                digest_name = chap_get_digest_name(digest_type);
 115                if (!digest_name)
 116                        continue;
 117
 118                pr_debug("Selected %s Algorithm\n", digest_name);
 119                if (chap_test_algorithm(digest_name) < 0) {
 120                        pr_err("failed to allocate %s algo\n", digest_name);
 121                } else {
 122                        r = digest_type;
 123                        goto out;
 124                }
 125        }
 126out:
 127        kfree(orig);
 128        return r;
 129}
 130
 131static void chap_close(struct iscsi_conn *conn)
 132{
 133        kfree(conn->auth_protocol);
 134        conn->auth_protocol = NULL;
 135}
 136
 137static struct iscsi_chap *chap_server_open(
 138        struct iscsi_conn *conn,
 139        struct iscsi_node_auth *auth,
 140        const char *a_str,
 141        char *aic_str,
 142        unsigned int *aic_len)
 143{
 144        int digest_type;
 145        struct iscsi_chap *chap;
 146
 147        if (!(auth->naf_flags & NAF_USERID_SET) ||
 148            !(auth->naf_flags & NAF_PASSWORD_SET)) {
 149                pr_err("CHAP user or password not set for"
 150                                " Initiator ACL\n");
 151                return NULL;
 152        }
 153
 154        conn->auth_protocol = kzalloc(sizeof(struct iscsi_chap), GFP_KERNEL);
 155        if (!conn->auth_protocol)
 156                return NULL;
 157
 158        chap = conn->auth_protocol;
 159        digest_type = chap_check_algorithm(a_str);
 160        switch (digest_type) {
 161        case CHAP_DIGEST_MD5:
 162                chap->digest_size = MD5_SIGNATURE_SIZE;
 163                break;
 164        case CHAP_DIGEST_SHA1:
 165                chap->digest_size = SHA1_SIGNATURE_SIZE;
 166                break;
 167        case CHAP_DIGEST_SHA256:
 168                chap->digest_size = SHA256_SIGNATURE_SIZE;
 169                break;
 170        case CHAP_DIGEST_SHA3_256:
 171                chap->digest_size = SHA3_256_SIGNATURE_SIZE;
 172                break;
 173        case CHAP_DIGEST_UNKNOWN:
 174        default:
 175                pr_err("Unsupported CHAP_A value\n");
 176                chap_close(conn);
 177                return NULL;
 178        }
 179
 180        chap->digest_name = chap_get_digest_name(digest_type);
 181
 182        /* Tie the challenge length to the digest size */
 183        chap->challenge_len = chap->digest_size;
 184
 185        pr_debug("[server] Got CHAP_A=%d\n", digest_type);
 186        *aic_len = sprintf(aic_str, "CHAP_A=%d", digest_type);
 187        *aic_len += 1;
 188        pr_debug("[server] Sending CHAP_A=%d\n", digest_type);
 189
 190        /*
 191         * Set Identifier.
 192         */
 193        chap->id = conn->tpg->tpg_chap_id++;
 194        *aic_len += sprintf(aic_str + *aic_len, "CHAP_I=%d", chap->id);
 195        *aic_len += 1;
 196        pr_debug("[server] Sending CHAP_I=%d\n", chap->id);
 197        /*
 198         * Generate Challenge.
 199         */
 200        if (chap_gen_challenge(conn, 1, aic_str, aic_len) < 0) {
 201                chap_close(conn);
 202                return NULL;
 203        }
 204
 205        return chap;
 206}
 207
 208static int chap_server_compute_hash(
 209        struct iscsi_conn *conn,
 210        struct iscsi_node_auth *auth,
 211        char *nr_in_ptr,
 212        char *nr_out_ptr,
 213        unsigned int *nr_out_len)
 214{
 215        unsigned long id;
 216        unsigned char id_as_uchar;
 217        unsigned char type;
 218        unsigned char identifier[10], *initiatorchg = NULL;
 219        unsigned char *initiatorchg_binhex = NULL;
 220        unsigned char *digest = NULL;
 221        unsigned char *response = NULL;
 222        unsigned char *client_digest = NULL;
 223        unsigned char *server_digest = NULL;
 224        unsigned char chap_n[MAX_CHAP_N_SIZE], chap_r[MAX_RESPONSE_LENGTH];
 225        size_t compare_len;
 226        struct iscsi_chap *chap = conn->auth_protocol;
 227        struct crypto_shash *tfm = NULL;
 228        struct shash_desc *desc = NULL;
 229        int auth_ret = -1, ret, initiatorchg_len;
 230
 231        digest = kzalloc(chap->digest_size, GFP_KERNEL);
 232        if (!digest) {
 233                pr_err("Unable to allocate the digest buffer\n");
 234                goto out;
 235        }
 236
 237        response = kzalloc(chap->digest_size * 2 + 2, GFP_KERNEL);
 238        if (!response) {
 239                pr_err("Unable to allocate the response buffer\n");
 240                goto out;
 241        }
 242
 243        client_digest = kzalloc(chap->digest_size, GFP_KERNEL);
 244        if (!client_digest) {
 245                pr_err("Unable to allocate the client_digest buffer\n");
 246                goto out;
 247        }
 248
 249        server_digest = kzalloc(chap->digest_size, GFP_KERNEL);
 250        if (!server_digest) {
 251                pr_err("Unable to allocate the server_digest buffer\n");
 252                goto out;
 253        }
 254
 255        memset(identifier, 0, 10);
 256        memset(chap_n, 0, MAX_CHAP_N_SIZE);
 257        memset(chap_r, 0, MAX_RESPONSE_LENGTH);
 258
 259        initiatorchg = kzalloc(CHAP_CHALLENGE_STR_LEN, GFP_KERNEL);
 260        if (!initiatorchg) {
 261                pr_err("Unable to allocate challenge buffer\n");
 262                goto out;
 263        }
 264
 265        initiatorchg_binhex = kzalloc(CHAP_CHALLENGE_STR_LEN, GFP_KERNEL);
 266        if (!initiatorchg_binhex) {
 267                pr_err("Unable to allocate initiatorchg_binhex buffer\n");
 268                goto out;
 269        }
 270        /*
 271         * Extract CHAP_N.
 272         */
 273        if (extract_param(nr_in_ptr, "CHAP_N", MAX_CHAP_N_SIZE, chap_n,
 274                                &type) < 0) {
 275                pr_err("Could not find CHAP_N.\n");
 276                goto out;
 277        }
 278        if (type == HEX) {
 279                pr_err("Could not find CHAP_N.\n");
 280                goto out;
 281        }
 282
 283        /* Include the terminating NULL in the compare */
 284        compare_len = strlen(auth->userid) + 1;
 285        if (strncmp(chap_n, auth->userid, compare_len) != 0) {
 286                pr_err("CHAP_N values do not match!\n");
 287                goto out;
 288        }
 289        pr_debug("[server] Got CHAP_N=%s\n", chap_n);
 290        /*
 291         * Extract CHAP_R.
 292         */
 293        if (extract_param(nr_in_ptr, "CHAP_R", MAX_RESPONSE_LENGTH, chap_r,
 294                                &type) < 0) {
 295                pr_err("Could not find CHAP_R.\n");
 296                goto out;
 297        }
 298        if (type != HEX) {
 299                pr_err("Could not find CHAP_R.\n");
 300                goto out;
 301        }
 302        if (strlen(chap_r) != chap->digest_size * 2) {
 303                pr_err("Malformed CHAP_R\n");
 304                goto out;
 305        }
 306        if (hex2bin(client_digest, chap_r, chap->digest_size) < 0) {
 307                pr_err("Malformed CHAP_R\n");
 308                goto out;
 309        }
 310
 311        pr_debug("[server] Got CHAP_R=%s\n", chap_r);
 312
 313        tfm = crypto_alloc_shash(chap->digest_name, 0, 0);
 314        if (IS_ERR(tfm)) {
 315                tfm = NULL;
 316                pr_err("Unable to allocate struct crypto_shash\n");
 317                goto out;
 318        }
 319
 320        desc = kmalloc(sizeof(*desc) + crypto_shash_descsize(tfm), GFP_KERNEL);
 321        if (!desc) {
 322                pr_err("Unable to allocate struct shash_desc\n");
 323                goto out;
 324        }
 325
 326        desc->tfm = tfm;
 327
 328        ret = crypto_shash_init(desc);
 329        if (ret < 0) {
 330                pr_err("crypto_shash_init() failed\n");
 331                goto out;
 332        }
 333
 334        ret = crypto_shash_update(desc, &chap->id, 1);
 335        if (ret < 0) {
 336                pr_err("crypto_shash_update() failed for id\n");
 337                goto out;
 338        }
 339
 340        ret = crypto_shash_update(desc, (char *)&auth->password,
 341                                  strlen(auth->password));
 342        if (ret < 0) {
 343                pr_err("crypto_shash_update() failed for password\n");
 344                goto out;
 345        }
 346
 347        ret = crypto_shash_finup(desc, chap->challenge,
 348                                 chap->challenge_len, server_digest);
 349        if (ret < 0) {
 350                pr_err("crypto_shash_finup() failed for challenge\n");
 351                goto out;
 352        }
 353
 354        bin2hex(response, server_digest, chap->digest_size);
 355        pr_debug("[server] %s Server Digest: %s\n",
 356                chap->digest_name, response);
 357
 358        if (memcmp(server_digest, client_digest, chap->digest_size) != 0) {
 359                pr_debug("[server] %s Digests do not match!\n\n",
 360                        chap->digest_name);
 361                goto out;
 362        } else
 363                pr_debug("[server] %s Digests match, CHAP connection"
 364                                " successful.\n\n", chap->digest_name);
 365        /*
 366         * One way authentication has succeeded, return now if mutual
 367         * authentication is not enabled.
 368         */
 369        if (!auth->authenticate_target) {
 370                auth_ret = 0;
 371                goto out;
 372        }
 373        /*
 374         * Get CHAP_I.
 375         */
 376        if (extract_param(nr_in_ptr, "CHAP_I", 10, identifier, &type) < 0) {
 377                pr_err("Could not find CHAP_I.\n");
 378                goto out;
 379        }
 380
 381        if (type == HEX)
 382                ret = kstrtoul(&identifier[2], 0, &id);
 383        else
 384                ret = kstrtoul(identifier, 0, &id);
 385
 386        if (ret < 0) {
 387                pr_err("kstrtoul() failed for CHAP identifier: %d\n", ret);
 388                goto out;
 389        }
 390        if (id > 255) {
 391                pr_err("chap identifier: %lu greater than 255\n", id);
 392                goto out;
 393        }
 394        /*
 395         * RFC 1994 says Identifier is no more than octet (8 bits).
 396         */
 397        pr_debug("[server] Got CHAP_I=%lu\n", id);
 398        /*
 399         * Get CHAP_C.
 400         */
 401        if (extract_param(nr_in_ptr, "CHAP_C", CHAP_CHALLENGE_STR_LEN,
 402                        initiatorchg, &type) < 0) {
 403                pr_err("Could not find CHAP_C.\n");
 404                goto out;
 405        }
 406
 407        if (type != HEX) {
 408                pr_err("Could not find CHAP_C.\n");
 409                goto out;
 410        }
 411        initiatorchg_len = DIV_ROUND_UP(strlen(initiatorchg), 2);
 412        if (!initiatorchg_len) {
 413                pr_err("Unable to convert incoming challenge\n");
 414                goto out;
 415        }
 416        if (initiatorchg_len > 1024) {
 417                pr_err("CHAP_C exceeds maximum binary size of 1024 bytes\n");
 418                goto out;
 419        }
 420        if (hex2bin(initiatorchg_binhex, initiatorchg, initiatorchg_len) < 0) {
 421                pr_err("Malformed CHAP_C\n");
 422                goto out;
 423        }
 424        pr_debug("[server] Got CHAP_C=%s\n", initiatorchg);
 425        /*
 426         * During mutual authentication, the CHAP_C generated by the
 427         * initiator must not match the original CHAP_C generated by
 428         * the target.
 429         */
 430        if (initiatorchg_len == chap->challenge_len &&
 431                                !memcmp(initiatorchg_binhex, chap->challenge,
 432                                initiatorchg_len)) {
 433                pr_err("initiator CHAP_C matches target CHAP_C, failing"
 434                       " login attempt\n");
 435                goto out;
 436        }
 437        /*
 438         * Generate CHAP_N and CHAP_R for mutual authentication.
 439         */
 440        ret = crypto_shash_init(desc);
 441        if (ret < 0) {
 442                pr_err("crypto_shash_init() failed\n");
 443                goto out;
 444        }
 445
 446        /* To handle both endiannesses */
 447        id_as_uchar = id;
 448        ret = crypto_shash_update(desc, &id_as_uchar, 1);
 449        if (ret < 0) {
 450                pr_err("crypto_shash_update() failed for id\n");
 451                goto out;
 452        }
 453
 454        ret = crypto_shash_update(desc, auth->password_mutual,
 455                                  strlen(auth->password_mutual));
 456        if (ret < 0) {
 457                pr_err("crypto_shash_update() failed for"
 458                                " password_mutual\n");
 459                goto out;
 460        }
 461        /*
 462         * Convert received challenge to binary hex.
 463         */
 464        ret = crypto_shash_finup(desc, initiatorchg_binhex, initiatorchg_len,
 465                                 digest);
 466        if (ret < 0) {
 467                pr_err("crypto_shash_finup() failed for ma challenge\n");
 468                goto out;
 469        }
 470
 471        /*
 472         * Generate CHAP_N and CHAP_R.
 473         */
 474        *nr_out_len = sprintf(nr_out_ptr, "CHAP_N=%s", auth->userid_mutual);
 475        *nr_out_len += 1;
 476        pr_debug("[server] Sending CHAP_N=%s\n", auth->userid_mutual);
 477        /*
 478         * Convert response from binary hex to ascii hext.
 479         */
 480        bin2hex(response, digest, chap->digest_size);
 481        *nr_out_len += sprintf(nr_out_ptr + *nr_out_len, "CHAP_R=0x%s",
 482                        response);
 483        *nr_out_len += 1;
 484        pr_debug("[server] Sending CHAP_R=0x%s\n", response);
 485        auth_ret = 0;
 486out:
 487        kfree_sensitive(desc);
 488        if (tfm)
 489                crypto_free_shash(tfm);
 490        kfree(initiatorchg);
 491        kfree(initiatorchg_binhex);
 492        kfree(digest);
 493        kfree(response);
 494        kfree(server_digest);
 495        kfree(client_digest);
 496        return auth_ret;
 497}
 498
 499u32 chap_main_loop(
 500        struct iscsi_conn *conn,
 501        struct iscsi_node_auth *auth,
 502        char *in_text,
 503        char *out_text,
 504        int *in_len,
 505        int *out_len)
 506{
 507        struct iscsi_chap *chap = conn->auth_protocol;
 508
 509        if (!chap) {
 510                chap = chap_server_open(conn, auth, in_text, out_text, out_len);
 511                if (!chap)
 512                        return 2;
 513                chap->chap_state = CHAP_STAGE_SERVER_AIC;
 514                return 0;
 515        } else if (chap->chap_state == CHAP_STAGE_SERVER_AIC) {
 516                convert_null_to_semi(in_text, *in_len);
 517                if (chap_server_compute_hash(conn, auth, in_text, out_text,
 518                                out_len) < 0) {
 519                        chap_close(conn);
 520                        return 2;
 521                }
 522                if (auth->authenticate_target)
 523                        chap->chap_state = CHAP_STAGE_SERVER_NR;
 524                else
 525                        *out_len = 0;
 526                chap_close(conn);
 527                return 1;
 528        }
 529
 530        return 2;
 531}
 532