]> www.infradead.org Git - users/sagi/libnvme.git/commitdiff
linux: add nvme_import_tls_key()
authorHannes Reinecke <hare@suse.de>
Wed, 21 Feb 2024 06:57:16 +0000 (07:57 +0100)
committerDaniel Wagner <wagi@monom.org>
Thu, 7 Mar 2024 13:49:46 +0000 (14:49 +0100)
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 <hare@suse.de>
src/libnvme.map
src/nvme/linux.c
src/nvme/linux.h

index 2591bc648205fc5c460f6e43de45491e5b6f516a..bd9b46834a62be74aaac3582d959fa67e959d9dd 100644 (file)
@@ -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;
index f69856c39287ea0380b2bf888eda12e952672d3d..5438c1594ff94439a5b344c38dc8334f7c68c3d3 100644 (file)
@@ -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;
+}
index 1cb583e55d15512529999e524efe1cadad867838..bf64b7de824df78c02c3e50132f2427c7c683971 100644 (file)
@@ -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