summaryrefslogtreecommitdiffstats
path: root/src/nvme/linux.c
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-08-05 08:35:48 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-08-05 08:35:48 +0000
commitfb4382cf6ceb11ce2c5781d14714e15e45022d03 (patch)
tree4d529e6152272fde35bc85955a300b4811f672ca /src/nvme/linux.c
parentReleasing debian version 1.9-1. (diff)
downloadlibnvme-fb4382cf6ceb11ce2c5781d14714e15e45022d03.tar.xz
libnvme-fb4382cf6ceb11ce2c5781d14714e15e45022d03.zip
Merging upstream version 1.10.
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'src/nvme/linux.c')
-rw-r--r--src/nvme/linux.c209
1 files changed, 134 insertions, 75 deletions
diff --git a/src/nvme/linux.c b/src/nvme/linux.c
index 25196fd..aff0544 100644
--- a/src/nvme/linux.c
+++ b/src/nvme/linux.c
@@ -18,7 +18,6 @@
#include <unistd.h>
#ifdef CONFIG_OPENSSL
-#include <openssl/engine.h>
#include <openssl/evp.h>
#include <openssl/hmac.h>
#include <openssl/kdf.h>
@@ -166,7 +165,7 @@ int nvme_get_telemetry_log(int fd, bool create, bool ctrl, bool rae, size_t max_
struct nvme_telemetry_log *telem;
enum nvme_cmd_get_log_lid lid;
- _cleanup_free_ void *log;
+ _cleanup_free_ void *log = NULL;
void *tmp;
int err;
size_t dalb;
@@ -296,8 +295,8 @@ int nvme_get_new_host_telemetry(int fd, struct nvme_telemetry_log **log,
int nvme_get_lba_status_log(int fd, bool rae, struct nvme_lba_status_log **log)
{
+ _cleanup_free_ struct nvme_lba_status_log *buf = NULL;
__u32 size;
- _cleanup_free_ struct nvme_lba_status_log *buf;
void *tmp;
int err;
struct nvme_get_log_args args = {
@@ -386,6 +385,16 @@ int nvme_namespace_detach_ctrls(int fd, __u32 nsid, __u16 num_ctrls,
NVME_DEFAULT_IOCTL_TIMEOUT);
}
+size_t nvme_get_ana_log_len_from_id_ctrl(const struct nvme_id_ctrl *id_ctrl,
+ bool rgo)
+{
+ __u32 nanagrpid = le32_to_cpu(id_ctrl->nanagrpid);
+ size_t size = sizeof(struct nvme_ana_log) +
+ nanagrpid * sizeof(struct nvme_ana_group_desc);
+
+ return rgo ? size : size + le32_to_cpu(id_ctrl->mnan) * sizeof(__le32);
+}
+
int nvme_get_ana_log_len(int fd, size_t *analen)
{
_cleanup_free_ struct nvme_id_ctrl *ctrl = NULL;
@@ -400,9 +409,7 @@ int nvme_get_ana_log_len(int fd, size_t *analen)
if (ret)
return ret;
- *analen = sizeof(struct nvme_ana_log) +
- le32_to_cpu(ctrl->nanagrpid) * sizeof(struct nvme_ana_group_desc) +
- le32_to_cpu(ctrl->mnan) * sizeof(__le32);
+ *analen = nvme_get_ana_log_len_from_id_ctrl(ctrl, false);
return 0;
}
@@ -544,22 +551,18 @@ static int derive_retained_key(int hmac, const char *hostnqn,
return -1;
}
-static int gen_tls_identity(const char *hostnqn, const char *subsysnqn,
- int version, int hmac, char *identity,
- unsigned char *retained, size_t key_len)
+static int derive_psk_digest(const char *hostnqn, const char *subsysnqn,
+ int version, int hmac,
+ unsigned char *retained, size_t key_len,
+ char *digest, size_t digest_len)
{
- if (version != 0) {
- nvme_msg(NULL, LOG_ERR, "NVMe TLS 2.0 is not supported; "
- "recompile with OpenSSL support.\n");
- errno = ENOTSUP;
- return -1;
- }
- sprintf(identity, "NVMe0R%02d %s %s",
- hmac, hostnqn, subsysnqn);
- return strlen(identity);
+ nvme_msg(NULL, LOG_ERR, "NVMe TLS 2.0 is not supported; "
+ "recompile with OpenSSL support.\n");
+ errno = ENOTSUP;
+ return -1;
}
-static int derive_tls_key(int hmac, const char *identity,
+static int derive_tls_key(int version, int hmac, const char *context,
unsigned char *retained,
unsigned char *psk, size_t key_len)
{
@@ -655,7 +658,7 @@ static int derive_retained_key(int hmac, const char *hostnqn,
return key_len;
}
-static int derive_tls_key(int hmac, const char *identity,
+static int derive_tls_key(int version, int hmac, const char *context,
unsigned char *retained,
unsigned char *psk, size_t key_len)
{
@@ -703,9 +706,20 @@ static int derive_tls_key(int hmac, const char *identity,
errno = ENOKEY;
return -1;
}
+ if (version == 1) {
+ char hash_str[4];
+
+ sprintf(hash_str, "%02d ", hmac);
+ if (EVP_PKEY_CTX_add1_hkdf_info(ctx,
+ (const unsigned char *)hash_str,
+ strlen(hash_str)) <= 0) {
+ errno = ENOKEY;
+ return -1;
+ }
+ }
if (EVP_PKEY_CTX_add1_hkdf_info(ctx,
- (const unsigned char *)identity,
- strlen(identity)) <= 0) {
+ (const unsigned char *)context,
+ strlen(context)) <= 0) {
errno = ENOKEY;
return -1;
}
@@ -731,9 +745,6 @@ int nvme_gen_dhchap_key(char *hostnqn, enum nvme_hmac_alg hmac,
_cleanup_hmac_ctx_ HMAC_CTX *hmac_ctx = NULL;
const EVP_MD *md;
- ENGINE_load_builtin_engines();
- ENGINE_register_all_complete();
-
hmac_ctx = HMAC_CTX_new();
if (!hmac_ctx) {
errno = ENOMEM;
@@ -788,28 +799,18 @@ int nvme_gen_dhchap_key(char *hostnqn, enum nvme_hmac_alg hmac,
return 0;
}
-static int gen_tls_identity(const char *hostnqn, const char *subsysnqn,
- int version, int hmac, char *identity,
- unsigned char *retained, size_t key_len)
+static int derive_psk_digest(const char *hostnqn, const char *subsysnqn,
+ int version, int hmac,
+ unsigned char *retained, size_t key_len,
+ char *digest, size_t digest_len)
{
static const char hmac_seed[] = "NVMe-over-Fabrics";
size_t hmac_len;
const EVP_MD *md = select_hmac(hmac, &hmac_len);
_cleanup_hmac_ctx_ HMAC_CTX *hmac_ctx = NULL;
_cleanup_free_ unsigned char *psk_ctx = NULL;
- _cleanup_free_ char *enc_ctx = NULL;
size_t len;
- if (version == 0) {
- sprintf(identity, "NVMe%01dR%02d %s %s",
- version, hmac, hostnqn, subsysnqn);
- return strlen(identity);
- }
- if (version > 1) {
- errno = EINVAL;
- return -1;
- }
-
hmac_ctx = HMAC_CTX_new();
if (!hmac_ctx) {
errno = ENOMEM;
@@ -856,17 +857,19 @@ static int gen_tls_identity(const char *hostnqn, const char *subsysnqn,
errno = ENOKEY;
return -1;
}
- enc_ctx = malloc(key_len * 2);
- memset(enc_ctx, 0, key_len * 2);
- len = base64_encode(psk_ctx, key_len, enc_ctx);
+ if (key_len * 2 > digest_len) {
+ errno = EINVAL;
+ return -1;
+ }
+ memset(digest, 0, digest_len);
+ len = base64_encode(psk_ctx, key_len, digest);
if (len < 0) {
errno = ENOKEY;
return len;
}
- sprintf(identity, "NVMe%01dR%02d %s %s %s",
- version, hmac, hostnqn, subsysnqn, enc_ctx);
- return strlen(identity);
+ return strlen(digest);
}
+
#endif /* !CONFIG_OPENSSL_1 */
#ifdef CONFIG_OPENSSL_3
@@ -961,9 +964,10 @@ int nvme_gen_dhchap_key(char *hostnqn, enum nvme_hmac_alg hmac,
return 0;
}
-static int gen_tls_identity(const char *hostnqn, const char *subsysnqn,
- int version, int hmac, char *identity,
- unsigned char *retained, size_t key_len)
+static int derive_psk_digest(const char *hostnqn, const char *subsysnqn,
+ int version, int hmac,
+ unsigned char *retained, size_t key_len,
+ char *digest, size_t digest_len)
{
static const char hmac_seed[] = "NVMe-over-Fabrics";
size_t hmac_len;
@@ -972,21 +976,10 @@ static int gen_tls_identity(const char *hostnqn, const char *subsysnqn,
_cleanup_evp_mac_ctx_ EVP_MAC_CTX *mac_ctx = NULL;
_cleanup_evp_mac_ EVP_MAC *mac = NULL;
char *progq = NULL;
- char *digest = NULL;
+ char *dig = NULL;
_cleanup_free_ unsigned char *psk_ctx = NULL;
- _cleanup_free_ char *enc_ctx = NULL;
size_t len;
- if (version == 0) {
- sprintf(identity, "NVMe%01dR%02d %s %s",
- version, hmac, hostnqn, subsysnqn);
- return strlen(identity);
- }
- if (version > 1) {
- errno = EINVAL;
- return -1;
- }
-
lib_ctx = OSSL_LIB_CTX_new();
if (!lib_ctx) {
errno = ENOMEM;
@@ -1005,19 +998,19 @@ static int gen_tls_identity(const char *hostnqn, const char *subsysnqn,
}
switch (hmac) {
case NVME_HMAC_ALG_SHA2_256:
- digest = OSSL_DIGEST_NAME_SHA2_256;
+ dig = OSSL_DIGEST_NAME_SHA2_256;
break;
case NVME_HMAC_ALG_SHA2_384:
- digest = OSSL_DIGEST_NAME_SHA2_384;
+ dig = OSSL_DIGEST_NAME_SHA2_384;
break;
default:
errno = EINVAL;
break;
}
- if (!digest)
+ if (!dig)
return -1;
*p++ = OSSL_PARAM_construct_utf8_string(OSSL_MAC_PARAM_DIGEST,
- digest, 0);
+ dig, 0);
*p = OSSL_PARAM_construct_end();
psk_ctx = malloc(key_len);
@@ -1061,18 +1054,38 @@ static int gen_tls_identity(const char *hostnqn, const char *subsysnqn,
errno = EMSGSIZE;
return -1;
}
- enc_ctx = malloc(hmac_len * 2);
- memset(enc_ctx, 0, hmac_len * 2);
- len = base64_encode(psk_ctx, hmac_len, enc_ctx);
+ if (hmac_len * 2 > digest_len) {
+ errno = EINVAL;
+ return -1;
+ }
+ memset(digest, 0, digest_len);
+ len = base64_encode(psk_ctx, hmac_len, digest);
if (len < 0) {
errno = ENOKEY;
return len;
}
+ return strlen(digest);
+}
+#endif /* !CONFIG_OPENSSL_3 */
+
+static int gen_tls_identity(const char *hostnqn, const char *subsysnqn,
+ int version, int hmac, char *digest,
+ char *identity)
+{
+ if (version == 0) {
+ sprintf(identity, "NVMe%01dR%02d %s %s",
+ version, hmac, hostnqn, subsysnqn);
+ return strlen(identity);
+ }
+ if (version > 1) {
+ errno = EINVAL;
+ return -1;
+ }
+
sprintf(identity, "NVMe%01dR%02d %s %s %s",
- version, hmac, hostnqn, subsysnqn, enc_ctx);
+ version, hmac, hostnqn, subsysnqn, digest);
return strlen(identity);
}
-#endif /* !CONFIG_OPENSSL_3 */
static int derive_nvme_keys(const char *hostnqn, const char *subsysnqn,
char *identity, int version,
@@ -1080,6 +1093,8 @@ static int derive_nvme_keys(const char *hostnqn, const char *subsysnqn,
unsigned char *psk, int key_len)
{
_cleanup_free_ unsigned char *retained = NULL;
+ _cleanup_free_ char *digest = NULL;
+ char *context = identity;
int ret = -1;
if (!hostnqn || !subsysnqn || !identity || !psk) {
@@ -1095,11 +1110,28 @@ static int derive_nvme_keys(const char *hostnqn, const char *subsysnqn,
ret = derive_retained_key(hmac, hostnqn, configured, retained, key_len);
if (ret < 0)
return ret;
+
+ if (version == 1) {
+ size_t digest_len = 2 * key_len;
+
+ digest = malloc(digest_len);
+ if (!digest) {
+ errno = ENOMEM;
+ return -1;
+ }
+ ret = derive_psk_digest(hostnqn, subsysnqn, version, hmac,
+ retained, key_len,
+ digest, digest_len);
+ if (ret)
+ return ret;
+ context = digest;
+ }
ret = gen_tls_identity(hostnqn, subsysnqn, version, hmac,
- identity, retained, key_len);
+ digest, identity);
if (ret < 0)
return ret;
- return derive_tls_key(hmac, identity, retained, psk, key_len);
+ return derive_tls_key(version, hmac, context, retained,
+ psk, key_len);
}
static size_t nvme_identity_len(int hmac, int version, const char *hostnqn,
@@ -1355,6 +1387,24 @@ long nvme_insert_tls_key_versioned(const char *keyring, const char *key_type,
return key;
}
+long nvme_revoke_tls_key(const char *keyring, const char *key_type,
+ const char *identity)
+{
+ key_serial_t keyring_id;
+ long key;
+
+ keyring_id = nvme_lookup_keyring(keyring);
+ if (keyring_id == 0) {
+ errno = ENOKEY;
+ return 0;
+ }
+
+ key = keyctl_search(keyring_id, key_type, identity, 0);
+ if (key < 0)
+ return -1;
+
+ return keyctl_revoke(key);
+}
#else
long nvme_lookup_keyring(const char *keyring)
{
@@ -1419,6 +1469,15 @@ long nvme_insert_tls_key_versioned(const char *keyring, const char *key_type,
errno = ENOTSUP;
return -1;
}
+
+long nvme_revoke_tls_key(const char *keyring, const char *key_type,
+ const char *identity)
+{
+ nvme_msg(NULL, LOG_ERR, "key operations not supported; "
+ "recompile with keyutils support.\n");
+ errno = ENOTSUP;
+ return -1;
+}
#endif
long nvme_insert_tls_key(const char *keyring, const char *key_type,
@@ -1513,10 +1572,10 @@ unsigned char *nvme_import_tls_key(const char *encoded_key, int *key_len,
return NULL;
}
crc = crc32(crc, decoded_key, decoded_len);
- key_crc = ((u_int32_t)decoded_key[decoded_len]) |
- ((u_int32_t)decoded_key[decoded_len + 1] << 8) |
- ((u_int32_t)decoded_key[decoded_len + 2] << 16) |
- ((u_int32_t)decoded_key[decoded_len + 3] << 24);
+ key_crc = ((uint32_t)decoded_key[decoded_len]) |
+ ((uint32_t)decoded_key[decoded_len + 1] << 8) |
+ ((uint32_t)decoded_key[decoded_len + 2] << 16) |
+ ((uint32_t)decoded_key[decoded_len + 3] << 24);
if (key_crc != crc) {
nvme_msg(NULL, LOG_ERR, "CRC mismatch (key %08x, crc %08x)",
key_crc, crc);