Skip to content

Commit e88a759

Browse files
Hannes Reineckekeithbusch
authored andcommitted
nvme-tcp: request secure channel concatenation
Add a fabrics option 'concat' to request secure channel concatenation as specified the NVME Base Specification v2.1, section 8.3.4.3: Secure Channel Concatenation. When secure channel concatenation is enabled a 'generated PSK' is inserted into the keyring such that it's available after reset. Signed-off-by: Hannes Reinecke <hare@kernel.org> Reviewed-by: Sagi Grimberg <sagi@grimberg.me> Signed-off-by: Keith Busch <kbusch@kernel.org>
1 parent 62eb893 commit e88a759

File tree

8 files changed

+205
-15
lines changed

8 files changed

+205
-15
lines changed

drivers/nvme/host/Kconfig

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -109,7 +109,7 @@ config NVME_HOST_AUTH
109109
bool "NVMe over Fabrics In-Band Authentication in host side"
110110
depends on NVME_CORE
111111
select NVME_AUTH
112-
select NVME_KEYRING if NVME_TCP_TLS
112+
select NVME_KEYRING
113113
help
114114
This provides support for NVMe over Fabrics In-Band Authentication in
115115
host side.

drivers/nvme/host/auth.c

Lines changed: 112 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212
#include "nvme.h"
1313
#include "fabrics.h"
1414
#include <linux/nvme-auth.h>
15+
#include <linux/nvme-keyring.h>
1516

1617
#define CHAP_BUF_SIZE 4096
1718
static struct kmem_cache *nvme_chap_buf_cache;
@@ -131,7 +132,13 @@ static int nvme_auth_set_dhchap_negotiate_data(struct nvme_ctrl *ctrl,
131132
data->auth_type = NVME_AUTH_COMMON_MESSAGES;
132133
data->auth_id = NVME_AUTH_DHCHAP_MESSAGE_NEGOTIATE;
133134
data->t_id = cpu_to_le16(chap->transaction);
134-
data->sc_c = 0; /* No secure channel concatenation */
135+
if (ctrl->opts->concat && chap->qid == 0) {
136+
if (ctrl->opts->tls_key)
137+
data->sc_c = NVME_AUTH_SECP_REPLACETLSPSK;
138+
else
139+
data->sc_c = NVME_AUTH_SECP_NEWTLSPSK;
140+
} else
141+
data->sc_c = NVME_AUTH_SECP_NOSC;
135142
data->napd = 1;
136143
data->auth_protocol[0].dhchap.authid = NVME_AUTH_DHCHAP_AUTH_ID;
137144
data->auth_protocol[0].dhchap.halen = 3;
@@ -311,8 +318,9 @@ static int nvme_auth_set_dhchap_reply_data(struct nvme_ctrl *ctrl,
311318
data->hl = chap->hash_len;
312319
data->dhvlen = cpu_to_le16(chap->host_key_len);
313320
memcpy(data->rval, chap->response, chap->hash_len);
314-
if (ctrl->ctrl_key) {
321+
if (ctrl->ctrl_key)
315322
chap->bi_directional = true;
323+
if (ctrl->ctrl_key || ctrl->opts->concat) {
316324
get_random_bytes(chap->c2, chap->hash_len);
317325
data->cvalid = 1;
318326
memcpy(data->rval + chap->hash_len, chap->c2,
@@ -322,7 +330,10 @@ static int nvme_auth_set_dhchap_reply_data(struct nvme_ctrl *ctrl,
322330
} else {
323331
memset(chap->c2, 0, chap->hash_len);
324332
}
325-
chap->s2 = nvme_auth_get_seqnum();
333+
if (ctrl->opts->concat)
334+
chap->s2 = 0;
335+
else
336+
chap->s2 = nvme_auth_get_seqnum();
326337
data->seqnum = cpu_to_le32(chap->s2);
327338
if (chap->host_key_len) {
328339
dev_dbg(ctrl->device, "%s: qid %d host public key %*ph\n",
@@ -677,6 +688,92 @@ static void nvme_auth_free_dhchap(struct nvme_dhchap_queue_context *chap)
677688
crypto_free_kpp(chap->dh_tfm);
678689
}
679690

691+
void nvme_auth_revoke_tls_key(struct nvme_ctrl *ctrl)
692+
{
693+
dev_dbg(ctrl->device, "Wipe generated TLS PSK %08x\n",
694+
key_serial(ctrl->opts->tls_key));
695+
key_revoke(ctrl->opts->tls_key);
696+
key_put(ctrl->opts->tls_key);
697+
ctrl->opts->tls_key = NULL;
698+
}
699+
EXPORT_SYMBOL_GPL(nvme_auth_revoke_tls_key);
700+
701+
static int nvme_auth_secure_concat(struct nvme_ctrl *ctrl,
702+
struct nvme_dhchap_queue_context *chap)
703+
{
704+
u8 *psk, *digest, *tls_psk;
705+
struct key *tls_key;
706+
size_t psk_len;
707+
int ret = 0;
708+
709+
if (!chap->sess_key) {
710+
dev_warn(ctrl->device,
711+
"%s: qid %d no session key negotiated\n",
712+
__func__, chap->qid);
713+
return -ENOKEY;
714+
}
715+
716+
if (chap->qid) {
717+
dev_warn(ctrl->device,
718+
"qid %d: secure concatenation not supported on I/O queues\n",
719+
chap->qid);
720+
return -EINVAL;
721+
}
722+
ret = nvme_auth_generate_psk(chap->hash_id, chap->sess_key,
723+
chap->sess_key_len,
724+
chap->c1, chap->c2,
725+
chap->hash_len, &psk, &psk_len);
726+
if (ret) {
727+
dev_warn(ctrl->device,
728+
"%s: qid %d failed to generate PSK, error %d\n",
729+
__func__, chap->qid, ret);
730+
return ret;
731+
}
732+
dev_dbg(ctrl->device,
733+
"%s: generated psk %*ph\n", __func__, (int)psk_len, psk);
734+
735+
ret = nvme_auth_generate_digest(chap->hash_id, psk, psk_len,
736+
ctrl->opts->subsysnqn,
737+
ctrl->opts->host->nqn, &digest);
738+
if (ret) {
739+
dev_warn(ctrl->device,
740+
"%s: qid %d failed to generate digest, error %d\n",
741+
__func__, chap->qid, ret);
742+
goto out_free_psk;
743+
};
744+
dev_dbg(ctrl->device, "%s: generated digest %s\n",
745+
__func__, digest);
746+
ret = nvme_auth_derive_tls_psk(chap->hash_id, psk, psk_len,
747+
digest, &tls_psk);
748+
if (ret) {
749+
dev_warn(ctrl->device,
750+
"%s: qid %d failed to derive TLS psk, error %d\n",
751+
__func__, chap->qid, ret);
752+
goto out_free_digest;
753+
};
754+
755+
tls_key = nvme_tls_psk_refresh(ctrl->opts->keyring,
756+
ctrl->opts->host->nqn,
757+
ctrl->opts->subsysnqn, chap->hash_id,
758+
tls_psk, psk_len, digest);
759+
if (IS_ERR(tls_key)) {
760+
ret = PTR_ERR(tls_key);
761+
dev_warn(ctrl->device,
762+
"%s: qid %d failed to insert generated key, error %d\n",
763+
__func__, chap->qid, ret);
764+
tls_key = NULL;
765+
}
766+
kfree_sensitive(tls_psk);
767+
if (ctrl->opts->tls_key)
768+
nvme_auth_revoke_tls_key(ctrl);
769+
ctrl->opts->tls_key = tls_key;
770+
out_free_digest:
771+
kfree_sensitive(digest);
772+
out_free_psk:
773+
kfree_sensitive(psk);
774+
return ret;
775+
}
776+
680777
static void nvme_queue_auth_work(struct work_struct *work)
681778
{
682779
struct nvme_dhchap_queue_context *chap =
@@ -833,6 +930,13 @@ static void nvme_queue_auth_work(struct work_struct *work)
833930
}
834931
if (!ret) {
835932
chap->error = 0;
933+
if (ctrl->opts->concat &&
934+
(ret = nvme_auth_secure_concat(ctrl, chap))) {
935+
dev_warn(ctrl->device,
936+
"%s: qid %d failed to enable secure concatenation\n",
937+
__func__, chap->qid);
938+
chap->error = ret;
939+
}
836940
return;
837941
}
838942

@@ -912,6 +1016,11 @@ static void nvme_ctrl_auth_work(struct work_struct *work)
9121016
"qid 0: authentication failed\n");
9131017
return;
9141018
}
1019+
/*
1020+
* Only run authentication on the admin queue for secure concatenation.
1021+
*/
1022+
if (ctrl->opts->concat)
1023+
return;
9151024

9161025
for (q = 1; q < ctrl->queue_count; q++) {
9171026
ret = nvme_auth_negotiate(ctrl, q);

drivers/nvme/host/fabrics.c

Lines changed: 31 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -472,8 +472,9 @@ int nvmf_connect_admin_queue(struct nvme_ctrl *ctrl)
472472
result = le32_to_cpu(res.u32);
473473
ctrl->cntlid = result & 0xFFFF;
474474
if (result & (NVME_CONNECT_AUTHREQ_ATR | NVME_CONNECT_AUTHREQ_ASCR)) {
475-
/* Secure concatenation is not implemented */
476-
if (result & NVME_CONNECT_AUTHREQ_ASCR) {
475+
/* Check for secure concatenation */
476+
if ((result & NVME_CONNECT_AUTHREQ_ASCR) &&
477+
!ctrl->opts->concat) {
477478
dev_warn(ctrl->device,
478479
"qid 0: secure concatenation is not supported\n");
479480
ret = -EOPNOTSUPP;
@@ -550,7 +551,7 @@ int nvmf_connect_io_queue(struct nvme_ctrl *ctrl, u16 qid)
550551
/* Secure concatenation is not implemented */
551552
if (result & NVME_CONNECT_AUTHREQ_ASCR) {
552553
dev_warn(ctrl->device,
553-
"qid 0: secure concatenation is not supported\n");
554+
"qid %d: secure concatenation is not supported\n", qid);
554555
ret = -EOPNOTSUPP;
555556
goto out_free_data;
556557
}
@@ -706,6 +707,7 @@ static const match_table_t opt_tokens = {
706707
#endif
707708
#ifdef CONFIG_NVME_TCP_TLS
708709
{ NVMF_OPT_TLS, "tls" },
710+
{ NVMF_OPT_CONCAT, "concat" },
709711
#endif
710712
{ NVMF_OPT_ERR, NULL }
711713
};
@@ -735,6 +737,7 @@ static int nvmf_parse_options(struct nvmf_ctrl_options *opts,
735737
opts->tls = false;
736738
opts->tls_key = NULL;
737739
opts->keyring = NULL;
740+
opts->concat = false;
738741

739742
options = o = kstrdup(buf, GFP_KERNEL);
740743
if (!options)
@@ -1053,6 +1056,14 @@ static int nvmf_parse_options(struct nvmf_ctrl_options *opts,
10531056
}
10541057
opts->tls = true;
10551058
break;
1059+
case NVMF_OPT_CONCAT:
1060+
if (!IS_ENABLED(CONFIG_NVME_TCP_TLS)) {
1061+
pr_err("TLS is not supported\n");
1062+
ret = -EINVAL;
1063+
goto out;
1064+
}
1065+
opts->concat = true;
1066+
break;
10561067
default:
10571068
pr_warn("unknown parameter or missing value '%s' in ctrl creation request\n",
10581069
p);
@@ -1079,6 +1090,23 @@ static int nvmf_parse_options(struct nvmf_ctrl_options *opts,
10791090
pr_warn("failfast tmo (%d) larger than controller loss tmo (%d)\n",
10801091
opts->fast_io_fail_tmo, ctrl_loss_tmo);
10811092
}
1093+
if (opts->concat) {
1094+
if (opts->tls) {
1095+
pr_err("Secure concatenation over TLS is not supported\n");
1096+
ret = -EINVAL;
1097+
goto out;
1098+
}
1099+
if (opts->tls_key) {
1100+
pr_err("Cannot specify a TLS key for secure concatenation\n");
1101+
ret = -EINVAL;
1102+
goto out;
1103+
}
1104+
if (!opts->dhchap_secret) {
1105+
pr_err("Need to enable DH-CHAP for secure concatenation\n");
1106+
ret = -EINVAL;
1107+
goto out;
1108+
}
1109+
}
10821110

10831111
opts->host = nvmf_host_add(hostnqn, &hostid);
10841112
if (IS_ERR(opts->host)) {

drivers/nvme/host/fabrics.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -66,6 +66,7 @@ enum {
6666
NVMF_OPT_TLS = 1 << 25,
6767
NVMF_OPT_KEYRING = 1 << 26,
6868
NVMF_OPT_TLS_KEY = 1 << 27,
69+
NVMF_OPT_CONCAT = 1 << 28,
6970
};
7071

7172
/**
@@ -101,6 +102,7 @@ enum {
101102
* @keyring: Keyring to use for key lookups
102103
* @tls_key: TLS key for encrypted connections (TCP)
103104
* @tls: Start TLS encrypted connections (TCP)
105+
* @concat: Enabled Secure channel concatenation (TCP)
104106
* @disable_sqflow: disable controller sq flow control
105107
* @hdr_digest: generate/verify header digest (TCP)
106108
* @data_digest: generate/verify data digest (TCP)
@@ -130,6 +132,7 @@ struct nvmf_ctrl_options {
130132
struct key *keyring;
131133
struct key *tls_key;
132134
bool tls;
135+
bool concat;
133136
bool disable_sqflow;
134137
bool hdr_digest;
135138
bool data_digest;

drivers/nvme/host/nvme.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1147,6 +1147,7 @@ void nvme_auth_stop(struct nvme_ctrl *ctrl);
11471147
int nvme_auth_negotiate(struct nvme_ctrl *ctrl, int qid);
11481148
int nvme_auth_wait(struct nvme_ctrl *ctrl, int qid);
11491149
void nvme_auth_free(struct nvme_ctrl *ctrl);
1150+
void nvme_auth_revoke_tls_key(struct nvme_ctrl *ctrl);
11501151
#else
11511152
static inline int nvme_auth_init_ctrl(struct nvme_ctrl *ctrl)
11521153
{
@@ -1169,6 +1170,7 @@ static inline int nvme_auth_wait(struct nvme_ctrl *ctrl, int qid)
11691170
return -EPROTONOSUPPORT;
11701171
}
11711172
static inline void nvme_auth_free(struct nvme_ctrl *ctrl) {};
1173+
static inline void nvme_auth_revoke_tls_key(struct nvme_ctrl *ctrl) {};
11721174
#endif
11731175

11741176
u32 nvme_command_effects(struct nvme_ctrl *ctrl, struct nvme_ns *ns,

drivers/nvme/host/sysfs.c

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -780,10 +780,10 @@ static umode_t nvme_tls_attrs_are_visible(struct kobject *kobj,
780780
return 0;
781781

782782
if (a == &dev_attr_tls_key.attr &&
783-
!ctrl->opts->tls)
783+
!ctrl->opts->tls && !ctrl->opts->concat)
784784
return 0;
785785
if (a == &dev_attr_tls_configured_key.attr &&
786-
!ctrl->opts->tls_key)
786+
(!ctrl->opts->tls_key || ctrl->opts->concat))
787787
return 0;
788788
if (a == &dev_attr_tls_keyring.attr &&
789789
!ctrl->opts->keyring)

0 commit comments

Comments
 (0)