[PATCH 2/8] nvme-keyring: add 'dhchap' key type

Hannes Reinecke hare at suse.de
Mon Apr 6 23:18:49 PDT 2026


On 4/1/26 20:13, Chris Leech wrote:
> On Tue, Mar 17, 2026 at 02:00:57PM +0100, Hannes Reinecke wrote:
>> Add a 'dhchap' keytype to store DH-HMAC-CHAP secret keys.
>> Keys are stored with a 'user-type' compatible payload, such
>> that one can use 'user_read()' to access the raw contents
>> and the 'read()' callback to get the base64-encoded key
>> data in the DH-HMAC-CHAP secret representation.
>>
>> Signed-off-by: Hannes Reinecke <hare at kernel.org>
>> ---
>>   drivers/nvme/common/keyring.c | 216 ++++++++++++++++++++++++++++++++++
>>   1 file changed, 216 insertions(+)
>>
>> diff --git a/drivers/nvme/common/keyring.c b/drivers/nvme/common/keyring.c
>> index 32d16c53133b..f7e18df438e6 100644
>> --- a/drivers/nvme/common/keyring.c
>> +++ b/drivers/nvme/common/keyring.c
>> @@ -4,6 +4,9 @@
>>    */
> ...
>> +/**
>> + * nvme_dhchap_psk_preparse - prepare DH-HMAC-CHAP key data
>> + * @prep: preparsed payload of the key data
>> + *
>> + * Decode the DH-HMAC-CHAP key data passed in in @prep and
>> + * store the resulting binary data. The binary data includes
>> + * space for the CRC, the version, and the hmac identifier,
>> + * but the data length is just the key data without the CRC.
>> + * This allows the user to read the key data via the
>> + * 'user_read()' function. The additional 'version' ahd 'hmac'
>> + * data is used in the ->read() callback to generate the
>> + * base64 encoded key.
>> + */
>> +static int nvme_dhchap_psk_preparse(struct key_preparsed_payload *prep)
>> +{
>> +	struct user_key_payload *upayload;
>> +	size_t datalen = prep->datalen, keylen;
>> +	int ret;
>> +	u32 crc;
>> +	u8 version, hmac;
>> +
>> +	if (!prep->data) {
>> +		pr_debug("%s: Empty data", __func__);
>> +		prep->payload.data[0] = NULL;
>> +		prep->quotalen = 0;
>> +		return -EINVAL;
>> +	}
>> +
>> +	if (sscanf(prep->data, "DHHC-%01hhu:%02hhu:%*s",
>> +		   &version, &hmac) != 2) {
>> +		pr_debug("%s: invalid key data '%s'\n", __func__,
>> +			 (char *)prep->data);
>> +		prep->payload.data[0] = NULL;
>> +		prep->quotalen = 0;
>> +		return -EINVAL;
>> +	}
> 
> version should be verified to be the expected value of 1 here
> (or hardcoded to only accept 1 in the sscanf call like the repalced
> code removed in the next patch)
>   
Indeed, will be changing it.

>> +	/* skip header and final ':' character */
>> +	datalen -= 11;
>> +
>> +	/*
>> +	 * payload is < key | version | hmac >
>> +	 * base64 decode will always return less data
>> +	 * than the encoded data, so allocating the size
>> +	 * of the encoded data will be large enough.
>> +	 */
>> +	upayload = kzalloc(sizeof(*upayload) + datalen, GFP_KERNEL);
>> +	if (!upayload) {
>> +		prep->payload.data[0] = NULL;
>> +		prep->quotalen = 0;
>> +		return -ENOMEM;
>> +	}
>> +
>> +	/* decode the data */
>> +	prep->quotalen = keylen;
> 
> Uninitialized keylen is being used here to set quotelen.
> 
Ok.

>> +	prep->payload.data[0] = upayload;
>> +	ret = base64_decode(prep->data + 10, datalen, upayload->data,
>> +			    true, BASE64_STD);
>> +	if (ret < 0) {
>> +		pr_debug("%s: Failed to decode key %s\n",
>> +			 __func__, (char *)prep->data + 10);
>> +		return ret;
>> +	}
>> +	ret -= 4;
>> +	crc = ~crc32(~0, upayload->data, ret);
>> +	if (get_unaligned_le32(upayload->data + ret) != crc) {
>> +		pr_debug("%s: CRC mismatch for key\n", __func__);
>> +		/* CRC mismatch */
>> +		return -EKEYREJECTED;
>> +	}
>> +	/* append version and hmac to the payload */
>> +	upayload->data[ret + 4] = version;
>> +	upayload->data[ret + 5] = hmac;
>> +	upayload->datalen = ret;
>> +	return 0;
>> +}
>> +
>> +/**
>> + * nvme_dhchap_decoded_key_size - Size of the base64-decoded key
>> + * @size: size of the encoded key
>> + *
>> + * Returns the expected size of the key after base64 decoding.
>> + */
> 
> Isn't this the expected size after encoding, and not decoding?
> It's used before a call to base64_encode.
> 
Yeah, you are right.

>> +static inline int nvme_dhchap_decoded_key_size(int size)
>> +{
>> +	int keylen = -EINVAL;
>> +
>> +	switch (size) {
>> +	case 32:
>> +		keylen = 48;
>> +		break;
>> +	case 48:
>> +		keylen = 72;
>> +		break;
>> +	case 64:
>> +		keylen = 92;
>> +		break;
>> +	default:
>> +		break;
>> +	}
>> +	return keylen;
>> +}
> 
> Why don't these keylen numbers match BASE64_CHARS()?
> 
Good question. They could.

>> +/**
>> + * nvme_dhchap_psk_read - read callback for dhchap key types
>> + * @key: key to read from
>> + * @buffer: buffer for the key contents
>> + * @buflen: length of @buffer
>> + *
>> + * Formets the DH-HMAC-CHAP key in base64-encoded form as
> 
> spelling typo /Formets/Formats/
>
Ok, will fix it up.

Cheers,

Hannes
-- 
Dr. Hannes Reinecke                  Kernel Storage Architect
hare at suse.de                                +49 911 74053 688
SUSE Software Solutions GmbH, Frankenstr. 146, 90461 Nürnberg
HRB 36809 (AG Nürnberg), GF: I. Totev, A. McDonald, W. Knoblich



More information about the Linux-nvme mailing list