Skip to content

Commit 146d79e

Browse files
bmeagherixlnocturno
authored andcommitted
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.
1 parent 6c5e8ad commit 146d79e

4 files changed

Lines changed: 207 additions & 1 deletion

File tree

iscsi-scst/usr/Makefile

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@ cc-option = $(shell if $(CC) $(1) -Werror -S -o /dev/null -xc /dev/null \
2323

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

2929
SRCS_ADM = iscsi_adm.c param.c

iscsi-scst/usr/af_alg.c

Lines changed: 84 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,84 @@
1+
// SPDX-License-Identifier: GPL-2.0-only
2+
/*
3+
* af_alg - wrapper functions to call AF_ALG hash algorithms.
4+
*
5+
* Copyright (C) 2025 Brian Meagher <brian.meagher@ixsystems.com>
6+
*
7+
* This program is free software; you can redistribute it and/or
8+
* modify it under the terms of the GNU General Public License
9+
* as published by the Free Software Foundation, version 2
10+
* of the License.
11+
*
12+
* This program is distributed in the hope that it will be useful,
13+
* but WITHOUT ANY WARRANTY; without even the implied warranty of
14+
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15+
* GNU General Public License for more details.
16+
*/
17+
18+
#include "af_alg.h"
19+
20+
#include <sys/socket.h>
21+
#include <linux/if_alg.h>
22+
#include <string.h>
23+
#include <sys/param.h>
24+
#include <stdbool.h>
25+
26+
int af_alg_init(const char *algorithm)
27+
{
28+
int sockfd, datafd, algo_len;
29+
struct sockaddr_alg sa = {
30+
.salg_family = AF_ALG,
31+
.salg_type = "hash",
32+
};
33+
34+
algo_len = strlen(algorithm);
35+
if (algo_len >= sizeof(sa.salg_name))
36+
return -1;
37+
38+
sockfd = socket(AF_ALG, SOCK_SEQPACKET, 0);
39+
if (sockfd == -1)
40+
return -1;
41+
42+
/* +1 for null-terminator */
43+
memcpy(sa.salg_name, algorithm, algo_len + 1);
44+
45+
if (bind(sockfd, (struct sockaddr *)&sa, sizeof(sa)) == -1) {
46+
close(sockfd);
47+
return -1;
48+
}
49+
50+
datafd = accept(sockfd, NULL, 0);
51+
if (datafd < 0) {
52+
close(sockfd);
53+
return -1;
54+
}
55+
close(sockfd);
56+
return datafd;
57+
}
58+
59+
void af_alg_update(int datafd, const void *data_in, size_t len)
60+
{
61+
send(datafd, data_in, len, MSG_MORE);
62+
}
63+
64+
ssize_t af_alg_final(int datafd, void *out, size_t len)
65+
{
66+
char buffer[1024];
67+
ssize_t bytes;
68+
69+
send(datafd, NULL, 0, 0);
70+
71+
bytes = recv(datafd, buffer, sizeof(buffer), 0);
72+
memcpy(out, buffer, MIN(len, bytes));
73+
return bytes;
74+
}
75+
76+
bool af_alg_supported(char *alg)
77+
{
78+
int sock = af_alg_init(alg);
79+
80+
if (sock < 0)
81+
return false;
82+
close(sock);
83+
return true;
84+
}

iscsi-scst/usr/af_alg.h

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
/* SPDX-License-Identifier: GPL-2.0-only */
2+
/*
3+
* Copyright (C) 2025 Brian Meagher <brian.meagher@ixsystems.com>
4+
*
5+
* This program is free software; you can redistribute it and/or
6+
* modify it under the terms of the GNU General Public License
7+
* as published by the Free Software Foundation, version 2
8+
* of the License.
9+
*
10+
* This program is distributed in the hope that it will be useful,
11+
* but WITHOUT ANY WARRANTY; without even the implied warranty of
12+
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13+
* GNU General Public License for more details.
14+
*/
15+
16+
#ifndef SCST_AF_ALG_H
17+
#define SCST_AF_ALG_H
18+
19+
#include <unistd.h>
20+
#include <stdbool.h>
21+
22+
#define SCST_AF_ALG_SHA256_NAME "sha256"
23+
#define SCST_AF_ALG_SHA3_256_NAME "sha3-256"
24+
25+
int af_alg_init(const char *algorithm);
26+
void af_alg_update(int datafd, const void *data_in, size_t len);
27+
ssize_t af_alg_final(int datafd, void *out, size_t len);
28+
bool af_alg_supported(char *alg);
29+
30+
#endif

iscsi-scst/usr/chap.c

Lines changed: 92 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,8 @@
3131
#include <unistd.h>
3232
#include "sha1.h"
3333
#include "md5.h"
34+
#include "af_alg.h"
35+
#include <sys/param.h>
3436

3537
#include "iscsid.h"
3638

@@ -39,9 +41,13 @@
3941

4042
#define CHAP_DIGEST_ALG_MD5 5
4143
#define CHAP_DIGEST_ALG_SHA1 6
44+
#define CHAP_DIGEST_ALG_SHA256 7
45+
#define CHAP_DIGEST_ALG_SHA3_256 8
4246

4347
#define CHAP_MD5_DIGEST_LEN 16
4448
#define CHAP_SHA1_DIGEST_LEN 20
49+
#define CHAP_SHA256_DIGEST_LEN 32
50+
#define CHAP_SHA3_256_DIGEST_LEN 32
4551

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

347+
static inline void
348+
chap_calc_digest_af_alg(char *alg, char chap_id,
349+
const char *secret, int secret_len,
350+
const u8 *challenge, int challenge_len,
351+
u8 *digest, int digest_len)
352+
{
353+
int datafd = af_alg_init(alg);
354+
char buffer[1024];
355+
int bytes;
356+
357+
if (datafd < 0) {
358+
log_error("CHAP unable to use %s algorithm", alg);
359+
return;
360+
}
361+
362+
af_alg_update(datafd, &chap_id, 1);
363+
af_alg_update(datafd, secret, secret_len);
364+
af_alg_update(datafd, challenge, challenge_len);
365+
bytes = af_alg_final(datafd, buffer, sizeof(buffer));
366+
close(datafd);
367+
memcpy(digest, buffer, MIN(bytes, digest_len));
368+
}
369+
370+
static inline void
371+
chap_calc_digest_sha256(char chap_id, const char *secret, int secret_len,
372+
const u8 *challenge, int challenge_len, u8 *digest)
373+
{
374+
chap_calc_digest_af_alg(SCST_AF_ALG_SHA256_NAME,
375+
chap_id, secret, secret_len,
376+
challenge, challenge_len,
377+
digest, CHAP_SHA256_DIGEST_LEN);
378+
}
379+
380+
static inline void
381+
chap_calc_digest_sha3_256(char chap_id, const char *secret, int secret_len,
382+
const u8 *challenge, int challenge_len, u8 *digest)
383+
{
384+
chap_calc_digest_af_alg(SCST_AF_ALG_SHA3_256_NAME,
385+
chap_id, secret, secret_len,
386+
challenge, challenge_len,
387+
digest, CHAP_SHA3_256_DIGEST_LEN);
388+
}
389+
341390
/*
342391
* To generate challenge for CHAP, use stronger random number generator as
343392
* opposed to simple rand().
@@ -374,7 +423,16 @@ static int chap_initiator_auth_create_challenge(struct connection *conn)
374423
conn->auth.chap.digest_alg = CHAP_DIGEST_ALG_SHA1;
375424
conn->auth_state = CHAP_AUTH_STATE_CHALLENGE;
376425
break;
426+
} else if (!strcmp(p, "7") && af_alg_supported(SCST_AF_ALG_SHA256_NAME)) {
427+
conn->auth.chap.digest_alg = CHAP_DIGEST_ALG_SHA256;
428+
conn->auth_state = CHAP_AUTH_STATE_CHALLENGE;
429+
break;
430+
} else if (!strcmp(p, "8") && af_alg_supported(SCST_AF_ALG_SHA3_256_NAME)) {
431+
conn->auth.chap.digest_alg = CHAP_DIGEST_ALG_SHA3_256;
432+
conn->auth_state = CHAP_AUTH_STATE_CHALLENGE;
433+
break;
377434
}
435+
378436
}
379437
if (!p)
380438
return CHAP_INITIATOR_ERROR;
@@ -458,6 +516,12 @@ static int chap_initiator_auth_check_response(struct connection *conn)
458516
case CHAP_DIGEST_ALG_SHA1:
459517
digest_len = CHAP_SHA1_DIGEST_LEN;
460518
break;
519+
case CHAP_DIGEST_ALG_SHA256:
520+
digest_len = CHAP_SHA256_DIGEST_LEN;
521+
break;
522+
case CHAP_DIGEST_ALG_SHA3_256:
523+
digest_len = CHAP_SHA3_256_DIGEST_LEN;
524+
break;
461525
default:
462526
retval = CHAP_TARGET_ERROR;
463527
goto out;
@@ -490,6 +554,18 @@ static int chap_initiator_auth_check_response(struct connection *conn)
490554
conn->auth.chap.challenge_size,
491555
our_digest);
492556
break;
557+
case CHAP_DIGEST_ALG_SHA256:
558+
chap_calc_digest_sha256(conn->auth.chap.id, pass, strlen(pass),
559+
conn->auth.chap.challenge,
560+
conn->auth.chap.challenge_size,
561+
our_digest);
562+
break;
563+
case CHAP_DIGEST_ALG_SHA3_256:
564+
chap_calc_digest_sha3_256(conn->auth.chap.id, pass, strlen(pass),
565+
conn->auth.chap.challenge,
566+
conn->auth.chap.challenge_size,
567+
our_digest);
568+
break;
493569
default:
494570
retval = CHAP_TARGET_ERROR;
495571
goto out;
@@ -571,6 +647,12 @@ static int chap_target_auth_create_response(struct connection *conn)
571647
case CHAP_DIGEST_ALG_SHA1:
572648
digest_len = CHAP_SHA1_DIGEST_LEN;
573649
break;
650+
case CHAP_DIGEST_ALG_SHA256:
651+
digest_len = CHAP_SHA256_DIGEST_LEN;
652+
break;
653+
case CHAP_DIGEST_ALG_SHA3_256:
654+
digest_len = CHAP_SHA3_256_DIGEST_LEN;
655+
break;
574656
default:
575657
retval = CHAP_TARGET_ERROR;
576658
goto out;
@@ -619,6 +701,16 @@ static int chap_target_auth_create_response(struct connection *conn)
619701
chap_calc_digest_sha1(chap_id, ISCSI_USER_PASS(user),
620702
strlen(ISCSI_USER_PASS(user)), challenge, challenge_len, digest);
621703
break;
704+
case CHAP_DIGEST_ALG_SHA256:
705+
chap_calc_digest_sha256(chap_id, ISCSI_USER_PASS(user),
706+
strlen(ISCSI_USER_PASS(user)),
707+
challenge, challenge_len, digest);
708+
break;
709+
case CHAP_DIGEST_ALG_SHA3_256:
710+
chap_calc_digest_sha3_256(chap_id, ISCSI_USER_PASS(user),
711+
strlen(ISCSI_USER_PASS(user)),
712+
challenge, challenge_len, digest);
713+
break;
622714
default:
623715
retval = CHAP_TARGET_ERROR;
624716
goto out;

0 commit comments

Comments
 (0)