mirror of
https://github.com/SCST-project/scst.git
synced 2026-05-18 11:11:27 +00:00
iscsi-scst: Add SHA256 and SHA3-256 support to CHAP
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.
This commit is contained in:
@@ -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
|
||||
|
||||
84
iscsi-scst/usr/af_alg.c
Normal file
84
iscsi-scst/usr/af_alg.c
Normal file
@@ -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 <brian.meagher@ixsystems.com>
|
||||
*
|
||||
* 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
iscsi-scst/usr/af_alg.h
Normal file
30
iscsi-scst/usr/af_alg.h
Normal file
@@ -0,0 +1,30 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0-only */
|
||||
/*
|
||||
* Copyright (C) 2025 Brian Meagher <brian.meagher@ixsystems.com>
|
||||
*
|
||||
* 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
|
||||
@@ -31,6 +31,8 @@
|
||||
#include <unistd.h>
|
||||
#include "sha1.h"
|
||||
#include "md5.h"
|
||||
#include "af_alg.h"
|
||||
#include <sys/param.h>
|
||||
|
||||
#include "iscsid.h"
|
||||
|
||||
@@ -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
|
||||
@@ -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().
|
||||
@@ -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;
|
||||
@@ -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;
|
||||
@@ -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;
|
||||
@@ -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;
|
||||
@@ -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;
|
||||
|
||||
Reference in New Issue
Block a user