Skip to content

Commit

Permalink
iscsi-scst: Add SHA256 and SHA3-256 support to CHAP
Browse files Browse the repository at this point in the history
Use the kernel userspace AL_ALG API to access additional hash
functions "sha256" and "sha3-256".

If configured for CHAP, on iSCSI login the client will present an
ordered list of desired algorithms.  During this negotiation, if
the client requests SHA256 or SHA3-256 we verify that the kernel
supports the algorithm before agreeing to use it.
  • Loading branch information
bmeagherix authored and lnocturno committed Feb 3, 2025
1 parent 6c5e8ad commit 146d79e
Show file tree
Hide file tree
Showing 4 changed files with 207 additions and 1 deletion.
2 changes: 1 addition & 1 deletion iscsi-scst/usr/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ cc-option = $(shell if $(CC) $(1) -Werror -S -o /dev/null -xc /dev/null \

SRCS_D = iscsid.c iscsi_scstd.c conn.c session.c target.c message.c ctldev.c \
log.c chap.c event.c param.c config.c isns.c md5.c sha1.c \
misc.c
misc.c af_alg.c
OBJS_D = $(SRCS_D:.c=.o)

SRCS_ADM = iscsi_adm.c param.c
Expand Down
84 changes: 84 additions & 0 deletions iscsi-scst/usr/af_alg.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,84 @@
// SPDX-License-Identifier: GPL-2.0-only
/*
* af_alg - wrapper functions to call AF_ALG hash algorithms.
*
* Copyright (C) 2025 Brian Meagher <[email protected]>
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation, version 2
* of the License.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*/

#include "af_alg.h"

#include <sys/socket.h>
#include <linux/if_alg.h>
#include <string.h>
#include <sys/param.h>
#include <stdbool.h>

int af_alg_init(const char *algorithm)
{
int sockfd, datafd, algo_len;
struct sockaddr_alg sa = {
.salg_family = AF_ALG,
.salg_type = "hash",
};

algo_len = strlen(algorithm);
if (algo_len >= sizeof(sa.salg_name))
return -1;

sockfd = socket(AF_ALG, SOCK_SEQPACKET, 0);
if (sockfd == -1)
return -1;

/* +1 for null-terminator */
memcpy(sa.salg_name, algorithm, algo_len + 1);

if (bind(sockfd, (struct sockaddr *)&sa, sizeof(sa)) == -1) {
close(sockfd);
return -1;
}

datafd = accept(sockfd, NULL, 0);
if (datafd < 0) {
close(sockfd);
return -1;
}
close(sockfd);
return datafd;
}

void af_alg_update(int datafd, const void *data_in, size_t len)
{
send(datafd, data_in, len, MSG_MORE);
}

ssize_t af_alg_final(int datafd, void *out, size_t len)
{
char buffer[1024];
ssize_t bytes;

send(datafd, NULL, 0, 0);

bytes = recv(datafd, buffer, sizeof(buffer), 0);
memcpy(out, buffer, MIN(len, bytes));
return bytes;
}

bool af_alg_supported(char *alg)
{
int sock = af_alg_init(alg);

if (sock < 0)
return false;
close(sock);
return true;
}
30 changes: 30 additions & 0 deletions iscsi-scst/usr/af_alg.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
/* SPDX-License-Identifier: GPL-2.0-only */
/*
* Copyright (C) 2025 Brian Meagher <[email protected]>
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation, version 2
* of the License.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*/

#ifndef SCST_AF_ALG_H
#define SCST_AF_ALG_H

#include <unistd.h>
#include <stdbool.h>

#define SCST_AF_ALG_SHA256_NAME "sha256"
#define SCST_AF_ALG_SHA3_256_NAME "sha3-256"

int af_alg_init(const char *algorithm);
void af_alg_update(int datafd, const void *data_in, size_t len);
ssize_t af_alg_final(int datafd, void *out, size_t len);
bool af_alg_supported(char *alg);

#endif
92 changes: 92 additions & 0 deletions iscsi-scst/usr/chap.c
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,8 @@
#include <unistd.h>
#include "sha1.h"
#include "md5.h"
#include "af_alg.h"
#include <sys/param.h>

#include "iscsid.h"

Expand All @@ -39,9 +41,13 @@

#define CHAP_DIGEST_ALG_MD5 5
#define CHAP_DIGEST_ALG_SHA1 6
#define CHAP_DIGEST_ALG_SHA256 7
#define CHAP_DIGEST_ALG_SHA3_256 8

#define CHAP_MD5_DIGEST_LEN 16
#define CHAP_SHA1_DIGEST_LEN 20
#define CHAP_SHA256_DIGEST_LEN 32
#define CHAP_SHA3_256_DIGEST_LEN 32

#define CHAP_INITIATOR_ERROR -1
#define CHAP_AUTH_ERROR -2
Expand Down Expand Up @@ -338,6 +344,49 @@ static inline void chap_calc_digest_sha1(char chap_id, const char *secret, int s
sha1_final(&ctx, digest);
}

static inline void
chap_calc_digest_af_alg(char *alg, char chap_id,
const char *secret, int secret_len,
const u8 *challenge, int challenge_len,
u8 *digest, int digest_len)
{
int datafd = af_alg_init(alg);
char buffer[1024];
int bytes;

if (datafd < 0) {
log_error("CHAP unable to use %s algorithm", alg);
return;
}

af_alg_update(datafd, &chap_id, 1);
af_alg_update(datafd, secret, secret_len);
af_alg_update(datafd, challenge, challenge_len);
bytes = af_alg_final(datafd, buffer, sizeof(buffer));
close(datafd);
memcpy(digest, buffer, MIN(bytes, digest_len));
}

static inline void
chap_calc_digest_sha256(char chap_id, const char *secret, int secret_len,
const u8 *challenge, int challenge_len, u8 *digest)
{
chap_calc_digest_af_alg(SCST_AF_ALG_SHA256_NAME,
chap_id, secret, secret_len,
challenge, challenge_len,
digest, CHAP_SHA256_DIGEST_LEN);
}

static inline void
chap_calc_digest_sha3_256(char chap_id, const char *secret, int secret_len,
const u8 *challenge, int challenge_len, u8 *digest)
{
chap_calc_digest_af_alg(SCST_AF_ALG_SHA3_256_NAME,
chap_id, secret, secret_len,
challenge, challenge_len,
digest, CHAP_SHA3_256_DIGEST_LEN);
}

/*
* To generate challenge for CHAP, use stronger random number generator as
* opposed to simple rand().
Expand Down Expand Up @@ -374,7 +423,16 @@ static int chap_initiator_auth_create_challenge(struct connection *conn)
conn->auth.chap.digest_alg = CHAP_DIGEST_ALG_SHA1;
conn->auth_state = CHAP_AUTH_STATE_CHALLENGE;
break;
} else if (!strcmp(p, "7") && af_alg_supported(SCST_AF_ALG_SHA256_NAME)) {
conn->auth.chap.digest_alg = CHAP_DIGEST_ALG_SHA256;
conn->auth_state = CHAP_AUTH_STATE_CHALLENGE;
break;
} else if (!strcmp(p, "8") && af_alg_supported(SCST_AF_ALG_SHA3_256_NAME)) {
conn->auth.chap.digest_alg = CHAP_DIGEST_ALG_SHA3_256;
conn->auth_state = CHAP_AUTH_STATE_CHALLENGE;
break;
}

}
if (!p)
return CHAP_INITIATOR_ERROR;
Expand Down Expand Up @@ -458,6 +516,12 @@ static int chap_initiator_auth_check_response(struct connection *conn)
case CHAP_DIGEST_ALG_SHA1:
digest_len = CHAP_SHA1_DIGEST_LEN;
break;
case CHAP_DIGEST_ALG_SHA256:
digest_len = CHAP_SHA256_DIGEST_LEN;
break;
case CHAP_DIGEST_ALG_SHA3_256:
digest_len = CHAP_SHA3_256_DIGEST_LEN;
break;
default:
retval = CHAP_TARGET_ERROR;
goto out;
Expand Down Expand Up @@ -490,6 +554,18 @@ static int chap_initiator_auth_check_response(struct connection *conn)
conn->auth.chap.challenge_size,
our_digest);
break;
case CHAP_DIGEST_ALG_SHA256:
chap_calc_digest_sha256(conn->auth.chap.id, pass, strlen(pass),
conn->auth.chap.challenge,
conn->auth.chap.challenge_size,
our_digest);
break;
case CHAP_DIGEST_ALG_SHA3_256:
chap_calc_digest_sha3_256(conn->auth.chap.id, pass, strlen(pass),
conn->auth.chap.challenge,
conn->auth.chap.challenge_size,
our_digest);
break;
default:
retval = CHAP_TARGET_ERROR;
goto out;
Expand Down Expand Up @@ -571,6 +647,12 @@ static int chap_target_auth_create_response(struct connection *conn)
case CHAP_DIGEST_ALG_SHA1:
digest_len = CHAP_SHA1_DIGEST_LEN;
break;
case CHAP_DIGEST_ALG_SHA256:
digest_len = CHAP_SHA256_DIGEST_LEN;
break;
case CHAP_DIGEST_ALG_SHA3_256:
digest_len = CHAP_SHA3_256_DIGEST_LEN;
break;
default:
retval = CHAP_TARGET_ERROR;
goto out;
Expand Down Expand Up @@ -619,6 +701,16 @@ static int chap_target_auth_create_response(struct connection *conn)
chap_calc_digest_sha1(chap_id, ISCSI_USER_PASS(user),
strlen(ISCSI_USER_PASS(user)), challenge, challenge_len, digest);
break;
case CHAP_DIGEST_ALG_SHA256:
chap_calc_digest_sha256(chap_id, ISCSI_USER_PASS(user),
strlen(ISCSI_USER_PASS(user)),
challenge, challenge_len, digest);
break;
case CHAP_DIGEST_ALG_SHA3_256:
chap_calc_digest_sha3_256(chap_id, ISCSI_USER_PASS(user),
strlen(ISCSI_USER_PASS(user)),
challenge, challenge_len, digest);
break;
default:
retval = CHAP_TARGET_ERROR;
goto out;
Expand Down

0 comments on commit 146d79e

Please sign in to comment.