[PATCH 11/17] nvme-tcp: request secure channel concatenation

Sagi Grimberg sagi at grimberg.me
Mon Apr 8 14:09:42 PDT 2024



On 08/04/2024 8:32, Hannes Reinecke wrote:
> On 4/7/24 23:41, Sagi Grimberg wrote:
>>
>>
>> On 18/03/2024 17:03, Hannes Reinecke wrote:
>>> From: Hannes Reinecke <hare at suse.de>
>>>
>>> Add a fabrics option 'concat' to request secure channel concatenation.
>>
>> maybe name it secconcat ? or secure_concat ?
>>
>>> When secure channel concatenation is enabled a 'generated PSK' is 
>>> inserted
>>> into the keyring such that it's available after reset.
>>
>> Umm, I'm not sure what this means? Is this the revoke action? what if
>> the user passes a keyring? I'm not entirely sure what is the 
>> interface semantics here.
>>
> No, this is not the 'revoke' action. This is the modification TP8018
> brought in. For secure concatenation the initial connection is done
> without encryption, DH-CHAP is run and generates the TLS PSK. Then
> the connection is reset, and the new connection starts TLS with the
> generated key.

Yes, I misread "it's available" and "it's not available". Sorry.

>
>>>
>>> Signed-off-by: Hannes Reinecke <hare at suse.de>
>>> ---
>>>   drivers/nvme/host/auth.c    | 108 
>>> ++++++++++++++++++++++++++++++++++--
>>>   drivers/nvme/host/fabrics.c |  25 ++++++++-
>>>   drivers/nvme/host/fabrics.h |   3 +
>>>   drivers/nvme/host/sysfs.c   |   2 +
>>>   drivers/nvme/host/tcp.c     |  53 ++++++++++++++++--
>>>   include/linux/nvme.h        |   7 +++
>>>   6 files changed, 186 insertions(+), 12 deletions(-)
>>>
>>> diff --git a/drivers/nvme/host/auth.c b/drivers/nvme/host/auth.c
>>> index a264b3ae078b..a4033a8f9607 100644
>>> --- a/drivers/nvme/host/auth.c
>>> +++ b/drivers/nvme/host/auth.c
>>> @@ -12,6 +12,7 @@
>>>   #include "nvme.h"
>>>   #include "fabrics.h"
>>>   #include <linux/nvme-auth.h>
>>> +#include <linux/nvme-keyring.h>
>>>   #define CHAP_BUF_SIZE 4096
>>>   static struct kmem_cache *nvme_chap_buf_cache;
>>> @@ -131,7 +132,12 @@ static int 
>>> nvme_auth_set_dhchap_negotiate_data(struct nvme_ctrl *ctrl,
>>>       data->auth_type = NVME_AUTH_COMMON_MESSAGES;
>>>       data->auth_id = NVME_AUTH_DHCHAP_MESSAGE_NEGOTIATE;
>>>       data->t_id = cpu_to_le16(chap->transaction);
>>> -    data->sc_c = 0; /* No secure channel concatenation */
>>> +    if (!ctrl->opts->concat || chap->qid != 0)
>>> +        data->sc_c = NVME_AUTH_SECP_NOSC;
>>> +    else if (ctrl->opts->tls_key)
>>> +        data->sc_c = NVME_AUTH_SECP_REPLACETLSPSK;
>>> +    else
>>> +        data->sc_c = NVME_AUTH_SECP_NEWTLSPSK;
>>>       data->napd = 1;
>>>       data->auth_protocol[0].dhchap.authid = NVME_AUTH_DHCHAP_AUTH_ID;
>>>       data->auth_protocol[0].dhchap.halen = 3;
>>> @@ -311,8 +317,9 @@ static int 
>>> nvme_auth_set_dhchap_reply_data(struct nvme_ctrl *ctrl,
>>>       data->hl = chap->hash_len;
>>>       data->dhvlen = cpu_to_le16(chap->host_key_len);
>>>       memcpy(data->rval, chap->response, chap->hash_len);
>>> -    if (ctrl->ctrl_key) {
>>> +    if (ctrl->ctrl_key)
>>>           chap->bi_directional = true;
>>> +    if (ctrl->ctrl_key || ctrl->opts->concat) {
>>>           get_random_bytes(chap->c2, chap->hash_len);
>>>           data->cvalid = 1;
>>>           memcpy(data->rval + chap->hash_len, chap->c2,
>>> @@ -322,7 +329,10 @@ static int 
>>> nvme_auth_set_dhchap_reply_data(struct nvme_ctrl *ctrl,
>>>       } else {
>>>           memset(chap->c2, 0, chap->hash_len);
>>>       }
>>> -    chap->s2 = nvme_auth_get_seqnum();
>>> +    if (ctrl->opts->concat)
>>> +        chap->s2 = 0;
>>> +    else
>>> +        chap->s2 = nvme_auth_get_seqnum();
>>>       data->seqnum = cpu_to_le32(chap->s2);
>>>       if (chap->host_key_len) {
>>>           dev_dbg(ctrl->device, "%s: qid %d host public key %*ph\n",
>>> @@ -677,6 +687,79 @@ static void nvme_auth_free_dhchap(struct 
>>> nvme_dhchap_queue_context *chap)
>>>           crypto_free_kpp(chap->dh_tfm);
>>>   }
>>> +static int nvme_auth_secure_concat(struct nvme_ctrl *ctrl,
>>> +                   struct nvme_dhchap_queue_context *chap)
>>> +{
>>> +    u8 *psk, *digest, *tls_psk;
>>> +    struct key *tls_key;
>>> +    size_t psk_len;
>>> +    int ret = 0;
>>> +
>>> +    if (!chap->sess_key) {
>>> +        dev_warn(ctrl->device,
>>> +             "%s: qid %d no session key negotiated\n",
>>> +             __func__, chap->qid);
>>> +        return -ENOKEY;
>>> +    }
>>> +
>>> +    psk = nvme_auth_generate_psk(chap->hash_id, chap->sess_key,
>>> +                     chap->sess_key_len,
>>> +                     chap->c1, chap->c2,
>>> +                     chap->hash_len, &psk_len);
>>> +    if (IS_ERR(psk)) {
>>> +        ret = PTR_ERR(psk);
>>> +        dev_warn(ctrl->device,
>>> +             "%s: qid %d failed to generate PSK, error %d\n",
>>> +             __func__, chap->qid, ret);
>>> +        return ret;
>>> +    }
>>> +    dev_dbg(ctrl->device,
>>> +          "%s: generated psk %*ph\n", __func__, (int)psk_len, psk);
>>> +
>>> +    digest = nvme_auth_generate_digest(chap->hash_id, psk, psk_len,
>>> +                       ctrl->opts->subsysnqn,
>>> +                       ctrl->opts->host->nqn);
>>> +    if (IS_ERR(digest)) {
>>> +        ret = PTR_ERR(digest);
>>> +        dev_warn(ctrl->device,
>>> +             "%s: qid %d failed to generate digest, error %d\n",
>>> +             __func__, chap->qid, ret);
>>> +        goto out_free_psk;
>>> +    };
>>> +    dev_dbg(ctrl->device, "%s: generated digest %s\n",
>>> +         __func__, digest);
>>> +    tls_psk = nvme_auth_derive_tls_psk(chap->hash_id, psk, psk_len, 
>>> digest);
>>> +    if (IS_ERR(tls_psk)) {
>>> +        ret = PTR_ERR(tls_psk);
>>> +        dev_warn(ctrl->device,
>>> +             "%s: qid %d failed to derive TLS psk, error %d\n",
>>> +             __func__, chap->qid, ret);
>>> +        goto out_free_digest;
>>> +    };
>>> +
>>> +    tls_key = nvme_tls_psk_refresh(ctrl->opts->keyring, 
>>> ctrl->opts->host->nqn,
>>> +                       ctrl->opts->subsysnqn, chap->hash_id,
>>> +                       true, tls_psk, psk_len, digest);
>>> +    if (IS_ERR(tls_key)) {
>>> +        ret = PTR_ERR(tls_key);
>>> +        dev_warn(ctrl->device,
>>> +             "%s: qid %d failed to insert generated key, error %d\n",
>>> +             __func__, chap->qid, ret);
>>> +        tls_key = NULL;
>>> +        kfree_sensitive(tls_psk);
>>> +    }
>>> +    if (ctrl->opts->tls_key) {
>>> +        key_revoke(ctrl->opts->tls_key);
>>> +        key_put(ctrl->opts->tls_key);
>>> +    }
>>
>> Question, is this for the case where the user passes both tls_key and
>> concat? Is this something that we expect users to do? What is the
>> benefit?

Answer?




More information about the Linux-nvme mailing list