Commit 8628bf01 authored by Konrad Sztyber's avatar Konrad Sztyber Committed by Tomasz Zawadzki
Browse files

nvme/auth: parse DH-HMAC-CHAP key



For now, no key transformation is supported (i.e. key hash has to be set
to 00).

Signed-off-by: default avatarKonrad Sztyber <konrad.sztyber@intel.com>
Change-Id: I345d054cd8efa77ebf6dd6ef88860e3e9b4c7d8a
Reviewed-on: https://review.spdk.io/gerrit/c/spdk/spdk/+/21986


Tested-by: default avatarSPDK CI Jenkins <sys_sgci@intel.com>
Reviewed-by: default avatarJim Harris <jim.harris@samsung.com>
Reviewed-by: default avatarBen Walker <ben@nvidia.com>
Community-CI: Mellanox Build Bot
parent 3aa690b5
Loading
Loading
Loading
Loading
+94 −1
Original line number Diff line number Diff line
@@ -2,11 +2,16 @@
 * Copyright (c) 2024 Intel Corporation.  All rights reserved.
 */

#include "spdk/base64.h"
#include "spdk/crc32.h"
#include "spdk/endian.h"
#include "spdk/log.h"
#include "spdk/string.h"
#include "spdk/util.h"
#include "nvme_internal.h"

#define NVME_AUTH_DATA_SIZE		4096
#define NVME_AUTH_CHAP_KEY_MAX_SIZE	256

#define AUTH_DEBUGLOG(q, fmt, ...) \
	SPDK_DEBUGLOG(nvme_auth, "[%s:%s:%u] " fmt, (q)->ctrlr->trid.subnqn, \
@@ -69,6 +74,94 @@ nvme_auth_print_cpl(struct spdk_nvme_qpair *qpair, const char *msg)
		    status->cpl.status.sct, status->timed_out ? "true" : "false");
}

static int
nvme_auth_transform_key(struct spdk_key *key, int hash, const void *keyin, size_t keylen,
			void *out, size_t outlen)
{
	switch (hash) {
	case SPDK_NVMF_DHCHAP_HASH_NONE:
		if (keylen > outlen) {
			SPDK_ERRLOG("Key buffer too small: %zu < %zu (key=%s)\n", outlen, keylen,
				    spdk_key_get_name(key));
			return -ENOBUFS;
		}
		memcpy(out, keyin, keylen);
		return keylen;
	case SPDK_NVMF_DHCHAP_HASH_SHA256:
	case SPDK_NVMF_DHCHAP_HASH_SHA384:
	case SPDK_NVMF_DHCHAP_HASH_SHA512:
		SPDK_ERRLOG("Key transformation is not supported\n");
		return -EINVAL;
	default:
		SPDK_ERRLOG("Unsupported key hash: 0x%x (key=%s)\n", hash, spdk_key_get_name(key));
		return -EINVAL;
	}
}

int nvme_auth_get_key(struct spdk_key *key, void *buf, size_t buflen);

int
nvme_auth_get_key(struct spdk_key *key, void *buf, size_t buflen)
{
	char keystr[NVME_AUTH_CHAP_KEY_MAX_SIZE + 1] = {};
	char keyb64[NVME_AUTH_CHAP_KEY_MAX_SIZE] = {};
	char *tmp, *secret;
	int rc, hash;
	size_t keylen;

	rc = spdk_key_get_key(key, keystr, NVME_AUTH_CHAP_KEY_MAX_SIZE);
	if (rc < 0) {
		SPDK_ERRLOG("Failed to load key=%s: %s\n", spdk_key_get_name(key),
			    spdk_strerror(-rc));
		goto out;
	}

	rc = sscanf(keystr, "DHHC-1:%02x:", &hash);
	if (rc != 1) {
		SPDK_ERRLOG("Invalid key format (key=%s)\n", spdk_key_get_name(key));
		rc = -EINVAL;
		goto out;

	}
	/* Start at the first character after second ":" and remove the trailing ":" */
	secret = &keystr[10];
	tmp = strstr(secret, ":");
	if (!tmp) {
		SPDK_ERRLOG("Invalid key format (key=%s)\n", spdk_key_get_name(key));
		rc = -EINVAL;
		goto out;
	}

	*tmp = '\0';
	keylen = sizeof(keyb64);
	rc = spdk_base64_decode(keyb64, &keylen, secret);
	if (rc != 0) {
		SPDK_ERRLOG("Invalid key format (key=%s)\n", spdk_key_get_name(key));
		rc = -EINVAL;
		goto out;
	}
	/* Only 32B, 48B, and 64B keys are supported (+ 4B, as they're followed by a crc32) */
	if (keylen != 36 && keylen != 52 && keylen != 68) {
		SPDK_ERRLOG("Invalid key size=%zu (key=%s)\n", keylen, spdk_key_get_name(key));
		rc = -EINVAL;
		goto out;
	}

	keylen -= 4;
	if (~spdk_crc32_ieee_update(keyb64, keylen, ~0) != from_le32(&keyb64[keylen])) {
		SPDK_ERRLOG("Invalid key checksum (key=%s)\n", spdk_key_get_name(key));
		rc = -EINVAL;
		goto out;
	}

	rc = nvme_auth_transform_key(key, hash, keyb64, keylen, buf, buflen);
out:
	spdk_memset_s(keystr, sizeof(keystr), 0, sizeof(keystr));
	spdk_memset_s(keyb64, sizeof(keyb64), 0, sizeof(keyb64));

	return rc;
}

static int
nvme_auth_submit_request(struct spdk_nvme_qpair *qpair,
			 enum spdk_nvmf_fabric_cmd_types type, uint32_t len)