diff --git a/iscsi-scst/usr/Makefile b/iscsi-scst/usr/Makefile index e50aad6f3..a7084dda7 100644 --- a/iscsi-scst/usr/Makefile +++ b/iscsi-scst/usr/Makefile @@ -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 diff --git a/iscsi-scst/usr/af_alg.c b/iscsi-scst/usr/af_alg.c new file mode 100644 index 000000000..eeb44fbbb --- /dev/null +++ b/iscsi-scst/usr/af_alg.c @@ -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 + * + * 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 +#include +#include +#include +#include + +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; +} diff --git a/iscsi-scst/usr/af_alg.h b/iscsi-scst/usr/af_alg.h new file mode 100644 index 000000000..7be0e734c --- /dev/null +++ b/iscsi-scst/usr/af_alg.h @@ -0,0 +1,30 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Copyright (C) 2025 Brian Meagher + * + * 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 +#include + +#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 diff --git a/iscsi-scst/usr/chap.c b/iscsi-scst/usr/chap.c index 2e6131816..3d4aec79e 100644 --- a/iscsi-scst/usr/chap.c +++ b/iscsi-scst/usr/chap.c @@ -31,6 +31,8 @@ #include #include "sha1.h" #include "md5.h" +#include "af_alg.h" +#include #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;