From: Hannes Reinecke Date: Wed, 21 Feb 2024 06:57:16 +0000 (+0100) Subject: linux: add nvme_import_tls_key() X-Git-Url: https://www.infradead.org/git/?a=commitdiff_plain;h=cbd0fbd4c36fecc4e4ffe63831c55d424ff5e403;p=users%2Fsagi%2Flibnvme.git linux: add nvme_import_tls_key() Add a function to import a TLS key in the PSK interchange format as defined in the NVMe TCP transport specification. Signed-off-by: Hannes Reinecke --- diff --git a/src/libnvme.map b/src/libnvme.map index 2591bc64..bd9b4683 100644 --- a/src/libnvme.map +++ b/src/libnvme.map @@ -3,6 +3,7 @@ LIBNVME_1.9 { global: nvme_export_tls_key; nvme_get_logging_level; + nvme_import_tls_key; nvme_read_key; nvme_submit_passthru; nvme_submit_passthru64; diff --git a/src/nvme/linux.c b/src/nvme/linux.c index f69856c3..5438c159 100644 --- a/src/nvme/linux.c +++ b/src/nvme/linux.c @@ -1391,3 +1391,69 @@ char *nvme_export_tls_key(const unsigned char *key_data, int key_len) return encoded_key; } + +unsigned char *nvme_import_tls_key(const char *encoded_key, int *key_len, + unsigned int *hmac) +{ + unsigned char decoded_key[128], *key_data; + unsigned int crc = crc32(0L, NULL, 0); + unsigned int key_crc; + int err, decoded_len; + + if (sscanf(encoded_key, "NVMeTLSkey-1:%02x:*s", &err) != 1) { + errno = EINVAL; + return NULL; + } + switch (err) { + case 1: + if (strlen(encoded_key) != 65) { + errno = EINVAL; + return NULL; + } + break; + case 2: + if (strlen(encoded_key) != 89) { + errno = EINVAL; + return NULL; + } + break; + default: + errno = EINVAL; + return NULL; + } + + *hmac = err; + err = base64_decode(encoded_key + 16, strlen(encoded_key) - 17, + decoded_key); + if (err < 0) { + errno = ENOKEY; + return NULL; + } + decoded_len = err; + decoded_len -= 4; + if (decoded_len != 32 && decoded_len != 48) { + errno = ENOKEY; + 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); + if (key_crc != crc) { + nvme_msg(NULL, LOG_ERR, "CRC mismatch (key %08x, crc %08x)", + key_crc, crc); + errno = ENOKEY; + return NULL; + } + + key_data = malloc(decoded_len); + if (!key_data) { + errno = ENOMEM; + return NULL; + } + memcpy(key_data, decoded_key, decoded_len); + + *key_len = decoded_len; + return key_data; +} diff --git a/src/nvme/linux.h b/src/nvme/linux.h index 1cb583e5..bf64b7de 100644 --- a/src/nvme/linux.h +++ b/src/nvme/linux.h @@ -384,6 +384,21 @@ char *nvme_generate_tls_key_identity(const char *hostnqn, const char *subsysnqn, */ char *nvme_export_tls_key(const unsigned char *key_data, int key_len); +/** + * nvme_import_tls_key() - Import a TLS key + * @encoded_key: TLS key in PSK interchange format + * @key_len: Length of the resulting key data + * @hmac: HMAC algorithm + * + * Imports @key_data in the PSK Interchange format as defined in section + * 3.6.1.5 of the NVMe TCP Transport specification. + * + * Return: The raw data of the PSK or NULL with errno set on error. It is + * the responsibility of the caller to free the returned string. + */ +unsigned char *nvme_import_tls_key(const char *encoded_key, int *key_len, + unsigned int *hmac); + /** * nvme_submit_passthru - Low level ioctl wrapper for passthru commands * @fd: File descriptor of the nvme device