Commit e036416b authored by Krzysztof Karas's avatar Krzysztof Karas Committed by Konrad Sztyber
Browse files

nvme_tcp: generate TLS PSK



Use retained psk to generate TLS PSK.

Change-Id: Ief475e92a124f91bd5eafba67d0cdaa2f411788c
Signed-off-by: default avatarKrzysztof Karas <krzysztof.karas@intel.com>
Reviewed-on: https://review.spdk.io/gerrit/c/spdk/spdk/+/16037


Reviewed-by: default avatarJim Harris <james.r.harris@intel.com>
Tested-by: default avatarSPDK CI Jenkins <sys_sgci@intel.com>
Reviewed-by: default avatarKonrad Sztyber <konrad.sztyber@intel.com>
Community-CI: Mellanox Build Bot
parent 68577d33
Loading
Loading
Loading
Loading
+80 −0
Original line number Diff line number Diff line
@@ -683,4 +683,84 @@ end:
	return rc;
}

static inline int
nvme_tcp_derive_tls_psk(const uint8_t *psk_in, uint64_t psk_in_len, const char *psk_identity,
			uint8_t *psk_out, uint64_t psk_out_size)
{
	EVP_PKEY_CTX *ctx;
	uint64_t sha256_digest_len = SHA256_DIGEST_LENGTH;
	char hkdf_info[NVME_TCP_HKDF_INFO_MAX_LEN] = {};
	const char *label = "tls13 nvme-tls-psk";
	size_t pos, labellen, idlen;
	int rc, hkdf_info_size;

	labellen = strlen(label);
	idlen = strlen(psk_identity);
	if (idlen > UINT8_MAX) {
		SPDK_ERRLOG("Invalid PSK ID: too long\n");
		return -1;
	}

	*(uint16_t *)&hkdf_info[0] = htons(psk_in_len);
	pos = sizeof(uint16_t);
	hkdf_info[pos] = (uint8_t)labellen;
	pos += sizeof(uint8_t);
	memcpy(&hkdf_info[pos], label, labellen);
	pos += labellen;
	hkdf_info[pos] = (uint8_t)idlen;
	pos += sizeof(uint8_t);
	memcpy(&hkdf_info[pos], psk_identity, idlen);
	pos += idlen;
	hkdf_info_size = pos;

	if (sha256_digest_len > psk_out_size) {
		SPDK_ERRLOG("Insufficient buffer size for out key!\n");
		return -1;
	}

	ctx = EVP_PKEY_CTX_new_id(EVP_PKEY_HKDF, NULL);
	if (!ctx) {
		SPDK_ERRLOG("Unable to initialize EVP_PKEY_CTX!\n");
		return -1;
	}

	if (EVP_PKEY_derive_init(ctx) != 1) {
		SPDK_ERRLOG("Unable to initialize key derivation ctx for HKDF!\n");
		rc = -ENOMEM;
		goto end;
	}
	if (EVP_PKEY_CTX_set_hkdf_md(ctx, EVP_sha256()) != 1) {
		SPDK_ERRLOG("Unable to set SHA256 method for HKDF!\n");
		rc = -EOPNOTSUPP;
		goto end;
	}
	/* PSK should already be in retained form, so we do not need to unhexlify it here. */
	if (EVP_PKEY_CTX_set1_hkdf_key(ctx, psk_in, psk_in_len) != 1) {
		SPDK_ERRLOG("Unable to set PSK key for HKDF!\n");
		rc = -ENOBUFS;
		goto end;
	}
	if (EVP_PKEY_CTX_add1_hkdf_info(ctx, hkdf_info, hkdf_info_size) != 1) {
		SPDK_ERRLOG("Unable to set info label for HKDF!\n");
		rc = -ENOBUFS;
		goto end;
	}
	if (EVP_PKEY_CTX_set1_hkdf_salt(ctx, NULL, 0) != 1) {
		SPDK_ERRLOG("Unable to set salt for HKDF!\n");
		rc = -EINVAL;
		goto end;
	}
	if (EVP_PKEY_derive(ctx, psk_out, &sha256_digest_len) != 1) {
		SPDK_ERRLOG("Unable to derive the PSK key!\n");
		rc = -EINVAL;
		goto end;
	}

	rc = sha256_digest_len;

end:
	EVP_PKEY_CTX_free(ctx);
	return rc;
}

#endif /* SPDK_INTERNAL_NVME_TCP_H */
+11 −2
Original line number Diff line number Diff line
@@ -2148,6 +2148,7 @@ static int
nvme_tcp_generate_tls_credentials(struct nvme_tcp_ctrlr *tctrlr)
{
	int rc;
	uint8_t psk_retained[SPDK_TLS_PSK_MAX_LEN] = {};

	assert(tctrlr != NULL);

@@ -2158,12 +2159,20 @@ nvme_tcp_generate_tls_credentials(struct nvme_tcp_ctrlr *tctrlr)
		return -EINVAL;
	}

	rc = nvme_tcp_derive_retained_psk(tctrlr->ctrlr.opts.psk, tctrlr->ctrlr.opts.hostnqn, tctrlr->psk,
					  sizeof(tctrlr->psk));
	rc = nvme_tcp_derive_retained_psk(tctrlr->ctrlr.opts.psk, tctrlr->ctrlr.opts.hostnqn, psk_retained,
					  sizeof(psk_retained));
	if (rc < 0) {
		SPDK_ERRLOG("Unable to derive retained PSK!\n");
		return -EINVAL;
	}

	rc = nvme_tcp_derive_tls_psk(psk_retained, rc, tctrlr->psk_identity, tctrlr->psk,
				     sizeof(tctrlr->psk));
	if (rc < 0) {
		SPDK_ERRLOG("Could not generate TLS PSK!\n");
		return rc;
	}

	tctrlr->psk_size = rc;

	return 0;
+9 −2
Original line number Diff line number Diff line
@@ -817,6 +817,7 @@ tcp_sock_get_key(uint8_t *out, int out_len, const char **cipher, const char *psk
	struct tcp_psk_entry *entry;
	struct spdk_nvmf_tcp_transport *ttransport = get_key_ctx;
	size_t psk_len;
	int rc;

	*cipher = NULL;

@@ -831,8 +832,14 @@ tcp_sock_get_key(uint8_t *out, int out_len, const char **cipher, const char *psk
				    out_len, psk_len);
			return -ENOBUFS;
		}
		memcpy(out, entry->psk, psk_len);
		return psk_len;

		/* Convert PSK to the TLS PSK format. */
		rc = nvme_tcp_derive_tls_psk(entry->psk, psk_len, psk_identity, out, out_len);
		if (rc < 0) {
			SPDK_ERRLOG("Could not generate TLS PSK\n");
		}

		return rc;
	}

	SPDK_ERRLOG("Could not find PSK for identity: %s\n", psk_identity);
+20 −0
Original line number Diff line number Diff line
@@ -1378,6 +1378,25 @@ test_nvmf_tcp_tls_generate_retained_psk(void)
					       sizeof(too_small_psk_retained)) < 0);
}

static void
test_nvmf_tcp_tls_generate_tls_psk(void)
{
	const char psk_id_reference[] = {"NVMe0R01 nqn.2016-06.io.spdk:host1 nqn.2016-06.io.spdk:cnode1"};
	const char hostnqn[] = {"nqn.2016-06.io.spdk:host1"};
	const char psk_reference[] = {"1234567890ABCDEF"};
	uint8_t psk_retained[SPDK_TLS_PSK_MAX_LEN] = {};
	uint8_t too_small_psk_tls[5] = {};
	int retained_size;

	retained_size = nvme_tcp_derive_retained_psk(psk_reference, hostnqn, psk_retained,
			SPDK_TLS_PSK_MAX_LEN);
	CU_ASSERT(retained_size > 0);

	/* Make sure that passing buffer insufficient in size errors out the function. */
	CU_ASSERT(nvme_tcp_derive_tls_psk(psk_retained, retained_size, psk_id_reference,
					  too_small_psk_tls, sizeof(too_small_psk_tls)) < 0);
}

int
main(int argc, char **argv)
{
@@ -1405,6 +1424,7 @@ main(int argc, char **argv)
	CU_ADD_TEST(suite, test_nvmf_tcp_tls_add_remove_credentials);
	CU_ADD_TEST(suite, test_nvmf_tcp_tls_generate_psk_id);
	CU_ADD_TEST(suite, test_nvmf_tcp_tls_generate_retained_psk);
	CU_ADD_TEST(suite, test_nvmf_tcp_tls_generate_tls_psk);

	CU_basic_set_mode(CU_BRM_VERBOSE);
	CU_basic_run_tests();